| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/bootstrap_natives.h" | 5 #include "vm/bootstrap_natives.h" |
| 6 | 6 |
| 7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
| 8 #include "vm/exceptions.h" | 8 #include "vm/exceptions.h" |
| 9 #include "vm/dart_api_impl.h" | 9 #include "vm/dart_api_impl.h" |
| 10 #include "vm/isolate.h" | 10 #include "vm/isolate.h" |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 intptr_t end = end_obj.Value(); | 55 intptr_t end = end_obj.Value(); |
| 56 if ((end < start) || (end > length)) { | 56 if ((end < start) || (end > length)) { |
| 57 Exceptions::ThrowArgumentError(end_obj); | 57 Exceptions::ThrowArgumentError(end_obj); |
| 58 } | 58 } |
| 59 | 59 |
| 60 // Unbox the array and determine the maximum element width. | 60 // Unbox the array and determine the maximum element width. |
| 61 bool is_one_byte_string = true; | 61 bool is_one_byte_string = true; |
| 62 intptr_t array_len = end - start; | 62 intptr_t array_len = end - start; |
| 63 intptr_t utf16_len = array_len; | 63 intptr_t utf16_len = array_len; |
| 64 int32_t* utf32_array = zone->Alloc<int32_t>(array_len); | 64 int32_t* utf32_array = zone->Alloc<int32_t>(array_len); |
| 65 Instance& index_object = Instance::Handle(isolate); | 65 Instance& index_object = Instance::Handle(zone); |
| 66 for (intptr_t i = 0; i < array_len; i++) { | 66 for (intptr_t i = 0; i < array_len; i++) { |
| 67 index_object ^= a.At(start + i); | 67 index_object ^= a.At(start + i); |
| 68 if (!index_object.IsSmi()) { | 68 if (!index_object.IsSmi()) { |
| 69 Exceptions::ThrowArgumentError(index_object); | 69 Exceptions::ThrowArgumentError(index_object); |
| 70 } | 70 } |
| 71 intptr_t value = Smi::Cast(index_object).Value(); | 71 intptr_t value = Smi::Cast(index_object).Value(); |
| 72 if (Utf::IsOutOfRange(value)) { | 72 if (Utf::IsOutOfRange(value)) { |
| 73 Exceptions::ThrowByType(Exceptions::kArgument, Object::empty_array()); | 73 Exceptions::ThrowByType(Exceptions::kArgument, Object::empty_array()); |
| 74 UNREACHABLE(); | 74 UNREACHABLE(); |
| 75 } | 75 } |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 | 163 |
| 164 | 164 |
| 165 DEFINE_NATIVE_ENTRY(StringBase_joinReplaceAllResult, 4) { | 165 DEFINE_NATIVE_ENTRY(StringBase_joinReplaceAllResult, 4) { |
| 166 const String& base = String::CheckedHandle(arguments->NativeArgAt(0)); | 166 const String& base = String::CheckedHandle(arguments->NativeArgAt(0)); |
| 167 GET_NON_NULL_NATIVE_ARGUMENT(GrowableObjectArray, | 167 GET_NON_NULL_NATIVE_ARGUMENT(GrowableObjectArray, |
| 168 matches_growable, arguments->NativeArgAt(1)); | 168 matches_growable, arguments->NativeArgAt(1)); |
| 169 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length_obj, arguments->NativeArgAt(2)); | 169 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length_obj, arguments->NativeArgAt(2)); |
| 170 GET_NON_NULL_NATIVE_ARGUMENT(Bool, is_onebyte_obj, arguments->NativeArgAt(3)); | 170 GET_NON_NULL_NATIVE_ARGUMENT(Bool, is_onebyte_obj, arguments->NativeArgAt(3)); |
| 171 | 171 |
| 172 intptr_t len = matches_growable.Length(); | 172 intptr_t len = matches_growable.Length(); |
| 173 const Array& matches = Array::Handle(isolate, matches_growable.data()); | 173 const Array& matches = Array::Handle(zone, matches_growable.data()); |
| 174 | 174 |
| 175 const intptr_t length = length_obj.Value(); | 175 const intptr_t length = length_obj.Value(); |
| 176 if (length < 0) { | 176 if (length < 0) { |
| 177 Exceptions::ThrowArgumentError(length_obj); | 177 Exceptions::ThrowArgumentError(length_obj); |
| 178 } | 178 } |
| 179 | 179 |
| 180 // Start out assuming result is one-byte if replacements are. | 180 // Start out assuming result is one-byte if replacements are. |
| 181 bool is_onebyte = is_onebyte_obj.value(); | 181 bool is_onebyte = is_onebyte_obj.value(); |
| 182 if (is_onebyte) { | 182 if (is_onebyte) { |
| 183 // If any of the base string slices are not one-byte, the result will be | 183 // If any of the base string slices are not one-byte, the result will be |
| 184 // a two-byte string. | 184 // a two-byte string. |
| 185 if (!base.IsOneByteString() && !base.IsExternalOneByteString()) { | 185 if (!base.IsOneByteString() && !base.IsExternalOneByteString()) { |
| 186 is_onebyte = CheckSlicesOneByte(base, matches, len); | 186 is_onebyte = CheckSlicesOneByte(base, matches, len); |
| 187 } | 187 } |
| 188 } | 188 } |
| 189 | 189 |
| 190 const intptr_t base_length = base.Length(); | 190 const intptr_t base_length = base.Length(); |
| 191 String& result = String::Handle(isolate); | 191 String& result = String::Handle(zone); |
| 192 if (is_onebyte) { | 192 if (is_onebyte) { |
| 193 result ^= OneByteString::New(length, Heap::kNew); | 193 result ^= OneByteString::New(length, Heap::kNew); |
| 194 } else { | 194 } else { |
| 195 result ^= TwoByteString::New(length, Heap::kNew); | 195 result ^= TwoByteString::New(length, Heap::kNew); |
| 196 } | 196 } |
| 197 Instance& object = Instance::Handle(isolate); | 197 Instance& object = Instance::Handle(zone); |
| 198 intptr_t write_index = 0; | 198 intptr_t write_index = 0; |
| 199 for (intptr_t i = 0; i < len; i++) { | 199 for (intptr_t i = 0; i < len; i++) { |
| 200 object ^= matches.At(i); | 200 object ^= matches.At(i); |
| 201 if (object.IsSmi()) { | 201 if (object.IsSmi()) { |
| 202 intptr_t slice_start = Smi::Cast(object).Value(); | 202 intptr_t slice_start = Smi::Cast(object).Value(); |
| 203 intptr_t slice_length = -1; | 203 intptr_t slice_length = -1; |
| 204 // Slices with limited ranges are stored in a single negative Smi. | 204 // Slices with limited ranges are stored in a single negative Smi. |
| 205 if (slice_start < 0) { | 205 if (slice_start < 0) { |
| 206 intptr_t bits = -slice_start; | 206 intptr_t bits = -slice_start; |
| 207 slice_start = bits >> kLengthSize; | 207 slice_start = bits >> kLengthSize; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); | 257 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); |
| 258 | 258 |
| 259 const intptr_t start = start_obj.Value(); | 259 const intptr_t start = start_obj.Value(); |
| 260 const intptr_t end = end_obj.Value(); | 260 const intptr_t end = end_obj.Value(); |
| 261 return OneByteString::New(receiver, start, end - start, Heap::kNew); | 261 return OneByteString::New(receiver, start, end - start, Heap::kNew); |
| 262 } | 262 } |
| 263 | 263 |
| 264 | 264 |
| 265 // This is high-performance code. | 265 // This is high-performance code. |
| 266 DEFINE_NATIVE_ENTRY(OneByteString_splitWithCharCode, 2) { | 266 DEFINE_NATIVE_ENTRY(OneByteString_splitWithCharCode, 2) { |
| 267 const String& receiver = String::CheckedHandle(isolate, | 267 const String& receiver = String::CheckedHandle(zone, |
| 268 arguments->NativeArgAt(0)); | 268 arguments->NativeArgAt(0)); |
| 269 ASSERT(receiver.IsOneByteString()); | 269 ASSERT(receiver.IsOneByteString()); |
| 270 GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_split_code, arguments->NativeArgAt(1)); | 270 GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_split_code, arguments->NativeArgAt(1)); |
| 271 const intptr_t len = receiver.Length(); | 271 const intptr_t len = receiver.Length(); |
| 272 const intptr_t split_code = smi_split_code.Value(); | 272 const intptr_t split_code = smi_split_code.Value(); |
| 273 const GrowableObjectArray& result = GrowableObjectArray::Handle( | 273 const GrowableObjectArray& result = GrowableObjectArray::Handle( |
| 274 isolate, | 274 zone, |
| 275 GrowableObjectArray::New(16, Heap::kNew)); | 275 GrowableObjectArray::New(16, Heap::kNew)); |
| 276 String& str = String::Handle(isolate); | 276 String& str = String::Handle(zone); |
| 277 intptr_t start = 0; | 277 intptr_t start = 0; |
| 278 intptr_t i = 0; | 278 intptr_t i = 0; |
| 279 for (; i < len; i++) { | 279 for (; i < len; i++) { |
| 280 if (split_code == OneByteString::CharAt(receiver, i)) { | 280 if (split_code == OneByteString::CharAt(receiver, i)) { |
| 281 str = OneByteString::SubStringUnchecked(receiver, | 281 str = OneByteString::SubStringUnchecked(receiver, |
| 282 start, | 282 start, |
| 283 (i - start), | 283 (i - start), |
| 284 Heap::kNew); | 284 Heap::kNew); |
| 285 result.Add(str); | 285 result.Add(str); |
| 286 start = i + 1; | 286 start = i + 1; |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 440 } | 440 } |
| 441 return TwoByteString::New(array, start * sizeof(uint16_t), length, space); | 441 return TwoByteString::New(array, start * sizeof(uint16_t), length, space); |
| 442 } else if (RawObject::IsTypedDataViewClassId(list.GetClassId())) { | 442 } else if (RawObject::IsTypedDataViewClassId(list.GetClassId())) { |
| 443 const intptr_t cid = list.GetClassId(); | 443 const intptr_t cid = list.GetClassId(); |
| 444 if (cid != kTypedDataUint16ArrayViewCid) { | 444 if (cid != kTypedDataUint16ArrayViewCid) { |
| 445 Exceptions::ThrowArgumentError(list); | 445 Exceptions::ThrowArgumentError(list); |
| 446 } | 446 } |
| 447 if (end > Smi::Value(TypedDataView::Length(list))) { | 447 if (end > Smi::Value(TypedDataView::Length(list))) { |
| 448 Exceptions::ThrowArgumentError(end_obj); | 448 Exceptions::ThrowArgumentError(end_obj); |
| 449 } | 449 } |
| 450 const Instance& data_obj = Instance::Handle(isolate, | 450 const Instance& data_obj = Instance::Handle(zone, |
| 451 TypedDataView::Data(list)); | 451 TypedDataView::Data(list)); |
| 452 intptr_t data_offset = Smi::Value(TypedDataView::OffsetInBytes(list)); | 452 intptr_t data_offset = Smi::Value(TypedDataView::OffsetInBytes(list)); |
| 453 if (data_obj.IsTypedData()) { | 453 if (data_obj.IsTypedData()) { |
| 454 const TypedData& array = TypedData::Cast(data_obj); | 454 const TypedData& array = TypedData::Cast(data_obj); |
| 455 return TwoByteString::New(array, data_offset + start * sizeof(uint16_t), | 455 return TwoByteString::New(array, data_offset + start * sizeof(uint16_t), |
| 456 length, space); | 456 length, space); |
| 457 } else if (data_obj.IsExternalTypedData()) { | 457 } else if (data_obj.IsExternalTypedData()) { |
| 458 const ExternalTypedData& array = ExternalTypedData::Cast(data_obj); | 458 const ExternalTypedData& array = ExternalTypedData::Cast(data_obj); |
| 459 return TwoByteString::New(array, data_offset + start * sizeof(uint16_t), | 459 return TwoByteString::New(array, data_offset + start * sizeof(uint16_t), |
| 460 length, space); | 460 length, space); |
| 461 } | 461 } |
| 462 } else if (list.IsArray()) { | 462 } else if (list.IsArray()) { |
| 463 const Array& array = Array::Cast(list); | 463 const Array& array = Array::Cast(list); |
| 464 if (end > array.Length()) { | 464 if (end > array.Length()) { |
| 465 Exceptions::ThrowArgumentError(end_obj); | 465 Exceptions::ThrowArgumentError(end_obj); |
| 466 } | 466 } |
| 467 const String& string = String::Handle(isolate, | 467 const String& string = String::Handle(zone, |
| 468 TwoByteString::New(length, space)); | 468 TwoByteString::New(length, space)); |
| 469 for (int i = 0; i < length; i++) { | 469 for (int i = 0; i < length; i++) { |
| 470 intptr_t value = | 470 intptr_t value = |
| 471 Smi::Value(reinterpret_cast<RawSmi*>(array.At(start + i))); | 471 Smi::Value(reinterpret_cast<RawSmi*>(array.At(start + i))); |
| 472 TwoByteString::SetCharAt(string, i, value); | 472 TwoByteString::SetCharAt(string, i, value); |
| 473 } | 473 } |
| 474 return string.raw(); | 474 return string.raw(); |
| 475 } else if (list.IsGrowableObjectArray()) { | 475 } else if (list.IsGrowableObjectArray()) { |
| 476 const GrowableObjectArray& array = GrowableObjectArray::Cast(list); | 476 const GrowableObjectArray& array = GrowableObjectArray::Cast(list); |
| 477 if (end > array.Length()) { | 477 if (end > array.Length()) { |
| 478 Exceptions::ThrowArgumentError(end_obj); | 478 Exceptions::ThrowArgumentError(end_obj); |
| 479 } | 479 } |
| 480 const String& string = String::Handle(isolate, | 480 const String& string = String::Handle(zone, |
| 481 TwoByteString::New(length, space)); | 481 TwoByteString::New(length, space)); |
| 482 for (int i = 0; i < length; i++) { | 482 for (int i = 0; i < length; i++) { |
| 483 intptr_t value = | 483 intptr_t value = |
| 484 Smi::Value(reinterpret_cast<RawSmi*>(array.At(start + i))); | 484 Smi::Value(reinterpret_cast<RawSmi*>(array.At(start + i))); |
| 485 TwoByteString::SetCharAt(string, i, value); | 485 TwoByteString::SetCharAt(string, i, value); |
| 486 } | 486 } |
| 487 return string.raw(); | 487 return string.raw(); |
| 488 } | 488 } |
| 489 UNREACHABLE(); | 489 UNREACHABLE(); |
| 490 return Object::null(); | 490 return Object::null(); |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 607 ? String::Handle(OneByteString::New(length_value, Heap::kNew)) | 607 ? String::Handle(OneByteString::New(length_value, Heap::kNew)) |
| 608 : String::Handle(TwoByteString::New(length_value, Heap::kNew)); | 608 : String::Handle(TwoByteString::New(length_value, Heap::kNew)); |
| 609 NoGCScope no_gc; | 609 NoGCScope no_gc; |
| 610 | 610 |
| 611 uint16_t* data_position = reinterpret_cast<uint16_t*>(codeUnits.DataAddr(0)); | 611 uint16_t* data_position = reinterpret_cast<uint16_t*>(codeUnits.DataAddr(0)); |
| 612 String::Copy(result, 0, data_position, length_value); | 612 String::Copy(result, 0, data_position, length_value); |
| 613 return result.raw(); | 613 return result.raw(); |
| 614 } | 614 } |
| 615 | 615 |
| 616 } // namespace dart | 616 } // namespace dart |
| OLD | NEW |