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 k_(this, MachineRepresentation::kTagged, SmiConstant(0)), | 16 k_(this, MachineRepresentation::kTagged, SmiConstant(0)), |
17 a_(this, MachineRepresentation::kTagged, SmiConstant(0)), | 17 a_(this, MachineRepresentation::kTagged, SmiConstant(0)), |
18 to_(this, MachineRepresentation::kTagged, SmiConstant(0)) {} | 18 to_(this, MachineRepresentation::kTagged, SmiConstant(0)) {} |
19 | 19 |
20 typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm)> | 20 typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm)> |
21 BuiltinResultGenerator; | 21 BuiltinResultGenerator; |
22 | 22 |
23 typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)> | 23 typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)> |
24 BuiltinResultIndexInitializer; | 24 BuiltinResultIndexInitializer; |
25 | 25 |
26 typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm, | 26 typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm, |
27 Node* k_value, Node* k)> | 27 ElementsKind o_kind, Node* k_value, Node* k)> |
28 CallResultProcessor; | 28 CallResultProcessor; |
29 | 29 |
30 typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)> | 30 typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)> |
31 PostLoopAction; | 31 PostLoopAction; |
32 | 32 |
33 Node* ForEachResultGenerator() { return UndefinedConstant(); } | 33 Node* ForEachResultGenerator() { return UndefinedConstant(); } |
34 | 34 |
35 Node* ForEachProcessor(Node* k_value, Node* k) { | 35 Node* ForEachProcessor(ElementsKind o_kind, Node* k_value, Node* k) { |
36 CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(), | 36 CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(), |
37 k_value, k, o()); | 37 k_value, k, o()); |
38 return a(); | 38 return a(); |
39 } | 39 } |
40 | 40 |
41 Node* SomeResultGenerator() { return FalseConstant(); } | 41 Node* SomeResultGenerator() { return FalseConstant(); } |
42 | 42 |
43 Node* SomeProcessor(Node* k_value, Node* k) { | 43 Node* SomeProcessor(ElementsKind o_kind, Node* k_value, Node* k) { |
44 Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), | 44 Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), |
45 this_arg(), k_value, k, o()); | 45 this_arg(), k_value, k, o()); |
46 Label false_continue(this), return_true(this); | 46 Label false_continue(this), return_true(this); |
47 BranchIfToBooleanIsTrue(value, &return_true, &false_continue); | 47 BranchIfToBooleanIsTrue(value, &return_true, &false_continue); |
48 Bind(&return_true); | 48 Bind(&return_true); |
49 Return(TrueConstant()); | 49 Return(TrueConstant()); |
50 Bind(&false_continue); | 50 Bind(&false_continue); |
51 return a(); | 51 return a(); |
52 } | 52 } |
53 | 53 |
54 Node* EveryResultGenerator() { return TrueConstant(); } | 54 Node* EveryResultGenerator() { return TrueConstant(); } |
55 | 55 |
56 Node* EveryProcessor(Node* k_value, Node* k) { | 56 Node* EveryProcessor(ElementsKind o_kind, Node* k_value, Node* k) { |
57 Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), | 57 Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), |
58 this_arg(), k_value, k, o()); | 58 this_arg(), k_value, k, o()); |
59 Label true_continue(this), return_false(this); | 59 Label true_continue(this), return_false(this); |
60 BranchIfToBooleanIsTrue(value, &true_continue, &return_false); | 60 BranchIfToBooleanIsTrue(value, &true_continue, &return_false); |
61 Bind(&return_false); | 61 Bind(&return_false); |
62 Return(FalseConstant()); | 62 Return(FalseConstant()); |
63 Bind(&true_continue); | 63 Bind(&true_continue); |
64 return a(); | 64 return a(); |
65 } | 65 } |
66 | 66 |
(...skipping 24 matching lines...) Expand all Loading... | |
91 // 9. Else initialValue is not present, | 91 // 9. Else initialValue is not present, |
92 Bind(&no_initial_value); | 92 Bind(&no_initial_value); |
93 | 93 |
94 // a. Let kPresent be false. | 94 // a. Let kPresent be false. |
95 a.Bind(TheHoleConstant()); | 95 a.Bind(TheHoleConstant()); |
96 Goto(&done); | 96 Goto(&done); |
97 Bind(&done); | 97 Bind(&done); |
98 return a.value(); | 98 return a.value(); |
99 } | 99 } |
100 | 100 |
101 Node* ReduceProcessor(Node* k_value, Node* k) { | 101 Node* ReduceProcessor(ElementsKind o_kind, Node* k_value, Node* k) { |
102 Variable result(this, MachineRepresentation::kTagged); | 102 Variable result(this, MachineRepresentation::kTagged); |
103 Label done(this, {&result}), initial(this); | 103 Label done(this, {&result}), initial(this); |
104 GotoIf(WordEqual(a(), TheHoleConstant()), &initial); | 104 GotoIf(WordEqual(a(), TheHoleConstant()), &initial); |
105 result.Bind(CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), | 105 result.Bind(CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), |
106 UndefinedConstant(), a(), k_value, k, o())); | 106 UndefinedConstant(), a(), k_value, k, o())); |
107 Goto(&done); | 107 Goto(&done); |
108 | 108 |
109 Bind(&initial); | 109 Bind(&initial); |
110 result.Bind(k_value); | 110 result.Bind(k_value); |
111 Goto(&done); | 111 Goto(&done); |
112 | 112 |
113 Bind(&done); | 113 Bind(&done); |
114 return result.value(); | 114 return result.value(); |
115 } | 115 } |
116 | 116 |
117 void ReducePostLoopAction() { | 117 void ReducePostLoopAction() { |
118 Label ok(this); | 118 Label ok(this); |
119 GotoIf(WordNotEqual(a(), TheHoleConstant()), &ok); | 119 GotoIf(WordNotEqual(a(), TheHoleConstant()), &ok); |
120 CallRuntime(Runtime::kThrowTypeError, context(), | 120 CallRuntime(Runtime::kThrowTypeError, context(), |
121 SmiConstant(MessageTemplate::kReduceNoInitial)); | 121 SmiConstant(MessageTemplate::kReduceNoInitial)); |
122 Unreachable(); | 122 Unreachable(); |
123 Bind(&ok); | 123 Bind(&ok); |
124 } | 124 } |
125 | 125 |
126 Node* FilterResultGenerator() { | 126 Node* FilterResultGenerator() { |
127 // 7. Let A be ArraySpeciesCreate(O, 0). | 127 // 7. Let A be ArraySpeciesCreate(O, 0). |
128 return ArraySpeciesCreate(context(), o(), SmiConstant(0)); | 128 return ArraySpeciesCreate(context(), o(), SmiConstant(0)); |
129 } | 129 } |
130 | 130 |
131 Node* FilterProcessor(Node* k_value, Node* k) { | 131 Node* FilterProcessor(ElementsKind o_kind, Node* k_value, Node* k) { |
132 // ii. Let selected be ToBoolean(? Call(callbackfn, T, kValue, k, O)). | 132 // ii. Let selected be ToBoolean(? Call(callbackfn, T, kValue, k, O)). |
133 Node* selected = CallJS(CodeFactory::Call(isolate()), context(), | 133 Node* selected = CallJS(CodeFactory::Call(isolate()), context(), |
134 callbackfn(), this_arg(), k_value, k, o()); | 134 callbackfn(), this_arg(), k_value, k, o()); |
135 Label true_continue(this, &to_), false_continue(this); | 135 Label true_continue(this, &to_), false_continue(this); |
136 BranchIfToBooleanIsTrue(selected, &true_continue, &false_continue); | 136 BranchIfToBooleanIsTrue(selected, &true_continue, &false_continue); |
137 Bind(&true_continue); | 137 Bind(&true_continue); |
138 // iii. If selected is true, then... | |
139 { | 138 { |
139 // iii. If selected is true, then... | |
140 Label after_work(this, &to_); | |
141 if (o_kind < DICTIONARY_ELEMENTS) { | |
danno
2017/04/03 15:35:27
Please use the predicates in elements-kind.h, e.g.
mvstanton
2017/04/06 08:57:36
Per our discussion, I'll just remove the o_kind pa
| |
142 Node* kind = nullptr; | |
143 | |
144 // If a() is a JSArray, we can have a fast path. | |
145 Label fast(this); | |
146 Label runtime(this); | |
147 Label object_push_pre(this), object_push(this), double_push(this); | |
danno
2017/04/03 15:35:27
I think you can make this slightly better. Since y
mvstanton
2017/04/06 08:57:36
Right, because of the vagaries of what can happen
| |
148 BranchIfFastJSArray(a(), context(), FastJSArrayAccessMode::ANY_ACCESS, | |
149 &fast, &runtime); | |
150 | |
151 Bind(&fast); | |
152 { | |
153 kind = EnsureArrayPushable(a(), &runtime); | |
154 GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)), | |
155 &object_push_pre); | |
156 | |
157 BuildAppendJSArray(FAST_SMI_ELEMENTS, a(), k_value, &runtime); | |
158 Goto(&after_work); | |
159 } | |
160 | |
161 Bind(&object_push_pre); | |
162 { | |
163 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | |
164 &double_push, &object_push); | |
165 } | |
166 | |
167 Bind(&object_push); | |
168 { | |
169 BuildAppendJSArray(FAST_ELEMENTS, a(), k_value, &runtime); | |
170 Goto(&after_work); | |
171 } | |
172 | |
173 Bind(&double_push); | |
174 { | |
175 BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, a(), k_value, &runtime); | |
176 Goto(&after_work); | |
177 } | |
178 | |
179 Bind(&runtime); | |
180 } | |
181 | |
140 // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue). | 182 // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue). |
141 CallRuntime(Runtime::kCreateDataProperty, context(), a(), to_.value(), | 183 CallRuntime(Runtime::kCreateDataProperty, context(), a(), to_.value(), |
142 k_value); | 184 k_value); |
185 Goto(&after_work); | |
143 | 186 |
144 // 2. Increase to by 1. | 187 Bind(&after_work); |
145 to_.Bind(NumberInc(to_.value())); | 188 { |
146 Goto(&false_continue); | 189 // 2. Increase to by 1. |
190 to_.Bind(NumberInc(to_.value())); | |
191 Goto(&false_continue); | |
192 } | |
147 } | 193 } |
148 Bind(&false_continue); | 194 Bind(&false_continue); |
149 return a(); | 195 return a(); |
150 } | 196 } |
151 | 197 |
152 Node* MapResultGenerator() { | 198 Node* MapResultGenerator() { |
153 // 5. Let A be ? ArraySpeciesCreate(O, len). | 199 // 5. Let A be ? ArraySpeciesCreate(O, len). |
154 return ArraySpeciesCreate(context(), o(), len_); | 200 return ArraySpeciesCreate(context(), o(), len_); |
155 } | 201 } |
156 | 202 |
157 Node* MapProcessor(Node* k_value, Node* k) { | 203 Node* MapProcessor(ElementsKind o_kind, Node* k_value, Node* k) { |
158 // i. Let kValue be ? Get(O, Pk). Performed by the caller of MapProcessor. | 204 // i. Let kValue be ? Get(O, Pk). Performed by the caller of MapProcessor. |
159 // ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O). | 205 // ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O). |
160 Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(), | 206 Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(), |
161 callbackfn(), this_arg(), k_value, k, o()); | 207 callbackfn(), this_arg(), k_value, k, o()); |
162 | 208 |
209 Label finished(this); | |
210 if (o_kind < DICTIONARY_ELEMENTS) { | |
211 Node* kind = nullptr; | |
212 Node* elements = nullptr; | |
213 | |
214 // If a() is a JSArray, we can have a fast path. | |
215 // mode is SMI_PARAMETERS because k has tagged representation. | |
216 ParameterMode mode = SMI_PARAMETERS; | |
217 Label fast(this); | |
218 Label runtime(this); | |
219 Label object_push_pre(this), object_push(this), double_push(this); | |
220 BranchIfFastJSArray(a(), context(), FastJSArrayAccessMode::ANY_ACCESS, | |
221 &fast, &runtime); | |
222 | |
223 Bind(&fast); | |
224 { | |
225 kind = EnsureArrayPushable(a(), &runtime); | |
226 elements = LoadElements(a()); | |
227 GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)), | |
danno
2017/04/03 15:35:27
Consider adding/using existing predicates in code-
mvstanton
2017/04/06 08:57:36
I use a "greater than" metaphor to avoid multiple
| |
228 &object_push_pre); | |
229 | |
230 TryStoreArrayElement(FAST_SMI_ELEMENTS, mode, &runtime, elements, k, | |
231 mappedValue); | |
232 Goto(&finished); | |
233 } | |
234 | |
235 Bind(&object_push_pre); | |
236 { | |
237 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | |
238 &double_push, &object_push); | |
239 } | |
240 | |
241 Bind(&object_push); | |
242 { | |
243 TryStoreArrayElement(FAST_ELEMENTS, mode, &runtime, elements, k, | |
244 mappedValue); | |
245 Goto(&finished); | |
246 } | |
247 | |
248 Bind(&double_push); | |
249 { | |
250 TryStoreArrayElement(FAST_DOUBLE_ELEMENTS, mode, &runtime, elements, k, | |
251 mappedValue); | |
252 Goto(&finished); | |
253 } | |
254 | |
255 Bind(&runtime); | |
256 } | |
257 | |
163 // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). | 258 // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). |
164 CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mappedValue); | 259 CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mappedValue); |
260 Goto(&finished); | |
261 | |
262 Bind(&finished); | |
165 return a(); | 263 return a(); |
166 } | 264 } |
167 | 265 |
168 void NullPostLoopAction() {} | 266 void NullPostLoopAction() {} |
169 | 267 |
170 protected: | 268 protected: |
171 Node* context() { return context_; } | 269 Node* context() { return context_; } |
172 Node* receiver() { return receiver_; } | 270 Node* receiver() { return receiver_; } |
173 Node* new_target() { return new_target_; } | 271 Node* new_target() { return new_target_; } |
174 Node* o() { return o_; } | 272 Node* o() { return o_; } |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
413 | 511 |
414 // d. If kPresent is true, then | 512 // d. If kPresent is true, then |
415 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); | 513 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); |
416 | 514 |
417 // i. Let kValue be Get(O, Pk). | 515 // i. Let kValue be Get(O, Pk). |
418 // ii. ReturnIfAbrupt(kValue). | 516 // ii. ReturnIfAbrupt(kValue). |
419 Node* k_value = GetProperty(context(), o(), k()); | 517 Node* k_value = GetProperty(context(), o(), k()); |
420 | 518 |
421 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). | 519 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). |
422 // iv. ReturnIfAbrupt(funcResult). | 520 // iv. ReturnIfAbrupt(funcResult). |
423 a_.Bind(processor(this, k_value, k())); | 521 a_.Bind(processor(this, DICTIONARY_ELEMENTS, k_value, k())); |
danno
2017/04/03 15:35:27
Although I know what you mean here, the elements m
| |
424 Goto(&done_element); | 522 Goto(&done_element); |
425 | 523 |
426 Bind(&done_element); | 524 Bind(&done_element); |
427 | 525 |
428 if (direction == ForEachDirection::kForward) { | 526 if (direction == ForEachDirection::kForward) { |
429 // e. Increase k by 1. | 527 // e. Increase k by 1. |
430 k_.Bind(NumberInc(k())); | 528 k_.Bind(NumberInc(k())); |
431 } else { | 529 } else { |
432 // e. Decrease k by 1. | 530 // e. Decrease k by 1. |
433 k_.Bind(NumberDec(k())); | 531 k_.Bind(NumberDec(k())); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
466 Node* elements = LoadElements(o_); | 564 Node* elements = LoadElements(o_); |
467 Node* base_ptr = | 565 Node* base_ptr = |
468 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); | 566 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); |
469 Node* external_ptr = | 567 Node* external_ptr = |
470 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, | 568 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, |
471 MachineType::Pointer()); | 569 MachineType::Pointer()); |
472 Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr); | 570 Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr); |
473 Node* value = LoadFixedTypedArrayElementAsTagged(data_ptr, index, kind, | 571 Node* value = LoadFixedTypedArrayElementAsTagged(data_ptr, index, kind, |
474 SMI_PARAMETERS); | 572 SMI_PARAMETERS); |
475 k_.Bind(index); | 573 k_.Bind(index); |
476 a_.Bind(processor(this, value, index)); | 574 a_.Bind(processor(this, kind, value, index)); |
477 }; | 575 }; |
478 BuildFastLoop(list, SmiConstant(0), len_, body, 1, | 576 BuildFastLoop(list, SmiConstant(0), len_, body, 1, |
479 ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost); | 577 ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost); |
480 } | 578 } |
481 | 579 |
482 void VisitAllFastElementsOneKind(ElementsKind kind, | 580 void VisitAllFastElementsOneKind(ElementsKind kind, |
483 const CallResultProcessor& processor, | 581 const CallResultProcessor& processor, |
484 Label* array_changed, ParameterMode mode, | 582 Label* array_changed, ParameterMode mode, |
485 ForEachDirection direction) { | 583 ForEachDirection direction) { |
486 Comment("begin VisitAllFastElementsOneKind"); | 584 Comment("begin VisitAllFastElementsOneKind"); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
522 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); | 620 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); |
523 Node* value = nullptr; | 621 Node* value = nullptr; |
524 if (kind == FAST_ELEMENTS) { | 622 if (kind == FAST_ELEMENTS) { |
525 value = LoadObjectField(elements, offset); | 623 value = LoadObjectField(elements, offset); |
526 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); | 624 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); |
527 } else { | 625 } else { |
528 Node* double_value = | 626 Node* double_value = |
529 LoadDoubleWithHoleCheck(elements, offset, &hole_element); | 627 LoadDoubleWithHoleCheck(elements, offset, &hole_element); |
530 value = AllocateHeapNumberWithValue(double_value); | 628 value = AllocateHeapNumberWithValue(double_value); |
531 } | 629 } |
532 a_.Bind(processor(this, value, k())); | 630 a_.Bind(processor(this, kind, value, k())); |
533 Goto(&one_element_done); | 631 Goto(&one_element_done); |
534 | 632 |
535 Bind(&hole_element); | 633 Bind(&hole_element); |
536 // Check if o's prototype change unexpectedly has elements after the | 634 // Check if o's prototype change unexpectedly has elements after the |
537 // callback in the case of a hole. | 635 // callback in the case of a hole. |
538 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, | 636 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, |
539 array_changed); | 637 array_changed); |
540 | 638 |
541 Bind(&one_element_done); | 639 Bind(&one_element_done); |
542 }, | 640 }, |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
625 CodeStubArguments args(this, ChangeInt32ToIntPtr(argc)); | 723 CodeStubArguments args(this, ChangeInt32ToIntPtr(argc)); |
626 Node* receiver = args.GetReceiver(); | 724 Node* receiver = args.GetReceiver(); |
627 Node* kind = nullptr; | 725 Node* kind = nullptr; |
628 | 726 |
629 Label fast(this); | 727 Label fast(this); |
630 BranchIfFastJSArray(receiver, context, FastJSArrayAccessMode::ANY_ACCESS, | 728 BranchIfFastJSArray(receiver, context, FastJSArrayAccessMode::ANY_ACCESS, |
631 &fast, &runtime); | 729 &fast, &runtime); |
632 | 730 |
633 Bind(&fast); | 731 Bind(&fast); |
634 { | 732 { |
635 // Disallow pushing onto prototypes. It might be the JSArray prototype. | |
636 // Disallow pushing onto non-extensible objects. | |
637 Comment("Disallow pushing onto prototypes"); | |
638 Node* map = LoadMap(receiver); | |
639 Node* bit_field2 = LoadMapBitField2(map); | |
640 int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) | | |
641 (1 << Map::kIsExtensible); | |
642 Node* test = Word32And(bit_field2, Int32Constant(mask)); | |
643 GotoIf(Word32NotEqual(test, Int32Constant(1 << Map::kIsExtensible)), | |
644 &runtime); | |
645 | |
646 // Disallow pushing onto arrays in dictionary named property mode. We need | |
647 // to figure out whether the length property is still writable. | |
648 Comment("Disallow pushing onto arrays in dictionary named property mode"); | |
649 GotoIf(IsDictionaryMap(map), &runtime); | |
650 | |
651 // Check whether the length property is writable. The length property is the | |
652 // only default named property on arrays. It's nonconfigurable, hence is | |
653 // guaranteed to stay the first property. | |
654 Node* descriptors = LoadMapDescriptors(map); | |
655 Node* details = | |
656 LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0)); | |
657 GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask), | |
658 &runtime); | |
659 | |
660 arg_index.Bind(IntPtrConstant(0)); | 733 arg_index.Bind(IntPtrConstant(0)); |
661 kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); | 734 kind = EnsureArrayPushable(receiver, &runtime); |
662 | |
663 GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)), | 735 GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)), |
664 &object_push_pre); | 736 &object_push_pre); |
665 | 737 |
666 Node* new_length = BuildAppendJSArray(FAST_SMI_ELEMENTS, context, receiver, | 738 Node* new_length = BuildAppendJSArray(FAST_SMI_ELEMENTS, receiver, args, |
667 args, arg_index, &smi_transition); | 739 arg_index, &smi_transition); |
668 args.PopAndReturn(new_length); | 740 args.PopAndReturn(new_length); |
669 } | 741 } |
670 | 742 |
671 // If the argument is not a smi, then use a heavyweight SetProperty to | 743 // If the argument is not a smi, then use a heavyweight SetProperty to |
672 // transition the array for only the single next element. If the argument is | 744 // transition the array for only the single next element. If the argument is |
673 // a smi, the failure is due to some other reason and we should fall back on | 745 // a smi, the failure is due to some other reason and we should fall back on |
674 // the most generic implementation for the rest of the array. | 746 // the most generic implementation for the rest of the array. |
675 Bind(&smi_transition); | 747 Bind(&smi_transition); |
676 { | 748 { |
677 Node* arg = args.AtIndex(arg_index.value()); | 749 Node* arg = args.AtIndex(arg_index.value()); |
(...skipping 17 matching lines...) Expand all Loading... | |
695 } | 767 } |
696 | 768 |
697 Bind(&object_push_pre); | 769 Bind(&object_push_pre); |
698 { | 770 { |
699 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | 771 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), |
700 &double_push, &object_push); | 772 &double_push, &object_push); |
701 } | 773 } |
702 | 774 |
703 Bind(&object_push); | 775 Bind(&object_push); |
704 { | 776 { |
705 Node* new_length = BuildAppendJSArray(FAST_ELEMENTS, context, receiver, | 777 Node* new_length = BuildAppendJSArray(FAST_ELEMENTS, receiver, args, |
706 args, arg_index, &default_label); | 778 arg_index, &default_label); |
707 args.PopAndReturn(new_length); | 779 args.PopAndReturn(new_length); |
708 } | 780 } |
709 | 781 |
710 Bind(&double_push); | 782 Bind(&double_push); |
711 { | 783 { |
712 Node* new_length = | 784 Node* new_length = BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, receiver, args, |
713 BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver, args, | 785 arg_index, &double_transition); |
714 arg_index, &double_transition); | |
715 args.PopAndReturn(new_length); | 786 args.PopAndReturn(new_length); |
716 } | 787 } |
717 | 788 |
718 // If the argument is not a double, then use a heavyweight SetProperty to | 789 // If the argument is not a double, then use a heavyweight SetProperty to |
719 // transition the array for only the single next element. If the argument is | 790 // transition the array for only the single next element. If the argument is |
720 // a double, the failure is due to some other reason and we should fall back | 791 // a double, the failure is due to some other reason and we should fall back |
721 // on the most generic implementation for the rest of the array. | 792 // on the most generic implementation for the rest of the array. |
722 Bind(&double_transition); | 793 Bind(&double_transition); |
723 { | 794 { |
724 Node* arg = args.AtIndex(arg_index.value()); | 795 Node* arg = args.AtIndex(arg_index.value()); |
(...skipping 1392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2117 { | 2188 { |
2118 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); | 2189 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); |
2119 CallRuntime(Runtime::kThrowTypeError, context, message, | 2190 CallRuntime(Runtime::kThrowTypeError, context, message, |
2120 HeapConstant(operation)); | 2191 HeapConstant(operation)); |
2121 Unreachable(); | 2192 Unreachable(); |
2122 } | 2193 } |
2123 } | 2194 } |
2124 | 2195 |
2125 } // namespace internal | 2196 } // namespace internal |
2126 } // namespace v8 | 2197 } // namespace v8 |
OLD | NEW |