[vm] Remove external strings

This change removes support for external strings from the VM along with
Dart_NewExternalLatin1String, Dart_NewExternalUTF16String and
Dart_IsExternalString Dart C API functions.

External strings are not used by the VM nor any known embedder, but
Dart VM was paying the maintenance and performance price for
the external string implementation classes.

TEST=ci

Change-Id: I094cd2d2b7ec0840e9f09e1ca9e5a7acd4e78c28
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/358760
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov 2024-03-20 20:08:13 +00:00 committed by Commit Queue
parent 2d1c691625
commit 17d6ba15b6
64 changed files with 513 additions and 2128 deletions

View file

@ -124,6 +124,7 @@ advantage of these improvements, set your package's
[#53785]: https://github.com/dart-lang/sdk/issues/53785
### Dart Runtime
- Dart VM flags and options can now be provided to any executable
generated using `dart compile exe` via the `DART_VM_OPTIONS` environment
variable. `DART_VM_OPTIONS` should be set to a list of comma-separated flags
@ -137,6 +138,10 @@ advantage of these improvements, set your package's
DART_VM_OPTIONS=--random_seed=42,--verbose_gc
```
- Dart VM no longer supports external strings: `Dart_IsExternalString`,
`Dart_NewExternalLatin1String` and `Dart_NewExternalUTF16String` functions are
removed from Dart C API.
### Tools
#### DevTools

View file

@ -62,8 +62,6 @@ final tests = <IsolateTest>[
case {
'_oneByteFunction': {'type': '@Function'},
'_twoByteFunction': {'type': '@Function'},
'_externalOneByteFunction': {'type': '@Function'},
'_externalTwoByteFunction': {'type': '@Function'},
}) {
// Running with compiled regexp.
} else {

View file

@ -1926,7 +1926,6 @@ DART_EXPORT bool Dart_IsDouble(Dart_Handle object);
DART_EXPORT bool Dart_IsBoolean(Dart_Handle object);
DART_EXPORT bool Dart_IsString(Dart_Handle object);
DART_EXPORT bool Dart_IsStringLatin1(Dart_Handle object); /* (ISO-8859-1) */
DART_EXPORT bool Dart_IsExternalString(Dart_Handle object);
DART_EXPORT bool Dart_IsList(Dart_Handle object);
DART_EXPORT bool Dart_IsMap(Dart_Handle object);
DART_EXPORT bool Dart_IsLibrary(Dart_Handle object);
@ -2293,48 +2292,6 @@ DART_EXPORT Dart_Handle Dart_NewStringFromUTF16(const uint16_t* utf16_array,
DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const int32_t* utf32_array,
intptr_t length);
/**
* Returns a String which references an external array of
* Latin-1 (ISO-8859-1) encoded characters.
*
* \param latin1_array Array of Latin-1 encoded characters. This must not move.
* \param length The length of the characters array.
* \param peer An external pointer to associate with this string.
* \param external_allocation_size The number of externally allocated
* bytes for peer. Used to inform the garbage collector.
* \param callback A callback to be called when this string is finalized.
*
* \return The String object if no error occurs. Otherwise returns
* an error handle.
*/
DART_EXPORT Dart_Handle
Dart_NewExternalLatin1String(const uint8_t* latin1_array,
intptr_t length,
void* peer,
intptr_t external_allocation_size,
Dart_HandleFinalizer callback);
/**
* Returns a String which references an external array of UTF-16 encoded
* characters.
*
* \param utf16_array An array of UTF-16 encoded characters. This must not move.
* \param length The length of the characters array.
* \param peer An external pointer to associate with this string.
* \param external_allocation_size The number of externally allocated
* bytes for peer. Used to inform the garbage collector.
* \param callback A callback to be called when this string is finalized.
*
* \return The String object if no error occurs. Otherwise returns
* an error handle.
*/
DART_EXPORT Dart_Handle
Dart_NewExternalUTF16String(const uint16_t* utf16_array,
intptr_t length,
void* peer,
intptr_t external_allocation_size,
Dart_HandleFinalizer callback);
/**
* Gets the C string representation of a String.
* (It is a sequence of UTF-8 encoded values with a '\0' termination.)

View file

@ -104,19 +104,13 @@ DEFINE_NATIVE_ENTRY(StringBase_substringUnchecked, 0, 3) {
static uint16_t CharacterLimit(const String& string,
intptr_t start,
intptr_t end) {
ASSERT(string.IsTwoByteString() || string.IsExternalTwoByteString());
ASSERT(string.IsTwoByteString());
// Maybe do loop unrolling, and handle two uint16_t in a single uint32_t
// operation.
NoSafepointScope no_safepoint;
uint16_t result = 0;
if (string.IsTwoByteString()) {
for (intptr_t i = start; i < end; i++) {
result |= TwoByteString::CharAt(string, i);
}
} else {
for (intptr_t i = start; i < end; i++) {
result |= ExternalTwoByteString::CharAt(string, i);
}
for (intptr_t i = start; i < end; i++) {
result |= TwoByteString::CharAt(string, i);
}
return result;
}
@ -180,7 +174,7 @@ DEFINE_NATIVE_ENTRY(StringBase_joinReplaceAllResult, 0, 4) {
if (is_onebyte) {
// If any of the base string slices are not one-byte, the result will be
// a two-byte string.
if (!base.IsOneByteString() && !base.IsExternalOneByteString()) {
if (!base.IsOneByteString()) {
is_onebyte = CheckSlicesOneByte(base, matches, len);
}
}

View file

@ -324,11 +324,6 @@ static void ContentsFinalizer(void* isolate_callback_data, void* peer) {
delete[] data;
}
static void FilenameFinalizer(void* isolate_callback_data, void* peer) {
char* filename = reinterpret_cast<char*>(peer);
delete[] filename;
}
#endif
DEFINE_NATIVE_ENTRY(VMService_DecodeAssets, 0, 1) {
@ -365,9 +360,8 @@ DEFINE_NATIVE_ENTRY(VMService_DecodeAssets, 0, 1) {
uint8_t* contents = archive.NextContent();
intptr_t contents_length = archive.NextContentLength();
Dart_Handle dart_filename = Dart_NewExternalLatin1String(
reinterpret_cast<uint8_t*>(filename), filename_length, filename,
filename_length, FilenameFinalizer);
Dart_Handle dart_filename = Dart_NewStringFromUTF8(
reinterpret_cast<uint8_t*>(filename), filename_length);
ASSERT(!Dart_IsError(dart_filename));
Dart_Handle dart_contents = Dart_NewExternalTypedDataWithFinalizer(

View file

@ -442,14 +442,6 @@ class InstanceViewElement extends CustomElement implements Renderable {
if (_instance.twoByteFunction != null) {
members.add(member('twoByteFunction', _instance.twoByteFunction));
}
if (_instance.externalOneByteFunction != null) {
members.add(member(
'externalOneByteFunction', _instance.externalOneByteFunction));
}
if (_instance.externalTwoByteFunction != null) {
members.add(member(
'externalTwoByteFunction', _instance.externalTwoByteFunction));
}
if (_instance.oneByteBytecode != null) {
members.add(member('oneByteBytecode', _instance.oneByteBytecode));
}

View file

@ -449,18 +449,6 @@ abstract class Instance extends Object implements InstanceRef {
/// RegExp
FunctionRef? get twoByteFunction;
/// [optional]
///
/// Provided for instance kinds:
/// RegExp
FunctionRef? get externalOneByteFunction;
/// [optional]
///
/// Provided for instance kinds:
/// RegExp
FunctionRef? get externalTwoByteFunction;
/// [optional]
///
/// Provided for instance kinds:

View file

@ -2896,8 +2896,6 @@ class Instance extends HeapObject implements M.Instance {
Breakpoint? activationBreakpoint; // If a Closure.
ServiceFunction? oneByteFunction; // If a RegExp.
ServiceFunction? twoByteFunction; // If a RegExp.
ServiceFunction? externalOneByteFunction; // If a RegExp.
ServiceFunction? externalTwoByteFunction; // If a RegExp.
Instance? oneByteBytecode; // If a RegExp.
Instance? twoByteBytecode; // If a RegExp.
bool? isCaseSensitive; // If a RegExp.
@ -2984,10 +2982,6 @@ class Instance extends HeapObject implements M.Instance {
bool isCompiled = map['_oneByteFunction'] is ServiceFunction;
oneByteFunction = isCompiled ? map['_oneByteFunction'] : null;
twoByteFunction = isCompiled ? map['_twoByteFunction'] : null;
externalOneByteFunction =
isCompiled ? map['_externalOneByteFunction'] : null;
externalTwoByteFunction =
isCompiled ? map['_externalTwoByteFunction'] : null;
oneByteBytecode = map['_oneByteBytecode'];
twoByteBytecode = map['_twoByteBytecode'];

View file

@ -51,10 +51,6 @@ var tests = <IsolateTest>[
expect(f1 is ServiceFunction, isTrue);
var f2 = await regex.twoByteFunction!.load();
expect(f2 is ServiceFunction, isTrue);
var f3 = await regex.externalOneByteFunction!.load();
expect(f3 is ServiceFunction, isTrue);
var f4 = await regex.externalTwoByteFunction!.load();
expect(f4 is ServiceFunction, isTrue);
}
}
];

View file

@ -168,7 +168,6 @@ main() {
"Dart_IsCompilationError",
"Dart_IsDouble",
"Dart_IsError",
"Dart_IsExternalString",
"Dart_IsFatalError",
"Dart_IsFunction",
"Dart_IsFuture",
@ -238,10 +237,8 @@ main() {
"Dart_NewByteBuffer",
"Dart_NewCompilationError",
"Dart_NewDouble",
"Dart_NewExternalLatin1String",
"Dart_NewExternalTypedData",
"Dart_NewExternalTypedDataWithFinalizer",
"Dart_NewExternalUTF16String",
"Dart_NewFinalizableHandle",
"Dart_NewInteger",
"Dart_NewIntegerFromHexCString",

View file

@ -205,47 +205,6 @@ void benchmark(int count) {
benchmark->set_score(elapsed_time);
}
static void NoopFinalizer(void* isolate_callback_data, void* peer) {}
//
// Measure time accessing internal and external strings.
//
BENCHMARK(DartStringAccess) {
const int kNumIterations = 10000000;
Timer timer;
timer.Start();
Dart_EnterScope();
// Create strings.
uint8_t data8[] = {'o', 'n', 'e', 0xFF};
int external_peer_data = 123;
intptr_t char_size;
intptr_t str_len;
Dart_Handle external_string = Dart_NewExternalLatin1String(
data8, ARRAY_SIZE(data8), &external_peer_data, sizeof(data8),
NoopFinalizer);
Dart_Handle internal_string = NewString("two");
// Run benchmark.
for (int64_t i = 0; i < kNumIterations; i++) {
EXPECT(Dart_IsString(internal_string));
EXPECT(!Dart_IsExternalString(internal_string));
EXPECT_VALID(external_string);
EXPECT(Dart_IsExternalString(external_string));
void* external_peer = nullptr;
EXPECT_VALID(Dart_StringGetProperties(external_string, &char_size, &str_len,
&external_peer));
EXPECT_EQ(1, char_size);
EXPECT_EQ(4, str_len);
EXPECT_EQ(&external_peer_data, external_peer);
}
Dart_ExitScope();
timer.Stop();
int64_t elapsed_time = timer.TotalElapsedTime();
benchmark->set_score(elapsed_time);
}
static void vmservice_resolver(Dart_NativeArguments args) {}
static Dart_NativeFunction NativeResolver(Dart_Handle name,

View file

@ -255,10 +255,6 @@ void ClassFinalizer::VerifyBootstrapClasses() {
ASSERT_EQUAL(OneByteString::InstanceSize(), cls.host_instance_size());
cls = object_store->two_byte_string_class();
ASSERT_EQUAL(TwoByteString::InstanceSize(), cls.host_instance_size());
cls = object_store->external_one_byte_string_class();
ASSERT_EQUAL(ExternalOneByteString::InstanceSize(), cls.host_instance_size());
cls = object_store->external_two_byte_string_class();
ASSERT_EQUAL(ExternalTwoByteString::InstanceSize(), cls.host_instance_size());
cls = object_store->double_class();
ASSERT_EQUAL(Double::InstanceSize(), cls.host_instance_size());
cls = object_store->bool_class();

View file

@ -132,9 +132,7 @@ static constexpr intptr_t kClassIdTagMax = (1 << 20) - 1;
#define CLASS_LIST_STRINGS(V) \
V(String) \
V(OneByteString) \
V(TwoByteString) \
V(ExternalOneByteString) \
V(ExternalTwoByteString)
V(TwoByteString)
#define CLASS_LIST_TYPED_DATA(V) \
V(Int8Array) \
@ -274,7 +272,6 @@ bool IsNumberClassId(intptr_t index);
bool IsIntegerClassId(intptr_t index);
bool IsStringClassId(intptr_t index);
bool IsOneByteStringClassId(intptr_t index);
bool IsExternalStringClassId(intptr_t index);
bool IsBuiltinListClassId(intptr_t index);
bool IsTypeClassId(intptr_t index);
bool IsTypedDataBaseClassId(intptr_t index);
@ -348,21 +345,14 @@ inline bool IsIntegerClassId(intptr_t index) {
// Make sure this check is updated when new StringCid types are added.
COMPILE_ASSERT(kOneByteStringCid == kStringCid + 1 &&
kTwoByteStringCid == kStringCid + 2 &&
kExternalOneByteStringCid == kStringCid + 3 &&
kExternalTwoByteStringCid == kStringCid + 4);
kTwoByteStringCid == kStringCid + 2);
inline bool IsStringClassId(intptr_t index) {
return (index >= kStringCid && index <= kExternalTwoByteStringCid);
return (index >= kStringCid && index <= kTwoByteStringCid);
}
inline bool IsOneByteStringClassId(intptr_t index) {
return (index == kOneByteStringCid || index == kExternalOneByteStringCid);
}
inline bool IsExternalStringClassId(intptr_t index) {
return (index == kExternalOneByteStringCid ||
index == kExternalTwoByteStringCid);
return (index == kOneByteStringCid);
}
inline bool IsArrayClassId(intptr_t index) {

View file

@ -975,7 +975,7 @@ static void JumpIfString(Assembler* assembler,
Register cid,
Register tmp,
Label* target) {
assembler->RangeCheck(cid, tmp, kOneByteStringCid, kExternalTwoByteStringCid,
assembler->RangeCheck(cid, tmp, kOneByteStringCid, kTwoByteStringCid,
Assembler::kIfInRange, target);
}
@ -983,7 +983,7 @@ static void JumpIfNotString(Assembler* assembler,
Register cid,
Register tmp,
Label* target) {
assembler->RangeCheck(cid, tmp, kOneByteStringCid, kExternalTwoByteStringCid,
assembler->RangeCheck(cid, tmp, kOneByteStringCid, kTwoByteStringCid,
Assembler::kIfNotInRange, target);
}

View file

@ -1131,7 +1131,7 @@ static void JumpIfString(Assembler* assembler,
Register cid,
Register tmp,
Label* target) {
assembler->RangeCheck(cid, tmp, kOneByteStringCid, kExternalTwoByteStringCid,
assembler->RangeCheck(cid, tmp, kOneByteStringCid, kTwoByteStringCid,
Assembler::kIfInRange, target);
}
@ -1139,7 +1139,7 @@ static void JumpIfNotString(Assembler* assembler,
Register cid,
Register tmp,
Label* target) {
assembler->RangeCheck(cid, tmp, kOneByteStringCid, kExternalTwoByteStringCid,
assembler->RangeCheck(cid, tmp, kOneByteStringCid, kTwoByteStringCid,
Assembler::kIfNotInRange, target);
}

View file

@ -1100,15 +1100,13 @@ static void JumpIfNotInteger(Assembler* assembler,
}
static void JumpIfString(Assembler* assembler, Register cid, Label* target) {
assembler->RangeCheck(cid, kNoRegister, kOneByteStringCid,
kExternalTwoByteStringCid, Assembler::kIfInRange,
target);
assembler->RangeCheck(cid, kNoRegister, kOneByteStringCid, kTwoByteStringCid,
Assembler::kIfInRange, target);
}
static void JumpIfNotString(Assembler* assembler, Register cid, Label* target) {
assembler->RangeCheck(cid, kNoRegister, kOneByteStringCid,
kExternalTwoByteStringCid, Assembler::kIfNotInRange,
target);
assembler->RangeCheck(cid, kNoRegister, kOneByteStringCid, kTwoByteStringCid,
Assembler::kIfNotInRange, target);
}
static void JumpIfNotList(Assembler* assembler, Register cid, Label* target) {

View file

@ -1161,7 +1161,7 @@ static void JumpIfString(Assembler* assembler,
Register cid,
Register tmp,
Label* target) {
assembler->RangeCheck(cid, tmp, kOneByteStringCid, kExternalTwoByteStringCid,
assembler->RangeCheck(cid, tmp, kOneByteStringCid, kTwoByteStringCid,
Assembler::kIfInRange, target);
}
@ -1169,7 +1169,7 @@ static void JumpIfNotString(Assembler* assembler,
Register cid,
Register tmp,
Label* target) {
assembler->RangeCheck(cid, tmp, kOneByteStringCid, kExternalTwoByteStringCid,
assembler->RangeCheck(cid, tmp, kOneByteStringCid, kTwoByteStringCid,
Assembler::kIfNotInRange, target);
}

View file

@ -1002,15 +1002,13 @@ static void JumpIfNotInteger(Assembler* assembler,
}
static void JumpIfString(Assembler* assembler, Register cid, Label* target) {
assembler->RangeCheck(cid, kNoRegister, kOneByteStringCid,
kExternalTwoByteStringCid, Assembler::kIfInRange,
target);
assembler->RangeCheck(cid, kNoRegister, kOneByteStringCid, kTwoByteStringCid,
Assembler::kIfInRange, target);
}
static void JumpIfNotString(Assembler* assembler, Register cid, Label* target) {
assembler->RangeCheck(cid, kNoRegister, kOneByteStringCid,
kExternalTwoByteStringCid, Assembler::kIfNotInRange,
target);
assembler->RangeCheck(cid, kNoRegister, kOneByteStringCid, kTwoByteStringCid,
Assembler::kIfNotInRange, target);
}
static void JumpIfNotList(Assembler* assembler, Register cid, Label* target) {

View file

@ -1569,8 +1569,6 @@ void FlowGraphCompiler::GenerateStringTypeCheck(
GrowableArray<intptr_t> args;
args.Add(kOneByteStringCid);
args.Add(kTwoByteStringCid);
args.Add(kExternalOneByteStringCid);
args.Add(kExternalTwoByteStringCid);
CheckClassIds(class_id_reg, args, is_instance_lbl, is_not_instance_lbl);
}

View file

@ -6754,7 +6754,6 @@ static AlignmentType StrengthenAlignment(intptr_t cid,
case kExternalTypedDataUint8ArrayCid:
case kExternalTypedDataUint8ClampedArrayCid:
case kOneByteStringCid:
case kExternalOneByteStringCid:
// Don't need to worry about alignment for accessing bytes.
return kAlignedAccess;
case kTypedDataFloat64x2ArrayCid:

View file

@ -3305,8 +3305,6 @@ class MemoryCopyInstr : public TemplateInstruction<5, NoThrow> {
switch (array_cid) {
case kOneByteStringCid:
case kTwoByteStringCid:
case kExternalOneByteStringCid:
case kExternalTwoByteStringCid:
return true;
default:
return false;
@ -8721,7 +8719,7 @@ bool Definition::IsInt64Definition() {
}
// Calls into the runtime and performs a case-insensitive comparison of the
// UTF16 strings (i.e. TwoByteString or ExternalTwoByteString) located at
// UTF16 strings (i.e. TwoByteString) located at
// str[lhs_index:lhs_index + length] and str[rhs_index:rhs_index + length].
// Depending on [handle_surrogates], we will treat the strings as either
// UCS2 (no surrogate handling) or UTF16 (surrogates handled appropriately).
@ -8735,7 +8733,7 @@ class CaseInsensitiveCompareInstr
bool handle_surrogates,
intptr_t cid)
: handle_surrogates_(handle_surrogates), cid_(cid) {
ASSERT(cid == kTwoByteStringCid || cid == kExternalTwoByteStringCid);
ASSERT(cid == kTwoByteStringCid);
ASSERT(index_scale() == 2);
SetInputAt(0, str);
SetInputAt(1, lhs_index);
@ -8749,7 +8747,6 @@ class CaseInsensitiveCompareInstr
Value* length() const { return inputs_[3]; }
const RuntimeEntry& TargetFunction() const;
bool IsExternal() const { return cid_ == kExternalTwoByteStringCid; }
intptr_t class_id() const { return cid_; }
intptr_t index_scale() const {

View file

@ -408,14 +408,6 @@ void MemoryCopyInstr::EmitComputeStartPointer(FlowGraphCompiler* compiler,
offset =
compiler::target::TwoByteString::data_offset() - kHeapObjectTag;
break;
case kExternalOneByteStringCid:
__ LoadFromSlot(array_reg, array_reg,
Slot::ExternalOneByteString_external_data());
break;
case kExternalTwoByteStringCid:
__ LoadFromSlot(array_reg, array_reg,
Slot::ExternalTwoByteString_external_data());
break;
default:
UNREACHABLE();
break;
@ -2301,8 +2293,7 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
case kTypedDataUint8ClampedArrayCid:
case kExternalTypedDataUint8ArrayCid:
case kExternalTypedDataUint8ClampedArrayCid:
case kOneByteStringCid:
case kExternalOneByteStringCid: {
case kOneByteStringCid: {
const Register result = locs()->out(0).reg();
ASSERT(representation() == kUnboxedIntPtr);
ASSERT(index_scale() == 1);
@ -2321,8 +2312,7 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
break;
}
case kTypedDataUint16ArrayCid:
case kTwoByteStringCid:
case kExternalTwoByteStringCid: {
case kTwoByteStringCid: {
const Register result = locs()->out(0).reg();
ASSERT(representation() == kUnboxedIntPtr);
if (aligned()) {
@ -2923,13 +2913,11 @@ void LoadCodeUnitsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register result2 = result_pair->At(1).reg();
switch (class_id()) {
case kOneByteStringCid:
case kExternalOneByteStringCid:
ASSERT(element_count() == 4);
__ ldr(result1, element_address);
__ eor(result2, result2, compiler::Operand(result2));
break;
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
ASSERT(element_count() == 2);
__ ldr(result1, element_address);
__ eor(result2, result2, compiler::Operand(result2));
@ -2942,7 +2930,6 @@ void LoadCodeUnitsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register result = locs()->out(0).reg();
switch (class_id()) {
case kOneByteStringCid:
case kExternalOneByteStringCid:
switch (element_count()) {
case 1:
__ ldrb(result, element_address);
@ -2958,7 +2945,6 @@ void LoadCodeUnitsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
}
break;
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
switch (element_count()) {
case 1:
__ ldrh(result, element_address);

View file

@ -323,14 +323,6 @@ void MemoryCopyInstr::EmitComputeStartPointer(FlowGraphCompiler* compiler,
offset =
compiler::target::TwoByteString::data_offset() - kHeapObjectTag;
break;
case kExternalOneByteStringCid:
__ LoadFromSlot(array_reg, array_reg,
Slot::ExternalOneByteString_external_data());
break;
case kExternalTwoByteStringCid:
__ LoadFromSlot(array_reg, array_reg,
Slot::ExternalTwoByteString_external_data());
break;
default:
UNREACHABLE();
break;
@ -1981,7 +1973,6 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
case kExternalTypedDataUint8ArrayCid:
case kExternalTypedDataUint8ClampedArrayCid:
case kOneByteStringCid:
case kExternalOneByteStringCid:
ASSERT(representation() == kUnboxedIntPtr);
ASSERT(index_scale() == 1);
__ ldr(result, element_address, compiler::kUnsignedByte);
@ -1992,7 +1983,6 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
break;
case kTypedDataUint16ArrayCid:
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
ASSERT(representation() == kUnboxedIntPtr);
__ ldr(result, element_address, compiler::kUnsignedTwoBytes);
break;
@ -2026,7 +2016,6 @@ void LoadCodeUnitsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register result = locs()->out(0).reg();
switch (class_id()) {
case kOneByteStringCid:
case kExternalOneByteStringCid:
switch (element_count()) {
case 1:
sz = compiler::kUnsignedByte;
@ -2042,7 +2031,6 @@ void LoadCodeUnitsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
}
break;
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
switch (element_count()) {
case 1:
sz = compiler::kUnsignedTwoBytes;

View file

@ -200,14 +200,6 @@ void MemoryCopyInstr::EmitComputeStartPointer(FlowGraphCompiler* compiler,
offset =
compiler::target::TwoByteString::data_offset() - kHeapObjectTag;
break;
case kExternalOneByteStringCid:
__ LoadFromSlot(array_reg, array_reg,
Slot::ExternalOneByteString_external_data());
break;
case kExternalTwoByteStringCid:
__ LoadFromSlot(array_reg, array_reg,
Slot::ExternalTwoByteString_external_data());
break;
default:
UNREACHABLE();
break;
@ -1701,8 +1693,7 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
case kTypedDataUint8ClampedArrayCid:
case kExternalTypedDataUint8ArrayCid:
case kExternalTypedDataUint8ClampedArrayCid:
case kOneByteStringCid:
case kExternalOneByteStringCid: {
case kOneByteStringCid: {
const Register result = locs()->out(0).reg();
ASSERT(representation() == kUnboxedIntPtr);
ASSERT(index_scale() == 1);
@ -1716,8 +1707,7 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
break;
}
case kTypedDataUint16ArrayCid:
case kTwoByteStringCid:
case kExternalTwoByteStringCid: {
case kTwoByteStringCid: {
const Register result = locs()->out(0).reg();
ASSERT(representation() == kUnboxedIntPtr);
__ movzxw(result, element_address);
@ -3839,13 +3829,11 @@ void LoadCodeUnitsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
switch (class_id()) {
case kOneByteStringCid:
case kExternalOneByteStringCid:
ASSERT(element_count() == 4);
__ movl(result1, element_address);
__ xorl(result2, result2);
break;
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
ASSERT(element_count() == 2);
__ movl(result1, element_address);
__ xorl(result2, result2);
@ -3858,7 +3846,6 @@ void LoadCodeUnitsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register result = locs()->out(0).reg();
switch (class_id()) {
case kOneByteStringCid:
case kExternalOneByteStringCid:
switch (element_count()) {
case 1:
__ movzxb(result, element_address);
@ -3874,7 +3861,6 @@ void LoadCodeUnitsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
}
break;
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
switch (element_count()) {
case 1:
__ movzxw(result, element_address);

View file

@ -404,14 +404,6 @@ void MemoryCopyInstr::EmitComputeStartPointer(FlowGraphCompiler* compiler,
offset =
compiler::target::TwoByteString::data_offset() - kHeapObjectTag;
break;
case kExternalOneByteStringCid:
__ LoadFromSlot(array_reg, array_reg,
Slot::ExternalOneByteString_external_data());
break;
case kExternalTwoByteStringCid:
__ LoadFromSlot(array_reg, array_reg,
Slot::ExternalTwoByteString_external_data());
break;
default:
UNREACHABLE();
break;
@ -2170,8 +2162,7 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
case kTypedDataUint8ClampedArrayCid:
case kExternalTypedDataUint8ArrayCid:
case kExternalTypedDataUint8ClampedArrayCid:
case kOneByteStringCid:
case kExternalOneByteStringCid: {
case kOneByteStringCid: {
ASSERT(representation() == kUnboxedIntPtr);
ASSERT(index_scale() == 1);
const Register result = locs()->out(0).reg();
@ -2185,8 +2176,7 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
break;
}
case kTypedDataUint16ArrayCid:
case kTwoByteStringCid:
case kExternalTwoByteStringCid: {
case kTwoByteStringCid: {
ASSERT(representation() == kUnboxedIntPtr);
const Register result = locs()->out(0).reg();
__ lhu(result, element_address);
@ -2242,7 +2232,6 @@ void LoadCodeUnitsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register result = locs()->out(0).reg();
switch (class_id()) {
case kOneByteStringCid:
case kExternalOneByteStringCid:
switch (element_count()) {
case 1:
sz = compiler::kUnsignedByte;
@ -2258,7 +2247,6 @@ void LoadCodeUnitsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
}
break;
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
switch (element_count()) {
case 1:
sz = compiler::kUnsignedTwoBytes;

View file

@ -633,8 +633,6 @@ ISOLATE_UNIT_TEST_CASE(HierarchyInfo_String_Subtype) {
GrowableArray<intptr_t> expected_concrete_cids;
expected_concrete_cids.Add(kOneByteStringCid);
expected_concrete_cids.Add(kTwoByteStringCid);
expected_concrete_cids.Add(kExternalOneByteStringCid);
expected_concrete_cids.Add(kExternalTwoByteStringCid);
GrowableArray<intptr_t> expected_abstract_cids;
expected_abstract_cids.Add(type.type_class_id());

View file

@ -291,14 +291,6 @@ void MemoryCopyInstr::EmitComputeStartPointer(FlowGraphCompiler* compiler,
offset =
compiler::target::TwoByteString::data_offset() - kHeapObjectTag;
break;
case kExternalOneByteStringCid:
__ LoadFromSlot(array_reg, array_reg,
Slot::ExternalOneByteString_external_data());
break;
case kExternalTwoByteStringCid:
__ LoadFromSlot(array_reg, array_reg,
Slot::ExternalTwoByteString_external_data());
break;
default:
UNREACHABLE();
break;
@ -1918,7 +1910,6 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
case kExternalTypedDataUint8ArrayCid:
case kExternalTypedDataUint8ClampedArrayCid:
case kOneByteStringCid:
case kExternalOneByteStringCid:
ASSERT(representation() == kUnboxedIntPtr);
__ movzxb(result, element_address);
break;
@ -1928,7 +1919,6 @@ void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
break;
case kTypedDataUint16ArrayCid:
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
ASSERT(representation() == kUnboxedIntPtr);
__ movzxw(result, element_address);
break;
@ -1975,7 +1965,6 @@ void LoadCodeUnitsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register result = locs()->out(0).reg();
switch (class_id()) {
case kOneByteStringCid:
case kExternalOneByteStringCid:
switch (element_count()) {
case 1:
__ movzxb(result, element_address);
@ -1993,7 +1982,6 @@ void LoadCodeUnitsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ SmiTag(result);
break;
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
switch (element_count()) {
case 1:
__ movzxw(result, element_address);

View file

@ -3209,19 +3209,6 @@ static Definition* PrepareInlineStringIndexOp(FlowGraph* flow_graph,
index = flow_graph->CreateCheckBound(length, index, call->deopt_id());
cursor = flow_graph->AppendTo(cursor, index, call->env(), FlowGraph::kValue);
// For external strings: Load backing store.
if (cid == kExternalOneByteStringCid) {
str = new LoadFieldInstr(
new Value(str), Slot::ExternalOneByteString_external_data(),
InnerPointerAccess::kCannotBeInnerPointer, call->source());
cursor = flow_graph->AppendTo(cursor, str, nullptr, FlowGraph::kValue);
} else if (cid == kExternalTwoByteStringCid) {
str = new LoadFieldInstr(
new Value(str), Slot::ExternalTwoByteString_external_data(),
InnerPointerAccess::kCannotBeInnerPointer, call->source());
cursor = flow_graph->AppendTo(cursor, str, nullptr, FlowGraph::kValue);
}
LoadIndexedInstr* load_indexed = new (Z) LoadIndexedInstr(
new (Z) Value(str), new (Z) Value(index), /*index_unboxed=*/false,
compiler::target::Instance::ElementSizeFor(cid), cid, kAlignedAccess,
@ -3244,7 +3231,7 @@ static bool InlineStringBaseCharAt(FlowGraph* flow_graph,
FunctionEntryInstr** entry,
Instruction** last,
Definition** result) {
if ((cid != kOneByteStringCid) && (cid != kExternalOneByteStringCid)) {
if (cid != kOneByteStringCid) {
return false;
}
Definition* str = receiver;
@ -3278,9 +3265,7 @@ static bool InlineStringCodeUnitAt(FlowGraph* flow_graph,
if (cid == kDynamicCid) {
ASSERT(call->IsStaticCall());
return false;
} else if ((cid != kOneByteStringCid) && (cid != kTwoByteStringCid) &&
(cid != kExternalOneByteStringCid) &&
(cid != kExternalTwoByteStringCid)) {
} else if ((cid != kOneByteStringCid) && (cid != kTwoByteStringCid)) {
return false;
}
Definition* str = receiver;
@ -4379,8 +4364,6 @@ bool FlowGraphInliner::TryInlineRecognizedMethod(
}
case MethodRecognizer::kOneByteStringCodeUnitAt:
case MethodRecognizer::kTwoByteStringCodeUnitAt:
case MethodRecognizer::kExternalOneByteStringCodeUnitAt:
case MethodRecognizer::kExternalTwoByteStringCodeUnitAt:
return InlineStringCodeUnitAt(flow_graph, call, receiver, receiver_cid,
graph_entry, entry, last, result);
case MethodRecognizer::kStringBaseCharAt:

View file

@ -91,7 +91,6 @@ Representation RepresentationUtils::RepresentationOfArrayElement(
case kTypedDataInt8ArrayCid:
return kUnboxedInt8;
case kOneByteStringCid:
case kExternalOneByteStringCid:
case kTypedDataUint8ArrayCid:
case kTypedDataUint8ClampedArrayCid:
case kExternalTypedDataUint8ArrayCid:
@ -100,7 +99,6 @@ Representation RepresentationUtils::RepresentationOfArrayElement(
case kTypedDataInt16ArrayCid:
return kUnboxedInt16;
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
case kTypedDataUint16ArrayCid:
return kUnboxedUint16;
case kTypedDataInt32ArrayCid:

View file

@ -2998,13 +2998,11 @@ void LoadCodeUnitsInstr::InferRange(RangeAnalysis* analysis, Range* range) {
ASSERT(element_count_ > 0);
switch (class_id()) {
case kOneByteStringCid:
case kExternalOneByteStringCid:
ASSERT(element_count_ <= 4);
*range = Range(zero, RangeBoundary::FromConstant(
Utils::NBitMask(kBitsPerByte * element_count_)));
break;
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
ASSERT(element_count_ <= 2);
*range = Range(zero, RangeBoundary::FromConstant(Utils::NBitMask(
2 * kBitsPerByte * element_count_)));

View file

@ -596,8 +596,6 @@ class Place : public ValueObject {
case kImmutableArrayCid:
case kOneByteStringCid:
case kTwoByteStringCid:
case kExternalOneByteStringCid:
case kExternalTwoByteStringCid:
// Object arrays and strings do not allow accessing them through
// different types. No need to attach scale.
return kNoSize;

View file

@ -244,8 +244,6 @@ const Slot& Slot::GetLengthFieldForArrayCid(intptr_t array_cid) {
case kOneByteStringCid:
case kTwoByteStringCid:
case kExternalOneByteStringCid:
case kExternalTwoByteStringCid:
return GetNativeSlot(Kind::kString_length);
case kArrayCid:

View file

@ -212,11 +212,7 @@ NONNULLABLE_BOXED_NATIVE_SLOTS_LIST(FOR_EACH_NATIVE_SLOT)
AOT_ONLY_UNBOXED_NATIVE_ADDRESS_SLOTS_LIST(V) \
V(Function, UntaggedFunction, entry_point, false, FINAL) \
V(FinalizerBase, UntaggedFinalizerBase, isolate, false, VAR) \
V(PointerBase, UntaggedPointerBase, data, true, VAR) \
V(ExternalOneByteString, UntaggedExternalOneByteString, external_data, \
false, FINAL) \
V(ExternalTwoByteString, UntaggedExternalTwoByteString, external_data, \
false, FINAL)
V(PointerBase, UntaggedPointerBase, data, true, VAR)
// For uses that do not need to know whether a given slot may contain an
// inner pointer to a GC-able object or not. (Generally, such users only need

View file

@ -1738,9 +1738,7 @@ CompileType LoadFieldInstr::ComputeType() const {
CompileType LoadCodeUnitsInstr::ComputeType() const {
switch (class_id()) {
case kOneByteStringCid:
case kExternalOneByteStringCid:
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
return can_pack_into_smi() ? CompileType::FromCid(kSmiCid)
: CompileType::Int();
default:

View file

@ -547,17 +547,6 @@ static bool BuildCodeUnitAt(FlowGraph* flow_graph, intptr_t cid) {
index =
PrepareIndexedOp(flow_graph, &builder, str, index, Slot::String_length());
// For external strings: Load external data.
if (cid == kExternalOneByteStringCid) {
str = builder.AddDefinition(new LoadFieldInstr(
new Value(str), Slot::ExternalOneByteString_external_data(),
InnerPointerAccess::kCannotBeInnerPointer, builder.Source()));
} else if (cid == kExternalTwoByteStringCid) {
str = builder.AddDefinition(new LoadFieldInstr(
new Value(str), Slot::ExternalTwoByteString_external_data(),
InnerPointerAccess::kCannotBeInnerPointer, builder.Source()));
}
Definition* load = builder.AddDefinition(new LoadIndexedInstr(
new Value(str), new Value(index), /*index_unboxed=*/false,
target::Instance::ElementSizeFor(cid), cid, kAlignedAccess,
@ -590,16 +579,6 @@ bool GraphIntrinsifier::Build_TwoByteStringCodeUnitAt(FlowGraph* flow_graph) {
return BuildCodeUnitAt(flow_graph, kTwoByteStringCid);
}
bool GraphIntrinsifier::Build_ExternalOneByteStringCodeUnitAt(
FlowGraph* flow_graph) {
return BuildCodeUnitAt(flow_graph, kExternalOneByteStringCid);
}
bool GraphIntrinsifier::Build_ExternalTwoByteStringCodeUnitAt(
FlowGraph* flow_graph) {
return BuildCodeUnitAt(flow_graph, kExternalTwoByteStringCid);
}
static bool BuildSimdOp(FlowGraph* flow_graph, intptr_t cid, Token::Kind kind) {
if (!FlowGraphCompiler::SupportsUnboxedSimd128()) return false;

View file

@ -454,10 +454,6 @@ namespace dart {
V(_StringBase, get:length, StringBaseLength, 0x5842648b) \
V(_OneByteString, codeUnitAt, OneByteStringCodeUnitAt, 0x17ea7d30) \
V(_TwoByteString, codeUnitAt, TwoByteStringCodeUnitAt, 0x17ea7d30) \
V(_ExternalOneByteString, codeUnitAt, ExternalOneByteStringCodeUnitAt, \
0x17ea7d30) \
V(_ExternalTwoByteString, codeUnitAt, ExternalTwoByteStringCodeUnitAt, \
0x17ea7d30) \
V(_Smi, ~, Smi_bitNegate, 0x82466cfc) \
V(_IntegerImplementation, +, Integer_add, 0x6f06d26c) \
V(_IntegerImplementation, -, Integer_sub, 0x630fe15d) \

View file

@ -550,8 +550,7 @@ word Instance::native_fields_array_offset() {
}
word Instance::DataOffsetFor(intptr_t cid) {
if (dart::IsExternalTypedDataClassId(cid) ||
dart::IsExternalStringClassId(cid)) {
if (dart::IsExternalTypedDataClassId(cid)) {
// Elements start at offset 0 of the external data.
return 0;
}
@ -592,10 +591,6 @@ word Instance::ElementSizeFor(intptr_t cid) {
return dart::OneByteString::kBytesPerElement;
case kTwoByteStringCid:
return dart::TwoByteString::kBytesPerElement;
case kExternalOneByteStringCid:
return dart::ExternalOneByteString::kBytesPerElement;
case kExternalTwoByteStringCid:
return dart::ExternalTwoByteString::kBytesPerElement;
default:
UNIMPLEMENTED();
return 0;

View file

@ -813,20 +813,6 @@ class TwoByteString : public AllStatic {
static word element_offset(intptr_t index);
};
class ExternalOneByteString : public AllStatic {
public:
static word external_data_offset();
static word InstanceSize();
FINAL_CLASS();
};
class ExternalTwoByteString : public AllStatic {
public:
static word external_data_offset();
static word InstanceSize();
FINAL_CLASS();
};
class Int32x4 : public AllStatic {
public:
static word value_offset();

File diff suppressed because it is too large Load diff

View file

@ -138,8 +138,6 @@
FIELD(Context, num_variables_offset) \
FIELD(Context, parent_offset) \
FIELD(Double, value_offset) \
FIELD(ExternalOneByteString, external_data_offset) \
FIELD(ExternalTwoByteString, external_data_offset) \
FIELD(Float32x4, value_offset) \
FIELD(Float64x2, value_offset) \
FIELD(Field, initializer_function_offset) \
@ -421,8 +419,6 @@
SIZEOF(Context, header_size, UntaggedContext) \
SIZEOF(Double, InstanceSize, UntaggedDouble) \
SIZEOF(DynamicLibrary, InstanceSize, UntaggedDynamicLibrary) \
SIZEOF(ExternalOneByteString, InstanceSize, UntaggedExternalOneByteString) \
SIZEOF(ExternalTwoByteString, InstanceSize, UntaggedExternalTwoByteString) \
SIZEOF(ExternalTypedData, InstanceSize, UntaggedExternalTypedData) \
SIZEOF(FfiTrampolineData, InstanceSize, UntaggedFfiTrampolineData) \
SIZEOF(Field, InstanceSize, UntaggedField) \

View file

@ -567,23 +567,11 @@ bool Api::StringGetPeerHelper(NativeArguments* arguments,
return false;
}
intptr_t cid = raw_obj->GetClassId();
if (cid == kExternalOneByteStringCid) {
ExternalOneByteStringPtr raw_string =
static_cast<ExternalOneByteStringPtr>(raw_obj);
*peer = raw_string->untag()->peer_;
return true;
}
if (cid == kOneByteStringCid || cid == kTwoByteStringCid) {
auto isolate_group = arguments->thread()->isolate_group();
*peer = isolate_group->heap()->GetPeer(raw_obj);
return (*peer != nullptr);
}
if (cid == kExternalTwoByteStringCid) {
ExternalTwoByteStringPtr raw_string =
static_cast<ExternalTwoByteStringPtr>(raw_obj);
*peer = raw_string->untag()->peer_;
return true;
}
return false;
}
@ -2370,13 +2358,6 @@ DART_EXPORT bool Dart_IsStringLatin1(Dart_Handle object) {
return IsOneByteStringClassId(Api::ClassId(object));
}
DART_EXPORT bool Dart_IsExternalString(Dart_Handle object) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return IsExternalStringClassId(Api::ClassId(object));
}
DART_EXPORT bool Dart_IsList(Dart_Handle object) {
DARTSCOPE(Thread::Current());
if (IsBuiltinListClassId(Api::ClassId(object))) {
@ -2909,50 +2890,6 @@ DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const int32_t* utf32_array,
return Api::NewHandle(T, String::FromUTF32(utf32_array, length));
}
DART_EXPORT Dart_Handle
Dart_NewExternalLatin1String(const uint8_t* latin1_array,
intptr_t length,
void* peer,
intptr_t external_allocation_size,
Dart_HandleFinalizer callback) {
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
if (latin1_array == nullptr && length != 0) {
RETURN_NULL_ERROR(latin1_array);
}
if (callback == nullptr) {
RETURN_NULL_ERROR(callback);
}
CHECK_LENGTH(length, String::kMaxElements);
CHECK_CALLBACK_STATE(T);
return Api::NewHandle(
T,
String::NewExternal(latin1_array, length, peer, external_allocation_size,
callback, T->heap()->SpaceForExternal(length)));
}
DART_EXPORT Dart_Handle
Dart_NewExternalUTF16String(const uint16_t* utf16_array,
intptr_t length,
void* peer,
intptr_t external_allocation_size,
Dart_HandleFinalizer callback) {
DARTSCOPE(Thread::Current());
if (utf16_array == nullptr && length != 0) {
RETURN_NULL_ERROR(utf16_array);
}
if (callback == nullptr) {
RETURN_NULL_ERROR(callback);
}
CHECK_LENGTH(length, String::kMaxElements);
CHECK_CALLBACK_STATE(T);
intptr_t bytes = length * sizeof(*utf16_array);
return Api::NewHandle(
T,
String::NewExternal(utf16_array, length, peer, external_allocation_size,
callback, T->heap()->SpaceForExternal(bytes)));
}
DART_EXPORT Dart_Handle Dart_StringToCString(Dart_Handle object,
const char** cstr) {
DARTSCOPE(Thread::Current());
@ -3098,13 +3035,8 @@ DART_EXPORT Dart_Handle Dart_StringGetProperties(Dart_Handle object,
ReusableObjectHandleScope reused_obj_handle(thread);
const String& str = Api::UnwrapStringHandle(reused_obj_handle, object);
if (!str.IsNull()) {
if (str.IsExternal()) {
*peer = str.GetPeer();
ASSERT(*peer != nullptr);
} else {
NoSafepointScope no_safepoint_scope;
*peer = thread->heap()->GetPeer(str.ptr());
}
NoSafepointScope no_safepoint_scope;
*peer = thread->heap()->GetPeer(str.ptr());
*char_size = str.CharSize();
*str_len = str.Length();
return Api::Success();

View file

@ -1560,11 +1560,6 @@ TEST_CASE(DartAPI_ArrayValues) {
}
}
static void MallocFinalizer(void* isolate_callback_data, void* peer) {
free(peer);
}
static void NoopFinalizer(void* isolate_callback_data, void* peer) {}
TEST_CASE(DartAPI_IsString) {
uint8_t latin1[] = {'o', 'n', 'e', 0xC2, 0xA2};
@ -1572,7 +1567,6 @@ TEST_CASE(DartAPI_IsString) {
EXPECT_VALID(latin1str);
EXPECT(Dart_IsString(latin1str));
EXPECT(Dart_IsStringLatin1(latin1str));
EXPECT(!Dart_IsExternalString(latin1str));
intptr_t len = -1;
EXPECT_VALID(Dart_StringLength(latin1str, &len));
EXPECT_EQ(4, len);
@ -1591,7 +1585,6 @@ TEST_CASE(DartAPI_IsString) {
EXPECT_VALID(str8);
EXPECT(Dart_IsString(str8));
EXPECT(Dart_IsStringLatin1(str8));
EXPECT(!Dart_IsExternalString(str8));
uint8_t latin1_array[] = {0, 0, 0, 0, 0};
len = 5;
@ -1602,44 +1595,22 @@ TEST_CASE(DartAPI_IsString) {
EXPECT_EQ(data8[i], latin1_array[i]);
}
Dart_Handle ext8 = Dart_NewExternalLatin1String(
data8, ARRAY_SIZE(data8), data8, sizeof(data8), NoopFinalizer);
EXPECT_VALID(ext8);
EXPECT(Dart_IsString(ext8));
EXPECT(Dart_IsExternalString(ext8));
EXPECT_VALID(Dart_StringGetProperties(ext8, &char_size, &str_len, &peer));
EXPECT_EQ(1, char_size);
EXPECT_EQ(4, str_len);
EXPECT_EQ(data8, peer);
uint16_t data16[] = {'t', 'w', 'o', 0xFFFF};
Dart_Handle str16 = Dart_NewStringFromUTF16(data16, ARRAY_SIZE(data16));
EXPECT_VALID(str16);
EXPECT(Dart_IsString(str16));
EXPECT(!Dart_IsStringLatin1(str16));
EXPECT(!Dart_IsExternalString(str16));
EXPECT_VALID(Dart_StringGetProperties(str16, &char_size, &str_len, &peer));
EXPECT_EQ(2, char_size);
EXPECT_EQ(4, str_len);
EXPECT(!peer);
Dart_Handle ext16 = Dart_NewExternalUTF16String(
data16, ARRAY_SIZE(data16), data16, sizeof(data16), NoopFinalizer);
EXPECT_VALID(ext16);
EXPECT(Dart_IsString(ext16));
EXPECT(Dart_IsExternalString(ext16));
EXPECT_VALID(Dart_StringGetProperties(ext16, &char_size, &str_len, &peer));
EXPECT_EQ(2, char_size);
EXPECT_EQ(4, str_len);
EXPECT_EQ(data16, peer);
int32_t data32[] = {'f', 'o', 'u', 'r', 0x10FFFF};
Dart_Handle str32 = Dart_NewStringFromUTF32(data32, ARRAY_SIZE(data32));
EXPECT_VALID(str32);
EXPECT(Dart_IsString(str32));
EXPECT(!Dart_IsExternalString(str32));
}
TEST_CASE(DartAPI_NewString) {
@ -1735,91 +1706,6 @@ TEST_CASE(DartAPI_CopyUTF8EncodingOfString) {
EXPECT_EQ(0, memcmp(utf8_encoded, utf8_encoded_copy, utf8_length));
}
static void ExternalStringCallbackFinalizer(void* isolate_callback_data,
void* peer) {
*static_cast<int*>(peer) *= 2;
}
TEST_CASE(DartAPI_ExternalStringCallback) {
int peer8 = 40;
int peer16 = 41;
{
Dart_EnterScope();
uint8_t data8[] = {'h', 'e', 'l', 'l', 'o'};
Dart_Handle obj8 = Dart_NewExternalLatin1String(
data8, ARRAY_SIZE(data8), &peer8, sizeof(data8),
ExternalStringCallbackFinalizer);
EXPECT_VALID(obj8);
uint16_t data16[] = {'h', 'e', 'l', 'l', 'o'};
Dart_Handle obj16 = Dart_NewExternalUTF16String(
data16, ARRAY_SIZE(data16), &peer16, sizeof(data16),
ExternalStringCallbackFinalizer);
EXPECT_VALID(obj16);
Dart_ExitScope();
}
{
TransitionNativeToVM transition(thread);
EXPECT_EQ(40, peer8);
EXPECT_EQ(41, peer16);
GCTestHelper::CollectNewSpace();
EXPECT_EQ(80, peer8);
EXPECT_EQ(82, peer16);
}
}
TEST_CASE(DartAPI_ExternalStringPretenure) {
{
Dart_EnterScope();
size_t kBig = 16 * MB;
uint8_t* big_data8 = reinterpret_cast<uint8_t*>(calloc(kBig, 1));
Dart_Handle big8 =
Dart_NewExternalLatin1String(big_data8, // data
kBig / sizeof(uint8_t), // length
big_data8, // peer
kBig, // external size
MallocFinalizer);
EXPECT_VALID(big8);
uint16_t* big_data16 = reinterpret_cast<uint16_t*>(calloc(kBig, 1));
Dart_Handle big16 =
Dart_NewExternalUTF16String(big_data16, // data
kBig / sizeof(uint16_t), // length
big_data16, // peer
kBig, // external size
MallocFinalizer);
static const uint8_t small_data8[] = {'f', 'o', 'o'};
Dart_Handle small8 = Dart_NewExternalLatin1String(
small_data8, ARRAY_SIZE(small_data8), nullptr, sizeof(small_data8),
NoopFinalizer);
EXPECT_VALID(small8);
static const uint16_t small_data16[] = {'b', 'a', 'r'};
Dart_Handle small16 = Dart_NewExternalUTF16String(
small_data16, ARRAY_SIZE(small_data16), nullptr, sizeof(small_data16),
NoopFinalizer);
EXPECT_VALID(small16);
{
CHECK_API_SCOPE(thread);
TransitionNativeToVM transition(thread);
HANDLESCOPE(thread);
String& handle = String::Handle();
handle ^= Api::UnwrapHandle(big8);
EXPECT(handle.IsOld());
handle ^= Api::UnwrapHandle(big16);
EXPECT(handle.IsOld());
handle ^= Api::UnwrapHandle(small8);
EXPECT(handle.IsNew());
handle ^= Api::UnwrapHandle(small16);
EXPECT(handle.IsNew());
}
Dart_ExitScope();
}
}
TEST_CASE(DartAPI_ExternalTypedDataPretenure) {
{
Dart_EnterScope();
@ -7183,7 +7069,6 @@ TEST_CASE(DartAPI_ThrowException) {
static intptr_t kNativeArgumentNativeField1Value = 30;
static intptr_t kNativeArgumentNativeField2Value = 40;
static intptr_t native_arg_str_peer = 100;
static void NativeArgumentCreate(Dart_NativeArguments args) {
Dart_Handle lib = Dart_LookupLibrary(NewString(TestCase::url()));
Dart_Handle type =
@ -7251,9 +7136,11 @@ static void NativeArgumentAccess(Dart_NativeArguments args) {
EXPECT_STREQ("abcdefg", cstr);
EXPECT(arg_values[5].as_string.peer == nullptr);
EXPECT(arg_values[6].as_string.dart_str == nullptr);
EXPECT(arg_values[6].as_string.peer ==
reinterpret_cast<void*>(&native_arg_str_peer));
EXPECT_VALID(arg_values[6].as_string.dart_str);
EXPECT(Dart_IsString(arg_values[6].as_string.dart_str));
EXPECT_VALID(Dart_StringToCString(arg_values[6].as_string.dart_str, &cstr));
EXPECT_STREQ("string", cstr);
EXPECT(arg_values[6].as_string.peer == nullptr);
EXPECT(arg_values[7].as_native_fields.values[0] == 60);
EXPECT(arg_values[7].as_native_fields.values[1] == 80);
@ -7357,13 +7244,11 @@ int testMain(String extstr) {
const char* ascii_str = "string";
intptr_t ascii_str_length = strlen(ascii_str);
Dart_Handle extstr = Dart_NewExternalLatin1String(
reinterpret_cast<const uint8_t*>(ascii_str), ascii_str_length,
reinterpret_cast<void*>(&native_arg_str_peer), ascii_str_length,
NoopFinalizer);
Dart_Handle str = Dart_NewStringFromUTF8(
reinterpret_cast<const uint8_t*>(ascii_str), ascii_str_length);
Dart_Handle args[1];
args[0] = extstr;
args[0] = str;
Dart_Handle result = Dart_Invoke(lib, NewString("testMain"), 1, args);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
@ -9551,30 +9436,6 @@ TEST_CASE(DartAPI_CollectTwoOldSpacePeers) {
}
}
TEST_CASE(DartAPI_ExternalStringIndexOf) {
const char* kScriptChars =
"testMain(String pattern) {\n"
" var str = 'Hello World';\n"
" return str.indexOf(pattern);\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
uint8_t data8[] = {'W'};
Dart_Handle ext8 = Dart_NewExternalLatin1String(
data8, ARRAY_SIZE(data8), data8, sizeof(data8), NoopFinalizer);
EXPECT_VALID(ext8);
EXPECT(Dart_IsString(ext8));
EXPECT(Dart_IsExternalString(ext8));
Dart_Handle dart_args[1];
dart_args[0] = ext8;
Dart_Handle result = Dart_Invoke(lib, NewString("testMain"), 1, dart_args);
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(6, value);
}
TEST_CASE(DartAPI_StringFromExternalTypedData) {
const char* kScriptChars =
"test(external) {\n"

View file

@ -376,14 +376,8 @@ bool JSONWriter::AddDartString(const String& s,
NoSafepointScope no_safepoint;
if (s.IsOneByteString()) {
buffer_.AddEscapedLatin1(OneByteString::CharAddr(s, offset), count);
} else if (s.IsExternalOneByteString()) {
buffer_.AddEscapedLatin1(ExternalOneByteString::CharAddr(s, offset),
count);
} else if (s.IsTwoByteString()) {
buffer_.AddEscapedUTF16(TwoByteString::CharAddr(s, offset), count);
} else if (s.IsExternalTwoByteString()) {
buffer_.AddEscapedUTF16(ExternalTwoByteString::CharAddr(s, offset),
count);
} else {
UNREACHABLE();
}

View file

@ -1577,20 +1577,6 @@ void Object::FinalizeReadOnlyObject(ObjectPtr object) {
ASSERT(size <= str->untag()->HeapSize());
memset(reinterpret_cast<void*>(UntaggedObject::ToAddr(str) + size), 0,
str->untag()->HeapSize() - size);
} else if (cid == kExternalOneByteStringCid) {
ExternalOneByteStringPtr str =
static_cast<ExternalOneByteStringPtr>(object);
if (String::GetCachedHash(str) == 0) {
intptr_t hash = String::Hash(str);
String::SetCachedHashIfNotSet(str, hash);
}
} else if (cid == kExternalTwoByteStringCid) {
ExternalTwoByteStringPtr str =
static_cast<ExternalTwoByteStringPtr>(object);
if (String::GetCachedHash(str) == 0) {
intptr_t hash = String::Hash(str);
String::SetCachedHashIfNotSet(str, hash);
}
} else if (cid == kCodeSourceMapCid) {
CodeSourceMapPtr map = CodeSourceMap::RawCast(object);
intptr_t size = CodeSourceMap::UnroundedSize(map);
@ -1906,16 +1892,6 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group,
RegisterPrivateClass(cls, Symbols::TwoByteString(), core_lib);
pending_classes.Add(cls);
cls = Class::NewStringClass(kExternalOneByteStringCid, isolate_group);
object_store->set_external_one_byte_string_class(cls);
RegisterPrivateClass(cls, Symbols::ExternalOneByteString(), core_lib);
pending_classes.Add(cls);
cls = Class::NewStringClass(kExternalTwoByteStringCid, isolate_group);
object_store->set_external_two_byte_string_class(cls);
RegisterPrivateClass(cls, Symbols::ExternalTwoByteString(), core_lib);
pending_classes.Add(cls);
// Pre-register the isolate library so the native class implementations can
// be hooked up before compiling it.
Library& isolate_lib = Library::Handle(
@ -2658,12 +2634,6 @@ ErrorPtr Object::Init(IsolateGroup* isolate_group,
cls = Class::NewStringClass(kTwoByteStringCid, isolate_group);
object_store->set_two_byte_string_class(cls);
cls = Class::NewStringClass(kExternalOneByteStringCid, isolate_group);
object_store->set_external_one_byte_string_class(cls);
cls = Class::NewStringClass(kExternalTwoByteStringCid, isolate_group);
object_store->set_external_two_byte_string_class(cls);
cls = Class::New<Bool, RTN::Bool>(isolate_group);
object_store->set_bool_class(cls);
@ -5322,19 +5292,11 @@ ClassPtr Class::NewStringClass(intptr_t class_id, IsolateGroup* isolate_group) {
host_instance_size = OneByteString::InstanceSize();
target_instance_size = compiler::target::RoundedAllocationSize(
RTN::OneByteString::InstanceSize());
} else if (class_id == kTwoByteStringCid) {
} else {
ASSERT(class_id == kTwoByteStringCid);
host_instance_size = TwoByteString::InstanceSize();
target_instance_size = compiler::target::RoundedAllocationSize(
RTN::TwoByteString::InstanceSize());
} else if (class_id == kExternalOneByteStringCid) {
host_instance_size = ExternalOneByteString::InstanceSize();
target_instance_size = compiler::target::RoundedAllocationSize(
RTN::ExternalOneByteString::InstanceSize());
} else {
ASSERT(class_id == kExternalTwoByteStringCid);
host_instance_size = ExternalTwoByteString::InstanceSize();
target_instance_size = compiler::target::RoundedAllocationSize(
RTN::ExternalTwoByteString::InstanceSize());
}
Class& result = Class::Handle(New<String, RTN::String>(
class_id, isolate_group, /*register_class=*/false));
@ -5632,8 +5594,6 @@ const char* Class::GenerateUserVisibleName() const {
return Symbols::Double().ToCString();
case kOneByteStringCid:
case kTwoByteStringCid:
case kExternalOneByteStringCid:
case kExternalTwoByteStringCid:
return Symbols::_String().ToCString();
case kArrayCid:
case kImmutableArrayCid:
@ -21108,10 +21068,6 @@ intptr_t Instance::ElementSizeFor(intptr_t cid) {
return OneByteString::kBytesPerElement;
case kTwoByteStringCid:
return TwoByteString::kBytesPerElement;
case kExternalOneByteStringCid:
return ExternalOneByteString::kBytesPerElement;
case kExternalTwoByteStringCid:
return ExternalTwoByteString::kBytesPerElement;
default:
UNIMPLEMENTED();
return 0;
@ -21119,7 +21075,7 @@ intptr_t Instance::ElementSizeFor(intptr_t cid) {
}
intptr_t Instance::DataOffsetFor(intptr_t cid) {
if (IsExternalTypedDataClassId(cid) || IsExternalStringClassId(cid)) {
if (IsExternalTypedDataClassId(cid)) {
// Elements start at offset 0 of the external data.
return 0;
}
@ -23728,15 +23684,9 @@ void StringHasher::Add(const String& str, intptr_t begin_index, intptr_t len) {
if (str.IsOneByteString()) {
NoSafepointScope no_safepoint;
Add(OneByteString::CharAddr(str, begin_index), len);
} else if (str.IsExternalOneByteString()) {
NoSafepointScope no_safepoint;
Add(ExternalOneByteString::CharAddr(str, begin_index), len);
} else if (str.IsTwoByteString()) {
NoSafepointScope no_safepoint;
Add(TwoByteString::CharAddr(str, begin_index), len);
} else if (str.IsExternalOneByteString()) {
NoSafepointScope no_safepoint;
Add(ExternalTwoByteString::CharAddr(str, begin_index), len);
} else {
UNREACHABLE();
}
@ -23758,25 +23708,11 @@ uword String::HashConcat(const String& str1, const String& str2) {
uword String::Hash(StringPtr raw) {
StringHasher hasher;
uword length = Smi::Value(raw->untag()->length());
if (raw->IsOneByteString() || raw->IsExternalOneByteString()) {
const uint8_t* data;
if (raw->IsOneByteString()) {
data = static_cast<OneByteStringPtr>(raw)->untag()->data();
} else {
ASSERT(raw->IsExternalOneByteString());
ExternalOneByteStringPtr str = static_cast<ExternalOneByteStringPtr>(raw);
data = str->untag()->external_data_;
}
if (raw->IsOneByteString()) {
const uint8_t* data = static_cast<OneByteStringPtr>(raw)->untag()->data();
return String::Hash(data, length);
} else {
const uint16_t* data;
if (raw->IsTwoByteString()) {
data = static_cast<TwoByteStringPtr>(raw)->untag()->data();
} else {
ASSERT(raw->IsExternalTwoByteString());
ExternalTwoByteStringPtr str = static_cast<ExternalTwoByteStringPtr>(raw);
data = str->untag()->external_data_;
}
const uint16_t* data = static_cast<TwoByteStringPtr>(raw)->untag()->data();
return String::Hash(data, length);
}
}
@ -23801,23 +23737,13 @@ uword String::Hash(const uint16_t* characters, intptr_t len) {
intptr_t String::CharSize() const {
intptr_t class_id = ptr()->GetClassId();
if (class_id == kOneByteStringCid || class_id == kExternalOneByteStringCid) {
if (class_id == kOneByteStringCid) {
return kOneByteChar;
}
ASSERT(class_id == kTwoByteStringCid ||
class_id == kExternalTwoByteStringCid);
ASSERT(class_id == kTwoByteStringCid);
return kTwoByteChar;
}
void* String::GetPeer() const {
intptr_t class_id = ptr()->GetClassId();
if (class_id == kExternalOneByteStringCid) {
return ExternalOneByteString::GetPeer(*this);
}
ASSERT(class_id == kExternalTwoByteStringCid);
return ExternalTwoByteString::GetPeer(*this);
}
bool String::Equals(const Instance& other) const {
if (this->ptr() == other.ptr()) {
// Both handles point to the same raw instance.
@ -24079,26 +24005,6 @@ StringPtr String::New(const String& str, Heap::Space space) {
return result.ptr();
}
StringPtr String::NewExternal(const uint8_t* characters,
intptr_t len,
void* peer,
intptr_t external_allocation_size,
Dart_HandleFinalizer callback,
Heap::Space space) {
return ExternalOneByteString::New(characters, len, peer,
external_allocation_size, callback, space);
}
StringPtr String::NewExternal(const uint16_t* characters,
intptr_t len,
void* peer,
intptr_t external_allocation_size,
Dart_HandleFinalizer callback,
Heap::Space space) {
return ExternalTwoByteString::New(characters, len, peer,
external_allocation_size, callback, space);
}
void String::Copy(const String& dst,
intptr_t dst_offset,
const uint8_t* characters,
@ -24154,28 +24060,16 @@ void String::Copy(const String& dst,
if (len > 0) {
intptr_t char_size = src.CharSize();
if (char_size == kOneByteChar) {
if (src.IsOneByteString()) {
NoSafepointScope no_safepoint;
String::Copy(dst, dst_offset, OneByteString::CharAddr(src, src_offset),
len);
} else {
ASSERT(src.IsExternalOneByteString());
NoSafepointScope no_safepoint;
String::Copy(dst, dst_offset,
ExternalOneByteString::CharAddr(src, src_offset), len);
}
ASSERT(src.IsOneByteString());
NoSafepointScope no_safepoint;
String::Copy(dst, dst_offset, OneByteString::CharAddr(src, src_offset),
len);
} else {
ASSERT(char_size == kTwoByteChar);
if (src.IsTwoByteString()) {
NoSafepointScope no_safepoint;
String::Copy(dst, dst_offset, TwoByteString::CharAddr(src, src_offset),
len);
} else {
ASSERT(src.IsExternalTwoByteString());
NoSafepointScope no_safepoint;
String::Copy(dst, dst_offset,
ExternalTwoByteString::CharAddr(src, src_offset), len);
}
ASSERT(src.IsTwoByteString());
NoSafepointScope no_safepoint;
String::Copy(dst, dst_offset, TwoByteString::CharAddr(src, src_offset),
len);
}
}
}
@ -24184,18 +24078,8 @@ StringPtr String::EscapeSpecialCharacters(const String& str) {
if (str.IsOneByteString()) {
return OneByteString::EscapeSpecialCharacters(str);
}
if (str.IsTwoByteString()) {
return TwoByteString::EscapeSpecialCharacters(str);
}
if (str.IsExternalOneByteString()) {
return ExternalOneByteString::EscapeSpecialCharacters(str);
}
ASSERT(str.IsExternalTwoByteString());
// If EscapeSpecialCharacters is frequently called on external two byte
// strings, we should implement it directly on ExternalTwoByteString rather
// than first converting to a TwoByteString.
return TwoByteString::EscapeSpecialCharacters(
String::Handle(TwoByteString::New(str, Heap::kNew)));
ASSERT(str.IsTwoByteString());
return TwoByteString::EscapeSpecialCharacters(str);
}
static bool IsPercent(int32_t c) {
@ -24548,8 +24432,6 @@ bool String::ParseDouble(const String& str,
const uint8_t* startChar;
if (str.IsOneByteString()) {
startChar = OneByteString::CharAddr(str, start);
} else if (str.IsExternalOneByteString()) {
startChar = ExternalOneByteString::CharAddr(str, start);
} else {
uint8_t* chars = Thread::Current()->zone()->Alloc<uint8_t>(length);
for (intptr_t i = 0; i < length; i++) {
@ -24627,12 +24509,6 @@ static bool EqualsIgnoringPrivateKey(const String& str1, const String& str2) {
return dart::EqualsIgnoringPrivateKey<type, OneByteString>(str1, str2); \
case kTwoByteStringCid: \
return dart::EqualsIgnoringPrivateKey<type, TwoByteString>(str1, str2); \
case kExternalOneByteStringCid: \
return dart::EqualsIgnoringPrivateKey<type, ExternalOneByteString>( \
str1, str2); \
case kExternalTwoByteStringCid: \
return dart::EqualsIgnoringPrivateKey<type, ExternalTwoByteString>( \
str1, str2); \
} \
UNREACHABLE();
@ -24650,14 +24526,6 @@ bool String::EqualsIgnoringPrivateKey(const String& str1, const String& str2) {
case kTwoByteStringCid:
EQUALS_IGNORING_PRIVATE_KEY(str2_class_id, TwoByteString, str1, str2);
break;
case kExternalOneByteStringCid:
EQUALS_IGNORING_PRIVATE_KEY(str2_class_id, ExternalOneByteString, str1,
str2);
break;
case kExternalTwoByteStringCid:
EQUALS_IGNORING_PRIVATE_KEY(str2_class_id, ExternalTwoByteString, str1,
str2);
break;
}
UNREACHABLE();
return false;
@ -24713,39 +24581,6 @@ OneByteStringPtr OneByteString::EscapeSpecialCharacters(const String& str) {
return OneByteString::raw(Symbols::Empty());
}
OneByteStringPtr ExternalOneByteString::EscapeSpecialCharacters(
const String& str) {
intptr_t len = str.Length();
if (len > 0) {
intptr_t num_escapes = 0;
for (intptr_t i = 0; i < len; i++) {
num_escapes += EscapeOverhead(CharAt(str, i));
}
const String& dststr =
String::Handle(OneByteString::New(len + num_escapes, Heap::kNew));
intptr_t index = 0;
for (intptr_t i = 0; i < len; i++) {
uint8_t ch = CharAt(str, i);
if (IsSpecialCharacter(ch)) {
OneByteString::SetCharAt(dststr, index, '\\');
OneByteString::SetCharAt(dststr, index + 1, SpecialCharacter(ch));
index += 2;
} else if (IsAsciiNonprintable(ch)) {
OneByteString::SetCharAt(dststr, index, '\\');
OneByteString::SetCharAt(dststr, index + 1, 'x');
OneByteString::SetCharAt(dststr, index + 2, GetHexCharacter(ch >> 4));
OneByteString::SetCharAt(dststr, index + 3, GetHexCharacter(ch & 0xF));
index += 4;
} else {
OneByteString::SetCharAt(dststr, index, ch);
index += 1;
}
}
return OneByteString::raw(dststr);
}
return OneByteString::raw(Symbols::Empty());
}
OneByteStringPtr OneByteString::New(intptr_t len, Heap::Space space) {
ASSERT((IsolateGroup::Current() == Dart::vm_isolate_group()) ||
((IsolateGroup::Current()->object_store() != nullptr) &&
@ -25076,58 +24911,6 @@ TwoByteStringPtr TwoByteString::Transform(int32_t (*mapping)(int32_t ch),
return TwoByteString::raw(result);
}
ExternalOneByteStringPtr ExternalOneByteString::New(
const uint8_t* data,
intptr_t len,
void* peer,
intptr_t external_allocation_size,
Dart_HandleFinalizer callback,
Heap::Space space) {
ASSERT(IsolateGroup::Current()
->object_store()
->external_one_byte_string_class() != Class::null());
if (len < 0 || len > kMaxElements) {
// This should be caught before we reach here.
FATAL("Fatal error in ExternalOneByteString::New: invalid len %" Pd "\n",
len);
}
const auto& result =
String::Handle(Object::Allocate<ExternalOneByteString>(space));
#if !defined(HASH_IN_OBJECT_HEADER)
result.ptr()->untag()->set_hash(Smi::New(0));
#endif
result.SetLength(len);
SetExternalData(result, data, peer);
AddFinalizer(result, peer, callback, external_allocation_size);
return ExternalOneByteString::raw(result);
}
ExternalTwoByteStringPtr ExternalTwoByteString::New(
const uint16_t* data,
intptr_t len,
void* peer,
intptr_t external_allocation_size,
Dart_HandleFinalizer callback,
Heap::Space space) {
ASSERT(IsolateGroup::Current()
->object_store()
->external_two_byte_string_class() != Class::null());
if (len < 0 || len > kMaxElements) {
// This should be caught before we reach here.
FATAL("Fatal error in ExternalTwoByteString::New: invalid len %" Pd "\n",
len);
}
const auto& result =
String::Handle(Object::Allocate<ExternalTwoByteString>(space));
#if !defined(HASH_IN_OBJECT_HEADER)
result.ptr()->untag()->set_hash(Smi::New(0));
#endif
result.SetLength(len);
SetExternalData(result, data, peer);
AddFinalizer(result, peer, callback, external_allocation_size);
return ExternalTwoByteString::raw(result);
}
const char* Bool::ToCString() const {
return value() ? "true" : "false";
}
@ -26953,10 +26736,6 @@ void RegExp::set_function(intptr_t cid,
return untag()->set_one_byte_sticky(value.ptr());
case kTwoByteStringCid:
return untag()->set_two_byte_sticky(value.ptr());
case kExternalOneByteStringCid:
return untag()->set_external_one_byte_sticky(value.ptr());
case kExternalTwoByteStringCid:
return untag()->set_external_two_byte_sticky(value.ptr());
}
} else {
switch (cid) {
@ -26964,10 +26743,6 @@ void RegExp::set_function(intptr_t cid,
return untag()->set_one_byte(value.ptr());
case kTwoByteStringCid:
return untag()->set_two_byte(value.ptr());
case kExternalOneByteStringCid:
return untag()->set_external_one_byte(value.ptr());
case kExternalTwoByteStringCid:
return untag()->set_external_two_byte(value.ptr());
}
}
}
@ -27012,8 +26787,7 @@ RegExpPtr RegExp::New(Zone* zone, Heap::Space space) {
const Class& owner =
Class::Handle(zone, lib.LookupClass(Symbols::RegExp()));
for (intptr_t cid = kOneByteStringCid; cid <= kExternalTwoByteStringCid;
cid++) {
for (intptr_t cid = kOneByteStringCid; cid <= kTwoByteStringCid; cid++) {
CreateSpecializedFunction(thread, zone, result, cid, /*sticky=*/false,
owner);
CreateSpecializedFunction(thread, zone, result, cid, /*sticky=*/true,

View file

@ -1020,8 +1020,6 @@ class Object {
friend class Simd128MessageDeserializationCluster;
friend class OneByteString;
friend class TwoByteString;
friend class ExternalOneByteString;
friend class ExternalTwoByteString;
friend class Thread;
#define REUSABLE_FRIEND_DECLARATION(name) \
@ -10290,20 +10288,6 @@ class String : public Instance {
return ptr()->GetClassId() == kTwoByteStringCid;
}
bool IsExternalOneByteString() const {
return ptr()->GetClassId() == kExternalOneByteStringCid;
}
bool IsExternalTwoByteString() const {
return ptr()->GetClassId() == kExternalTwoByteStringCid;
}
bool IsExternal() const {
return IsExternalStringClassId(ptr()->GetClassId());
}
void* GetPeer() const;
char* ToMallocCString() const;
void ToUTF8(uint8_t* utf8_array, intptr_t array_len) const;
static const char* ToCString(Thread* thread, StringPtr ptr);
@ -10477,8 +10461,6 @@ class String : public Instance {
friend class ConcatString; // SetHash
friend class OneByteString;
friend class TwoByteString;
friend class ExternalOneByteString;
friend class ExternalTwoByteString;
friend class UntaggedOneByteString;
friend class RODataSerializationCluster; // SetHash
friend class Pass2Visitor; // Stack "handle"
@ -10638,7 +10620,6 @@ class OneByteString : public AllStatic {
ALLSTATIC_CONTAINS_COMPRESSED_IMPLEMENTATION(OneByteString, String);
friend class Class;
friend class ExternalOneByteString;
friend class FlowGraphSerializer;
friend class ImageWriter;
friend class String;
@ -10771,187 +10752,6 @@ class TwoByteString : public AllStatic {
friend class JSONWriter;
};
class ExternalOneByteString : public AllStatic {
public:
static uint16_t CharAt(const String& str, intptr_t index) {
ASSERT(str.IsExternalOneByteString());
return ExternalOneByteString::CharAt(
static_cast<ExternalOneByteStringPtr>(str.ptr()), index);
}
static uint16_t CharAt(ExternalOneByteStringPtr str, intptr_t index) {
ASSERT(index >= 0 && index < String::LengthOf(str));
return str->untag()->external_data_[index];
}
static void* GetPeer(const String& str) { return untag(str)->peer_; }
static intptr_t external_data_offset() {
return OFFSET_OF(UntaggedExternalOneByteString, external_data_);
}
// We use the same maximum elements for all strings.
static constexpr intptr_t kBytesPerElement = 1;
static constexpr intptr_t kMaxElements = String::kMaxElements;
static intptr_t InstanceSize() {
return String::RoundedAllocationSize(sizeof(UntaggedExternalOneByteString));
}
static ExternalOneByteStringPtr New(const uint8_t* characters,
intptr_t len,
void* peer,
intptr_t external_allocation_size,
Dart_HandleFinalizer callback,
Heap::Space space);
static ExternalOneByteStringPtr null() {
return static_cast<ExternalOneByteStringPtr>(Object::null());
}
static OneByteStringPtr EscapeSpecialCharacters(const String& str);
static OneByteStringPtr EncodeIRI(const String& str);
static OneByteStringPtr DecodeIRI(const String& str);
static const ClassId kClassId = kExternalOneByteStringCid;
private:
static ExternalOneByteStringPtr raw(const String& str) {
return static_cast<ExternalOneByteStringPtr>(str.ptr());
}
static const UntaggedExternalOneByteString* untag(const String& str) {
return reinterpret_cast<const UntaggedExternalOneByteString*>(str.untag());
}
static const uint8_t* CharAddr(const String& str, intptr_t index) {
ASSERT((index >= 0) && (index < str.Length()));
ASSERT(str.IsExternalOneByteString());
return &(untag(str)->external_data_[index]);
}
static const uint8_t* DataStart(const String& str) {
ASSERT(str.IsExternalOneByteString());
return untag(str)->external_data_;
}
static void SetExternalData(const String& str,
const uint8_t* data,
void* peer) {
ASSERT(str.IsExternalOneByteString());
ASSERT(!IsolateGroup::Current()->heap()->Contains(
reinterpret_cast<uword>(data)));
str.StoreNonPointer(&untag(str)->external_data_, data);
str.StoreNonPointer(&untag(str)->peer_, peer);
}
static void Finalize(void* isolate_callback_data,
Dart_WeakPersistentHandle handle,
void* peer);
static intptr_t NextFieldOffset() {
// Indicates this class cannot be extended by dart code.
return -kWordSize;
}
ALLSTATIC_CONTAINS_COMPRESSED_IMPLEMENTATION(ExternalOneByteString, String);
friend class Class;
friend class String;
friend class StringHasher;
friend class Symbols;
friend class Utf8;
friend class JSONWriter;
};
class ExternalTwoByteString : public AllStatic {
public:
static uint16_t CharAt(const String& str, intptr_t index) {
ASSERT(str.IsExternalTwoByteString());
return ExternalTwoByteString::CharAt(
static_cast<ExternalTwoByteStringPtr>(str.ptr()), index);
}
static uint16_t CharAt(ExternalTwoByteStringPtr str, intptr_t index) {
ASSERT(index >= 0 && index < String::LengthOf(str));
return str->untag()->external_data_[index];
}
static void* GetPeer(const String& str) { return untag(str)->peer_; }
static intptr_t external_data_offset() {
return OFFSET_OF(UntaggedExternalTwoByteString, external_data_);
}
// We use the same maximum elements for all strings.
static constexpr intptr_t kBytesPerElement = 2;
static constexpr intptr_t kMaxElements = String::kMaxElements;
static intptr_t InstanceSize() {
return String::RoundedAllocationSize(sizeof(UntaggedExternalTwoByteString));
}
static ExternalTwoByteStringPtr New(const uint16_t* characters,
intptr_t len,
void* peer,
intptr_t external_allocation_size,
Dart_HandleFinalizer callback,
Heap::Space space = Heap::kNew);
static ExternalTwoByteStringPtr null() {
return static_cast<ExternalTwoByteStringPtr>(Object::null());
}
static const ClassId kClassId = kExternalTwoByteStringCid;
private:
static ExternalTwoByteStringPtr raw(const String& str) {
return static_cast<ExternalTwoByteStringPtr>(str.ptr());
}
static const UntaggedExternalTwoByteString* untag(const String& str) {
return reinterpret_cast<const UntaggedExternalTwoByteString*>(str.untag());
}
static const uint16_t* CharAddr(const String& str, intptr_t index) {
ASSERT((index >= 0) && (index < str.Length()));
ASSERT(str.IsExternalTwoByteString());
return &(untag(str)->external_data_[index]);
}
static const uint16_t* DataStart(const String& str) {
ASSERT(str.IsExternalTwoByteString());
return untag(str)->external_data_;
}
static void SetExternalData(const String& str,
const uint16_t* data,
void* peer) {
ASSERT(str.IsExternalTwoByteString());
ASSERT(!IsolateGroup::Current()->heap()->Contains(
reinterpret_cast<uword>(data)));
str.StoreNonPointer(&untag(str)->external_data_, data);
str.StoreNonPointer(&untag(str)->peer_, peer);
}
static void Finalize(void* isolate_callback_data,
Dart_WeakPersistentHandle handle,
void* peer);
static intptr_t NextFieldOffset() {
// Indicates this class cannot be extended by dart code.
return -kWordSize;
}
ALLSTATIC_CONTAINS_COMPRESSED_IMPLEMENTATION(ExternalTwoByteString, String);
friend class Class;
friend class String;
friend class StringHasher;
friend class Symbols;
friend class JSONWriter;
};
// Matches null_patch.dart / bool_patch.dart.
static constexpr intptr_t kNullIdentityHash = 2011;
static constexpr intptr_t kTrueIdentityHash = 1231;
@ -12981,10 +12781,6 @@ class RegExp : public Instance {
return OFFSET_OF(UntaggedRegExp, one_byte_sticky_);
case kTwoByteStringCid:
return OFFSET_OF(UntaggedRegExp, two_byte_sticky_);
case kExternalOneByteStringCid:
return OFFSET_OF(UntaggedRegExp, external_one_byte_sticky_);
case kExternalTwoByteStringCid:
return OFFSET_OF(UntaggedRegExp, external_two_byte_sticky_);
}
} else {
switch (cid) {
@ -12992,10 +12788,6 @@ class RegExp : public Instance {
return OFFSET_OF(UntaggedRegExp, one_byte_);
case kTwoByteStringCid:
return OFFSET_OF(UntaggedRegExp, two_byte_);
case kExternalOneByteStringCid:
return OFFSET_OF(UntaggedRegExp, external_one_byte_);
case kExternalTwoByteStringCid:
return OFFSET_OF(UntaggedRegExp, external_two_byte_);
}
}
@ -13010,10 +12802,6 @@ class RegExp : public Instance {
return static_cast<FunctionPtr>(untag()->one_byte_sticky());
case kTwoByteStringCid:
return static_cast<FunctionPtr>(untag()->two_byte_sticky());
case kExternalOneByteStringCid:
return static_cast<FunctionPtr>(untag()->external_one_byte_sticky());
case kExternalTwoByteStringCid:
return static_cast<FunctionPtr>(untag()->external_two_byte_sticky());
}
} else {
switch (cid) {
@ -13021,10 +12809,6 @@ class RegExp : public Instance {
return static_cast<FunctionPtr>(untag()->one_byte());
case kTwoByteStringCid:
return static_cast<FunctionPtr>(untag()->two_byte());
case kExternalOneByteStringCid:
return static_cast<FunctionPtr>(untag()->external_one_byte());
case kExternalTwoByteStringCid:
return static_cast<FunctionPtr>(untag()->external_two_byte());
}
}
@ -13592,12 +13376,6 @@ inline uint16_t String::CharAt(StringPtr str, intptr_t index) {
return OneByteString::CharAt(static_cast<OneByteStringPtr>(str), index);
case kTwoByteStringCid:
return TwoByteString::CharAt(static_cast<TwoByteStringPtr>(str), index);
case kExternalOneByteStringCid:
return ExternalOneByteString::CharAt(
static_cast<ExternalOneByteStringPtr>(str), index);
case kExternalTwoByteStringCid:
return ExternalTwoByteString::CharAt(
static_cast<ExternalTwoByteStringPtr>(str), index);
}
UNREACHABLE();
return 0;

View file

@ -1160,14 +1160,6 @@ class Pass2Visitor : public ObjectVisitor,
writer_->WriteUnsigned(len);
writer_->WriteUnsigned(trunc_len);
writer_->WriteBytes(&str->untag()->data()[0], trunc_len);
} else if (cid == kExternalOneByteStringCid) {
ExternalOneByteStringPtr str = static_cast<ExternalOneByteStringPtr>(obj);
intptr_t len = Smi::Value(str->untag()->length());
intptr_t trunc_len = Utils::Minimum(len, kMaxStringElements);
writer_->WriteUnsigned(kLatin1Data);
writer_->WriteUnsigned(len);
writer_->WriteUnsigned(trunc_len);
writer_->WriteBytes(&str->untag()->external_data_[0], trunc_len);
} else if (cid == kTwoByteStringCid) {
TwoByteStringPtr str = static_cast<TwoByteStringPtr>(obj);
intptr_t len = Smi::Value(str->untag()->length());
@ -1176,14 +1168,6 @@ class Pass2Visitor : public ObjectVisitor,
writer_->WriteUnsigned(len);
writer_->WriteUnsigned(trunc_len);
writer_->WriteBytes(&str->untag()->data()[0], trunc_len * 2);
} else if (cid == kExternalTwoByteStringCid) {
ExternalTwoByteStringPtr str = static_cast<ExternalTwoByteStringPtr>(obj);
intptr_t len = Smi::Value(str->untag()->length());
intptr_t trunc_len = Utils::Minimum(len, kMaxStringElements);
writer_->WriteUnsigned(kUTF16Data);
writer_->WriteUnsigned(len);
writer_->WriteUnsigned(trunc_len);
writer_->WriteBytes(&str->untag()->external_data_[0], trunc_len * 2);
} else if (cid == kArrayCid || cid == kImmutableArrayCid) {
writer_->WriteUnsigned(kLengthData);
writer_->WriteUnsigned(
@ -1784,8 +1768,6 @@ uint32_t HeapSnapshotWriter::GetHeapSnapshotIdentityHash(Thread* thread,
case kCodeSourceMapCid:
case kCompressedStackMapsCid:
case kDoubleCid:
case kExternalOneByteStringCid:
case kExternalTwoByteStringCid:
case kGrowableObjectArrayCid:
case kImmutableArrayCid:
case kConstMapCid:

View file

@ -193,8 +193,6 @@ static bool MightNeedReHashing(ObjectPtr object) {
// same hash codes.
if (cid == kOneByteStringCid) return false;
if (cid == kTwoByteStringCid) return false;
if (cid == kExternalOneByteStringCid) return false;
if (cid == kExternalTwoByteStringCid) return false;
if (cid == kMintCid) return false;
if (cid == kDoubleCid) return false;
if (cid == kBoolCid) return false;
@ -476,8 +474,6 @@ class IdentityMap {
break;
case kOneByteStringCid:
case kTwoByteStringCid:
case kExternalOneByteStringCid:
case kExternalTwoByteStringCid:
hash = String::Hash(static_cast<StringPtr>(object));
hash = Object::SetCachedHashIfNotSet(object, hash);
break;

View file

@ -1971,18 +1971,10 @@ void RegExp::PrintJSONImpl(JSONStream* stream, bool ref) const {
jsobj.AddProperty("_oneByteFunction", func);
func = function(kTwoByteStringCid, /*sticky=*/false);
jsobj.AddProperty("_twoByteFunction", func);
func = function(kExternalOneByteStringCid, /*sticky=*/false);
jsobj.AddProperty("_externalOneByteFunction", func);
func = function(kExternalTwoByteStringCid, /*sticky=*/false);
jsobj.AddProperty("_externalTwoByteFunction", func);
func = function(kOneByteStringCid, /*sticky=*/true);
jsobj.AddProperty("_oneByteFunctionSticky", func);
func = function(kTwoByteStringCid, /*sticky=*/true);
jsobj.AddProperty("_twoByteFunctionSticky", func);
func = function(kExternalOneByteStringCid, /*sticky=*/true);
jsobj.AddProperty("_externalOneByteFunctionSticky", func);
func = function(kExternalTwoByteStringCid, /*sticky=*/true);
jsobj.AddProperty("_externalTwoByteFunctionSticky", func);
} else {
TypedData& bc = TypedData::Handle();
bc = bytecode(/*is_one_byte=*/true, /*sticky=*/false);

View file

@ -118,8 +118,6 @@ class ObjectPointerVisitor;
RW(Class, future_or_class) \
RW(Class, one_byte_string_class) \
RW(Class, two_byte_string_class) \
RW(Class, external_one_byte_string_class) \
RW(Class, external_two_byte_string_class) \
RW(Type, bool_type) \
RW(Class, bool_class) \
RW(Class, array_class) \

View file

@ -1642,38 +1642,6 @@ ISOLATE_UNIT_TEST_CASE(StringEqualsUTF32) {
EXPECT(!th_str.Equals(chars, 3));
}
static void NoopFinalizer(void* isolate_callback_data, void* peer) {}
ISOLATE_UNIT_TEST_CASE(ExternalOneByteString) {
uint8_t characters[] = {0xF6, 0xF1, 0xE9};
intptr_t len = ARRAY_SIZE(characters);
const String& str = String::Handle(ExternalOneByteString::New(
characters, len, nullptr, 0, NoopFinalizer, Heap::kNew));
EXPECT(!str.IsOneByteString());
EXPECT(str.IsExternalOneByteString());
EXPECT_EQ(str.Length(), len);
EXPECT(str.Equals("\xC3\xB6\xC3\xB1\xC3\xA9"));
const String& copy = String::Handle(String::SubString(str, 0, len));
EXPECT(!copy.IsExternalOneByteString());
EXPECT(copy.IsOneByteString());
EXPECT_EQ(len, copy.Length());
EXPECT(copy.Equals(str));
const String& concat = String::Handle(String::Concat(str, str));
EXPECT(!concat.IsExternalOneByteString());
EXPECT(concat.IsOneByteString());
EXPECT_EQ(len * 2, concat.Length());
EXPECT(concat.Equals("\xC3\xB6\xC3\xB1\xC3\xA9\xC3\xB6\xC3\xB1\xC3\xA9"));
const String& substr = String::Handle(String::SubString(str, 1, 1));
EXPECT(!substr.IsExternalOneByteString());
EXPECT(substr.IsOneByteString());
EXPECT_EQ(1, substr.Length());
EXPECT(substr.Equals("\xC3\xB1"));
}
ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersOneByteString) {
uint8_t characters[] = {'a', '\n', '\f', '\b', '\t',
'\v', '\r', '\\', '$', 'z'};
@ -1693,29 +1661,6 @@ ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersOneByteString) {
EXPECT_EQ(escaped_empty_str.Length(), 0);
}
ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersExternalOneByteString) {
uint8_t characters[] = {'a', '\n', '\f', '\b', '\t',
'\v', '\r', '\\', '$', 'z'};
intptr_t len = ARRAY_SIZE(characters);
const String& str = String::Handle(ExternalOneByteString::New(
characters, len, nullptr, 0, NoopFinalizer, Heap::kNew));
EXPECT(!str.IsOneByteString());
EXPECT(str.IsExternalOneByteString());
EXPECT_EQ(str.Length(), len);
EXPECT(str.Equals("a\n\f\b\t\v\r\\$z"));
const String& escaped_str =
String::Handle(String::EscapeSpecialCharacters(str));
EXPECT(escaped_str.Equals("a\\n\\f\\b\\t\\v\\r\\\\\\$z"));
const String& empty_str = String::Handle(ExternalOneByteString::New(
characters, 0, nullptr, 0, NoopFinalizer, Heap::kNew));
const String& escaped_empty_str =
String::Handle(String::EscapeSpecialCharacters(empty_str));
EXPECT_EQ(empty_str.Length(), 0);
EXPECT_EQ(escaped_empty_str.Length(), 0);
}
ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersTwoByteString) {
uint16_t characters[] = {'a', '\n', '\f', '\b', '\t',
'\v', '\r', '\\', '$', 'z'};
@ -1738,60 +1683,6 @@ ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersTwoByteString) {
EXPECT_EQ(escaped_empty_str.Length(), 0);
}
ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersExternalTwoByteString) {
uint16_t characters[] = {'a', '\n', '\f', '\b', '\t',
'\v', '\r', '\\', '$', 'z'};
intptr_t len = ARRAY_SIZE(characters);
const String& str = String::Handle(ExternalTwoByteString::New(
characters, len, nullptr, 0, NoopFinalizer, Heap::kNew));
EXPECT(str.IsExternalTwoByteString());
EXPECT_EQ(str.Length(), len);
EXPECT(str.Equals("a\n\f\b\t\v\r\\$z"));
const String& escaped_str =
String::Handle(String::EscapeSpecialCharacters(str));
EXPECT(escaped_str.Equals("a\\n\\f\\b\\t\\v\\r\\\\\\$z"));
const String& empty_str = String::Handle(ExternalTwoByteString::New(
characters, 0, nullptr, 0, NoopFinalizer, Heap::kNew));
const String& escaped_empty_str =
String::Handle(String::EscapeSpecialCharacters(empty_str));
EXPECT_EQ(empty_str.Length(), 0);
EXPECT_EQ(escaped_empty_str.Length(), 0);
}
ISOLATE_UNIT_TEST_CASE(ExternalTwoByteString) {
uint16_t characters[] = {0x1E6B, 0x1E85, 0x1E53};
intptr_t len = ARRAY_SIZE(characters);
const String& str = String::Handle(ExternalTwoByteString::New(
characters, len, nullptr, 0, NoopFinalizer, Heap::kNew));
EXPECT(!str.IsTwoByteString());
EXPECT(str.IsExternalTwoByteString());
EXPECT_EQ(str.Length(), len);
EXPECT(str.Equals("\xE1\xB9\xAB\xE1\xBA\x85\xE1\xB9\x93"));
const String& copy = String::Handle(String::SubString(str, 0, len));
EXPECT(!copy.IsExternalTwoByteString());
EXPECT(copy.IsTwoByteString());
EXPECT_EQ(len, copy.Length());
EXPECT(copy.Equals(str));
const String& concat = String::Handle(String::Concat(str, str));
EXPECT(!concat.IsExternalTwoByteString());
EXPECT(concat.IsTwoByteString());
EXPECT_EQ(len * 2, concat.Length());
EXPECT(
concat.Equals("\xE1\xB9\xAB\xE1\xBA\x85\xE1\xB9\x93"
"\xE1\xB9\xAB\xE1\xBA\x85\xE1\xB9\x93"));
const String& substr = String::Handle(String::SubString(str, 1, 1));
EXPECT(!substr.IsExternalTwoByteString());
EXPECT(substr.IsTwoByteString());
EXPECT_EQ(1, substr.Length());
EXPECT(substr.Equals("\xE1\xBA\x85"));
}
ISOLATE_UNIT_TEST_CASE(Symbol) {
const String& one = String::Handle(Symbols::New(thread, "Eins"));
EXPECT(one.IsSymbol());
@ -3438,39 +3329,6 @@ ISOLATE_UNIT_TEST_CASE(EqualsIgnoringPrivate) {
mangled_name = OneByteString::New("foo@12345.named@12345");
bare_name = OneByteString::New("foo.name");
EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
const char* ext_mangled_str = "foo@12345.name@12345";
const char* ext_bare_str = "foo.name";
const char* ext_bad_bare_str = "foo.named";
String& ext_mangled_name = String::Handle();
String& ext_bare_name = String::Handle();
String& ext_bad_bare_name = String::Handle();
mangled_name = OneByteString::New("foo@12345.name@12345");
ext_mangled_name = ExternalOneByteString::New(
reinterpret_cast<const uint8_t*>(ext_mangled_str),
strlen(ext_mangled_str), nullptr, 0, NoopFinalizer, Heap::kNew);
EXPECT(ext_mangled_name.IsExternalOneByteString());
ext_bare_name = ExternalOneByteString::New(
reinterpret_cast<const uint8_t*>(ext_bare_str), strlen(ext_bare_str),
nullptr, 0, NoopFinalizer, Heap::kNew);
EXPECT(ext_bare_name.IsExternalOneByteString());
ext_bad_bare_name = ExternalOneByteString::New(
reinterpret_cast<const uint8_t*>(ext_bad_bare_str),
strlen(ext_bad_bare_str), nullptr, 0, NoopFinalizer, Heap::kNew);
EXPECT(ext_bad_bare_name.IsExternalOneByteString());
// str1 - OneByteString, str2 - ExternalOneByteString.
EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, ext_bare_name));
EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, ext_bad_bare_name));
// str1 - ExternalOneByteString, str2 - OneByteString.
EXPECT(String::EqualsIgnoringPrivateKey(ext_mangled_name, bare_name));
// str1 - ExternalOneByteString, str2 - ExternalOneByteString.
EXPECT(String::EqualsIgnoringPrivateKey(ext_mangled_name, ext_bare_name));
EXPECT(
!String::EqualsIgnoringPrivateKey(ext_mangled_name, ext_bad_bare_name));
}
ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION(ArrayNew_Overflow_Crash, "Crash") {
@ -7443,48 +7301,6 @@ void init() {
HashSetNonConstEqualsConst(kScript);
}
TEST_CASE(OneByteStringExternalEqualsInternal) {
const char* kScript = R"(
makeInternalString() {
return String.fromCharCodes(<int>[1, 1, 2, 3, 5, 8, 13]);
}
bool equalsAB(String a, String b) => !identical(a, b) && (a == b);
bool equalsBA(String a, String b) => !identical(b, a) && (b == a);
)";
Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
EXPECT_VALID(lib);
Dart_Handle internal_string =
Dart_Invoke(lib, NewString("makeInternalString"), 0, nullptr);
EXPECT_VALID(internal_string);
Dart_Handle external_string;
uint8_t characters[] = {1, 1, 2, 3, 5, 8, 13};
intptr_t len = ARRAY_SIZE(characters);
{
TransitionNativeToVM transition(thread);
const String& str = String::Handle(ExternalOneByteString::New(
characters, len, nullptr, 0, NoopFinalizer, Heap::kNew));
EXPECT(!str.IsOneByteString());
EXPECT(str.IsExternalOneByteString());
external_string = Api::NewHandle(thread, str.ptr());
}
Dart_Handle args[2] = {internal_string, external_string};
Dart_Handle equalsAB_result =
Dart_Invoke(lib, NewString("equalsAB"), 2, args);
EXPECT_VALID(equalsAB_result);
EXPECT_TRUE(equalsAB_result);
Dart_Handle equalsBA_result =
Dart_Invoke(lib, NewString("equalsBA"), 2, args);
EXPECT_VALID(equalsBA_result);
EXPECT_TRUE(equalsBA_result);
}
static void CheckConcatAll(const String* data[], intptr_t n) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
@ -7517,44 +7333,6 @@ ISOLATE_UNIT_TEST_CASE(Symbols_FromConcatAll) {
CheckConcatAll(data, 3);
}
{
uint8_t characters[] = {0xF6, 0xF1, 0xE9};
intptr_t len = ARRAY_SIZE(characters);
const String& str = String::Handle(ExternalOneByteString::New(
characters, len, nullptr, 0, NoopFinalizer, Heap::kNew));
const String* data[3] = {&str, &Symbols::Dot(), &str};
CheckConcatAll(data, 3);
}
{
uint16_t characters[] = {'a', '\n', '\f', '\b', '\t',
'\v', '\r', '\\', '$', 'z'};
intptr_t len = ARRAY_SIZE(characters);
const String& str = String::Handle(ExternalTwoByteString::New(
characters, len, nullptr, 0, NoopFinalizer, Heap::kNew));
const String* data[3] = {&str, &Symbols::Dot(), &str};
CheckConcatAll(data, 3);
}
{
uint8_t characters1[] = {0xF6, 0xF1, 0xE9};
intptr_t len1 = ARRAY_SIZE(characters1);
const String& str1 = String::Handle(ExternalOneByteString::New(
characters1, len1, nullptr, 0, NoopFinalizer, Heap::kNew));
uint16_t characters2[] = {'a', '\n', '\f', '\b', '\t',
'\v', '\r', '\\', '$', 'z'};
intptr_t len2 = ARRAY_SIZE(characters2);
const String& str2 = String::Handle(ExternalTwoByteString::New(
characters2, len2, nullptr, 0, NoopFinalizer, Heap::kNew));
const String* data[3] = {&str1, &Symbols::Dot(), &str2};
CheckConcatAll(data, 3);
}
{
const String& empty = String::Handle(String::New(""));
const String* data[3] = {&Symbols::TypeError(), &empty,

View file

@ -538,8 +538,6 @@ COMPRESSED_VISITOR(ApiError)
COMPRESSED_VISITOR(LanguageError)
COMPRESSED_VISITOR(UnhandledException)
COMPRESSED_VISITOR(UnwindError)
COMPRESSED_VISITOR(ExternalOneByteString)
COMPRESSED_VISITOR(ExternalTwoByteString)
COMPRESSED_VISITOR(GrowableObjectArray)
COMPRESSED_VISITOR(Map)
COMPRESSED_VISITOR(Set)

View file

@ -3181,24 +3181,6 @@ class UntaggedTypedDataView : public UntaggedTypedDataBase {
friend class ScavengerVisitorBase;
};
class UntaggedExternalOneByteString : public UntaggedString {
RAW_HEAP_OBJECT_IMPLEMENTATION(ExternalOneByteString);
const uint8_t* external_data_;
void* peer_;
friend class Api;
friend class String;
};
class UntaggedExternalTwoByteString : public UntaggedString {
RAW_HEAP_OBJECT_IMPLEMENTATION(ExternalTwoByteString);
const uint16_t* external_data_;
void* peer_;
friend class Api;
friend class String;
};
class UntaggedBool : public UntaggedInstance {
RAW_HEAP_OBJECT_IMPLEMENTATION(Bool);
VISIT_NOTHING();
@ -3516,13 +3498,9 @@ class UntaggedRegExp : public UntaggedInstance {
COMPRESSED_POINTER_FIELD(StringPtr, pattern)
COMPRESSED_POINTER_FIELD(ObjectPtr, one_byte) // FunctionPtr or TypedDataPtr
COMPRESSED_POINTER_FIELD(ObjectPtr, two_byte)
COMPRESSED_POINTER_FIELD(ObjectPtr, external_one_byte)
COMPRESSED_POINTER_FIELD(ObjectPtr, external_two_byte)
COMPRESSED_POINTER_FIELD(ObjectPtr, one_byte_sticky)
COMPRESSED_POINTER_FIELD(ObjectPtr, two_byte_sticky)
COMPRESSED_POINTER_FIELD(ObjectPtr, external_one_byte_sticky)
COMPRESSED_POINTER_FIELD(ObjectPtr, external_two_byte_sticky)
VISIT_TO(external_two_byte_sticky)
VISIT_TO(two_byte_sticky)
CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
std::atomic<intptr_t> num_bracket_expressions_;

View file

@ -195,12 +195,8 @@ namespace dart {
F(RegExp, pattern_) \
F(RegExp, one_byte_) \
F(RegExp, two_byte_) \
F(RegExp, external_one_byte_) \
F(RegExp, external_two_byte_) \
F(RegExp, one_byte_sticky_) \
F(RegExp, two_byte_sticky_) \
F(RegExp, external_one_byte_sticky_) \
F(RegExp, external_two_byte_sticky_) \
F(SuspendState, function_data_) \
F(SuspendState, then_callback_) \
F(SuspendState, error_callback_) \

View file

@ -5304,8 +5304,7 @@ RegExpEngine::CompilationResult RegExpEngine::CompileIR(
const Function& function = parsed_function->function();
const intptr_t specialization_cid = function.string_specialization_cid();
const bool is_sticky = function.is_sticky_specialization();
const bool is_one_byte = (specialization_cid == kOneByteStringCid ||
specialization_cid == kExternalOneByteStringCid);
const bool is_one_byte = (specialization_cid == kOneByteStringCid);
RegExp& regexp = RegExp::Handle(zone, function.regexp());
const String& pattern = String::Handle(zone, regexp.pattern());
@ -5588,8 +5587,7 @@ RegExpPtr RegExpEngine::CreateRegExp(Thread* thread,
const Class& owner =
Class::Handle(zone, lib.LookupClass(Symbols::RegExp()));
for (intptr_t cid = kOneByteStringCid; cid <= kExternalTwoByteStringCid;
cid++) {
for (intptr_t cid = kOneByteStringCid; cid <= kTwoByteStringCid; cid++) {
CreateSpecializedFunction(thread, zone, regexp, cid, /*sticky=*/false,
owner);
CreateSpecializedFunction(thread, zone, regexp, cid, /*sticky=*/true,

View file

@ -423,8 +423,7 @@ static intptr_t Prepare(const RegExp& regexp,
const String& subject,
bool sticky,
Zone* zone) {
bool is_one_byte =
subject.IsOneByteString() || subject.IsExternalOneByteString();
bool is_one_byte = subject.IsOneByteString();
if (regexp.bytecode(is_one_byte, sticky) == TypedData::null()) {
const String& pattern = String::Handle(zone, regexp.pattern());
@ -475,8 +474,7 @@ static ObjectPtr ExecRaw(const RegExp& regexp,
int32_t* output,
intptr_t output_size,
Zone* zone) {
bool is_one_byte =
subject.IsOneByteString() || subject.IsExternalOneByteString();
bool is_one_byte = subject.IsOneByteString();
// We must have done EnsureCompiledIrregexp, so we can get the number of
// registers.

View file

@ -89,11 +89,9 @@ IRRegExpMacroAssembler::IRRegExpMacroAssembler(
block_id_(1) {
switch (specialization_cid) {
case kOneByteStringCid:
case kExternalOneByteStringCid:
mode_ = ASCII;
break;
case kTwoByteStringCid:
case kExternalTwoByteStringCid:
mode_ = UC16;
break;
default:
@ -1723,22 +1721,6 @@ Value* IRRegExpMacroAssembler::LoadCodeUnitsAt(LocalVariable* index,
intptr_t characters) {
// Bind the pattern as the load receiver.
Value* pattern_val = BindLoadLocal(*string_param_);
if (IsExternalStringClassId(specialization_cid_)) {
// The data of an external string is stored through one indirection.
const Slot* slot = nullptr;
if (specialization_cid_ == kExternalOneByteStringCid) {
slot = &Slot::ExternalOneByteString_external_data();
} else if (specialization_cid_ == kExternalTwoByteStringCid) {
slot = &Slot::ExternalTwoByteString_external_data();
} else {
UNREACHABLE();
}
// This pushes an untagged value on the stack which is immediately consumed
// by LoadCodeUnitsAtInstr below.
pattern_val = Bind(new (Z) LoadFieldInstr(
pattern_val, *slot, InnerPointerAccess::kCannotBeInnerPointer,
InstructionSource()));
}
// Here pattern_val might be untagged so this must not trigger a GC.
Value* index_val = BindLoadLocal(*index);

View file

@ -698,10 +698,10 @@ ObjectPtr IrregexpInterpreter::Match(const TypedData& bytecode,
previous_char = subject.CharAt(start_position - 1);
}
if (subject.IsOneByteString() || subject.IsExternalOneByteString()) {
if (subject.IsOneByteString()) {
return RawMatch<uint8_t>(bytecode, subject, registers, start_position,
previous_char);
} else if (subject.IsTwoByteString() || subject.IsExternalTwoByteString()) {
} else if (subject.IsTwoByteString()) {
return RawMatch<uint16_t>(bytecode, subject, registers, start_position,
previous_char);
} else {

View file

@ -66,50 +66,4 @@ ISOLATE_UNIT_TEST_CASE(RegExp_TwoByteString) {
EXPECT_EQ(3, smi_2.Value());
}
static void NoopFinalizer(void* isolate_callback_data, void* peer) {}
ISOLATE_UNIT_TEST_CASE(RegExp_ExternalOneByteString) {
uint8_t chars[] = {'a', 'b', 'c', 'b', 'a'};
intptr_t len = ARRAY_SIZE(chars);
const String& str = String::Handle(ExternalOneByteString::New(
chars, len, nullptr, 0, NoopFinalizer, Heap::kNew));
const String& pat =
String::Handle(Symbols::New(thread, String::Handle(String::New("bc"))));
const Array& res = Array::Handle(Match(pat, str));
EXPECT_EQ(2, res.Length());
const Object& res_1 = Object::Handle(res.At(0));
const Object& res_2 = Object::Handle(res.At(1));
EXPECT(res_1.IsSmi());
EXPECT(res_2.IsSmi());
const Smi& smi_1 = Smi::Cast(res_1);
const Smi& smi_2 = Smi::Cast(res_2);
EXPECT_EQ(1, smi_1.Value());
EXPECT_EQ(3, smi_2.Value());
}
ISOLATE_UNIT_TEST_CASE(RegExp_ExternalTwoByteString) {
uint16_t chars[] = {'a', 'b', 'c', 'b', 'a'};
intptr_t len = ARRAY_SIZE(chars);
const String& str = String::Handle(ExternalTwoByteString::New(
chars, len, nullptr, 0, NoopFinalizer, Heap::kNew));
const String& pat =
String::Handle(Symbols::New(thread, String::Handle(String::New("bc"))));
const Array& res = Array::Handle(Match(pat, str));
EXPECT_EQ(2, res.Length());
const Object& res_1 = Object::Handle(res.At(0));
const Object& res_2 = Object::Handle(res.At(1));
EXPECT(res_1.IsSmi());
EXPECT(res_2.IsSmi());
const Smi& smi_1 = Smi::Cast(res_1);
const Smi& smi_2 = Smi::Cast(res_2);
EXPECT_EQ(1, smi_1.Value());
EXPECT_EQ(3, smi_2.Value());
}
} // namespace dart

View file

@ -292,10 +292,8 @@ StringPtr Symbols::FromConcatAll(
intptr_t str_len = lengths[i];
if (str_len > 0) {
const String& str = strs[i];
ASSERT(str.IsOneByteString() || str.IsExternalOneByteString());
const uint8_t* src_p = str.IsOneByteString()
? OneByteString::DataStart(str)
: ExternalOneByteString::DataStart(str);
ASSERT(str.IsOneByteString());
const uint8_t* src_p = OneByteString::DataStart(str);
memmove(buffer, src_p, str_len);
buffer += str_len;
}
@ -312,14 +310,10 @@ StringPtr Symbols::FromConcatAll(
const String& str = strs[i];
if (str.IsTwoByteString()) {
memmove(buffer, TwoByteString::DataStart(str), str_len * 2);
} else if (str.IsExternalTwoByteString()) {
memmove(buffer, ExternalTwoByteString::DataStart(str), str_len * 2);
} else {
// One-byte to two-byte string copy.
ASSERT(str.IsOneByteString() || str.IsExternalOneByteString());
const uint8_t* src_p = str.IsOneByteString()
? OneByteString::DataStart(str)
: ExternalOneByteString::DataStart(str);
ASSERT(str.IsOneByteString());
const uint8_t* src_p = OneByteString::DataStart(str);
for (int n = 0; n < str_len; n++) {
buffer[n] = src_p[n];
}

View file

@ -98,8 +98,6 @@ class ObjectPointerVisitor;
V(ExceptionVar, ":exception_var") \
V(Expando, "Expando") \
V(ExprTemp, ":expr_temp") \
V(ExternalOneByteString, "_ExternalOneByteString") \
V(ExternalTwoByteString, "_ExternalTwoByteString") \
V(FfiAbiSpecificMapping, "_FfiAbiSpecificMapping") \
V(FfiAsyncCallback, "_FfiAsyncCallback") \
V(FfiBool, "Bool") \

View file

@ -423,8 +423,6 @@ DEFINE_TAGGED_POINTER(PointerBase, Instance)
DEFINE_TAGGED_POINTER(TypedDataBase, PointerBase)
DEFINE_TAGGED_POINTER(TypedData, TypedDataBase)
DEFINE_TAGGED_POINTER(TypedDataView, TypedDataBase)
DEFINE_TAGGED_POINTER(ExternalOneByteString, String)
DEFINE_TAGGED_POINTER(ExternalTwoByteString, String)
DEFINE_TAGGED_POINTER(Bool, Instance)
DEFINE_TAGGED_POINTER(Array, Instance)
DEFINE_TAGGED_POINTER(ImmutableArray, Array)

View file

@ -19,21 +19,16 @@ static constexpr uintptr_t kAsciiWordMask = 0x80808080u;
#endif
intptr_t Utf8::Length(const String& str) {
if (str.IsOneByteString() || str.IsExternalOneByteString()) {
if (str.IsOneByteString()) {
// For 1-byte strings, all code points < 0x80 have single-byte UTF-8
// encodings and all >= 0x80 have two-byte encodings. To get the length,
// start with the number of code points and add the number of high bits in
// the bytes.
uintptr_t char_length = str.Length();
uintptr_t length = char_length;
const uintptr_t* data;
NoSafepointScope no_safepoint;
if (str.IsOneByteString()) {
data = reinterpret_cast<const uintptr_t*>(OneByteString::DataStart(str));
} else {
data = reinterpret_cast<const uintptr_t*>(
ExternalOneByteString::DataStart(str));
}
const uintptr_t* data =
reinterpret_cast<const uintptr_t*>(OneByteString::DataStart(str));
uintptr_t i;
for (i = sizeof(uintptr_t); i <= char_length; i += sizeof(uintptr_t)) {
uintptr_t chunk = *data++;
@ -71,17 +66,12 @@ intptr_t Utf8::Encode(const String& src, char* dst, intptr_t len) {
uintptr_t array_len = len;
intptr_t pos = 0;
ASSERT(static_cast<intptr_t>(array_len) >= Length(src));
if (src.IsOneByteString() || src.IsExternalOneByteString()) {
if (src.IsOneByteString()) {
// For 1-byte strings, all code points < 0x80 have single-byte UTF-8
// encodings and all >= 0x80 have two-byte encodings.
const uintptr_t* data;
NoSafepointScope scope;
if (src.IsOneByteString()) {
data = reinterpret_cast<const uintptr_t*>(OneByteString::DataStart(src));
} else {
data = reinterpret_cast<const uintptr_t*>(
ExternalOneByteString::DataStart(src));
}
const uintptr_t* data =
reinterpret_cast<const uintptr_t*>(OneByteString::DataStart(src));
uintptr_t char_length = src.Length();
uintptr_t pos = 0;
ASSERT(kMaxOneByteChar + 1 == 0x80);

View file

@ -14,8 +14,6 @@ class ClassID {
@pragma("vm:entry-point")
static final int cidArray = 0;
@pragma("vm:entry-point")
static final int cidExternalOneByteString = 0;
@pragma("vm:entry-point")
static final int cidGrowableObjectArray = 0;
@pragma("vm:entry-point")
static final int cidImmutableArray = 0;

View file

@ -111,8 +111,7 @@ abstract final class _StringBase implements String {
bool get _isOneByte {
// Alternatively return false and override it on one-byte string classes.
int id = ClassID.getID(this);
return id == ClassID.cidOneByteString ||
id == ClassID.cidExternalOneByteString;
return id == ClassID.cidOneByteString;
}
/**
@ -1084,8 +1083,7 @@ final class _OneByteString extends _StringBase {
// Specialize for single character pattern.
final pCid = ClassID.getID(pattern);
if ((pCid == ClassID.cidOneByteString) ||
(pCid == ClassID.cidTwoByteString) ||
(pCid == ClassID.cidExternalOneByteString)) {
(pCid == ClassID.cidTwoByteString)) {
final String patternAsString = unsafeCast<String>(pattern);
final len = this.length;
if ((patternAsString.length == 1) && (start >= 0) && (start < len)) {
@ -1107,8 +1105,7 @@ final class _OneByteString extends _StringBase {
bool contains(Pattern pattern, [int start = 0]) {
final pCid = ClassID.getID(pattern);
if ((pCid == ClassID.cidOneByteString) ||
(pCid == ClassID.cidTwoByteString) ||
(pCid == ClassID.cidExternalOneByteString)) {
(pCid == ClassID.cidTwoByteString)) {
final String patternAsString = unsafeCast<String>(pattern);
final len = this.length;
if ((patternAsString.length == 1) && (start >= 0) && (start < len)) {
@ -1147,8 +1144,7 @@ final class _OneByteString extends _StringBase {
String padLeft(int width, [String padding = ' ']) {
int padCid = ClassID.getID(padding);
if ((padCid != ClassID.cidOneByteString) &&
(padCid != ClassID.cidExternalOneByteString)) {
if (padCid != ClassID.cidOneByteString) {
return super.padLeft(width, padding);
}
int length = this.length;
@ -1178,8 +1174,7 @@ final class _OneByteString extends _StringBase {
String padRight(int width, [String padding = ' ']) {
int padCid = ClassID.getID(padding);
if ((padCid != ClassID.cidOneByteString) &&
(padCid != ClassID.cidExternalOneByteString)) {
if (padCid != ClassID.cidOneByteString) {
return super.padRight(width, padding);
}
int length = this.length;
@ -1321,7 +1316,7 @@ final class _OneByteString extends _StringBase {
}
// Should be optimizable to a memory move.
// Accepts both _OneByteString and _ExternalOneByteString as argument.
// Accepts _OneByteString as argument.
// Returns index after last character written.
int _setRange(int index, String oneByteString, int start, int end) {
assert(oneByteString._isOneByte);
@ -1401,48 +1396,6 @@ final class _TwoByteString extends _StringBase {
}
}
@pragma('vm:deeply-immutable')
@pragma("vm:entry-point")
final class _ExternalOneByteString extends _StringBase {
factory _ExternalOneByteString._uninstantiable() {
throw "Unreachable";
}
bool _isWhitespace(int codeUnit) {
return _StringBase._isOneByteWhitespace(codeUnit);
}
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:exact-result-type", "dart:core#_Smi")
@pragma("vm:external-name", "String_codeUnitAt")
external int codeUnitAt(int index);
bool operator ==(Object other) {
return super == other;
}
}
@pragma('vm:deeply-immutable')
@pragma("vm:entry-point")
final class _ExternalTwoByteString extends _StringBase {
factory _ExternalTwoByteString._uninstantiable() {
throw "Unreachable";
}
bool _isWhitespace(int codeUnit) {
return _StringBase._isTwoByteWhitespace(codeUnit);
}
@pragma("vm:recognized", "graph-intrinsic")
@pragma("vm:exact-result-type", "dart:core#_Smi")
@pragma("vm:external-name", "String_codeUnitAt")
external int codeUnitAt(int index);
bool operator ==(Object other) {
return super == other;
}
}
final class _StringMatch implements Match {
const _StringMatch(this.start, this.input, this.pattern);