Index: runtime/lib/string.cc |
diff --git a/runtime/lib/string.cc b/runtime/lib/string.cc |
index 2dd69e54f47d279453292688d874bf02d85513e9..c72f14f32c26c7ef0956870e82966e35e667cd49 100644 |
--- a/runtime/lib/string.cc |
+++ b/runtime/lib/string.cc |
@@ -407,6 +407,92 @@ DEFINE_NATIVE_ENTRY(ExternalOneByteString_getCid, 0) { |
} |
+DEFINE_NATIVE_ENTRY(TwoByteString_allocateFromTwoByteList, 3) { |
+ Instance& list = Instance::CheckedHandle(arguments->NativeArgAt(0)); |
+ GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); |
+ GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); |
+ |
+ intptr_t start = start_obj.Value(); |
+ intptr_t end = end_obj.Value(); |
+ if (start < 0) { |
+ Exceptions::ThrowArgumentError(start_obj); |
+ } |
+ intptr_t length = end - start; |
+ if (length < 0) { |
+ Exceptions::ThrowArgumentError(end_obj); |
+ } |
+ |
+ Heap::Space space = isolate->heap()->SpaceForAllocation(kTwoByteStringCid); |
+ if (list.IsTypedData()) { |
+ const TypedData& array = TypedData::Cast(list); |
+ if (array.ElementType() != kUint16ArrayElement) { |
+ Exceptions::ThrowArgumentError(list); |
+ } |
+ if (end > array.Length()) { |
+ Exceptions::ThrowArgumentError(end_obj); |
+ } |
+ return TwoByteString::New(array, start * sizeof(uint16_t), length, space); |
+ } else if (list.IsExternalTypedData()) { |
+ const ExternalTypedData& array = ExternalTypedData::Cast(list); |
+ if (array.ElementType() != kUint16ArrayElement) { |
+ Exceptions::ThrowArgumentError(list); |
+ } |
+ if (end > array.Length()) { |
+ Exceptions::ThrowArgumentError(end_obj); |
+ } |
+ return TwoByteString::New(array, start * sizeof(uint16_t), length, space); |
+ } else if (RawObject::IsTypedDataViewClassId(list.GetClassId())) { |
+ const intptr_t cid = list.GetClassId(); |
+ if (cid != kTypedDataUint16ArrayViewCid) { |
+ Exceptions::ThrowArgumentError(list); |
+ } |
+ if (end > Smi::Value(TypedDataView::Length(list))) { |
+ Exceptions::ThrowArgumentError(end_obj); |
+ } |
+ const Instance& data_obj = Instance::Handle(isolate, |
+ TypedDataView::Data(list)); |
+ intptr_t data_offset = Smi::Value(TypedDataView::OffsetInBytes(list)); |
+ if (data_obj.IsTypedData()) { |
+ const TypedData& array = TypedData::Cast(data_obj); |
+ return TwoByteString::New(array, data_offset + start * sizeof(uint16_t), |
+ length, space); |
+ } else if (data_obj.IsExternalTypedData()) { |
+ const ExternalTypedData& array = ExternalTypedData::Cast(data_obj); |
+ return TwoByteString::New(array, data_offset + start * sizeof(uint16_t), |
+ length, space); |
+ } |
+ } else if (list.IsArray()) { |
+ const Array& array = Array::Cast(list); |
+ if (end > array.Length()) { |
+ Exceptions::ThrowArgumentError(end_obj); |
+ } |
+ const String& string = String::Handle(isolate, |
+ TwoByteString::New(length, space)); |
+ for (int i = 0; i < length; i++) { |
+ intptr_t value = |
+ Smi::Value(reinterpret_cast<RawSmi*>(array.At(start + i))); |
+ TwoByteString::SetCharAt(string, i, value); |
+ } |
+ return string.raw(); |
+ } else if (list.IsGrowableObjectArray()) { |
+ const GrowableObjectArray& array = GrowableObjectArray::Cast(list); |
+ if (end > array.Length()) { |
+ Exceptions::ThrowArgumentError(end_obj); |
+ } |
+ const String& string = String::Handle(isolate, |
+ TwoByteString::New(length, space)); |
+ for (int i = 0; i < length; i++) { |
+ intptr_t value = |
+ Smi::Value(reinterpret_cast<RawSmi*>(array.At(start + i))); |
+ TwoByteString::SetCharAt(string, i, value); |
+ } |
+ return string.raw(); |
+ } |
+ UNREACHABLE(); |
+ return Object::null(); |
+} |
+ |
+ |
DEFINE_NATIVE_ENTRY(String_getHashCode, 1) { |
const String& receiver = String::CheckedHandle(arguments->NativeArgAt(0)); |
intptr_t hash_val = receiver.Hash(); |