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 |