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 |