OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins.h" | 5 #include "src/builtins.h" |
6 | 6 |
7 #include "src/api.h" | 7 #include "src/api.h" |
8 #include "src/api-natives.h" | 8 #include "src/api-natives.h" |
9 #include "src/arguments.h" | 9 #include "src/arguments.h" |
10 #include "src/base/once.h" | 10 #include "src/base/once.h" |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 } | 276 } |
277 } | 277 } |
278 if (target_kind != origin_kind) { | 278 if (target_kind != origin_kind) { |
279 JSObject::TransitionElementsKind(array, target_kind); | 279 JSObject::TransitionElementsKind(array, target_kind); |
280 return handle(array->elements(), isolate); | 280 return handle(array->elements(), isolate); |
281 } | 281 } |
282 return elms; | 282 return elms; |
283 } | 283 } |
284 | 284 |
285 | 285 |
286 MUST_USE_RESULT static Object* CallJsBuiltin( | 286 MUST_USE_RESULT static Object* CallJsIntrinsic( |
287 Isolate* isolate, | 287 Isolate* isolate, Handle<JSFunction> function, |
288 const char* name, | |
289 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { | 288 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) { |
290 HandleScope handleScope(isolate); | 289 HandleScope handleScope(isolate); |
291 | |
292 Handle<Object> js_builtin = Object::GetProperty( | |
293 isolate, | |
294 handle(isolate->native_context()->builtins(), isolate), | |
295 name).ToHandleChecked(); | |
296 Handle<JSFunction> function = Handle<JSFunction>::cast(js_builtin); | |
297 int argc = args.length() - 1; | 290 int argc = args.length() - 1; |
298 ScopedVector<Handle<Object> > argv(argc); | 291 ScopedVector<Handle<Object> > argv(argc); |
299 for (int i = 0; i < argc; ++i) { | 292 for (int i = 0; i < argc; ++i) { |
300 argv[i] = args.at<Object>(i + 1); | 293 argv[i] = args.at<Object>(i + 1); |
301 } | 294 } |
302 Handle<Object> result; | 295 Handle<Object> result; |
303 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 296 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
304 isolate, result, | 297 isolate, result, |
305 Execution::Call(isolate, | 298 Execution::Call(isolate, |
306 function, | 299 function, |
307 args.receiver(), | 300 args.receiver(), |
308 argc, | 301 argc, |
309 argv.start())); | 302 argv.start())); |
310 return *result; | 303 return *result; |
311 } | 304 } |
312 | 305 |
313 | 306 |
314 BUILTIN(ArrayPush) { | 307 BUILTIN(ArrayPush) { |
315 HandleScope scope(isolate); | 308 HandleScope scope(isolate); |
316 Handle<Object> receiver = args.receiver(); | 309 Handle<Object> receiver = args.receiver(); |
317 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 310 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
318 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1); | 311 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1); |
319 Handle<FixedArrayBase> elms_obj; | 312 Handle<FixedArrayBase> elms_obj; |
320 if (!maybe_elms_obj.ToHandle(&elms_obj)) { | 313 if (!maybe_elms_obj.ToHandle(&elms_obj)) { |
321 return CallJsBuiltin(isolate, "$arrayPush", args); | 314 return CallJsIntrinsic(isolate, isolate->array_push(), args); |
322 } | 315 } |
323 // Fast Elements Path | 316 // Fast Elements Path |
324 int push_size = args.length() - 1; | 317 int push_size = args.length() - 1; |
325 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 318 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
326 int len = Smi::cast(array->length())->value(); | 319 int len = Smi::cast(array->length())->value(); |
327 if (push_size == 0) { | 320 if (push_size == 0) { |
328 return Smi::FromInt(len); | 321 return Smi::FromInt(len); |
329 } | 322 } |
330 if (push_size > 0 && | 323 if (push_size > 0 && |
331 JSArray::WouldChangeReadOnlyLength(array, len + push_size)) { | 324 JSArray::WouldChangeReadOnlyLength(array, len + push_size)) { |
332 return CallJsBuiltin(isolate, "$arrayPush", args); | 325 return CallJsIntrinsic(isolate, isolate->array_push(), args); |
333 } | 326 } |
334 DCHECK(!array->map()->is_observed()); | 327 DCHECK(!array->map()->is_observed()); |
335 ElementsAccessor* accessor = array->GetElementsAccessor(); | 328 ElementsAccessor* accessor = array->GetElementsAccessor(); |
336 int new_length = accessor->Push(array, elms_obj, &args[1], push_size, | 329 int new_length = accessor->Push(array, elms_obj, &args[1], push_size, |
337 ElementsAccessor::kDirectionReverse); | 330 ElementsAccessor::kDirectionReverse); |
338 return Smi::FromInt(new_length); | 331 return Smi::FromInt(new_length); |
339 } | 332 } |
340 | 333 |
341 | 334 |
342 BUILTIN(ArrayPop) { | 335 BUILTIN(ArrayPop) { |
343 HandleScope scope(isolate); | 336 HandleScope scope(isolate); |
344 Handle<Object> receiver = args.receiver(); | 337 Handle<Object> receiver = args.receiver(); |
345 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 338 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
346 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); | 339 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); |
347 Handle<FixedArrayBase> elms_obj; | 340 Handle<FixedArrayBase> elms_obj; |
348 if (!maybe_elms_obj.ToHandle(&elms_obj)) { | 341 if (!maybe_elms_obj.ToHandle(&elms_obj)) { |
349 return CallJsBuiltin(isolate, "$arrayPop", args); | 342 return CallJsIntrinsic(isolate, isolate->array_pop(), args); |
350 } | 343 } |
351 | 344 |
352 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 345 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
353 DCHECK(!array->map()->is_observed()); | 346 DCHECK(!array->map()->is_observed()); |
354 | 347 |
355 uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value()); | 348 uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value()); |
356 if (len == 0) return isolate->heap()->undefined_value(); | 349 if (len == 0) return isolate->heap()->undefined_value(); |
357 | 350 |
358 if (JSArray::HasReadOnlyLength(array)) { | 351 if (JSArray::HasReadOnlyLength(array)) { |
359 return CallJsBuiltin(isolate, "$arrayPop", args); | 352 return CallJsIntrinsic(isolate, isolate->array_pop(), args); |
360 } | 353 } |
361 | 354 |
362 uint32_t new_length = len - 1; | 355 uint32_t new_length = len - 1; |
363 Handle<Object> element; | 356 Handle<Object> element; |
364 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 357 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
365 isolate, element, Object::GetElement(isolate, array, new_length)); | 358 isolate, element, Object::GetElement(isolate, array, new_length)); |
366 | 359 |
367 JSArray::SetLength(array, new_length); | 360 JSArray::SetLength(array, new_length); |
368 return *element; | 361 return *element; |
369 } | 362 } |
370 | 363 |
371 | 364 |
372 BUILTIN(ArrayShift) { | 365 BUILTIN(ArrayShift) { |
373 HandleScope scope(isolate); | 366 HandleScope scope(isolate); |
374 Heap* heap = isolate->heap(); | 367 Heap* heap = isolate->heap(); |
375 Handle<Object> receiver = args.receiver(); | 368 Handle<Object> receiver = args.receiver(); |
376 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 369 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
377 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); | 370 EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0); |
378 Handle<FixedArrayBase> elms_obj; | 371 Handle<FixedArrayBase> elms_obj; |
379 if (!maybe_elms_obj.ToHandle(&elms_obj) || | 372 if (!maybe_elms_obj.ToHandle(&elms_obj) || |
380 !IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) { | 373 !IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) { |
381 return CallJsBuiltin(isolate, "$arrayShift", args); | 374 return CallJsIntrinsic(isolate, isolate->array_shift(), args); |
382 } | 375 } |
383 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 376 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
384 DCHECK(!array->map()->is_observed()); | 377 DCHECK(!array->map()->is_observed()); |
385 | 378 |
386 int len = Smi::cast(array->length())->value(); | 379 int len = Smi::cast(array->length())->value(); |
387 if (len == 0) return heap->undefined_value(); | 380 if (len == 0) return heap->undefined_value(); |
388 | 381 |
389 if (JSArray::HasReadOnlyLength(array)) { | 382 if (JSArray::HasReadOnlyLength(array)) { |
390 return CallJsBuiltin(isolate, "$arrayShift", args); | 383 return CallJsIntrinsic(isolate, isolate->array_shift(), args); |
391 } | 384 } |
392 | 385 |
393 // Get first element | 386 // Get first element |
394 Handle<Object> first; | 387 Handle<Object> first; |
395 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, first, | 388 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, first, |
396 Object::GetElement(isolate, array, 0)); | 389 Object::GetElement(isolate, array, 0)); |
397 | 390 |
398 if (heap->CanMoveObjectStart(*elms_obj)) { | 391 if (heap->CanMoveObjectStart(*elms_obj)) { |
399 array->set_elements(heap->LeftTrimFixedArray(*elms_obj, 1)); | 392 array->set_elements(heap->LeftTrimFixedArray(*elms_obj, 1)); |
400 } else { | 393 } else { |
(...skipping 17 matching lines...) Expand all Loading... |
418 } | 411 } |
419 | 412 |
420 | 413 |
421 BUILTIN(ArrayUnshift) { | 414 BUILTIN(ArrayUnshift) { |
422 HandleScope scope(isolate); | 415 HandleScope scope(isolate); |
423 Handle<Object> receiver = args.receiver(); | 416 Handle<Object> receiver = args.receiver(); |
424 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 417 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
425 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1); | 418 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1); |
426 Handle<FixedArrayBase> elms_obj; | 419 Handle<FixedArrayBase> elms_obj; |
427 if (!maybe_elms_obj.ToHandle(&elms_obj)) { | 420 if (!maybe_elms_obj.ToHandle(&elms_obj)) { |
428 return CallJsBuiltin(isolate, "$arrayUnshift", args); | 421 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); |
429 } | 422 } |
430 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 423 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
431 DCHECK(!array->map()->is_observed()); | 424 DCHECK(!array->map()->is_observed()); |
432 if (!array->HasFastSmiOrObjectElements()) { | 425 if (!array->HasFastSmiOrObjectElements()) { |
433 return CallJsBuiltin(isolate, "$arrayUnshift", args); | 426 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); |
434 } | 427 } |
435 int len = Smi::cast(array->length())->value(); | 428 int len = Smi::cast(array->length())->value(); |
436 int to_add = args.length() - 1; | 429 int to_add = args.length() - 1; |
437 int new_length = len + to_add; | 430 int new_length = len + to_add; |
438 // Currently fixed arrays cannot grow too big, so | 431 // Currently fixed arrays cannot grow too big, so |
439 // we should never hit this case. | 432 // we should never hit this case. |
440 DCHECK(to_add <= (Smi::kMaxValue - len)); | 433 DCHECK(to_add <= (Smi::kMaxValue - len)); |
441 | 434 |
442 if (to_add > 0 && JSArray::WouldChangeReadOnlyLength(array, len + to_add)) { | 435 if (to_add > 0 && JSArray::WouldChangeReadOnlyLength(array, len + to_add)) { |
443 return CallJsBuiltin(isolate, "$arrayUnshift", args); | 436 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); |
444 } | 437 } |
445 | 438 |
446 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); | 439 Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj); |
447 | 440 |
448 if (new_length > elms->length()) { | 441 if (new_length > elms->length()) { |
449 // New backing storage is needed. | 442 // New backing storage is needed. |
450 int capacity = new_length + (new_length >> 1) + 16; | 443 int capacity = new_length + (new_length >> 1) + 16; |
451 Handle<FixedArray> new_elms = | 444 Handle<FixedArray> new_elms = |
452 isolate->factory()->NewUninitializedFixedArray(capacity); | 445 isolate->factory()->NewUninitializedFixedArray(capacity); |
453 | 446 |
(...skipping 29 matching lines...) Expand all Loading... |
483 Handle<Object> receiver = args.receiver(); | 476 Handle<Object> receiver = args.receiver(); |
484 int len = -1; | 477 int len = -1; |
485 int relative_start = 0; | 478 int relative_start = 0; |
486 int relative_end = 0; | 479 int relative_end = 0; |
487 { | 480 { |
488 DisallowHeapAllocation no_gc; | 481 DisallowHeapAllocation no_gc; |
489 if (receiver->IsJSArray()) { | 482 if (receiver->IsJSArray()) { |
490 JSArray* array = JSArray::cast(*receiver); | 483 JSArray* array = JSArray::cast(*receiver); |
491 if (!IsJSArrayFastElementMovingAllowed(isolate, array)) { | 484 if (!IsJSArrayFastElementMovingAllowed(isolate, array)) { |
492 AllowHeapAllocation allow_allocation; | 485 AllowHeapAllocation allow_allocation; |
493 return CallJsBuiltin(isolate, "$arraySlice", args); | 486 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
494 } | 487 } |
495 | 488 |
496 if (!array->HasFastElements()) { | 489 if (!array->HasFastElements()) { |
497 AllowHeapAllocation allow_allocation; | 490 AllowHeapAllocation allow_allocation; |
498 return CallJsBuiltin(isolate, "$arraySlice", args); | 491 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
499 } | 492 } |
500 | 493 |
501 len = Smi::cast(array->length())->value(); | 494 len = Smi::cast(array->length())->value(); |
502 } else { | 495 } else { |
503 // Array.slice(arguments, ...) is quite a common idiom (notably more | 496 // Array.slice(arguments, ...) is quite a common idiom (notably more |
504 // than 50% of invocations in Web apps). Treat it in C++ as well. | 497 // than 50% of invocations in Web apps). Treat it in C++ as well. |
505 Map* arguments_map = | 498 Map* arguments_map = |
506 isolate->context()->native_context()->sloppy_arguments_map(); | 499 isolate->context()->native_context()->sloppy_arguments_map(); |
507 | 500 |
508 bool is_arguments_object_with_fast_elements = | 501 bool is_arguments_object_with_fast_elements = |
509 receiver->IsJSObject() && | 502 receiver->IsJSObject() && |
510 JSObject::cast(*receiver)->map() == arguments_map; | 503 JSObject::cast(*receiver)->map() == arguments_map; |
511 if (!is_arguments_object_with_fast_elements) { | 504 if (!is_arguments_object_with_fast_elements) { |
512 AllowHeapAllocation allow_allocation; | 505 AllowHeapAllocation allow_allocation; |
513 return CallJsBuiltin(isolate, "$arraySlice", args); | 506 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
514 } | 507 } |
515 JSObject* object = JSObject::cast(*receiver); | 508 JSObject* object = JSObject::cast(*receiver); |
516 | 509 |
517 if (!object->HasFastElements()) { | 510 if (!object->HasFastElements()) { |
518 AllowHeapAllocation allow_allocation; | 511 AllowHeapAllocation allow_allocation; |
519 return CallJsBuiltin(isolate, "$arraySlice", args); | 512 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
520 } | 513 } |
521 | 514 |
522 Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex); | 515 Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex); |
523 if (!len_obj->IsSmi()) { | 516 if (!len_obj->IsSmi()) { |
524 AllowHeapAllocation allow_allocation; | 517 AllowHeapAllocation allow_allocation; |
525 return CallJsBuiltin(isolate, "$arraySlice", args); | 518 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
526 } | 519 } |
527 len = Smi::cast(len_obj)->value(); | 520 len = Smi::cast(len_obj)->value(); |
528 if (len > object->elements()->length()) { | 521 if (len > object->elements()->length()) { |
529 AllowHeapAllocation allow_allocation; | 522 AllowHeapAllocation allow_allocation; |
530 return CallJsBuiltin(isolate, "$arraySlice", args); | 523 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
531 } | 524 } |
532 } | 525 } |
533 | 526 |
534 DCHECK(len >= 0); | 527 DCHECK(len >= 0); |
535 int n_arguments = args.length() - 1; | 528 int n_arguments = args.length() - 1; |
536 | 529 |
537 // Note carefully choosen defaults---if argument is missing, | 530 // Note carefully choosen defaults---if argument is missing, |
538 // it's undefined which gets converted to 0 for relative_start | 531 // it's undefined which gets converted to 0 for relative_start |
539 // and to len for relative_end. | 532 // and to len for relative_end. |
540 relative_start = 0; | 533 relative_start = 0; |
541 relative_end = len; | 534 relative_end = len; |
542 if (n_arguments > 0) { | 535 if (n_arguments > 0) { |
543 Object* arg1 = args[1]; | 536 Object* arg1 = args[1]; |
544 if (arg1->IsSmi()) { | 537 if (arg1->IsSmi()) { |
545 relative_start = Smi::cast(arg1)->value(); | 538 relative_start = Smi::cast(arg1)->value(); |
546 } else if (arg1->IsHeapNumber()) { | 539 } else if (arg1->IsHeapNumber()) { |
547 double start = HeapNumber::cast(arg1)->value(); | 540 double start = HeapNumber::cast(arg1)->value(); |
548 if (start < kMinInt || start > kMaxInt) { | 541 if (start < kMinInt || start > kMaxInt) { |
549 AllowHeapAllocation allow_allocation; | 542 AllowHeapAllocation allow_allocation; |
550 return CallJsBuiltin(isolate, "$arraySlice", args); | 543 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
551 } | 544 } |
552 relative_start = std::isnan(start) ? 0 : static_cast<int>(start); | 545 relative_start = std::isnan(start) ? 0 : static_cast<int>(start); |
553 } else if (!arg1->IsUndefined()) { | 546 } else if (!arg1->IsUndefined()) { |
554 AllowHeapAllocation allow_allocation; | 547 AllowHeapAllocation allow_allocation; |
555 return CallJsBuiltin(isolate, "$arraySlice", args); | 548 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
556 } | 549 } |
557 if (n_arguments > 1) { | 550 if (n_arguments > 1) { |
558 Object* arg2 = args[2]; | 551 Object* arg2 = args[2]; |
559 if (arg2->IsSmi()) { | 552 if (arg2->IsSmi()) { |
560 relative_end = Smi::cast(arg2)->value(); | 553 relative_end = Smi::cast(arg2)->value(); |
561 } else if (arg2->IsHeapNumber()) { | 554 } else if (arg2->IsHeapNumber()) { |
562 double end = HeapNumber::cast(arg2)->value(); | 555 double end = HeapNumber::cast(arg2)->value(); |
563 if (end < kMinInt || end > kMaxInt) { | 556 if (end < kMinInt || end > kMaxInt) { |
564 AllowHeapAllocation allow_allocation; | 557 AllowHeapAllocation allow_allocation; |
565 return CallJsBuiltin(isolate, "$arraySlice", args); | 558 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
566 } | 559 } |
567 relative_end = std::isnan(end) ? 0 : static_cast<int>(end); | 560 relative_end = std::isnan(end) ? 0 : static_cast<int>(end); |
568 } else if (!arg2->IsUndefined()) { | 561 } else if (!arg2->IsUndefined()) { |
569 AllowHeapAllocation allow_allocation; | 562 AllowHeapAllocation allow_allocation; |
570 return CallJsBuiltin(isolate, "$arraySlice", args); | 563 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
571 } | 564 } |
572 } | 565 } |
573 } | 566 } |
574 } | 567 } |
575 | 568 |
576 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. | 569 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. |
577 int k = (relative_start < 0) ? Max(len + relative_start, 0) | 570 int k = (relative_start < 0) ? Max(len + relative_start, 0) |
578 : Min(relative_start, len); | 571 : Min(relative_start, len); |
579 | 572 |
580 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. | 573 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. |
(...skipping 14 matching lines...) Expand all Loading... |
595 for (int i = k; i < final; i++) { | 588 for (int i = k; i < final; i++) { |
596 if (!accessor->HasElement(object, i, elms)) { | 589 if (!accessor->HasElement(object, i, elms)) { |
597 packed = false; | 590 packed = false; |
598 break; | 591 break; |
599 } | 592 } |
600 } | 593 } |
601 if (packed) { | 594 if (packed) { |
602 kind = GetPackedElementsKind(kind); | 595 kind = GetPackedElementsKind(kind); |
603 } else if (!receiver->IsJSArray()) { | 596 } else if (!receiver->IsJSArray()) { |
604 AllowHeapAllocation allow_allocation; | 597 AllowHeapAllocation allow_allocation; |
605 return CallJsBuiltin(isolate, "$arraySlice", args); | 598 return CallJsIntrinsic(isolate, isolate->array_slice(), args); |
606 } | 599 } |
607 } | 600 } |
608 | 601 |
609 Handle<JSArray> result_array = | 602 Handle<JSArray> result_array = |
610 isolate->factory()->NewJSArray(kind, result_len, result_len); | 603 isolate->factory()->NewJSArray(kind, result_len, result_len); |
611 | 604 |
612 DisallowHeapAllocation no_gc; | 605 DisallowHeapAllocation no_gc; |
613 if (result_len == 0) return *result_array; | 606 if (result_len == 0) return *result_array; |
614 | 607 |
615 ElementsAccessor* accessor = object->GetElementsAccessor(); | 608 ElementsAccessor* accessor = object->GetElementsAccessor(); |
616 accessor->CopyElements( | 609 accessor->CopyElements( |
617 elms, k, kind, handle(result_array->elements(), isolate), 0, result_len); | 610 elms, k, kind, handle(result_array->elements(), isolate), 0, result_len); |
618 return *result_array; | 611 return *result_array; |
619 } | 612 } |
620 | 613 |
621 | 614 |
622 BUILTIN(ArraySplice) { | 615 BUILTIN(ArraySplice) { |
623 HandleScope scope(isolate); | 616 HandleScope scope(isolate); |
624 Heap* heap = isolate->heap(); | 617 Heap* heap = isolate->heap(); |
625 Handle<Object> receiver = args.receiver(); | 618 Handle<Object> receiver = args.receiver(); |
626 MaybeHandle<FixedArrayBase> maybe_elms_obj = | 619 MaybeHandle<FixedArrayBase> maybe_elms_obj = |
627 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); | 620 EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3); |
628 Handle<FixedArrayBase> elms_obj; | 621 Handle<FixedArrayBase> elms_obj; |
629 if (!maybe_elms_obj.ToHandle(&elms_obj)) { | 622 if (!maybe_elms_obj.ToHandle(&elms_obj)) { |
630 return CallJsBuiltin(isolate, "$arraySplice", args); | 623 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
631 } | 624 } |
632 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 625 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
633 DCHECK(!array->map()->is_observed()); | 626 DCHECK(!array->map()->is_observed()); |
634 | 627 |
635 int len = Smi::cast(array->length())->value(); | 628 int len = Smi::cast(array->length())->value(); |
636 | 629 |
637 int n_arguments = args.length() - 1; | 630 int n_arguments = args.length() - 1; |
638 | 631 |
639 int relative_start = 0; | 632 int relative_start = 0; |
640 if (n_arguments > 0) { | 633 if (n_arguments > 0) { |
641 DisallowHeapAllocation no_gc; | 634 DisallowHeapAllocation no_gc; |
642 Object* arg1 = args[1]; | 635 Object* arg1 = args[1]; |
643 if (arg1->IsSmi()) { | 636 if (arg1->IsSmi()) { |
644 relative_start = Smi::cast(arg1)->value(); | 637 relative_start = Smi::cast(arg1)->value(); |
645 } else if (arg1->IsHeapNumber()) { | 638 } else if (arg1->IsHeapNumber()) { |
646 double start = HeapNumber::cast(arg1)->value(); | 639 double start = HeapNumber::cast(arg1)->value(); |
647 if (start < kMinInt || start > kMaxInt) { | 640 if (start < kMinInt || start > kMaxInt) { |
648 AllowHeapAllocation allow_allocation; | 641 AllowHeapAllocation allow_allocation; |
649 return CallJsBuiltin(isolate, "$arraySplice", args); | 642 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
650 } | 643 } |
651 relative_start = std::isnan(start) ? 0 : static_cast<int>(start); | 644 relative_start = std::isnan(start) ? 0 : static_cast<int>(start); |
652 } else if (!arg1->IsUndefined()) { | 645 } else if (!arg1->IsUndefined()) { |
653 AllowHeapAllocation allow_allocation; | 646 AllowHeapAllocation allow_allocation; |
654 return CallJsBuiltin(isolate, "$arraySplice", args); | 647 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
655 } | 648 } |
656 } | 649 } |
657 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) | 650 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) |
658 : Min(relative_start, len); | 651 : Min(relative_start, len); |
659 | 652 |
660 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is | 653 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is |
661 // given as a request to delete all the elements from the start. | 654 // given as a request to delete all the elements from the start. |
662 // And it differs from the case of undefined delete count. | 655 // And it differs from the case of undefined delete count. |
663 // This does not follow ECMA-262, but we do the same for | 656 // This does not follow ECMA-262, but we do the same for |
664 // compatibility. | 657 // compatibility. |
665 int actual_delete_count; | 658 int actual_delete_count; |
666 if (n_arguments == 1) { | 659 if (n_arguments == 1) { |
667 DCHECK(len - actual_start >= 0); | 660 DCHECK(len - actual_start >= 0); |
668 actual_delete_count = len - actual_start; | 661 actual_delete_count = len - actual_start; |
669 } else { | 662 } else { |
670 int value = 0; // ToInteger(undefined) == 0 | 663 int value = 0; // ToInteger(undefined) == 0 |
671 if (n_arguments > 1) { | 664 if (n_arguments > 1) { |
672 DisallowHeapAllocation no_gc; | 665 DisallowHeapAllocation no_gc; |
673 Object* arg2 = args[2]; | 666 Object* arg2 = args[2]; |
674 if (arg2->IsSmi()) { | 667 if (arg2->IsSmi()) { |
675 value = Smi::cast(arg2)->value(); | 668 value = Smi::cast(arg2)->value(); |
676 } else { | 669 } else { |
677 AllowHeapAllocation allow_allocation; | 670 AllowHeapAllocation allow_allocation; |
678 return CallJsBuiltin(isolate, "$arraySplice", args); | 671 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
679 } | 672 } |
680 } | 673 } |
681 actual_delete_count = Min(Max(value, 0), len - actual_start); | 674 actual_delete_count = Min(Max(value, 0), len - actual_start); |
682 } | 675 } |
683 | 676 |
684 ElementsKind elements_kind = array->GetElementsKind(); | 677 ElementsKind elements_kind = array->GetElementsKind(); |
685 | 678 |
686 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0; | 679 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0; |
687 int new_length = len - actual_delete_count + item_count; | 680 int new_length = len - actual_delete_count + item_count; |
688 | 681 |
689 // For double mode we do not support changing the length. | 682 // For double mode we do not support changing the length. |
690 if (new_length > len && IsFastDoubleElementsKind(elements_kind)) { | 683 if (new_length > len && IsFastDoubleElementsKind(elements_kind)) { |
691 return CallJsBuiltin(isolate, "$arraySplice", args); | 684 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
692 } | 685 } |
693 | 686 |
694 if (new_length != len && JSArray::HasReadOnlyLength(array)) { | 687 if (new_length != len && JSArray::HasReadOnlyLength(array)) { |
695 AllowHeapAllocation allow_allocation; | 688 AllowHeapAllocation allow_allocation; |
696 return CallJsBuiltin(isolate, "$arraySplice", args); | 689 return CallJsIntrinsic(isolate, isolate->array_splice(), args); |
697 } | 690 } |
698 | 691 |
699 if (new_length == 0) { | 692 if (new_length == 0) { |
700 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements( | 693 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements( |
701 elms_obj, elements_kind, actual_delete_count); | 694 elms_obj, elements_kind, actual_delete_count); |
702 array->set_elements(heap->empty_fixed_array()); | 695 array->set_elements(heap->empty_fixed_array()); |
703 array->set_length(Smi::FromInt(0)); | 696 array->set_length(Smi::FromInt(0)); |
704 return *result; | 697 return *result; |
705 } | 698 } |
706 | 699 |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
846 ElementsKind elements_kind = GetInitialFastElementsKind(); | 839 ElementsKind elements_kind = GetInitialFastElementsKind(); |
847 bool has_double = false; | 840 bool has_double = false; |
848 { | 841 { |
849 DisallowHeapAllocation no_gc; | 842 DisallowHeapAllocation no_gc; |
850 Context* native_context = isolate->context()->native_context(); | 843 Context* native_context = isolate->context()->native_context(); |
851 Object* array_proto = native_context->array_function()->prototype(); | 844 Object* array_proto = native_context->array_function()->prototype(); |
852 PrototypeIterator iter(isolate, array_proto, | 845 PrototypeIterator iter(isolate, array_proto, |
853 PrototypeIterator::START_AT_RECEIVER); | 846 PrototypeIterator::START_AT_RECEIVER); |
854 if (!ArrayPrototypeHasNoElements(&iter)) { | 847 if (!ArrayPrototypeHasNoElements(&iter)) { |
855 AllowHeapAllocation allow_allocation; | 848 AllowHeapAllocation allow_allocation; |
856 return CallJsBuiltin(isolate, "$arrayConcat", args); | 849 return CallJsIntrinsic(isolate, isolate->array_concat(), args); |
857 } | 850 } |
858 | 851 |
859 // Iterate through all the arguments performing checks | 852 // Iterate through all the arguments performing checks |
860 // and calculating total length. | 853 // and calculating total length. |
861 bool is_holey = false; | 854 bool is_holey = false; |
862 for (int i = 0; i < n_arguments; i++) { | 855 for (int i = 0; i < n_arguments; i++) { |
863 Object* arg = args[i]; | 856 Object* arg = args[i]; |
864 PrototypeIterator iter(isolate, arg); | 857 PrototypeIterator iter(isolate, arg); |
865 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements() || | 858 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements() || |
866 iter.GetCurrent() != array_proto) { | 859 iter.GetCurrent() != array_proto) { |
867 AllowHeapAllocation allow_allocation; | 860 AllowHeapAllocation allow_allocation; |
868 return CallJsBuiltin(isolate, "$arrayConcat", args); | 861 return CallJsIntrinsic(isolate, isolate->array_concat(), args); |
869 } | 862 } |
870 int len = Smi::cast(JSArray::cast(arg)->length())->value(); | 863 int len = Smi::cast(JSArray::cast(arg)->length())->value(); |
871 | 864 |
872 // We shouldn't overflow when adding another len. | 865 // We shouldn't overflow when adding another len. |
873 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); | 866 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); |
874 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); | 867 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); |
875 USE(kHalfOfMaxInt); | 868 USE(kHalfOfMaxInt); |
876 result_len += len; | 869 result_len += len; |
877 DCHECK(result_len >= 0); | 870 DCHECK(result_len >= 0); |
878 | 871 |
879 if (result_len > FixedDoubleArray::kMaxLength) { | 872 if (result_len > FixedDoubleArray::kMaxLength) { |
880 AllowHeapAllocation allow_allocation; | 873 AllowHeapAllocation allow_allocation; |
881 return CallJsBuiltin(isolate, "$arrayConcat", args); | 874 return CallJsIntrinsic(isolate, isolate->array_concat(), args); |
882 } | 875 } |
883 | 876 |
884 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind(); | 877 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind(); |
885 has_double = has_double || IsFastDoubleElementsKind(arg_kind); | 878 has_double = has_double || IsFastDoubleElementsKind(arg_kind); |
886 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind); | 879 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind); |
887 if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) { | 880 if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) { |
888 elements_kind = arg_kind; | 881 elements_kind = arg_kind; |
889 } | 882 } |
890 } | 883 } |
891 if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind); | 884 if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind); |
(...skipping 642 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1534 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) | 1527 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) |
1535 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) | 1528 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) |
1536 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) | 1529 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) |
1537 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 1530 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) |
1538 #undef DEFINE_BUILTIN_ACCESSOR_C | 1531 #undef DEFINE_BUILTIN_ACCESSOR_C |
1539 #undef DEFINE_BUILTIN_ACCESSOR_A | 1532 #undef DEFINE_BUILTIN_ACCESSOR_A |
1540 | 1533 |
1541 | 1534 |
1542 } // namespace internal | 1535 } // namespace internal |
1543 } // namespace v8 | 1536 } // namespace v8 |
OLD | NEW |