Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/builtins.h" | 5 #include "src/builtins/builtins.h" |
| 6 #include "src/builtins/builtins-utils.h" | 6 #include "src/builtins/builtins-utils.h" |
| 7 | 7 |
| 8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
| 9 #include "src/code-stub-assembler.h" | 9 #include "src/code-stub-assembler.h" |
| 10 #include "src/contexts.h" | 10 #include "src/contexts.h" |
| (...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 420 | 420 |
| 421 if (JSArray::HasReadOnlyLength(array)) { | 421 if (JSArray::HasReadOnlyLength(array)) { |
| 422 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); | 422 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); |
| 423 } | 423 } |
| 424 | 424 |
| 425 ElementsAccessor* accessor = array->GetElementsAccessor(); | 425 ElementsAccessor* accessor = array->GetElementsAccessor(); |
| 426 int new_length = accessor->Unshift(array, &args, to_add); | 426 int new_length = accessor->Unshift(array, &args, to_add); |
| 427 return Smi::FromInt(new_length); | 427 return Smi::FromInt(new_length); |
| 428 } | 428 } |
| 429 | 429 |
| 430 class ForEachCodeStubAssembler : public CodeStubAssembler { | 430 class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| 431 public: | 431 public: |
| 432 explicit ForEachCodeStubAssembler(compiler::CodeAssemblerState* state) | 432 explicit ArrayBuiltinCodeStubAssembler(compiler::CodeAssemblerState* state) |
| 433 : CodeStubAssembler(state) {} | 433 : CodeStubAssembler(state) {} |
| 434 | 434 |
| 435 void VisitOneElement(Node* context, Node* this_arg, Node* o, Node* k, | 435 typedef std::function<Node*(Node* o, Node* len)> BuiltinResultGenerator; |
| 436 Node* callbackfn) { | 436 typedef std::function<void(Node* a, Node* pK, Node* value)> |
| 437 Comment("begin VisitOneElement"); | 437 CallResultProcessor; |
| 438 | 438 |
| 439 // a. Let Pk be ToString(k). | 439 void GenerateArrayIteratingBuiltinBody(const char* name, Node* receiver, |
| 440 Node* p_k = ToString(context, k); | 440 Node* callbackfn, Node* this_arg, |
| 441 Node* context, | |
| 442 BuiltinResultGenerator generator, | |
|
Igor Sheludko
2017/03/10 14:14:44
const X&
danno
2017/03/13 07:22:06
Done.
| |
| 443 CallResultProcessor processor) { | |
|
Igor Sheludko
2017/03/10 14:14:45
Same here.
danno
2017/03/13 07:22:06
Done.
| |
| 444 Variable k(this, MachineRepresentation::kTagged, SmiConstant(0)); | |
| 445 Label non_array(this), slow(this, &k), array_changes(this, &k); | |
| 441 | 446 |
| 442 // b. Let kPresent be HasProperty(O, Pk). | 447 // TODO(danno): Seriously? Do we really need to throw the exact error |
| 443 // c. ReturnIfAbrupt(kPresent). | 448 // message on null and undefined so that the webkit tests pass? |
| 444 Node* k_present = | 449 Label throw_null_undefined_exception(this, Label::kDeferred); |
| 445 CallStub(CodeFactory::HasProperty(isolate()), context, p_k, o); | 450 GotoIf(WordEqual(receiver, NullConstant()), |
| 451 &throw_null_undefined_exception); | |
| 452 GotoIf(WordEqual(receiver, UndefinedConstant()), | |
| 453 &throw_null_undefined_exception); | |
| 446 | 454 |
| 447 // d. If kPresent is true, then | 455 // By the book: taken directly from the ECMAScript 2015 specification |
| 448 Label not_present(this); | |
| 449 GotoIf(WordNotEqual(k_present, TrueConstant()), ¬_present); | |
| 450 | 456 |
| 451 // i. Let kValue be Get(O, Pk). | 457 // 1. Let O be ToObject(this value). |
| 452 // ii. ReturnIfAbrupt(kValue). | 458 // 2. ReturnIfAbrupt(O) |
| 453 Node* k_value = | 459 Node* o = CallStub(CodeFactory::ToObject(isolate()), context, receiver); |
| 454 CallStub(CodeFactory::GetProperty(isolate()), context, o, k); | |
| 455 | 460 |
| 456 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). | 461 // 3. Let len be ToLength(Get(O, "length")). |
| 457 // iv. ReturnIfAbrupt(funcResult). | 462 // 4. ReturnIfAbrupt(len). |
| 458 CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg, k_value, | 463 Variable merged_length(this, MachineRepresentation::kTagged); |
| 459 k, o); | 464 Label has_length(this, &merged_length), not_js_array(this); |
| 465 GotoIf(DoesntHaveInstanceType(o, JS_ARRAY_TYPE), ¬_js_array); | |
| 466 merged_length.Bind(LoadJSArrayLength(o)); | |
| 467 Goto(&has_length); | |
| 468 Bind(¬_js_array); | |
| 469 Node* len_property = | |
| 470 CallStub(CodeFactory::GetProperty(isolate()), context, o, | |
| 471 HeapConstant(isolate()->factory()->length_string())); | |
| 472 merged_length.Bind( | |
| 473 CallStub(CodeFactory::ToLength(isolate()), context, len_property)); | |
| 474 Goto(&has_length); | |
| 475 Bind(&has_length); | |
| 476 Node* len = merged_length.value(); | |
| 460 | 477 |
| 461 Goto(¬_present); | 478 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. |
| 462 Bind(¬_present); | 479 Label type_exception(this, Label::kDeferred); |
| 463 Comment("end VisitOneElement"); | 480 Label done(this); |
| 481 GotoIf(TaggedIsSmi(callbackfn), &type_exception); | |
| 482 Branch(IsCallableMap(LoadMap(callbackfn)), &done, &type_exception); | |
| 483 | |
| 484 Bind(&throw_null_undefined_exception); | |
| 485 { | |
| 486 std::string s("Array.prototype."); | |
| 487 s += name; | |
|
Igor Sheludko
2017/03/10 14:14:45
name could just be a "Array.prototype.smth" for si
danno
2017/03/13 07:22:06
Unfortunately, these must match the method name ex
Igor Sheludko
2017/03/13 08:21:20
I meant to pass full method name as a parameter in
| |
| 488 CallRuntime(Runtime::kThrowTypeError, context, | |
| 489 SmiConstant(MessageTemplate::kCalledOnNullOrUndefined), | |
| 490 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked( | |
| 491 s.c_str()))); | |
| 492 Unreachable(); | |
| 493 } | |
| 494 | |
| 495 Bind(&type_exception); | |
| 496 { | |
| 497 CallRuntime(Runtime::kThrowTypeError, context, | |
| 498 SmiConstant(MessageTemplate::kCalledNonCallable), callbackfn); | |
| 499 Unreachable(); | |
| 500 } | |
| 501 | |
| 502 Bind(&done); | |
| 503 | |
| 504 Node* a = generator(o, len); | |
| 505 | |
| 506 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. | |
| 507 // [Already done by the arguments adapter] | |
| 508 | |
| 509 HandleFastElements(context, this_arg, o, len, callbackfn, processor, a, k, | |
| 510 &slow); | |
| 511 | |
| 512 // 7. Let k be 0. | |
| 513 // Already done above in initialization of the Variable k | |
| 514 | |
| 515 Bind(&slow); | |
| 516 { | |
| 517 // 8. Repeat, while k < len | |
| 518 Label loop(this, &k); | |
| 519 Label after_loop(this); | |
| 520 Goto(&loop); | |
| 521 Bind(&loop); | |
| 522 { | |
| 523 GotoUnlessNumberLessThan(k.value(), len, &after_loop); | |
| 524 | |
| 525 Label done_element(this); | |
| 526 // a. Let Pk be ToString(k). | |
| 527 Node* p_k = ToString(context, k.value()); | |
| 528 | |
| 529 // b. Let kPresent be HasProperty(O, Pk). | |
| 530 // c. ReturnIfAbrupt(kPresent). | |
| 531 Node* k_present = | |
| 532 CallStub(CodeFactory::HasProperty(isolate()), context, p_k, o); | |
| 533 | |
| 534 // d. If kPresent is true, then | |
| 535 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); | |
| 536 | |
| 537 // i. Let kValue be Get(O, Pk). | |
| 538 // ii. ReturnIfAbrupt(kValue). | |
| 539 Node* k_value = CallStub(CodeFactory::GetProperty(isolate()), context, | |
| 540 o, k.value()); | |
| 541 | |
| 542 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). | |
| 543 // iv. ReturnIfAbrupt(funcResult). | |
| 544 Node* result = CallJS(CodeFactory::Call(isolate()), context, callbackfn, | |
| 545 this_arg, k_value, k.value(), o); | |
| 546 | |
| 547 processor(a, p_k, result); | |
| 548 Goto(&done_element); | |
| 549 Bind(&done_element); | |
| 550 | |
| 551 // e. Increase k by 1. | |
| 552 k.Bind(NumberInc(k.value())); | |
| 553 Goto(&loop); | |
| 554 } | |
| 555 Bind(&after_loop); | |
| 556 Return(a); | |
| 557 } | |
| 464 } | 558 } |
| 465 | 559 |
| 466 void VisitAllFastElements(Node* context, ElementsKind kind, Node* this_arg, | 560 private: |
| 467 Node* o, Node* len, Node* callbackfn, | 561 Node* VisitAllFastElementsOneKind(Node* context, ElementsKind kind, |
| 468 ParameterMode mode) { | 562 Node* this_arg, Node* o, Node* len, |
| 469 Comment("begin VisitAllFastElements"); | 563 Node* callbackfn, |
| 564 CallResultProcessor processor, Node* a, | |
|
Igor Sheludko
2017/03/10 14:14:45
Same here.
danno
2017/03/13 07:22:06
Done.
| |
| 565 Label* array_changed, ParameterMode mode) { | |
| 566 Comment("begin VisitAllFastElementsOneKind"); | |
| 470 Variable original_map(this, MachineRepresentation::kTagged); | 567 Variable original_map(this, MachineRepresentation::kTagged); |
| 471 original_map.Bind(LoadMap(o)); | 568 original_map.Bind(LoadMap(o)); |
| 472 VariableList list({&original_map}, zone()); | 569 VariableList list({&original_map}, zone()); |
| 570 Node* last_index = nullptr; | |
| 473 BuildFastLoop( | 571 BuildFastLoop( |
| 474 list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode), | 572 list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode), |
| 475 [context, kind, this, o, &original_map, callbackfn, this_arg, | 573 [context, kind, this, o, &original_map, callbackfn, this_arg, processor, |
|
Igor Sheludko
2017/03/10 14:14:44
I think these long capture lists do not contribute
danno
2017/03/13 07:22:06
Done.
| |
| 476 mode](Node* index) { | 574 a, array_changed, &last_index, mode](Node* index) { |
| 477 Label one_element_done(this), array_changed(this, Label::kDeferred), | 575 last_index = index; |
| 478 hole_element(this); | 576 Label one_element_done(this), hole_element(this); |
| 479 | 577 |
| 480 // Check if o's map has changed during the callback. If so, we have to | 578 // Check if o's map has changed during the callback. If so, we have to |
| 481 // fall back to the slower spec implementation for the rest of the | 579 // fall back to the slower spec implementation for the rest of the |
| 482 // iteration. | 580 // iteration. |
| 483 Node* o_map = LoadMap(o); | 581 Node* o_map = LoadMap(o); |
| 484 GotoIf(WordNotEqual(o_map, original_map.value()), &array_changed); | 582 GotoIf(WordNotEqual(o_map, original_map.value()), array_changed); |
| 485 | 583 |
| 486 // Check if o's length has changed during the callback and if the | 584 // Check if o's length has changed during the callback and if the |
| 487 // index is now out of range of the new length. | 585 // index is now out of range of the new length. |
| 488 Node* tagged_index = ParameterToTagged(index, mode); | 586 Node* tagged_index = ParameterToTagged(index, mode); |
| 489 GotoIf(SmiGreaterThanOrEqual(tagged_index, LoadJSArrayLength(o)), | 587 GotoIf(SmiGreaterThanOrEqual(tagged_index, LoadJSArrayLength(o)), |
| 490 &array_changed); | 588 array_changed); |
| 491 | 589 |
| 492 // Re-load the elements array. If may have been resized. | 590 // Re-load the elements array. If may have been resized. |
| 493 Node* elements = LoadElements(o); | 591 Node* elements = LoadElements(o); |
| 494 | 592 |
| 495 // Fast case: load the element directly from the elements FixedArray | 593 // Fast case: load the element directly from the elements FixedArray |
| 496 // and call the callback if the element is not the hole. | 594 // and call the callback if the element is not the hole. |
| 497 DCHECK(kind == FAST_ELEMENTS || kind == FAST_DOUBLE_ELEMENTS); | 595 DCHECK(kind == FAST_ELEMENTS || kind == FAST_DOUBLE_ELEMENTS); |
| 498 int base_size = kind == FAST_ELEMENTS | 596 int base_size = kind == FAST_ELEMENTS |
| 499 ? FixedArray::kHeaderSize | 597 ? FixedArray::kHeaderSize |
| 500 : (FixedArray::kHeaderSize - kHeapObjectTag); | 598 : (FixedArray::kHeaderSize - kHeapObjectTag); |
| 501 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); | 599 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); |
| 502 Node* value = nullptr; | 600 Node* value = nullptr; |
| 503 if (kind == FAST_ELEMENTS) { | 601 if (kind == FAST_ELEMENTS) { |
| 504 value = LoadObjectField(elements, offset); | 602 value = LoadObjectField(elements, offset); |
| 505 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); | 603 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); |
| 506 } else { | 604 } else { |
| 507 Node* double_value = | 605 Node* double_value = |
| 508 LoadDoubleWithHoleCheck(elements, offset, &hole_element); | 606 LoadDoubleWithHoleCheck(elements, offset, &hole_element); |
| 509 value = AllocateHeapNumberWithValue(double_value); | 607 value = AllocateHeapNumberWithValue(double_value); |
| 510 } | 608 } |
| 511 CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg, | 609 Node* result = CallJS(CodeFactory::Call(isolate()), context, |
| 512 value, tagged_index, o); | 610 callbackfn, this_arg, value, tagged_index, o); |
| 611 processor(a, tagged_index, result); | |
| 513 Goto(&one_element_done); | 612 Goto(&one_element_done); |
| 514 | 613 |
| 515 Bind(&hole_element); | 614 Bind(&hole_element); |
| 615 // Check if o's prototype change unexpectedly has elements after the | |
| 616 // callback in the case of a hole. | |
| 516 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, | 617 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, |
| 517 &array_changed); | 618 array_changed); |
| 518 | |
| 519 // O's changed during the forEach. Use the implementation precisely | |
| 520 // specified in the spec for the rest of the iteration, also making | |
| 521 // the failed original_map sticky in case of a subseuent change that | |
| 522 // goes back to the original map. | |
| 523 Bind(&array_changed); | |
| 524 VisitOneElement(context, this_arg, o, ParameterToTagged(index, mode), | |
| 525 callbackfn); | |
| 526 original_map.Bind(UndefinedConstant()); | |
| 527 Goto(&one_element_done); | |
| 528 | 619 |
| 529 Bind(&one_element_done); | 620 Bind(&one_element_done); |
| 530 }, | 621 }, |
| 531 1, mode, IndexAdvanceMode::kPost); | 622 1, mode, IndexAdvanceMode::kPost); |
| 532 Comment("end VisitAllFastElements"); | 623 Comment("end VisitAllFastElementsOneKind"); |
| 624 return last_index; | |
| 625 } | |
| 626 | |
| 627 void HandleFastElements(Node* context, Node* this_arg, Node* o, Node* len, | |
| 628 Node* callbackfn, CallResultProcessor processor, | |
| 629 Node* a, Variable& k, Label* slow) { | |
| 630 Label switch_on_elements_kind(this), fast_elements(this), | |
| 631 maybe_double_elements(this), fast_double_elements(this); | |
| 632 | |
| 633 Comment("begin HandleFastElements"); | |
| 634 // Non-smi lengths must use the slow path. | |
| 635 GotoIf(TaggedIsNotSmi(len), slow); | |
| 636 | |
| 637 BranchIfFastJSArray(o, context, | |
| 638 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, | |
| 639 &switch_on_elements_kind, slow); | |
| 640 | |
| 641 Bind(&switch_on_elements_kind); | |
| 642 // Select by ElementsKind | |
| 643 Node* o_map = LoadMap(o); | |
| 644 Node* bit_field2 = LoadMapBitField2(o_map); | |
| 645 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); | |
| 646 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | |
| 647 &maybe_double_elements, &fast_elements); | |
| 648 | |
| 649 ParameterMode mode = OptimalParameterMode(); | |
| 650 Bind(&fast_elements); | |
| 651 { | |
| 652 Label array_changed(this, Label::kDeferred); | |
| 653 Node* last_index = VisitAllFastElementsOneKind( | |
| 654 context, FAST_ELEMENTS, this_arg, o, len, callbackfn, processor, a, | |
| 655 &array_changed, mode); | |
| 656 | |
| 657 // No exception, return success | |
| 658 Return(a); | |
| 659 | |
| 660 Bind(&array_changed); | |
| 661 k.Bind(ParameterToTagged(last_index, mode)); | |
| 662 Goto(slow); | |
| 663 } | |
| 664 | |
| 665 Bind(&maybe_double_elements); | |
| 666 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)), | |
| 667 slow, &fast_double_elements); | |
| 668 | |
| 669 Bind(&fast_double_elements); | |
| 670 { | |
| 671 Label array_changed(this, Label::kDeferred); | |
| 672 Node* last_index = VisitAllFastElementsOneKind( | |
| 673 context, FAST_DOUBLE_ELEMENTS, this_arg, o, len, callbackfn, | |
| 674 processor, a, &array_changed, mode); | |
| 675 | |
| 676 // No exception, return success | |
| 677 Return(a); | |
| 678 | |
| 679 Bind(&array_changed); | |
| 680 k.Bind(ParameterToTagged(last_index, mode)); | |
| 681 Goto(slow); | |
| 682 } | |
| 533 } | 683 } |
| 534 }; | 684 }; |
| 535 | 685 |
| 536 TF_BUILTIN(ArrayForEach, ForEachCodeStubAssembler) { | 686 TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) { |
| 537 Label non_array(this), examine_elements(this), fast_elements(this), | |
| 538 slow(this), maybe_double_elements(this), fast_double_elements(this); | |
| 539 | |
| 540 Node* receiver = Parameter(ForEachDescriptor::kReceiver); | 687 Node* receiver = Parameter(ForEachDescriptor::kReceiver); |
| 541 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); | 688 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); |
| 542 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); | 689 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); |
| 543 Node* context = Parameter(ForEachDescriptor::kContext); | 690 Node* context = Parameter(ForEachDescriptor::kContext); |
| 544 | 691 |
| 545 // TODO(danno): Seriously? Do we really need to throw the exact error message | 692 GenerateArrayIteratingBuiltinBody( |
| 546 // on null and undefined so that the webkit tests pass? | 693 "forEach", receiver, callbackfn, this_arg, context, |
| 547 Label throw_null_undefined_exception(this, Label::kDeferred); | 694 [this](Node*, Node*) { return UndefinedConstant(); }, |
|
Igor Sheludko
2017/03/10 14:14:44
[=]
danno
2017/03/13 07:22:06
Done.
| |
| 548 GotoIf(WordEqual(receiver, NullConstant()), &throw_null_undefined_exception); | 695 [](Node* a, Node* p_k, Node* value) {}); |
| 549 GotoIf(WordEqual(receiver, UndefinedConstant()), | 696 } |
| 550 &throw_null_undefined_exception); | |
| 551 | 697 |
| 552 // By the book: taken directly from the ECMAScript 2015 specification | 698 TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) { |
| 699 Node* receiver = Parameter(ForEachDescriptor::kReceiver); | |
| 700 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); | |
| 701 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); | |
| 702 Node* context = Parameter(ForEachDescriptor::kContext); | |
| 553 | 703 |
| 554 // 1. Let O be ToObject(this value). | 704 GenerateArrayIteratingBuiltinBody( |
| 555 // 2. ReturnIfAbrupt(O) | 705 "every", receiver, callbackfn, this_arg, context, |
| 556 Node* o = CallStub(CodeFactory::ToObject(isolate()), context, receiver); | 706 [this](Node*, Node*) { return TrueConstant(); }, |
|
Igor Sheludko
2017/03/10 14:14:44
[=]
danno
2017/03/13 07:22:06
Done.
| |
| 707 [this](Node* a, Node* p_k, Node* value) { | |
|
Igor Sheludko
2017/03/10 14:14:44
Same here.
danno
2017/03/13 07:22:06
Done.
| |
| 708 Label true_continue(this), return_false(this); | |
| 709 BranchIfToBooleanIsTrue(value, &true_continue, &return_false); | |
| 710 Bind(&return_false); | |
| 711 Return(FalseConstant()); | |
| 712 Bind(&true_continue); | |
| 713 }); | |
| 714 } | |
| 557 | 715 |
| 558 // 3. Let len be ToLength(Get(O, "length")). | 716 TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) { |
| 559 // 4. ReturnIfAbrupt(len). | 717 Node* receiver = Parameter(ForEachDescriptor::kReceiver); |
| 560 Variable merged_length(this, MachineRepresentation::kTagged); | 718 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); |
| 561 Label has_length(this, &merged_length), not_js_array(this); | 719 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); |
| 562 GotoIf(DoesntHaveInstanceType(o, JS_ARRAY_TYPE), ¬_js_array); | 720 Node* context = Parameter(ForEachDescriptor::kContext); |
| 563 merged_length.Bind(LoadJSArrayLength(o)); | |
| 564 Goto(&has_length); | |
| 565 Bind(¬_js_array); | |
| 566 Node* len_property = | |
| 567 CallStub(CodeFactory::GetProperty(isolate()), context, o, | |
| 568 HeapConstant(isolate()->factory()->length_string())); | |
| 569 merged_length.Bind( | |
| 570 CallStub(CodeFactory::ToLength(isolate()), context, len_property)); | |
| 571 Goto(&has_length); | |
| 572 Bind(&has_length); | |
| 573 Node* len = merged_length.value(); | |
| 574 | 721 |
| 575 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. | 722 GenerateArrayIteratingBuiltinBody( |
| 576 Label type_exception(this, Label::kDeferred); | 723 "some", receiver, callbackfn, this_arg, context, |
| 577 GotoIf(TaggedIsSmi(callbackfn), &type_exception); | 724 [this](Node*, Node*) { return FalseConstant(); }, |
|
Igor Sheludko
2017/03/10 14:14:44
[=]
danno
2017/03/13 07:22:06
Done.
| |
| 578 GotoIfNot(IsCallableMap(LoadMap(callbackfn)), &type_exception); | 725 [this](Node* a, Node* p_k, Node* value) { |
|
Igor Sheludko
2017/03/10 14:14:44
Same here.
danno
2017/03/13 07:22:06
Done.
| |
| 579 | 726 Label false_continue(this), return_true(this); |
| 580 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. | 727 BranchIfToBooleanIsTrue(value, &return_true, &false_continue); |
| 581 // [Already done by the arguments adapter] | 728 Bind(&return_true); |
| 582 | 729 Return(TrueConstant()); |
| 583 // Non-smi lengths must use the slow path. | 730 Bind(&false_continue); |
| 584 GotoIf(TaggedIsNotSmi(len), &slow); | 731 }); |
| 585 | |
| 586 BranchIfFastJSArray(o, context, | |
| 587 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, | |
| 588 &examine_elements, &slow); | |
| 589 | |
| 590 Bind(&examine_elements); | |
| 591 | |
| 592 ParameterMode mode = OptimalParameterMode(); | |
| 593 | |
| 594 // Select by ElementsKind | |
| 595 Node* o_map = LoadMap(o); | |
| 596 Node* bit_field2 = LoadMapBitField2(o_map); | |
| 597 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); | |
| 598 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | |
| 599 &maybe_double_elements, &fast_elements); | |
| 600 | |
| 601 Bind(&fast_elements); | |
| 602 { | |
| 603 VisitAllFastElements(context, FAST_ELEMENTS, this_arg, o, len, callbackfn, | |
| 604 mode); | |
| 605 | |
| 606 // No exception, return success | |
| 607 Return(UndefinedConstant()); | |
| 608 } | |
| 609 | |
| 610 Bind(&maybe_double_elements); | |
| 611 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)), | |
| 612 &slow, &fast_double_elements); | |
| 613 | |
| 614 Bind(&fast_double_elements); | |
| 615 { | |
| 616 VisitAllFastElements(context, FAST_DOUBLE_ELEMENTS, this_arg, o, len, | |
| 617 callbackfn, mode); | |
| 618 | |
| 619 // No exception, return success | |
| 620 Return(UndefinedConstant()); | |
| 621 } | |
| 622 | |
| 623 Bind(&slow); | |
| 624 { | |
| 625 // By the book: taken from the ECMAScript 2015 specification (cont.) | |
| 626 | |
| 627 // 7. Let k be 0. | |
| 628 Variable k(this, MachineRepresentation::kTagged); | |
| 629 k.Bind(SmiConstant(0)); | |
| 630 | |
| 631 // 8. Repeat, while k < len | |
| 632 Label loop(this, &k); | |
| 633 Label after_loop(this); | |
| 634 Goto(&loop); | |
| 635 Bind(&loop); | |
| 636 { | |
| 637 GotoUnlessNumberLessThan(k.value(), len, &after_loop); | |
| 638 | |
| 639 VisitOneElement(context, this_arg, o, k.value(), callbackfn); | |
| 640 | |
| 641 // e. Increase k by 1. | |
| 642 k.Bind(NumberInc(k.value())); | |
| 643 Goto(&loop); | |
| 644 } | |
| 645 Bind(&after_loop); | |
| 646 Return(UndefinedConstant()); | |
| 647 } | |
| 648 | |
| 649 Bind(&throw_null_undefined_exception); | |
| 650 { | |
| 651 CallRuntime(Runtime::kThrowTypeError, context, | |
| 652 SmiConstant(MessageTemplate::kCalledOnNullOrUndefined), | |
| 653 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked( | |
| 654 "Array.prototype.forEach"))); | |
| 655 Unreachable(); | |
| 656 } | |
| 657 | |
| 658 Bind(&type_exception); | |
| 659 { | |
| 660 CallRuntime(Runtime::kThrowTypeError, context, | |
| 661 SmiConstant(MessageTemplate::kCalledNonCallable), callbackfn); | |
| 662 Unreachable(); | |
| 663 } | |
| 664 } | 732 } |
| 665 | 733 |
| 666 BUILTIN(ArraySlice) { | 734 BUILTIN(ArraySlice) { |
| 667 HandleScope scope(isolate); | 735 HandleScope scope(isolate); |
| 668 Handle<Object> receiver = args.receiver(); | 736 Handle<Object> receiver = args.receiver(); |
| 669 int len = -1; | 737 int len = -1; |
| 670 int relative_start = 0; | 738 int relative_start = 0; |
| 671 int relative_end = 0; | 739 int relative_end = 0; |
| 672 | 740 |
| 673 if (receiver->IsJSArray()) { | 741 if (receiver->IsJSArray()) { |
| (...skipping 2171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2845 { | 2913 { |
| 2846 Node* message = assembler.SmiConstant(MessageTemplate::kDetachedOperation); | 2914 Node* message = assembler.SmiConstant(MessageTemplate::kDetachedOperation); |
| 2847 assembler.CallRuntime(Runtime::kThrowTypeError, context, message, | 2915 assembler.CallRuntime(Runtime::kThrowTypeError, context, message, |
| 2848 assembler.HeapConstant(operation)); | 2916 assembler.HeapConstant(operation)); |
| 2849 assembler.Unreachable(); | 2917 assembler.Unreachable(); |
| 2850 } | 2918 } |
| 2851 } | 2919 } |
| 2852 | 2920 |
| 2853 } // namespace internal | 2921 } // namespace internal |
| 2854 } // namespace v8 | 2922 } // namespace v8 |
| OLD | NEW |