| OLD | NEW |
| 1 // Copyright 2017 the V8 project authors. All rights reserved. | 1 // Copyright 2017 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-utils-gen.h" | 5 #include "src/builtins/builtins-utils-gen.h" |
| 6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
| 7 #include "src/code-stub-assembler.h" | 7 #include "src/code-stub-assembler.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| 11 | 11 |
| 12 class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { | 12 class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| 13 public: | 13 public: |
| 14 explicit ArrayBuiltinCodeStubAssembler(compiler::CodeAssemblerState* state) | 14 explicit ArrayBuiltinCodeStubAssembler(compiler::CodeAssemblerState* state) |
| 15 : CodeStubAssembler(state) {} | 15 : CodeStubAssembler(state) {} |
| 16 | 16 |
| 17 typedef std::function<Node*(Node* o, Node* len)> BuiltinResultGenerator; | 17 typedef std::function<Node*(Node* o, Node* len)> BuiltinResultGenerator; |
| 18 typedef std::function<void(Node* a, Node* pK, Node* value)> | 18 typedef std::function<void(Node* a, Node* pK, Node* value)> |
| 19 CallResultProcessor; | 19 CallResultProcessor; |
| 20 | 20 |
| 21 void GenerateArrayIteratingBuiltinBody( | 21 void GenerateIteratingArrayBuiltinBody( |
| 22 const char* name, Node* receiver, Node* callbackfn, Node* this_arg, | 22 const char* name, const BuiltinResultGenerator& generator, |
| 23 Node* context, const BuiltinResultGenerator& generator, | 23 const CallResultProcessor& processor, |
| 24 const CallResultProcessor& processor) { | 24 const Callable& slow_case_continuation) { |
| 25 Node* receiver = Parameter(IteratingArrayBuiltinDescriptor::kReceiver); |
| 26 Node* callbackfn = Parameter(IteratingArrayBuiltinDescriptor::kCallback); |
| 27 Node* this_arg = Parameter(IteratingArrayBuiltinDescriptor::kThisArg); |
| 28 Node* context = Parameter(IteratingArrayBuiltinDescriptor::kContext); |
| 29 Node* new_target = Parameter(IteratingArrayBuiltinDescriptor::kNewTarget); |
| 30 |
| 25 Variable k(this, MachineRepresentation::kTagged, SmiConstant(0)); | 31 Variable k(this, MachineRepresentation::kTagged, SmiConstant(0)); |
| 26 Label non_array(this), slow(this, &k), array_changes(this, &k); | 32 Label non_array(this), slow(this, &k), array_changes(this, &k); |
| 27 | 33 |
| 28 // TODO(danno): Seriously? Do we really need to throw the exact error | 34 // TODO(danno): Seriously? Do we really need to throw the exact error |
| 29 // message on null and undefined so that the webkit tests pass? | 35 // message on null and undefined so that the webkit tests pass? |
| 30 Label throw_null_undefined_exception(this, Label::kDeferred); | 36 Label throw_null_undefined_exception(this, Label::kDeferred); |
| 31 GotoIf(WordEqual(receiver, NullConstant()), | 37 GotoIf(WordEqual(receiver, NullConstant()), |
| 32 &throw_null_undefined_exception); | 38 &throw_null_undefined_exception); |
| 33 GotoIf(WordEqual(receiver, UndefinedConstant()), | 39 GotoIf(WordEqual(receiver, UndefinedConstant()), |
| 34 &throw_null_undefined_exception); | 40 &throw_null_undefined_exception); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. | 90 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. |
| 85 // [Already done by the arguments adapter] | 91 // [Already done by the arguments adapter] |
| 86 | 92 |
| 87 HandleFastElements(context, this_arg, o, len, callbackfn, processor, a, k, | 93 HandleFastElements(context, this_arg, o, len, callbackfn, processor, a, k, |
| 88 &slow); | 94 &slow); |
| 89 | 95 |
| 90 // 7. Let k be 0. | 96 // 7. Let k be 0. |
| 91 // Already done above in initialization of the Variable k | 97 // Already done above in initialization of the Variable k |
| 92 | 98 |
| 93 Bind(&slow); | 99 Bind(&slow); |
| 100 |
| 101 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, |
| 102 MachineType::TaggedPointer()); |
| 103 TailCallStub( |
| 104 slow_case_continuation, context, target, new_target, |
| 105 Int32Constant(IteratingArrayBuiltinLoopContinuationDescriptor::kArity), |
| 106 receiver, callbackfn, this_arg, a, o, k.value(), len); |
| 107 } |
| 108 |
| 109 void GenerateIteratingArrayBuiltinLoopContinuation( |
| 110 const CallResultProcessor& processor) { |
| 111 Node* callbackfn = |
| 112 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kCallback); |
| 113 Node* this_arg = |
| 114 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kThisArg); |
| 115 Node* a = |
| 116 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kArray); |
| 117 Node* o = |
| 118 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kObject); |
| 119 Node* initial_k = |
| 120 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kInitialK); |
| 121 Node* len = |
| 122 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kLength); |
| 123 Node* context = |
| 124 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kContext); |
| 125 |
| 126 // 8. Repeat, while k < len |
| 127 Variable k(this, MachineRepresentation::kTagged, initial_k); |
| 128 Label loop(this, &k); |
| 129 Label after_loop(this); |
| 130 Goto(&loop); |
| 131 Bind(&loop); |
| 94 { | 132 { |
| 95 // 8. Repeat, while k < len | 133 GotoUnlessNumberLessThan(k.value(), len, &after_loop); |
| 96 Label loop(this, &k); | 134 |
| 97 Label after_loop(this); | 135 Label done_element(this); |
| 136 // a. Let Pk be ToString(k). |
| 137 Node* p_k = ToString(context, k.value()); |
| 138 |
| 139 // b. Let kPresent be HasProperty(O, Pk). |
| 140 // c. ReturnIfAbrupt(kPresent). |
| 141 Node* k_present = HasProperty(o, p_k, context); |
| 142 |
| 143 // d. If kPresent is true, then |
| 144 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); |
| 145 |
| 146 // i. Let kValue be Get(O, Pk). |
| 147 // ii. ReturnIfAbrupt(kValue). |
| 148 Node* k_value = GetProperty(context, o, k.value()); |
| 149 |
| 150 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). |
| 151 // iv. ReturnIfAbrupt(funcResult). |
| 152 Node* result = CallJS(CodeFactory::Call(isolate()), context, callbackfn, |
| 153 this_arg, k_value, k.value(), o); |
| 154 |
| 155 processor(a, p_k, result); |
| 156 Goto(&done_element); |
| 157 Bind(&done_element); |
| 158 |
| 159 // e. Increase k by 1. |
| 160 k.Bind(NumberInc(k.value())); |
| 98 Goto(&loop); | 161 Goto(&loop); |
| 99 Bind(&loop); | 162 } |
| 100 { | 163 Bind(&after_loop); |
| 101 GotoUnlessNumberLessThan(k.value(), len, &after_loop); | 164 Return(a); |
| 165 } |
| 102 | 166 |
| 103 Label done_element(this); | 167 void ForEachProcessor(Node* a, Node* p_k, Node* value) {} |
| 104 // a. Let Pk be ToString(k). | |
| 105 Node* p_k = ToString(context, k.value()); | |
| 106 | 168 |
| 107 // b. Let kPresent be HasProperty(O, Pk). | 169 void SomeProcessor(Node* a, Node* p_k, Node* value) { |
| 108 // c. ReturnIfAbrupt(kPresent). | 170 Label false_continue(this), return_true(this); |
| 109 Node* k_present = | 171 BranchIfToBooleanIsTrue(value, &return_true, &false_continue); |
| 110 CallStub(CodeFactory::HasProperty(isolate()), context, p_k, o); | 172 Bind(&return_true); |
| 173 Return(TrueConstant()); |
| 174 Bind(&false_continue); |
| 175 } |
| 111 | 176 |
| 112 // d. If kPresent is true, then | 177 void EveryProcessor(Node* a, Node* p_k, Node* value) { |
| 113 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); | 178 Label true_continue(this), return_false(this); |
| 114 | 179 BranchIfToBooleanIsTrue(value, &true_continue, &return_false); |
| 115 // i. Let kValue be Get(O, Pk). | 180 Bind(&return_false); |
| 116 // ii. ReturnIfAbrupt(kValue). | 181 Return(FalseConstant()); |
| 117 Node* k_value = GetProperty(context, o, k.value()); | 182 Bind(&true_continue); |
| 118 | |
| 119 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). | |
| 120 // iv. ReturnIfAbrupt(funcResult). | |
| 121 Node* result = CallJS(CodeFactory::Call(isolate()), context, callbackfn, | |
| 122 this_arg, k_value, k.value(), o); | |
| 123 | |
| 124 processor(a, p_k, result); | |
| 125 Goto(&done_element); | |
| 126 Bind(&done_element); | |
| 127 | |
| 128 // e. Increase k by 1. | |
| 129 k.Bind(NumberInc(k.value())); | |
| 130 Goto(&loop); | |
| 131 } | |
| 132 Bind(&after_loop); | |
| 133 Return(a); | |
| 134 } | |
| 135 } | 183 } |
| 136 | 184 |
| 137 private: | 185 private: |
| 138 Node* VisitAllFastElementsOneKind(Node* context, ElementsKind kind, | 186 Node* VisitAllFastElementsOneKind(Node* context, ElementsKind kind, |
| 139 Node* this_arg, Node* o, Node* len, | 187 Node* this_arg, Node* o, Node* len, |
| 140 Node* callbackfn, | 188 Node* callbackfn, |
| 141 const CallResultProcessor& processor, | 189 const CallResultProcessor& processor, |
| 142 Node* a, Label* array_changed, | 190 Node* a, Label* array_changed, |
| 143 ParameterMode mode) { | 191 ParameterMode mode) { |
| 144 Comment("begin VisitAllFastElementsOneKind"); | 192 Comment("begin VisitAllFastElementsOneKind"); |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 407 | 455 |
| 408 Bind(&runtime); | 456 Bind(&runtime); |
| 409 { | 457 { |
| 410 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, | 458 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, |
| 411 MachineType::TaggedPointer()); | 459 MachineType::TaggedPointer()); |
| 412 TailCallStub(CodeFactory::ArrayPush(isolate()), context, target, new_target, | 460 TailCallStub(CodeFactory::ArrayPush(isolate()), context, target, new_target, |
| 413 argc); | 461 argc); |
| 414 } | 462 } |
| 415 } | 463 } |
| 416 | 464 |
| 417 TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) { | 465 TF_BUILTIN(ArrayForEachLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
| 418 Node* receiver = Parameter(ForEachDescriptor::kReceiver); | 466 GenerateIteratingArrayBuiltinLoopContinuation( |
| 419 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); | 467 [this](Node* a, Node* p_k, Node* value) { |
| 420 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); | 468 ForEachProcessor(a, p_k, value); |
| 421 Node* context = Parameter(ForEachDescriptor::kContext); | 469 }); |
| 422 | |
| 423 GenerateArrayIteratingBuiltinBody( | |
| 424 "Array.prototype.forEach", receiver, callbackfn, this_arg, context, | |
| 425 [=](Node*, Node*) { return UndefinedConstant(); }, | |
| 426 [](Node* a, Node* p_k, Node* value) {}); | |
| 427 } | 470 } |
| 428 | 471 |
| 429 TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) { | 472 TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) { |
| 430 Node* receiver = Parameter(ForEachDescriptor::kReceiver); | 473 GenerateIteratingArrayBuiltinBody( |
| 431 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); | 474 "Array.prototype.forEach", |
| 432 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); | 475 [=](Node*, Node*) { return UndefinedConstant(); }, |
| 433 Node* context = Parameter(ForEachDescriptor::kContext); | 476 [this](Node* a, Node* p_k, Node* value) { |
| 477 ForEachProcessor(a, p_k, value); |
| 478 }, |
| 479 CodeFactory::ArrayForEachLoopContinuation(isolate())); |
| 480 } |
| 434 | 481 |
| 435 GenerateArrayIteratingBuiltinBody( | 482 TF_BUILTIN(ArraySomeLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
| 436 "Array.prototype.every", receiver, callbackfn, this_arg, context, | 483 GenerateIteratingArrayBuiltinLoopContinuation( |
| 437 [=](Node*, Node*) { return TrueConstant(); }, | 484 [this](Node* a, Node* p_k, Node* value) { |
| 438 [=](Node* a, Node* p_k, Node* value) { | 485 SomeProcessor(a, p_k, value); |
| 439 Label true_continue(this), return_false(this); | |
| 440 BranchIfToBooleanIsTrue(value, &true_continue, &return_false); | |
| 441 Bind(&return_false); | |
| 442 Return(FalseConstant()); | |
| 443 Bind(&true_continue); | |
| 444 }); | 486 }); |
| 445 } | 487 } |
| 446 | 488 |
| 447 TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) { | 489 TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) { |
| 448 Node* receiver = Parameter(ForEachDescriptor::kReceiver); | 490 GenerateIteratingArrayBuiltinBody( |
| 449 Node* callbackfn = Parameter(ForEachDescriptor::kCallback); | 491 "Array.prototype.some", [=](Node*, Node*) { return FalseConstant(); }, |
| 450 Node* this_arg = Parameter(ForEachDescriptor::kThisArg); | 492 [this](Node* a, Node* p_k, Node* value) { SomeProcessor(a, p_k, value); }, |
| 451 Node* context = Parameter(ForEachDescriptor::kContext); | 493 CodeFactory::ArraySomeLoopContinuation(isolate())); |
| 494 } |
| 452 | 495 |
| 453 GenerateArrayIteratingBuiltinBody( | 496 TF_BUILTIN(ArrayEveryLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
| 454 "Array.prototype.some", receiver, callbackfn, this_arg, context, | 497 GenerateIteratingArrayBuiltinLoopContinuation( |
| 455 [=](Node*, Node*) { return FalseConstant(); }, | 498 [this](Node* a, Node* p_k, Node* value) { |
| 456 [=](Node* a, Node* p_k, Node* value) { | 499 EveryProcessor(a, p_k, value); |
| 457 Label false_continue(this), return_true(this); | |
| 458 BranchIfToBooleanIsTrue(value, &return_true, &false_continue); | |
| 459 Bind(&return_true); | |
| 460 Return(TrueConstant()); | |
| 461 Bind(&false_continue); | |
| 462 }); | 500 }); |
| 463 } | 501 } |
| 464 | 502 |
| 503 TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) { |
| 504 GenerateIteratingArrayBuiltinBody( |
| 505 "Array.prototype.every", [=](Node*, Node*) { return TrueConstant(); }, |
| 506 [this](Node* a, Node* p_k, Node* value) { |
| 507 EveryProcessor(a, p_k, value); |
| 508 }, |
| 509 CodeFactory::ArrayEveryLoopContinuation(isolate())); |
| 510 } |
| 511 |
| 465 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { | 512 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { |
| 466 Node* object = Parameter(1); | 513 Node* object = Parameter(1); |
| 467 Node* context = Parameter(4); | 514 Node* context = Parameter(4); |
| 468 | 515 |
| 469 Label call_runtime(this), return_true(this), return_false(this); | 516 Label call_runtime(this), return_true(this), return_false(this); |
| 470 | 517 |
| 471 GotoIf(TaggedIsSmi(object), &return_false); | 518 GotoIf(TaggedIsSmi(object), &return_false); |
| 472 Node* instance_type = LoadInstanceType(object); | 519 Node* instance_type = LoadInstanceType(object); |
| 473 | 520 |
| 474 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), | 521 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), |
| (...skipping 1034 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1509 { | 1556 { |
| 1510 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); | 1557 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); |
| 1511 CallRuntime(Runtime::kThrowTypeError, context, message, | 1558 CallRuntime(Runtime::kThrowTypeError, context, message, |
| 1512 HeapConstant(operation)); | 1559 HeapConstant(operation)); |
| 1513 Unreachable(); | 1560 Unreachable(); |
| 1514 } | 1561 } |
| 1515 } | 1562 } |
| 1516 | 1563 |
| 1517 } // namespace internal | 1564 } // namespace internal |
| 1518 } // namespace v8 | 1565 } // namespace v8 |
| OLD | NEW |