| 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/dart_api_impl.h" |
| 8 #include "vm/exceptions.h" | 9 #include "vm/exceptions.h" |
| 9 #include "vm/dart_api_impl.h" | |
| 10 #include "vm/isolate.h" | 10 #include "vm/isolate.h" |
| 11 #include "vm/native_entry.h" | 11 #include "vm/native_entry.h" |
| 12 #include "vm/object.h" | 12 #include "vm/object.h" |
| 13 #include "vm/symbols.h" | 13 #include "vm/symbols.h" |
| 14 #include "vm/unicode.h" | 14 #include "vm/unicode.h" |
| 15 | 15 |
| 16 namespace dart { | 16 namespace dart { |
| 17 | 17 |
| 18 DEFINE_NATIVE_ENTRY(String_fromEnvironment, 3) { | 18 DEFINE_NATIVE_ENTRY(String_fromEnvironment, 3) { |
| 19 GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(1)); | 19 GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(1)); |
| 20 GET_NATIVE_ARGUMENT(String, default_value, arguments->NativeArgAt(2)); | 20 GET_NATIVE_ARGUMENT(String, default_value, arguments->NativeArgAt(2)); |
| 21 // Call the embedder to supply us with the environment. | 21 // Call the embedder to supply us with the environment. |
| 22 const String& env_value = | 22 const String& env_value = |
| 23 String::Handle(Api::GetEnvironmentValue(thread, name)); | 23 String::Handle(Api::GetEnvironmentValue(thread, name)); |
| 24 if (!env_value.IsNull()) { | 24 if (!env_value.IsNull()) { |
| 25 return Symbols::New(thread, env_value); | 25 return Symbols::New(thread, env_value); |
| 26 } | 26 } |
| 27 return default_value.raw(); | 27 return default_value.raw(); |
| 28 } | 28 } |
| 29 | 29 |
| 30 | |
| 31 DEFINE_NATIVE_ENTRY(StringBase_createFromCodePoints, 3) { | 30 DEFINE_NATIVE_ENTRY(StringBase_createFromCodePoints, 3) { |
| 32 GET_NON_NULL_NATIVE_ARGUMENT(Instance, list, arguments->NativeArgAt(0)); | 31 GET_NON_NULL_NATIVE_ARGUMENT(Instance, list, arguments->NativeArgAt(0)); |
| 33 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); | 32 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); |
| 34 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); | 33 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); |
| 35 | 34 |
| 36 Array& a = Array::Handle(); | 35 Array& a = Array::Handle(); |
| 37 intptr_t length; | 36 intptr_t length; |
| 38 if (list.IsGrowableObjectArray()) { | 37 if (list.IsGrowableObjectArray()) { |
| 39 const GrowableObjectArray& growableArray = GrowableObjectArray::Cast(list); | 38 const GrowableObjectArray& growableArray = GrowableObjectArray::Cast(list); |
| 40 a ^= growableArray.data(); | 39 a ^= growableArray.data(); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 } | 81 } |
| 83 } | 82 } |
| 84 utf32_array[i] = value32; | 83 utf32_array[i] = value32; |
| 85 } | 84 } |
| 86 if (is_one_byte_string) { | 85 if (is_one_byte_string) { |
| 87 return OneByteString::New(utf32_array, array_len, Heap::kNew); | 86 return OneByteString::New(utf32_array, array_len, Heap::kNew); |
| 88 } | 87 } |
| 89 return TwoByteString::New(utf16_len, utf32_array, array_len, Heap::kNew); | 88 return TwoByteString::New(utf16_len, utf32_array, array_len, Heap::kNew); |
| 90 } | 89 } |
| 91 | 90 |
| 92 | |
| 93 DEFINE_NATIVE_ENTRY(StringBase_substringUnchecked, 3) { | 91 DEFINE_NATIVE_ENTRY(StringBase_substringUnchecked, 3) { |
| 94 const String& receiver = | 92 const String& receiver = |
| 95 String::CheckedHandle(zone, arguments->NativeArgAt(0)); | 93 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 96 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); | 94 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); |
| 97 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); | 95 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); |
| 98 | 96 |
| 99 intptr_t start = start_obj.Value(); | 97 intptr_t start = start_obj.Value(); |
| 100 intptr_t end = end_obj.Value(); | 98 intptr_t end = end_obj.Value(); |
| 101 return String::SubString(receiver, start, (end - start)); | 99 return String::SubString(receiver, start, (end - start)); |
| 102 } | 100 } |
| 103 | 101 |
| 104 | |
| 105 // Return the bitwise-or of all characters in the slice from start to end. | 102 // Return the bitwise-or of all characters in the slice from start to end. |
| 106 static uint16_t CharacterLimit(const String& string, | 103 static uint16_t CharacterLimit(const String& string, |
| 107 intptr_t start, | 104 intptr_t start, |
| 108 intptr_t end) { | 105 intptr_t end) { |
| 109 ASSERT(string.IsTwoByteString() || string.IsExternalTwoByteString()); | 106 ASSERT(string.IsTwoByteString() || string.IsExternalTwoByteString()); |
| 110 // Maybe do loop unrolling, and handle two uint16_t in a single uint32_t | 107 // Maybe do loop unrolling, and handle two uint16_t in a single uint32_t |
| 111 // operation. | 108 // operation. |
| 112 NoSafepointScope no_safepoint; | 109 NoSafepointScope no_safepoint; |
| 113 uint16_t result = 0; | 110 uint16_t result = 0; |
| 114 if (string.IsTwoByteString()) { | 111 if (string.IsTwoByteString()) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 } | 152 } |
| 156 uint16_t char_limit = CharacterLimit(base, slice_start, slice_end); | 153 uint16_t char_limit = CharacterLimit(base, slice_start, slice_end); |
| 157 if (char_limit > 0xff) { | 154 if (char_limit > 0xff) { |
| 158 return false; | 155 return false; |
| 159 } | 156 } |
| 160 } | 157 } |
| 161 } | 158 } |
| 162 return true; | 159 return true; |
| 163 } | 160 } |
| 164 | 161 |
| 165 | |
| 166 DEFINE_NATIVE_ENTRY(StringBase_joinReplaceAllResult, 4) { | 162 DEFINE_NATIVE_ENTRY(StringBase_joinReplaceAllResult, 4) { |
| 167 const String& base = String::CheckedHandle(zone, arguments->NativeArgAt(0)); | 163 const String& base = String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 168 GET_NON_NULL_NATIVE_ARGUMENT(GrowableObjectArray, matches_growable, | 164 GET_NON_NULL_NATIVE_ARGUMENT(GrowableObjectArray, matches_growable, |
| 169 arguments->NativeArgAt(1)); | 165 arguments->NativeArgAt(1)); |
| 170 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length_obj, arguments->NativeArgAt(2)); | 166 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length_obj, arguments->NativeArgAt(2)); |
| 171 GET_NON_NULL_NATIVE_ARGUMENT(Bool, is_onebyte_obj, arguments->NativeArgAt(3)); | 167 GET_NON_NULL_NATIVE_ARGUMENT(Bool, is_onebyte_obj, arguments->NativeArgAt(3)); |
| 172 | 168 |
| 173 intptr_t len = matches_growable.Length(); | 169 intptr_t len = matches_growable.Length(); |
| 174 const Array& matches = Array::Handle(zone, matches_growable.data()); | 170 const Array& matches = Array::Handle(zone, matches_growable.data()); |
| 175 | 171 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 String::CheckedHandle(zone, arguments->NativeArgAt(0)); | 249 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 254 ASSERT(receiver.IsOneByteString()); | 250 ASSERT(receiver.IsOneByteString()); |
| 255 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); | 251 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); |
| 256 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); | 252 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); |
| 257 | 253 |
| 258 const intptr_t start = start_obj.Value(); | 254 const intptr_t start = start_obj.Value(); |
| 259 const intptr_t end = end_obj.Value(); | 255 const intptr_t end = end_obj.Value(); |
| 260 return OneByteString::New(receiver, start, end - start, Heap::kNew); | 256 return OneByteString::New(receiver, start, end - start, Heap::kNew); |
| 261 } | 257 } |
| 262 | 258 |
| 263 | |
| 264 // This is high-performance code. | 259 // This is high-performance code. |
| 265 DEFINE_NATIVE_ENTRY(OneByteString_splitWithCharCode, 2) { | 260 DEFINE_NATIVE_ENTRY(OneByteString_splitWithCharCode, 2) { |
| 266 const String& receiver = | 261 const String& receiver = |
| 267 String::CheckedHandle(zone, arguments->NativeArgAt(0)); | 262 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 268 ASSERT(receiver.IsOneByteString()); | 263 ASSERT(receiver.IsOneByteString()); |
| 269 GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_split_code, arguments->NativeArgAt(1)); | 264 GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_split_code, arguments->NativeArgAt(1)); |
| 270 const intptr_t len = receiver.Length(); | 265 const intptr_t len = receiver.Length(); |
| 271 const intptr_t split_code = smi_split_code.Value(); | 266 const intptr_t split_code = smi_split_code.Value(); |
| 272 const GrowableObjectArray& result = GrowableObjectArray::Handle( | 267 const GrowableObjectArray& result = GrowableObjectArray::Handle( |
| 273 zone, GrowableObjectArray::New(16, Heap::kNew)); | 268 zone, GrowableObjectArray::New(16, Heap::kNew)); |
| 274 String& str = String::Handle(zone); | 269 String& str = String::Handle(zone); |
| 275 intptr_t start = 0; | 270 intptr_t start = 0; |
| 276 intptr_t i = 0; | 271 intptr_t i = 0; |
| 277 for (; i < len; i++) { | 272 for (; i < len; i++) { |
| 278 if (split_code == OneByteString::CharAt(receiver, i)) { | 273 if (split_code == OneByteString::CharAt(receiver, i)) { |
| 279 str = OneByteString::SubStringUnchecked(receiver, start, (i - start), | 274 str = OneByteString::SubStringUnchecked(receiver, start, (i - start), |
| 280 Heap::kNew); | 275 Heap::kNew); |
| 281 result.Add(str); | 276 result.Add(str); |
| 282 start = i + 1; | 277 start = i + 1; |
| 283 } | 278 } |
| 284 } | 279 } |
| 285 str = OneByteString::SubStringUnchecked(receiver, start, (i - start), | 280 str = OneByteString::SubStringUnchecked(receiver, start, (i - start), |
| 286 Heap::kNew); | 281 Heap::kNew); |
| 287 result.Add(str); | 282 result.Add(str); |
| 288 return result.raw(); | 283 return result.raw(); |
| 289 } | 284 } |
| 290 | 285 |
| 291 | |
| 292 DEFINE_NATIVE_ENTRY(OneByteString_allocate, 1) { | 286 DEFINE_NATIVE_ENTRY(OneByteString_allocate, 1) { |
| 293 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length_obj, arguments->NativeArgAt(0)); | 287 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length_obj, arguments->NativeArgAt(0)); |
| 294 return OneByteString::New(length_obj.Value(), Heap::kNew); | 288 return OneByteString::New(length_obj.Value(), Heap::kNew); |
| 295 } | 289 } |
| 296 | 290 |
| 297 | |
| 298 DEFINE_NATIVE_ENTRY(OneByteString_allocateFromOneByteList, 3) { | 291 DEFINE_NATIVE_ENTRY(OneByteString_allocateFromOneByteList, 3) { |
| 299 Instance& list = Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); | 292 Instance& list = Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 300 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); | 293 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); |
| 301 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); | 294 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); |
| 302 | 295 |
| 303 intptr_t start = start_obj.Value(); | 296 intptr_t start = start_obj.Value(); |
| 304 intptr_t end = end_obj.Value(); | 297 intptr_t end = end_obj.Value(); |
| 305 if (start < 0) { | 298 if (start < 0) { |
| 306 const Array& args = Array::Handle(Array::New(1)); | 299 const Array& args = Array::Handle(Array::New(1)); |
| 307 args.SetAt(0, start_obj); | 300 args.SetAt(0, start_obj); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 intptr_t value = | 367 intptr_t value = |
| 375 Smi::Value(reinterpret_cast<RawSmi*>(array.At(start + i))); | 368 Smi::Value(reinterpret_cast<RawSmi*>(array.At(start + i))); |
| 376 OneByteString::SetCharAt(string, i, value); | 369 OneByteString::SetCharAt(string, i, value); |
| 377 } | 370 } |
| 378 return string.raw(); | 371 return string.raw(); |
| 379 } | 372 } |
| 380 UNREACHABLE(); | 373 UNREACHABLE(); |
| 381 return Object::null(); | 374 return Object::null(); |
| 382 } | 375 } |
| 383 | 376 |
| 384 | |
| 385 DEFINE_NATIVE_ENTRY(OneByteString_setAt, 3) { | 377 DEFINE_NATIVE_ENTRY(OneByteString_setAt, 3) { |
| 386 GET_NON_NULL_NATIVE_ARGUMENT(String, receiver, arguments->NativeArgAt(0)); | 378 GET_NON_NULL_NATIVE_ARGUMENT(String, receiver, arguments->NativeArgAt(0)); |
| 387 ASSERT(receiver.IsOneByteString()); | 379 ASSERT(receiver.IsOneByteString()); |
| 388 GET_NON_NULL_NATIVE_ARGUMENT(Smi, index_obj, arguments->NativeArgAt(1)); | 380 GET_NON_NULL_NATIVE_ARGUMENT(Smi, index_obj, arguments->NativeArgAt(1)); |
| 389 GET_NON_NULL_NATIVE_ARGUMENT(Smi, code_point_obj, arguments->NativeArgAt(2)); | 381 GET_NON_NULL_NATIVE_ARGUMENT(Smi, code_point_obj, arguments->NativeArgAt(2)); |
| 390 ASSERT((0 <= code_point_obj.Value()) && (code_point_obj.Value() <= 0xFF)); | 382 ASSERT((0 <= code_point_obj.Value()) && (code_point_obj.Value() <= 0xFF)); |
| 391 OneByteString::SetCharAt(receiver, index_obj.Value(), code_point_obj.Value()); | 383 OneByteString::SetCharAt(receiver, index_obj.Value(), code_point_obj.Value()); |
| 392 return Object::null(); | 384 return Object::null(); |
| 393 } | 385 } |
| 394 | 386 |
| 395 | |
| 396 DEFINE_NATIVE_ENTRY(ExternalOneByteString_getCid, 0) { | 387 DEFINE_NATIVE_ENTRY(ExternalOneByteString_getCid, 0) { |
| 397 return Smi::New(kExternalOneByteStringCid); | 388 return Smi::New(kExternalOneByteStringCid); |
| 398 } | 389 } |
| 399 | 390 |
| 400 | |
| 401 DEFINE_NATIVE_ENTRY(TwoByteString_allocateFromTwoByteList, 3) { | 391 DEFINE_NATIVE_ENTRY(TwoByteString_allocateFromTwoByteList, 3) { |
| 402 Instance& list = Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); | 392 Instance& list = Instance::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 403 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); | 393 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_obj, arguments->NativeArgAt(1)); |
| 404 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); | 394 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end_obj, arguments->NativeArgAt(2)); |
| 405 | 395 |
| 406 intptr_t start = start_obj.Value(); | 396 intptr_t start = start_obj.Value(); |
| 407 intptr_t end = end_obj.Value(); | 397 intptr_t end = end_obj.Value(); |
| 408 if (start < 0) { | 398 if (start < 0) { |
| 409 Exceptions::ThrowArgumentError(start_obj); | 399 Exceptions::ThrowArgumentError(start_obj); |
| 410 } | 400 } |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 intptr_t value = | 466 intptr_t value = |
| 477 Smi::Value(reinterpret_cast<RawSmi*>(array.At(start + i))); | 467 Smi::Value(reinterpret_cast<RawSmi*>(array.At(start + i))); |
| 478 TwoByteString::SetCharAt(string, i, value); | 468 TwoByteString::SetCharAt(string, i, value); |
| 479 } | 469 } |
| 480 return string.raw(); | 470 return string.raw(); |
| 481 } | 471 } |
| 482 UNREACHABLE(); | 472 UNREACHABLE(); |
| 483 return Object::null(); | 473 return Object::null(); |
| 484 } | 474 } |
| 485 | 475 |
| 486 | |
| 487 DEFINE_NATIVE_ENTRY(String_getHashCode, 1) { | 476 DEFINE_NATIVE_ENTRY(String_getHashCode, 1) { |
| 488 const String& receiver = | 477 const String& receiver = |
| 489 String::CheckedHandle(zone, arguments->NativeArgAt(0)); | 478 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 490 intptr_t hash_val = receiver.Hash(); | 479 intptr_t hash_val = receiver.Hash(); |
| 491 ASSERT(hash_val > 0); | 480 ASSERT(hash_val > 0); |
| 492 ASSERT(Smi::IsValid(hash_val)); | 481 ASSERT(Smi::IsValid(hash_val)); |
| 493 return Smi::New(hash_val); | 482 return Smi::New(hash_val); |
| 494 } | 483 } |
| 495 | 484 |
| 496 | |
| 497 DEFINE_NATIVE_ENTRY(String_getLength, 1) { | 485 DEFINE_NATIVE_ENTRY(String_getLength, 1) { |
| 498 const String& receiver = | 486 const String& receiver = |
| 499 String::CheckedHandle(zone, arguments->NativeArgAt(0)); | 487 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 500 return Smi::New(receiver.Length()); | 488 return Smi::New(receiver.Length()); |
| 501 } | 489 } |
| 502 | 490 |
| 503 | |
| 504 static uint16_t StringValueAt(const String& str, const Integer& index) { | 491 static uint16_t StringValueAt(const String& str, const Integer& index) { |
| 505 if (index.IsSmi()) { | 492 if (index.IsSmi()) { |
| 506 const intptr_t index_value = Smi::Cast(index).Value(); | 493 const intptr_t index_value = Smi::Cast(index).Value(); |
| 507 if ((0 <= index_value) && (index_value < str.Length())) { | 494 if ((0 <= index_value) && (index_value < str.Length())) { |
| 508 return str.CharAt(index_value); | 495 return str.CharAt(index_value); |
| 509 } | 496 } |
| 510 } | 497 } |
| 511 | 498 |
| 512 // An index larger than Smi is always illegal. | 499 // An index larger than Smi is always illegal. |
| 513 Exceptions::ThrowRangeError("index", index, 0, str.Length() - 1); | 500 Exceptions::ThrowRangeError("index", index, 0, str.Length() - 1); |
| 514 return 0; | 501 return 0; |
| 515 } | 502 } |
| 516 | 503 |
| 517 | |
| 518 DEFINE_NATIVE_ENTRY(String_charAt, 2) { | 504 DEFINE_NATIVE_ENTRY(String_charAt, 2) { |
| 519 const String& receiver = | 505 const String& receiver = |
| 520 String::CheckedHandle(zone, arguments->NativeArgAt(0)); | 506 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 521 GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1)); | 507 GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1)); |
| 522 uint16_t value = StringValueAt(receiver, index); | 508 uint16_t value = StringValueAt(receiver, index); |
| 523 return Symbols::FromCharCode(thread, static_cast<int32_t>(value)); | 509 return Symbols::FromCharCode(thread, static_cast<int32_t>(value)); |
| 524 } | 510 } |
| 525 | 511 |
| 526 | |
| 527 // Returns the 16-bit UTF-16 code unit at the given index. | 512 // Returns the 16-bit UTF-16 code unit at the given index. |
| 528 DEFINE_NATIVE_ENTRY(String_codeUnitAt, 2) { | 513 DEFINE_NATIVE_ENTRY(String_codeUnitAt, 2) { |
| 529 const String& receiver = | 514 const String& receiver = |
| 530 String::CheckedHandle(zone, arguments->NativeArgAt(0)); | 515 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 531 GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1)); | 516 GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1)); |
| 532 uint16_t value = StringValueAt(receiver, index); | 517 uint16_t value = StringValueAt(receiver, index); |
| 533 return Smi::New(static_cast<intptr_t>(value)); | 518 return Smi::New(static_cast<intptr_t>(value)); |
| 534 } | 519 } |
| 535 | 520 |
| 536 | |
| 537 DEFINE_NATIVE_ENTRY(String_concat, 2) { | 521 DEFINE_NATIVE_ENTRY(String_concat, 2) { |
| 538 const String& receiver = | 522 const String& receiver = |
| 539 String::CheckedHandle(zone, arguments->NativeArgAt(0)); | 523 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 540 GET_NON_NULL_NATIVE_ARGUMENT(String, b, arguments->NativeArgAt(1)); | 524 GET_NON_NULL_NATIVE_ARGUMENT(String, b, arguments->NativeArgAt(1)); |
| 541 return String::Concat(receiver, b); | 525 return String::Concat(receiver, b); |
| 542 } | 526 } |
| 543 | 527 |
| 544 | |
| 545 DEFINE_NATIVE_ENTRY(String_toLowerCase, 1) { | 528 DEFINE_NATIVE_ENTRY(String_toLowerCase, 1) { |
| 546 const String& receiver = | 529 const String& receiver = |
| 547 String::CheckedHandle(zone, arguments->NativeArgAt(0)); | 530 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 548 ASSERT(!receiver.IsNull()); | 531 ASSERT(!receiver.IsNull()); |
| 549 return String::ToLowerCase(receiver); | 532 return String::ToLowerCase(receiver); |
| 550 } | 533 } |
| 551 | 534 |
| 552 | |
| 553 DEFINE_NATIVE_ENTRY(String_toUpperCase, 1) { | 535 DEFINE_NATIVE_ENTRY(String_toUpperCase, 1) { |
| 554 const String& receiver = | 536 const String& receiver = |
| 555 String::CheckedHandle(zone, arguments->NativeArgAt(0)); | 537 String::CheckedHandle(zone, arguments->NativeArgAt(0)); |
| 556 ASSERT(!receiver.IsNull()); | 538 ASSERT(!receiver.IsNull()); |
| 557 return String::ToUpperCase(receiver); | 539 return String::ToUpperCase(receiver); |
| 558 } | 540 } |
| 559 | 541 |
| 560 | |
| 561 DEFINE_NATIVE_ENTRY(String_concatRange, 3) { | 542 DEFINE_NATIVE_ENTRY(String_concatRange, 3) { |
| 562 GET_NON_NULL_NATIVE_ARGUMENT(Instance, argument, arguments->NativeArgAt(0)); | 543 GET_NON_NULL_NATIVE_ARGUMENT(Instance, argument, arguments->NativeArgAt(0)); |
| 563 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start, arguments->NativeArgAt(1)); | 544 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start, arguments->NativeArgAt(1)); |
| 564 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end, arguments->NativeArgAt(2)); | 545 GET_NON_NULL_NATIVE_ARGUMENT(Smi, end, arguments->NativeArgAt(2)); |
| 565 const intptr_t start_ix = start.Value(); | 546 const intptr_t start_ix = start.Value(); |
| 566 const intptr_t end_ix = end.Value(); | 547 const intptr_t end_ix = end.Value(); |
| 567 if (start_ix < 0) { | 548 if (start_ix < 0) { |
| 568 Exceptions::ThrowArgumentError(start); | 549 Exceptions::ThrowArgumentError(start); |
| 569 } | 550 } |
| 570 Array& strings = Array::Handle(); | 551 Array& strings = Array::Handle(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 586 // Check that the array contains strings. | 567 // Check that the array contains strings. |
| 587 Instance& elem = Instance::Handle(); | 568 Instance& elem = Instance::Handle(); |
| 588 for (intptr_t i = start_ix; i < end_ix; i++) { | 569 for (intptr_t i = start_ix; i < end_ix; i++) { |
| 589 elem ^= strings.At(i); | 570 elem ^= strings.At(i); |
| 590 ASSERT(elem.IsString()); | 571 ASSERT(elem.IsString()); |
| 591 } | 572 } |
| 592 #endif | 573 #endif |
| 593 return String::ConcatAllRange(strings, start_ix, end_ix, Heap::kNew); | 574 return String::ConcatAllRange(strings, start_ix, end_ix, Heap::kNew); |
| 594 } | 575 } |
| 595 | 576 |
| 596 | |
| 597 DEFINE_NATIVE_ENTRY(StringBuffer_createStringFromUint16Array, 3) { | 577 DEFINE_NATIVE_ENTRY(StringBuffer_createStringFromUint16Array, 3) { |
| 598 GET_NON_NULL_NATIVE_ARGUMENT(TypedData, codeUnits, arguments->NativeArgAt(0)); | 578 GET_NON_NULL_NATIVE_ARGUMENT(TypedData, codeUnits, arguments->NativeArgAt(0)); |
| 599 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length, arguments->NativeArgAt(1)); | 579 GET_NON_NULL_NATIVE_ARGUMENT(Smi, length, arguments->NativeArgAt(1)); |
| 600 GET_NON_NULL_NATIVE_ARGUMENT(Bool, isLatin1, arguments->NativeArgAt(2)); | 580 GET_NON_NULL_NATIVE_ARGUMENT(Bool, isLatin1, arguments->NativeArgAt(2)); |
| 601 intptr_t array_length = codeUnits.Length(); | 581 intptr_t array_length = codeUnits.Length(); |
| 602 intptr_t length_value = length.Value(); | 582 intptr_t length_value = length.Value(); |
| 603 if (length_value < 0 || length_value > array_length) { | 583 if (length_value < 0 || length_value > array_length) { |
| 604 Exceptions::ThrowRangeError("length", length, 0, array_length); | 584 Exceptions::ThrowRangeError("length", length, 0, array_length); |
| 605 } | 585 } |
| 606 const String& result = | 586 const String& result = |
| 607 isLatin1.value() | 587 isLatin1.value() |
| 608 ? String::Handle(OneByteString::New(length_value, Heap::kNew)) | 588 ? String::Handle(OneByteString::New(length_value, Heap::kNew)) |
| 609 : String::Handle(TwoByteString::New(length_value, Heap::kNew)); | 589 : String::Handle(TwoByteString::New(length_value, Heap::kNew)); |
| 610 NoSafepointScope no_safepoint; | 590 NoSafepointScope no_safepoint; |
| 611 | 591 |
| 612 uint16_t* data_position = reinterpret_cast<uint16_t*>(codeUnits.DataAddr(0)); | 592 uint16_t* data_position = reinterpret_cast<uint16_t*>(codeUnits.DataAddr(0)); |
| 613 String::Copy(result, 0, data_position, length_value); | 593 String::Copy(result, 0, data_position, length_value); |
| 614 return result.raw(); | 594 return result.raw(); |
| 615 } | 595 } |
| 616 | 596 |
| 617 } // namespace dart | 597 } // namespace dart |
| OLD | NEW |