| 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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 utf32_array[i] = value32; | 84 utf32_array[i] = value32; |
| 85 } | 85 } |
| 86 if (is_one_byte_string) { | 86 if (is_one_byte_string) { |
| 87 return OneByteString::New(utf32_array, array_len, Heap::kNew); | 87 return OneByteString::New(utf32_array, array_len, Heap::kNew); |
| 88 } | 88 } |
| 89 return TwoByteString::New(utf16_len, utf32_array, array_len, Heap::kNew); | 89 return TwoByteString::New(utf16_len, utf32_array, array_len, Heap::kNew); |
| 90 } | 90 } |
| 91 | 91 |
| 92 | 92 |
| 93 DEFINE_NATIVE_ENTRY(StringBase_substringUnchecked, 3) { | 93 DEFINE_NATIVE_ENTRY(StringBase_substringUnchecked, 3) { |
| 94 const String& receiver = String::CheckedHandle(zone, | 94 const String& receiver = |
| 95 arguments->NativeArgAt(0)); | 95 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 96 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); | 96 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); |
| 97 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); | 97 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); |
| 98 | 98 |
| 99 intptr_t start = start_obj.Value(); | 99 intptr_t start = start_obj.Value(); |
| 100 intptr_t end = end_obj.Value(); | 100 intptr_t end = end_obj.Value(); |
| 101 return String::SubString(receiver, start, (end - start)); | 101 return String::SubString(receiver, start, (end - start)); |
| 102 } | 102 } |
| 103 | 103 |
| 104 | 104 |
| 105 | |
| 106 // Return the bitwise-or of all characters in the slice from start to end. | 105 // Return the bitwise-or of all characters in the slice from start to end. |
| 107 static uint16_t CharacterLimit(const String& string, | 106 static uint16_t CharacterLimit(const String& string, |
| 108 intptr_t start, intptr_t end) { | 107 intptr_t start, |
| 108 intptr_t end) { |
| 109 ASSERT(string.IsTwoByteString() || string.IsExternalTwoByteString()); | 109 ASSERT(string.IsTwoByteString() || string.IsExternalTwoByteString()); |
| 110 // Maybe do loop unrolling, and handle two uint16_t in a single uint32_t | 110 // Maybe do loop unrolling, and handle two uint16_t in a single uint32_t |
| 111 // operation. | 111 // operation. |
| 112 NoSafepointScope no_safepoint; | 112 NoSafepointScope no_safepoint; |
| 113 uint16_t result = 0; | 113 uint16_t result = 0; |
| 114 if (string.IsTwoByteString()) { | 114 if (string.IsTwoByteString()) { |
| 115 for (intptr_t i = start; i < end; i++) { | 115 for (intptr_t i = start; i < end; i++) { |
| 116 result |= TwoByteString::CharAt(string, i); | 116 result |= TwoByteString::CharAt(string, i); |
| 117 } | 117 } |
| 118 } else { | 118 } else { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 157 if (char_limit > 0xff) { | 157 if (char_limit > 0xff) { |
| 158 return false; | 158 return false; |
| 159 } | 159 } |
| 160 } | 160 } |
| 161 } | 161 } |
| 162 return true; | 162 return true; |
| 163 } | 163 } |
| 164 | 164 |
| 165 | 165 |
| 166 DEFINE_NATIVE_ENTRY(StringBase_joinReplaceAllResult, 4) { | 166 DEFINE_NATIVE_ENTRY(StringBase_joinReplaceAllResult, 4) { |
| 167 const String& base = String::CheckedHandle(zone, | 167 const String& base = String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 168 arguments->NativeArgAt(0)); | 168 GET_NON_NULL_NATIVE_ARGUMENT(GrowableObjectArray, matches_growable, |
| 169 GET_NON_NULL_NATIVE_ARGUMENT(GrowableObjectArray, | 169 arguments->NativeArgAt(1)); |
| 170 matches_growable, arguments->NativeArgAt(1)); | |
| 171 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length_obj, arguments->NativeArgAt(2)); | 170 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length_obj, arguments->NativeArgAt(2)); |
| 172 GET_NON_NULL_NATIVE_ARGUMENT(Bool, is_onebyte_obj, arguments->NativeArgAt(3)); | 171 GET_NON_NULL_NATIVE_ARGUMENT(Bool, is_onebyte_obj, arguments->NativeArgAt(3)); |
| 173 | 172 |
| 174 intptr_t len = matches_growable.Length(); | 173 intptr_t len = matches_growable.Length(); |
| 175 const Array& matches = Array::Handle(zone, matches_growable.data()); | 174 const Array& matches = Array::Handle(zone, matches_growable.data()); |
| 176 | 175 |
| 177 const intptr_t length = length_obj.Value(); | 176 const intptr_t length = length_obj.Value(); |
| 178 if (length < 0) { | 177 if (length < 0) { |
| 179 Exceptions::ThrowArgumentError(length_obj); | 178 Exceptions::ThrowArgumentError(length_obj); |
| 180 } | 179 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 i++; | 211 i++; |
| 213 if (i < len) { // Otherwise slice_length stays at -1. | 212 if (i < len) { // Otherwise slice_length stays at -1. |
| 214 object ^= matches.At(i); | 213 object ^= matches.At(i); |
| 215 if (object.IsSmi()) { | 214 if (object.IsSmi()) { |
| 216 intptr_t slice_end = Smi::Cast(object).Value(); | 215 intptr_t slice_end = Smi::Cast(object).Value(); |
| 217 slice_length = slice_end - slice_start; | 216 slice_length = slice_end - slice_start; |
| 218 } | 217 } |
| 219 } | 218 } |
| 220 } | 219 } |
| 221 if (slice_length > 0) { | 220 if (slice_length > 0) { |
| 222 if (0 <= slice_start && | 221 if (0 <= slice_start && slice_start + slice_length <= base_length && |
| 223 slice_start + slice_length <= base_length && | |
| 224 write_index + slice_length <= length) { | 222 write_index + slice_length <= length) { |
| 225 String::Copy(result, write_index, | 223 String::Copy(result, write_index, base, slice_start, slice_length); |
| 226 base, slice_start, | |
| 227 slice_length); | |
| 228 write_index += slice_length; | 224 write_index += slice_length; |
| 229 continue; | 225 continue; |
| 230 } | 226 } |
| 231 } | 227 } |
| 232 // Either the slice_length was zero, | 228 // Either the slice_length was zero, |
| 233 // or the first smi was positive and not followed by another smi, | 229 // or the first smi was positive and not followed by another smi, |
| 234 // or the smis were not a valid slice of the base string, | 230 // or the smis were not a valid slice of the base string, |
| 235 // or the slice was too large to fit in the result. | 231 // or the slice was too large to fit in the result. |
| 236 // Something is wrong with the matches array! | 232 // Something is wrong with the matches array! |
| 237 Exceptions::ThrowArgumentError(matches_growable); | 233 Exceptions::ThrowArgumentError(matches_growable); |
| 238 } else if (object.IsString()) { | 234 } else if (object.IsString()) { |
| 239 const String& replacement = String::Cast(object); | 235 const String& replacement = String::Cast(object); |
| 240 intptr_t replacement_length = replacement.Length(); | 236 intptr_t replacement_length = replacement.Length(); |
| 241 if (write_index + replacement_length > length) { | 237 if (write_index + replacement_length > length) { |
| 242 // Invalid input data, either in matches list or the total length. | 238 // Invalid input data, either in matches list or the total length. |
| 243 Exceptions::ThrowArgumentError(matches_growable); | 239 Exceptions::ThrowArgumentError(matches_growable); |
| 244 } | 240 } |
| 245 String::Copy(result, write_index, replacement, 0, replacement_length); | 241 String::Copy(result, write_index, replacement, 0, replacement_length); |
| 246 write_index += replacement_length; | 242 write_index += replacement_length; |
| 247 } | 243 } |
| 248 } | 244 } |
| 249 if (write_index < length) { | 245 if (write_index < length) { |
| 250 Exceptions::ThrowArgumentError(matches_growable); | 246 Exceptions::ThrowArgumentError(matches_growable); |
| 251 } | 247 } |
| 252 return result.raw(); | 248 return result.raw(); |
| 253 } | 249 } |
| 254 | 250 |
| 255 DEFINE_NATIVE_ENTRY(OneByteString_substringUnchecked, 3) { | 251 DEFINE_NATIVE_ENTRY(OneByteString_substringUnchecked, 3) { |
| 256 const String& receiver = String::CheckedHandle(zone, | 252 const String& receiver = |
| 257 arguments->NativeArgAt(0)); | 253 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 258 ASSERT(receiver.IsOneByteString()); | 254 ASSERT(receiver.IsOneByteString()); |
| 259 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); | 255 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); |
| 260 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); | 256 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); |
| 261 | 257 |
| 262 const intptr_t start = start_obj.Value(); | 258 const intptr_t start = start_obj.Value(); |
| 263 const intptr_t end = end_obj.Value(); | 259 const intptr_t end = end_obj.Value(); |
| 264 return OneByteString::New(receiver, start, end - start, Heap::kNew); | 260 return OneByteString::New(receiver, start, end - start, Heap::kNew); |
| 265 } | 261 } |
| 266 | 262 |
| 267 | 263 |
| 268 // This is high-performance code. | 264 // This is high-performance code. |
| 269 DEFINE_NATIVE_ENTRY(OneByteString_splitWithCharCode, 2) { | 265 DEFINE_NATIVE_ENTRY(OneByteString_splitWithCharCode, 2) { |
| 270 const String& receiver = String::CheckedHandle(zone, | 266 const String& receiver = |
| 271 arguments->NativeArgAt(0)); | 267 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 272 ASSERT(receiver.IsOneByteString()); | 268 ASSERT(receiver.IsOneByteString()); |
| 273 GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_split_code, arguments->NativeArgAt(1)); | 269 GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_split_code, arguments->NativeArgAt(1)); |
| 274 const intptr_t len = receiver.Length(); | 270 const intptr_t len = receiver.Length(); |
| 275 const intptr_t split_code = smi_split_code.Value(); | 271 const intptr_t split_code = smi_split_code.Value(); |
| 276 const GrowableObjectArray& result = GrowableObjectArray::Handle( | 272 const GrowableObjectArray& result = GrowableObjectArray::Handle( |
| 277 zone, | 273 zone, GrowableObjectArray::New(16, Heap::kNew)); |
| 278 GrowableObjectArray::New(16, Heap::kNew)); | |
| 279 String& str = String::Handle(zone); | 274 String& str = String::Handle(zone); |
| 280 intptr_t start = 0; | 275 intptr_t start = 0; |
| 281 intptr_t i = 0; | 276 intptr_t i = 0; |
| 282 for (; i < len; i++) { | 277 for (; i < len; i++) { |
| 283 if (split_code == OneByteString::CharAt(receiver, i)) { | 278 if (split_code == OneByteString::CharAt(receiver, i)) { |
| 284 str = OneByteString::SubStringUnchecked(receiver, | 279 str = OneByteString::SubStringUnchecked(receiver, start, (i - start), |
| 285 start, | |
| 286 (i - start), | |
| 287 Heap::kNew); | 280 Heap::kNew); |
| 288 result.Add(str); | 281 result.Add(str); |
| 289 start = i + 1; | 282 start = i + 1; |
| 290 } | 283 } |
| 291 } | 284 } |
| 292 str = OneByteString::SubStringUnchecked(receiver, | 285 str = OneByteString::SubStringUnchecked(receiver, start, (i - start), |
| 293 start, | |
| 294 (i - start), | |
| 295 Heap::kNew); | 286 Heap::kNew); |
| 296 result.Add(str); | 287 result.Add(str); |
| 297 return result.raw(); | 288 return result.raw(); |
| 298 } | 289 } |
| 299 | 290 |
| 300 | 291 |
| 301 DEFINE_NATIVE_ENTRY(OneByteString_allocate, 1) { | 292 DEFINE_NATIVE_ENTRY(OneByteString_allocate, 1) { |
| 302 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length_obj, arguments->NativeArgAt(0)); | 293 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length_obj, arguments->NativeArgAt(0)); |
| 303 return OneByteString::New(length_obj.Value(), Heap::kNew); | 294 return OneByteString::New(length_obj.Value(), Heap::kNew); |
| 304 } | 295 } |
| 305 | 296 |
| 306 | 297 |
| 307 DEFINE_NATIVE_ENTRY(OneByteString_allocateFromOneByteList, 3) { | 298 DEFINE_NATIVE_ENTRY(OneByteString_allocateFromOneByteList, 3) { |
| 308 Instance& list = Instance::CheckedHandle(zone, | 299 Instance& list = Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 309 arguments->NativeArgAt(0)); | |
| 310 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); | 300 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); |
| 311 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); | 301 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); |
| 312 | 302 |
| 313 intptr_t start = start_obj.Value(); | 303 intptr_t start = start_obj.Value(); |
| 314 intptr_t end = end_obj.Value(); | 304 intptr_t end = end_obj.Value(); |
| 315 if (start < 0) { | 305 if (start < 0) { |
| 316 const Array& args = Array::Handle(Array::New(1)); | 306 const Array& args = Array::Handle(Array::New(1)); |
| 317 args.SetAt(0, start_obj); | 307 args.SetAt(0, start_obj); |
| 318 Exceptions::ThrowByType(Exceptions::kArgument, args); | 308 Exceptions::ThrowByType(Exceptions::kArgument, args); |
| 319 } | 309 } |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 402 return Object::null(); | 392 return Object::null(); |
| 403 } | 393 } |
| 404 | 394 |
| 405 | 395 |
| 406 DEFINE_NATIVE_ENTRY(ExternalOneByteString_getCid, 0) { | 396 DEFINE_NATIVE_ENTRY(ExternalOneByteString_getCid, 0) { |
| 407 return Smi::New(kExternalOneByteStringCid); | 397 return Smi::New(kExternalOneByteStringCid); |
| 408 } | 398 } |
| 409 | 399 |
| 410 | 400 |
| 411 DEFINE_NATIVE_ENTRY(TwoByteString_allocateFromTwoByteList, 3) { | 401 DEFINE_NATIVE_ENTRY(TwoByteString_allocateFromTwoByteList, 3) { |
| 412 Instance& list = Instance::CheckedHandle(zone, | 402 Instance& list = Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 413 arguments->NativeArgAt(0)); | |
| 414 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); | 403 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); |
| 415 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); | 404 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); |
| 416 | 405 |
| 417 intptr_t start = start_obj.Value(); | 406 intptr_t start = start_obj.Value(); |
| 418 intptr_t end = end_obj.Value(); | 407 intptr_t end = end_obj.Value(); |
| 419 if (start < 0) { | 408 if (start < 0) { |
| 420 Exceptions::ThrowArgumentError(start_obj); | 409 Exceptions::ThrowArgumentError(start_obj); |
| 421 } | 410 } |
| 422 intptr_t length = end - start; | 411 intptr_t length = end - start; |
| 423 if (length < 0) { | 412 if (length < 0) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 444 } | 433 } |
| 445 return TwoByteString::New(array, start * sizeof(uint16_t), length, space); | 434 return TwoByteString::New(array, start * sizeof(uint16_t), length, space); |
| 446 } else if (RawObject::IsTypedDataViewClassId(list.GetClassId())) { | 435 } else if (RawObject::IsTypedDataViewClassId(list.GetClassId())) { |
| 447 const intptr_t cid = list.GetClassId(); | 436 const intptr_t cid = list.GetClassId(); |
| 448 if (cid != kTypedDataUint16ArrayViewCid) { | 437 if (cid != kTypedDataUint16ArrayViewCid) { |
| 449 Exceptions::ThrowArgumentError(list); | 438 Exceptions::ThrowArgumentError(list); |
| 450 } | 439 } |
| 451 if (end > Smi::Value(TypedDataView::Length(list))) { | 440 if (end > Smi::Value(TypedDataView::Length(list))) { |
| 452 Exceptions::ThrowArgumentError(end_obj); | 441 Exceptions::ThrowArgumentError(end_obj); |
| 453 } | 442 } |
| 454 const Instance& data_obj = Instance::Handle(zone, | 443 const Instance& data_obj = |
| 455 TypedDataView::Data(list)); | 444 Instance::Handle(zone, TypedDataView::Data(list)); |
| 456 intptr_t data_offset = Smi::Value(TypedDataView::OffsetInBytes(list)); | 445 intptr_t data_offset = Smi::Value(TypedDataView::OffsetInBytes(list)); |
| 457 if (data_obj.IsTypedData()) { | 446 if (data_obj.IsTypedData()) { |
| 458 const TypedData& array = TypedData::Cast(data_obj); | 447 const TypedData& array = TypedData::Cast(data_obj); |
| 459 return TwoByteString::New(array, data_offset + start * sizeof(uint16_t), | 448 return TwoByteString::New(array, data_offset + start * sizeof(uint16_t), |
| 460 length, space); | 449 length, space); |
| 461 } else if (data_obj.IsExternalTypedData()) { | 450 } else if (data_obj.IsExternalTypedData()) { |
| 462 const ExternalTypedData& array = ExternalTypedData::Cast(data_obj); | 451 const ExternalTypedData& array = ExternalTypedData::Cast(data_obj); |
| 463 return TwoByteString::New(array, data_offset + start * sizeof(uint16_t), | 452 return TwoByteString::New(array, data_offset + start * sizeof(uint16_t), |
| 464 length, space); | 453 length, space); |
| 465 } | 454 } |
| 466 } else if (list.IsArray()) { | 455 } else if (list.IsArray()) { |
| 467 const Array& array = Array::Cast(list); | 456 const Array& array = Array::Cast(list); |
| 468 if (end > array.Length()) { | 457 if (end > array.Length()) { |
| 469 Exceptions::ThrowArgumentError(end_obj); | 458 Exceptions::ThrowArgumentError(end_obj); |
| 470 } | 459 } |
| 471 const String& string = String::Handle(zone, | 460 const String& string = |
| 472 TwoByteString::New(length, space)); | 461 String::Handle(zone, TwoByteString::New(length, space)); |
| 473 for (int i = 0; i < length; i++) { | 462 for (int i = 0; i < length; i++) { |
| 474 intptr_t value = | 463 intptr_t value = |
| 475 Smi::Value(reinterpret_cast<RawSmi*>(array.At(start + i))); | 464 Smi::Value(reinterpret_cast<RawSmi*>(array.At(start + i))); |
| 476 TwoByteString::SetCharAt(string, i, value); | 465 TwoByteString::SetCharAt(string, i, value); |
| 477 } | 466 } |
| 478 return string.raw(); | 467 return string.raw(); |
| 479 } else if (list.IsGrowableObjectArray()) { | 468 } else if (list.IsGrowableObjectArray()) { |
| 480 const GrowableObjectArray& array = GrowableObjectArray::Cast(list); | 469 const GrowableObjectArray& array = GrowableObjectArray::Cast(list); |
| 481 if (end > array.Length()) { | 470 if (end > array.Length()) { |
| 482 Exceptions::ThrowArgumentError(end_obj); | 471 Exceptions::ThrowArgumentError(end_obj); |
| 483 } | 472 } |
| 484 const String& string = String::Handle(zone, | 473 const String& string = |
| 485 TwoByteString::New(length, space)); | 474 String::Handle(zone, TwoByteString::New(length, space)); |
| 486 for (int i = 0; i < length; i++) { | 475 for (int i = 0; i < length; i++) { |
| 487 intptr_t value = | 476 intptr_t value = |
| 488 Smi::Value(reinterpret_cast<RawSmi*>(array.At(start + i))); | 477 Smi::Value(reinterpret_cast<RawSmi*>(array.At(start + i))); |
| 489 TwoByteString::SetCharAt(string, i, value); | 478 TwoByteString::SetCharAt(string, i, value); |
| 490 } | 479 } |
| 491 return string.raw(); | 480 return string.raw(); |
| 492 } | 481 } |
| 493 UNREACHABLE(); | 482 UNREACHABLE(); |
| 494 return Object::null(); | 483 return Object::null(); |
| 495 } | 484 } |
| 496 | 485 |
| 497 | 486 |
| 498 DEFINE_NATIVE_ENTRY(String_getHashCode, 1) { | 487 DEFINE_NATIVE_ENTRY(String_getHashCode, 1) { |
| 499 const String& receiver = String::CheckedHandle(zone, | 488 const String& receiver = |
| 500 arguments->NativeArgAt(0)); | 489 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 501 intptr_t hash_val = receiver.Hash(); | 490 intptr_t hash_val = receiver.Hash(); |
| 502 ASSERT(hash_val > 0); | 491 ASSERT(hash_val > 0); |
| 503 ASSERT(Smi::IsValid(hash_val)); | 492 ASSERT(Smi::IsValid(hash_val)); |
| 504 return Smi::New(hash_val); | 493 return Smi::New(hash_val); |
| 505 } | 494 } |
| 506 | 495 |
| 507 | 496 |
| 508 DEFINE_NATIVE_ENTRY(String_getLength, 1) { | 497 DEFINE_NATIVE_ENTRY(String_getLength, 1) { |
| 509 const String& receiver = String::CheckedHandle(zone, | 498 const String& receiver = |
| 510 arguments->NativeArgAt(0)); | 499 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 511 return Smi::New(receiver.Length()); | 500 return Smi::New(receiver.Length()); |
| 512 } | 501 } |
| 513 | 502 |
| 514 | 503 |
| 515 static uint16_t StringValueAt(const String& str, const Integer& index) { | 504 static uint16_t StringValueAt(const String& str, const Integer& index) { |
| 516 if (index.IsSmi()) { | 505 if (index.IsSmi()) { |
| 517 const intptr_t index_value = Smi::Cast(index).Value(); | 506 const intptr_t index_value = Smi::Cast(index).Value(); |
| 518 if ((0 <= index_value) && (index_value < str.Length())) { | 507 if ((0 <= index_value) && (index_value < str.Length())) { |
| 519 return str.CharAt(index_value); | 508 return str.CharAt(index_value); |
| 520 } | 509 } |
| 521 } | 510 } |
| 522 | 511 |
| 523 // An index larger than Smi is always illegal. | 512 // An index larger than Smi is always illegal. |
| 524 Exceptions::ThrowRangeError("index", index, 0, str.Length() - 1); | 513 Exceptions::ThrowRangeError("index", index, 0, str.Length() - 1); |
| 525 return 0; | 514 return 0; |
| 526 } | 515 } |
| 527 | 516 |
| 528 | 517 |
| 529 DEFINE_NATIVE_ENTRY(String_charAt, 2) { | 518 DEFINE_NATIVE_ENTRY(String_charAt, 2) { |
| 530 const String& receiver = String::CheckedHandle(zone, | 519 const String& receiver = |
| 531 arguments->NativeArgAt(0)); | 520 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 532 GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1)); | 521 GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1)); |
| 533 uint16_t value = StringValueAt(receiver, index); | 522 uint16_t value = StringValueAt(receiver, index); |
| 534 return Symbols::FromCharCode(thread, static_cast<int32_t>(value)); | 523 return Symbols::FromCharCode(thread, static_cast<int32_t>(value)); |
| 535 } | 524 } |
| 536 | 525 |
| 537 | 526 |
| 538 // Returns the 16-bit UTF-16 code unit at the given index. | 527 // Returns the 16-bit UTF-16 code unit at the given index. |
| 539 DEFINE_NATIVE_ENTRY(String_codeUnitAt, 2) { | 528 DEFINE_NATIVE_ENTRY(String_codeUnitAt, 2) { |
| 540 const String& receiver = String::CheckedHandle(zone, | 529 const String& receiver = |
| 541 arguments->NativeArgAt(0)); | 530 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 542 GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1)); | 531 GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1)); |
| 543 uint16_t value = StringValueAt(receiver, index); | 532 uint16_t value = StringValueAt(receiver, index); |
| 544 return Smi::New(static_cast<intptr_t>(value)); | 533 return Smi::New(static_cast<intptr_t>(value)); |
| 545 } | 534 } |
| 546 | 535 |
| 547 | 536 |
| 548 DEFINE_NATIVE_ENTRY(String_concat, 2) { | 537 DEFINE_NATIVE_ENTRY(String_concat, 2) { |
| 549 const String& receiver = String::CheckedHandle(zone, | 538 const String& receiver = |
| 550 arguments->NativeArgAt(0)); | 539 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 551 GET_NON_NULL_NATIVE_ARGUMENT(String, b, arguments->NativeArgAt(1)); | 540 GET_NON_NULL_NATIVE_ARGUMENT(String, b, arguments->NativeArgAt(1)); |
| 552 return String::Concat(receiver, b); | 541 return String::Concat(receiver, b); |
| 553 } | 542 } |
| 554 | 543 |
| 555 | 544 |
| 556 DEFINE_NATIVE_ENTRY(String_toLowerCase, 1) { | 545 DEFINE_NATIVE_ENTRY(String_toLowerCase, 1) { |
| 557 const String& receiver = String::CheckedHandle(zone, | 546 const String& receiver = |
| 558 arguments->NativeArgAt(0)); | 547 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 559 ASSERT(!receiver.IsNull()); | 548 ASSERT(!receiver.IsNull()); |
| 560 return String::ToLowerCase(receiver); | 549 return String::ToLowerCase(receiver); |
| 561 } | 550 } |
| 562 | 551 |
| 563 | 552 |
| 564 DEFINE_NATIVE_ENTRY(String_toUpperCase, 1) { | 553 DEFINE_NATIVE_ENTRY(String_toUpperCase, 1) { |
| 565 const String& receiver = String::CheckedHandle(zone, | 554 const String& receiver = |
| 566 arguments->NativeArgAt(0)); | 555 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 567 ASSERT(!receiver.IsNull()); | 556 ASSERT(!receiver.IsNull()); |
| 568 return String::ToUpperCase(receiver); | 557 return String::ToUpperCase(receiver); |
| 569 } | 558 } |
| 570 | 559 |
| 571 | 560 |
| 572 DEFINE_NATIVE_ENTRY(String_concatRange, 3) { | 561 DEFINE_NATIVE_ENTRY(String_concatRange, 3) { |
| 573 GET_NON_NULL_NATIVE_ARGUMENT(Instance, argument, arguments->NativeArgAt(0)); | 562 GET_NON_NULL_NATIVE_ARGUMENT(Instance, argument, arguments->NativeArgAt(0)); |
| 574 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start, arguments->NativeArgAt(1)); | 563 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start, arguments->NativeArgAt(1)); |
| 575 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end, arguments->NativeArgAt(2)); | 564 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end, arguments->NativeArgAt(2)); |
| 576 const intptr_t start_ix = start.Value(); | 565 const intptr_t start_ix = start.Value(); |
| 577 const intptr_t end_ix = end.Value(); | 566 const intptr_t end_ix = end.Value(); |
| 578 if (start_ix < 0) { | 567 if (start_ix < 0) { |
| 579 Exceptions::ThrowArgumentError(start); | 568 Exceptions::ThrowArgumentError(start); |
| 580 } | 569 } |
| 581 Array& strings = Array::Handle(); | 570 Array& strings = Array::Handle(); |
| 582 intptr_t length = -1; | 571 intptr_t length = -1; |
| 583 if (argument.IsArray()) { | 572 if (argument.IsArray()) { |
| 584 strings ^= argument.raw(); | 573 strings ^= argument.raw(); |
| 585 length = strings.Length(); | 574 length = strings.Length(); |
| 586 } else if (argument.IsGrowableObjectArray()) { | 575 } else if (argument.IsGrowableObjectArray()) { |
| 587 const GrowableObjectArray& g_array = GrowableObjectArray::Cast(argument); | 576 const GrowableObjectArray& g_array = GrowableObjectArray::Cast(argument); |
| 588 strings = g_array.data(); | 577 strings = g_array.data(); |
| 589 length = g_array.Length(); | 578 length = g_array.Length(); |
| 590 } else { | 579 } else { |
| 591 Exceptions::ThrowArgumentError(argument); | 580 Exceptions::ThrowArgumentError(argument); |
| 592 } | 581 } |
| 593 if (end_ix > length) { | 582 if (end_ix > length) { |
| 594 Exceptions::ThrowArgumentError(end); | 583 Exceptions::ThrowArgumentError(end); |
| 595 } | 584 } |
| 596 #if defined(DEBUG) | 585 #if defined(DEBUG) |
| 597 // Check that the array contains strings. | 586 // Check that the array contains strings. |
| 598 Instance& elem = Instance::Handle(); | 587 Instance& elem = Instance::Handle(); |
| 599 for (intptr_t i = start_ix; i < end_ix; i++) { | 588 for (intptr_t i = start_ix; i < end_ix; i++) { |
| 600 elem ^= strings.At(i); | 589 elem ^= strings.At(i); |
| 601 ASSERT(elem.IsString()); | 590 ASSERT(elem.IsString()); |
| 602 } | 591 } |
| 603 #endif | 592 #endif |
| 604 return String::ConcatAllRange(strings, start_ix, end_ix, Heap::kNew); | 593 return String::ConcatAllRange(strings, start_ix, end_ix, Heap::kNew); |
| 605 } | 594 } |
| 606 | 595 |
| 607 | 596 |
| 608 DEFINE_NATIVE_ENTRY(StringBuffer_createStringFromUint16Array, 3) { | 597 DEFINE_NATIVE_ENTRY(StringBuffer_createStringFromUint16Array, 3) { |
| 609 GET_NON_NULL_NATIVE_ARGUMENT(TypedData, codeUnits, arguments->NativeArgAt(0)); | 598 GET_NON_NULL_NATIVE_ARGUMENT(TypedData, codeUnits, arguments->NativeArgAt(0)); |
| 610 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length, arguments->NativeArgAt(1)); | 599 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length, arguments->NativeArgAt(1)); |
| 611 GET_NON_NULL_NATIVE_ARGUMENT(Bool, isLatin1, arguments->NativeArgAt(2)); | 600 GET_NON_NULL_NATIVE_ARGUMENT(Bool, isLatin1, arguments->NativeArgAt(2)); |
| 612 intptr_t array_length = codeUnits.Length(); | 601 intptr_t array_length = codeUnits.Length(); |
| 613 intptr_t length_value = length.Value(); | 602 intptr_t length_value = length.Value(); |
| 614 if (length_value < 0 || length_value > array_length) { | 603 if (length_value < 0 || length_value > array_length) { |
| 615 Exceptions::ThrowRangeError("length", length, 0, array_length); | 604 Exceptions::ThrowRangeError("length", length, 0, array_length); |
| 616 } | 605 } |
| 617 const String& result = isLatin1.value() | 606 const String& result = |
| 618 ? String::Handle(OneByteString::New(length_value, Heap::kNew)) | 607 isLatin1.value() |
| 619 : String::Handle(TwoByteString::New(length_value, Heap::kNew)); | 608 ? String::Handle(OneByteString::New(length_value, Heap::kNew)) |
| 609 : String::Handle(TwoByteString::New(length_value, Heap::kNew)); |
| 620 NoSafepointScope no_safepoint; | 610 NoSafepointScope no_safepoint; |
| 621 | 611 |
| 622 uint16_t* data_position = reinterpret_cast<uint16_t*>(codeUnits.DataAddr(0)); | 612 uint16_t* data_position = reinterpret_cast<uint16_t*>(codeUnits.DataAddr(0)); |
| 623 String::Copy(result, 0, data_position, length_value); | 613 String::Copy(result, 0, data_position, length_value); |
| 624 return result.raw(); | 614 return result.raw(); |
| 625 } | 615 } |
| 626 | 616 |
| 627 } // namespace dart | 617 } // namespace dart |
| OLD | NEW |