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<std::pair<Node*, Node*>( |
danno
2017/03/17 10:26:31
Per Camillo's comments, I am going to add comments
| |
18 typedef std::function<void(Node* a, Node* pK, Node* value)> | 18 ArrayBuiltinCodeStubAssembler* masm, Node* this_arg, Node* o, Node* len)> |
19 BuiltinResultGenerator; | |
20 | |
21 typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm, | |
22 Node* context, Node* callbackfn, Node* this_arg, | |
23 Node* k_value, Node* k, Node* o, Node* a)> | |
19 CallResultProcessor; | 24 CallResultProcessor; |
20 | 25 |
26 typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm, Node* context, | |
27 Node* a)> | |
28 PostLoopAction; | |
29 | |
21 void GenerateIteratingArrayBuiltinBody( | 30 void GenerateIteratingArrayBuiltinBody( |
22 const char* name, const BuiltinResultGenerator& generator, | 31 const char* name, const BuiltinResultGenerator& generator, |
23 const CallResultProcessor& processor, | 32 const CallResultProcessor& processor, const PostLoopAction& action, |
24 const Callable& slow_case_continuation) { | 33 const Callable& slow_case_continuation) { |
25 Node* receiver = Parameter(IteratingArrayBuiltinDescriptor::kReceiver); | 34 Node* receiver = Parameter(IteratingArrayBuiltinDescriptor::kReceiver); |
26 Node* callbackfn = Parameter(IteratingArrayBuiltinDescriptor::kCallback); | 35 Node* callbackfn = Parameter(IteratingArrayBuiltinDescriptor::kCallback); |
27 Node* this_arg = Parameter(IteratingArrayBuiltinDescriptor::kThisArg); | 36 Node* this_arg = Parameter(IteratingArrayBuiltinDescriptor::kThisArg); |
28 Node* context = Parameter(IteratingArrayBuiltinDescriptor::kContext); | 37 Node* context = Parameter(IteratingArrayBuiltinDescriptor::kContext); |
29 Node* new_target = Parameter(IteratingArrayBuiltinDescriptor::kNewTarget); | 38 Node* new_target = Parameter(IteratingArrayBuiltinDescriptor::kNewTarget); |
30 | 39 |
31 Variable k(this, MachineRepresentation::kTagged, SmiConstant(0)); | 40 Variable k(this, MachineRepresentation::kTagged, SmiConstant(0)); |
32 Label non_array(this), slow(this, &k), array_changes(this, &k); | 41 Variable a(this, MachineRepresentation::kTagged, UndefinedConstant()); |
42 Label non_array(this), slow(this, {&k, &a}), array_changes(this, {&k, &a}); | |
33 | 43 |
34 // TODO(danno): Seriously? Do we really need to throw the exact error | 44 // TODO(danno): Seriously? Do we really need to throw the exact error |
35 // message on null and undefined so that the webkit tests pass? | 45 // message on null and undefined so that the webkit tests pass? |
36 Label throw_null_undefined_exception(this, Label::kDeferred); | 46 Label throw_null_undefined_exception(this, Label::kDeferred); |
37 GotoIf(WordEqual(receiver, NullConstant()), | 47 GotoIf(WordEqual(receiver, NullConstant()), |
38 &throw_null_undefined_exception); | 48 &throw_null_undefined_exception); |
39 GotoIf(WordEqual(receiver, UndefinedConstant()), | 49 GotoIf(WordEqual(receiver, UndefinedConstant()), |
40 &throw_null_undefined_exception); | 50 &throw_null_undefined_exception); |
41 | 51 |
42 // By the book: taken directly from the ECMAScript 2015 specification | 52 // By the book: taken directly from the ECMAScript 2015 specification |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
78 | 88 |
79 Bind(&type_exception); | 89 Bind(&type_exception); |
80 { | 90 { |
81 CallRuntime(Runtime::kThrowTypeError, context, | 91 CallRuntime(Runtime::kThrowTypeError, context, |
82 SmiConstant(MessageTemplate::kCalledNonCallable), callbackfn); | 92 SmiConstant(MessageTemplate::kCalledNonCallable), callbackfn); |
83 Unreachable(); | 93 Unreachable(); |
84 } | 94 } |
85 | 95 |
86 Bind(&done); | 96 Bind(&done); |
87 | 97 |
88 Node* a = generator(o, len); | 98 Node* initial_a; |
99 Node* initial_k; | |
100 std::tie(initial_a, initial_k) = generator(this, this_arg, o, len); | |
89 | 101 |
90 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. | 102 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. |
91 // [Already done by the arguments adapter] | 103 // [Already done by the arguments adapter] |
92 | 104 |
93 HandleFastElements(context, this_arg, o, len, callbackfn, processor, a, k, | 105 // 7. Let k be 0. |
94 &slow); | 106 k.Bind(initial_k); |
107 a.Bind(initial_a); | |
95 | 108 |
96 // 7. Let k be 0. | 109 HandleFastElements(context, this_arg, o, len, callbackfn, processor, action, |
97 // Already done above in initialization of the Variable k | 110 a, k, &slow); |
98 | 111 |
99 Bind(&slow); | 112 Bind(&slow); |
100 | 113 |
101 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, | 114 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, |
102 MachineType::TaggedPointer()); | 115 MachineType::TaggedPointer()); |
103 TailCallStub( | 116 TailCallStub( |
104 slow_case_continuation, context, target, new_target, | 117 slow_case_continuation, context, target, new_target, |
105 Int32Constant(IteratingArrayBuiltinLoopContinuationDescriptor::kArity), | 118 Int32Constant(IteratingArrayBuiltinLoopContinuationDescriptor::kArity), |
106 receiver, callbackfn, this_arg, a, o, k.value(), len); | 119 receiver, callbackfn, this_arg, a.value(), o, k.value(), len); |
107 } | 120 } |
108 | 121 |
109 void GenerateIteratingArrayBuiltinLoopContinuation( | 122 void GenerateIteratingArrayBuiltinLoopContinuation( |
110 const CallResultProcessor& processor) { | 123 const CallResultProcessor& processor, const PostLoopAction& action) { |
111 Node* callbackfn = | 124 Node* callbackfn = |
112 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kCallback); | 125 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kCallback); |
113 Node* this_arg = | 126 Node* this_arg = |
114 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kThisArg); | 127 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kThisArg); |
115 Node* a = | 128 Node* initial_a = |
116 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kArray); | 129 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kArray); |
117 Node* o = | 130 Node* o = |
118 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kObject); | 131 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kObject); |
119 Node* initial_k = | 132 Node* initial_k = |
120 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kInitialK); | 133 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kInitialK); |
121 Node* len = | 134 Node* len = |
122 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kLength); | 135 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kLength); |
123 Node* context = | 136 Node* context = |
124 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kContext); | 137 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kContext); |
125 | 138 |
126 // 8. Repeat, while k < len | 139 // 8. Repeat, while k < len |
127 Variable k(this, MachineRepresentation::kTagged, initial_k); | 140 Variable k(this, MachineRepresentation::kTagged, initial_k); |
128 Label loop(this, &k); | 141 Variable a(this, MachineRepresentation::kTagged, initial_a); |
142 Label loop(this, {&k, &a}); | |
129 Label after_loop(this); | 143 Label after_loop(this); |
130 Goto(&loop); | 144 Goto(&loop); |
131 Bind(&loop); | 145 Bind(&loop); |
132 { | 146 { |
133 GotoUnlessNumberLessThan(k.value(), len, &after_loop); | 147 GotoUnlessNumberLessThan(k.value(), len, &after_loop); |
134 | 148 |
135 Label done_element(this); | 149 Label done_element(this); |
136 // a. Let Pk be ToString(k). | 150 // a. Let Pk be ToString(k). |
137 Node* p_k = ToString(context, k.value()); | 151 Node* p_k = ToString(context, k.value()); |
138 | 152 |
139 // b. Let kPresent be HasProperty(O, Pk). | 153 // b. Let kPresent be HasProperty(O, Pk). |
140 // c. ReturnIfAbrupt(kPresent). | 154 // c. ReturnIfAbrupt(kPresent). |
141 Node* k_present = HasProperty(o, p_k, context); | 155 Node* k_present = HasProperty(o, p_k, context); |
142 | 156 |
143 // d. If kPresent is true, then | 157 // d. If kPresent is true, then |
144 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); | 158 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); |
145 | 159 |
146 // i. Let kValue be Get(O, Pk). | 160 // i. Let kValue be Get(O, Pk). |
147 // ii. ReturnIfAbrupt(kValue). | 161 // ii. ReturnIfAbrupt(kValue). |
148 Node* k_value = GetProperty(context, o, k.value()); | 162 Node* k_value = GetProperty(context, o, k.value()); |
149 | 163 |
150 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). | 164 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). |
151 // iv. ReturnIfAbrupt(funcResult). | 165 // iv. ReturnIfAbrupt(funcResult). |
152 Node* result = CallJS(CodeFactory::Call(isolate()), context, callbackfn, | 166 a.Bind(processor(this, context, callbackfn, this_arg, k_value, k.value(), |
153 this_arg, k_value, k.value(), o); | 167 o, a.value())); |
154 | |
155 processor(a, p_k, result); | |
156 Goto(&done_element); | 168 Goto(&done_element); |
157 Bind(&done_element); | 169 Bind(&done_element); |
158 | 170 |
159 // e. Increase k by 1. | 171 // e. Increase k by 1. |
160 k.Bind(NumberInc(k.value())); | 172 k.Bind(NumberInc(k.value())); |
161 Goto(&loop); | 173 Goto(&loop); |
162 } | 174 } |
163 Bind(&after_loop); | 175 Bind(&after_loop); |
164 Return(a); | 176 |
177 action(this, context, a.value()); | |
178 | |
179 Return(a.value()); | |
165 } | 180 } |
166 | 181 |
167 void ForEachProcessor(Node* a, Node* p_k, Node* value) {} | 182 std::pair<Node*, Node*> ForEachResultGenerator(Node* this_arg, Node* o, |
183 Node* len) { | |
184 return std::make_pair(UndefinedConstant(), SmiConstant(0)); | |
185 } | |
168 | 186 |
169 void SomeProcessor(Node* a, Node* p_k, Node* value) { | 187 Node* ForEachProcessor(Node* context, Node* callbackfn, Node* this_arg, |
188 Node* k_value, Node* k, Node* o, Node* a) { | |
189 CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg, k_value, | |
190 k, o); | |
191 return a; | |
192 } | |
193 | |
194 std::pair<Node*, Node*> SomeResultGenerator(Node* this_arg, Node* o, | |
195 Node* len) { | |
196 return std::make_pair(FalseConstant(), SmiConstant(0)); | |
197 } | |
198 | |
199 Node* SomeProcessor(Node* context, Node* callbackfn, Node* this_arg, | |
200 Node* k_value, Node* k, Node* o, Node* a) { | |
201 Node* value = CallJS(CodeFactory::Call(isolate()), context, callbackfn, | |
202 this_arg, k_value, k, o); | |
170 Label false_continue(this), return_true(this); | 203 Label false_continue(this), return_true(this); |
171 BranchIfToBooleanIsTrue(value, &return_true, &false_continue); | 204 BranchIfToBooleanIsTrue(value, &return_true, &false_continue); |
172 Bind(&return_true); | 205 Bind(&return_true); |
173 Return(TrueConstant()); | 206 Return(TrueConstant()); |
174 Bind(&false_continue); | 207 Bind(&false_continue); |
208 return a; | |
175 } | 209 } |
176 | 210 |
177 void EveryProcessor(Node* a, Node* p_k, Node* value) { | 211 std::pair<Node*, Node*> EveryResultGenerator(Node* this_arg, Node* o, |
212 Node* len) { | |
213 return std::make_pair(TrueConstant(), SmiConstant(0)); | |
214 } | |
215 | |
216 Node* EveryProcessor(Node* context, Node* callbackfn, Node* this_arg, | |
217 Node* k_value, Node* k, Node* o, Node* a) { | |
218 Node* value = CallJS(CodeFactory::Call(isolate()), context, callbackfn, | |
219 this_arg, k_value, k, o); | |
178 Label true_continue(this), return_false(this); | 220 Label true_continue(this), return_false(this); |
179 BranchIfToBooleanIsTrue(value, &true_continue, &return_false); | 221 BranchIfToBooleanIsTrue(value, &true_continue, &return_false); |
180 Bind(&return_false); | 222 Bind(&return_false); |
181 Return(FalseConstant()); | 223 Return(FalseConstant()); |
182 Bind(&true_continue); | 224 Bind(&true_continue); |
225 return a; | |
183 } | 226 } |
184 | 227 |
228 std::pair<Node*, Node*> ReduceResultGenerator(Node* initial_value, Node* o, | |
229 Node* len) { | |
230 Variable a(this, MachineRepresentation::kTagged, UndefinedConstant()); | |
231 Label no_initial_value(this), has_initial_value(this), done(this, {&a}); | |
232 | |
233 // 8. If initialValue is present, then | |
234 Node* parent_frame_ptr = LoadParentFramePointer(); | |
235 Node* marker_or_function = LoadBufferObject( | |
236 parent_frame_ptr, CommonFrameConstants::kContextOrFrameTypeOffset); | |
237 GotoIf( | |
238 MarkerIsNotFrameType(marker_or_function, StackFrame::ARGUMENTS_ADAPTOR), | |
239 &has_initial_value); | |
240 | |
241 // Has arguments adapter, check count. | |
242 Node* adapted_parameter_count = LoadBufferObject( | |
243 parent_frame_ptr, ArgumentsAdaptorFrameConstants::kLengthOffset); | |
244 Branch(SmiLessThan(adapted_parameter_count, | |
245 SmiConstant(IteratingArrayBuiltinDescriptor::kThisArg)), | |
246 &no_initial_value, &has_initial_value); | |
247 | |
248 // a. Set accumulator to initialValue. | |
249 Bind(&has_initial_value); | |
250 a.Bind(initial_value); | |
251 Goto(&done); | |
252 | |
253 // 9. Else initialValue is not present, | |
254 Bind(&no_initial_value); | |
255 | |
256 // a. Let kPresent be false. | |
257 a.Bind(TheHoleConstant()); | |
258 Goto(&done); | |
259 Bind(&done); | |
260 return std::make_pair(a.value(), SmiConstant(0)); | |
261 } | |
262 | |
263 Node* ReduceProcessor(Node* context, Node* callbackfn, Node* this_arg, | |
264 Node* k_value, Node* k, Node* o, Node* a) { | |
265 Variable result(this, MachineRepresentation::kTagged); | |
266 Label done(this, {&result}), initial(this); | |
267 GotoIf(WordEqual(a, TheHoleConstant()), &initial); | |
268 result.Bind(CallJS(CodeFactory::Call(isolate()), context, callbackfn, | |
269 UndefinedConstant(), a, k_value, k, o)); | |
270 Goto(&done); | |
271 | |
272 Bind(&initial); | |
273 result.Bind(k_value); | |
274 Goto(&done); | |
275 | |
276 Bind(&done); | |
277 return result.value(); | |
278 } | |
279 | |
280 void ReducePostLoopAction(Node* context, Node* a) { | |
281 Label ok(this); | |
282 GotoIf(WordNotEqual(a, TheHoleConstant()), &ok); | |
283 CallRuntime(Runtime::kThrowTypeError, context, | |
284 SmiConstant(MessageTemplate::kReduceNoInitial)); | |
285 Unreachable(); | |
286 Bind(&ok); | |
287 } | |
288 | |
289 void NullPostLoopAction(Node* context, Node* a) {} | |
290 | |
185 private: | 291 private: |
186 Node* VisitAllFastElementsOneKind(Node* context, ElementsKind kind, | 292 Node* VisitAllFastElementsOneKind(Node* context, ElementsKind kind, |
187 Node* this_arg, Node* o, Node* len, | 293 Node* this_arg, Node* o, Node* len, |
188 Node* callbackfn, | 294 Node* callbackfn, |
189 const CallResultProcessor& processor, | 295 const CallResultProcessor& processor, |
190 Node* a, Label* array_changed, | 296 Variable& a, Label* array_changed, |
191 ParameterMode mode) { | 297 ParameterMode mode) { |
192 Comment("begin VisitAllFastElementsOneKind"); | 298 Comment("begin VisitAllFastElementsOneKind"); |
193 Variable original_map(this, MachineRepresentation::kTagged); | 299 Variable original_map(this, MachineRepresentation::kTagged); |
194 original_map.Bind(LoadMap(o)); | 300 original_map.Bind(LoadMap(o)); |
195 VariableList list({&original_map}, zone()); | 301 VariableList list({&original_map, &a}, zone()); |
196 Node* last_index = nullptr; | 302 Node* last_index = nullptr; |
197 BuildFastLoop( | 303 BuildFastLoop( |
198 list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode), | 304 list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode), |
199 [=, &original_map, &last_index](Node* index) { | 305 [=, &a, &original_map, &last_index](Node* index) { |
200 last_index = index; | 306 last_index = index; |
201 Label one_element_done(this), hole_element(this); | 307 Label one_element_done(this), hole_element(this); |
202 | 308 |
203 // Check if o's map has changed during the callback. If so, we have to | 309 // Check if o's map has changed during the callback. If so, we have to |
204 // fall back to the slower spec implementation for the rest of the | 310 // fall back to the slower spec implementation for the rest of the |
205 // iteration. | 311 // iteration. |
206 Node* o_map = LoadMap(o); | 312 Node* o_map = LoadMap(o); |
207 GotoIf(WordNotEqual(o_map, original_map.value()), array_changed); | 313 GotoIf(WordNotEqual(o_map, original_map.value()), array_changed); |
208 | 314 |
209 // Check if o's length has changed during the callback and if the | 315 // Check if o's length has changed during the callback and if the |
(...skipping 14 matching lines...) Expand all Loading... | |
224 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); | 330 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); |
225 Node* value = nullptr; | 331 Node* value = nullptr; |
226 if (kind == FAST_ELEMENTS) { | 332 if (kind == FAST_ELEMENTS) { |
227 value = LoadObjectField(elements, offset); | 333 value = LoadObjectField(elements, offset); |
228 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); | 334 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); |
229 } else { | 335 } else { |
230 Node* double_value = | 336 Node* double_value = |
231 LoadDoubleWithHoleCheck(elements, offset, &hole_element); | 337 LoadDoubleWithHoleCheck(elements, offset, &hole_element); |
232 value = AllocateHeapNumberWithValue(double_value); | 338 value = AllocateHeapNumberWithValue(double_value); |
233 } | 339 } |
234 Node* result = CallJS(CodeFactory::Call(isolate()), context, | 340 a.Bind(processor(this, context, callbackfn, this_arg, value, |
235 callbackfn, this_arg, value, tagged_index, o); | 341 tagged_index, o, a.value())); |
236 processor(a, tagged_index, result); | |
237 Goto(&one_element_done); | 342 Goto(&one_element_done); |
238 | 343 |
239 Bind(&hole_element); | 344 Bind(&hole_element); |
240 // Check if o's prototype change unexpectedly has elements after the | 345 // Check if o's prototype change unexpectedly has elements after the |
241 // callback in the case of a hole. | 346 // callback in the case of a hole. |
242 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, | 347 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, |
243 array_changed); | 348 array_changed); |
244 | 349 |
245 Bind(&one_element_done); | 350 Bind(&one_element_done); |
246 }, | 351 }, |
247 1, mode, IndexAdvanceMode::kPost); | 352 1, mode, IndexAdvanceMode::kPost); |
248 Comment("end VisitAllFastElementsOneKind"); | 353 Comment("end VisitAllFastElementsOneKind"); |
249 return last_index; | 354 return last_index; |
250 } | 355 } |
251 | 356 |
252 void HandleFastElements(Node* context, Node* this_arg, Node* o, Node* len, | 357 void HandleFastElements(Node* context, Node* this_arg, Node* o, Node* len, |
253 Node* callbackfn, CallResultProcessor processor, | 358 Node* callbackfn, |
254 Node* a, Variable& k, Label* slow) { | 359 const CallResultProcessor& processor, |
360 const PostLoopAction& action, Variable& a, | |
361 Variable& k, Label* slow) { | |
255 Label switch_on_elements_kind(this), fast_elements(this), | 362 Label switch_on_elements_kind(this), fast_elements(this), |
256 maybe_double_elements(this), fast_double_elements(this); | 363 maybe_double_elements(this), fast_double_elements(this); |
257 | 364 |
258 Comment("begin HandleFastElements"); | 365 Comment("begin HandleFastElements"); |
259 // Non-smi lengths must use the slow path. | 366 // Non-smi lengths must use the slow path. |
260 GotoIf(TaggedIsNotSmi(len), slow); | 367 GotoIf(TaggedIsNotSmi(len), slow); |
261 | 368 |
262 BranchIfFastJSArray(o, context, | 369 BranchIfFastJSArray(o, context, |
263 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, | 370 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, |
264 &switch_on_elements_kind, slow); | 371 &switch_on_elements_kind, slow); |
265 | 372 |
266 Bind(&switch_on_elements_kind); | 373 Bind(&switch_on_elements_kind); |
267 // Select by ElementsKind | 374 // Select by ElementsKind |
268 Node* o_map = LoadMap(o); | 375 Node* o_map = LoadMap(o); |
269 Node* bit_field2 = LoadMapBitField2(o_map); | 376 Node* bit_field2 = LoadMapBitField2(o_map); |
270 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); | 377 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); |
271 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | 378 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), |
272 &maybe_double_elements, &fast_elements); | 379 &maybe_double_elements, &fast_elements); |
273 | 380 |
274 ParameterMode mode = OptimalParameterMode(); | 381 ParameterMode mode = OptimalParameterMode(); |
275 Bind(&fast_elements); | 382 Bind(&fast_elements); |
276 { | 383 { |
277 Label array_changed(this, Label::kDeferred); | 384 Label array_changed(this, Label::kDeferred); |
278 Node* last_index = VisitAllFastElementsOneKind( | 385 Node* last_index = VisitAllFastElementsOneKind( |
279 context, FAST_ELEMENTS, this_arg, o, len, callbackfn, processor, a, | 386 context, FAST_ELEMENTS, this_arg, o, len, callbackfn, processor, a, |
280 &array_changed, mode); | 387 &array_changed, mode); |
281 | 388 |
389 action(this, context, a.value()); | |
390 | |
282 // No exception, return success | 391 // No exception, return success |
283 Return(a); | 392 Return(a.value()); |
284 | 393 |
285 Bind(&array_changed); | 394 Bind(&array_changed); |
286 k.Bind(ParameterToTagged(last_index, mode)); | 395 k.Bind(ParameterToTagged(last_index, mode)); |
287 Goto(slow); | 396 Goto(slow); |
288 } | 397 } |
289 | 398 |
290 Bind(&maybe_double_elements); | 399 Bind(&maybe_double_elements); |
291 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)), | 400 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)), |
292 slow, &fast_double_elements); | 401 slow, &fast_double_elements); |
293 | 402 |
294 Bind(&fast_double_elements); | 403 Bind(&fast_double_elements); |
295 { | 404 { |
296 Label array_changed(this, Label::kDeferred); | 405 Label array_changed(this, Label::kDeferred); |
297 Node* last_index = VisitAllFastElementsOneKind( | 406 Node* last_index = VisitAllFastElementsOneKind( |
298 context, FAST_DOUBLE_ELEMENTS, this_arg, o, len, callbackfn, | 407 context, FAST_DOUBLE_ELEMENTS, this_arg, o, len, callbackfn, |
299 processor, a, &array_changed, mode); | 408 processor, a, &array_changed, mode); |
300 | 409 |
410 action(this, context, a.value()); | |
411 | |
301 // No exception, return success | 412 // No exception, return success |
302 Return(a); | 413 Return(a.value()); |
303 | 414 |
304 Bind(&array_changed); | 415 Bind(&array_changed); |
305 k.Bind(ParameterToTagged(last_index, mode)); | 416 k.Bind(ParameterToTagged(last_index, mode)); |
306 Goto(slow); | 417 Goto(slow); |
307 } | 418 } |
308 } | 419 } |
309 }; | 420 }; |
310 | 421 |
311 TF_BUILTIN(FastArrayPush, CodeStubAssembler) { | 422 TF_BUILTIN(FastArrayPush, CodeStubAssembler) { |
312 Variable arg_index(this, MachineType::PointerRepresentation()); | 423 Variable arg_index(this, MachineType::PointerRepresentation()); |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
457 { | 568 { |
458 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, | 569 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, |
459 MachineType::TaggedPointer()); | 570 MachineType::TaggedPointer()); |
460 TailCallStub(CodeFactory::ArrayPush(isolate()), context, target, new_target, | 571 TailCallStub(CodeFactory::ArrayPush(isolate()), context, target, new_target, |
461 argc); | 572 argc); |
462 } | 573 } |
463 } | 574 } |
464 | 575 |
465 TF_BUILTIN(ArrayForEachLoopContinuation, ArrayBuiltinCodeStubAssembler) { | 576 TF_BUILTIN(ArrayForEachLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
466 GenerateIteratingArrayBuiltinLoopContinuation( | 577 GenerateIteratingArrayBuiltinLoopContinuation( |
467 [this](Node* a, Node* p_k, Node* value) { | 578 &ArrayBuiltinCodeStubAssembler::ForEachProcessor, |
468 ForEachProcessor(a, p_k, value); | 579 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); |
469 }); | |
470 } | 580 } |
471 | 581 |
472 TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) { | 582 TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) { |
473 GenerateIteratingArrayBuiltinBody( | 583 GenerateIteratingArrayBuiltinBody( |
474 "Array.prototype.forEach", | 584 "Array.prototype.forEach", |
475 [=](Node*, Node*) { return UndefinedConstant(); }, | 585 &ArrayBuiltinCodeStubAssembler::ForEachResultGenerator, |
476 [this](Node* a, Node* p_k, Node* value) { | 586 &ArrayBuiltinCodeStubAssembler::ForEachProcessor, |
477 ForEachProcessor(a, p_k, value); | 587 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction, |
478 }, | |
479 CodeFactory::ArrayForEachLoopContinuation(isolate())); | 588 CodeFactory::ArrayForEachLoopContinuation(isolate())); |
480 } | 589 } |
481 | 590 |
482 TF_BUILTIN(ArraySomeLoopContinuation, ArrayBuiltinCodeStubAssembler) { | 591 TF_BUILTIN(ArraySomeLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
483 GenerateIteratingArrayBuiltinLoopContinuation( | 592 GenerateIteratingArrayBuiltinLoopContinuation( |
484 [this](Node* a, Node* p_k, Node* value) { | 593 &ArrayBuiltinCodeStubAssembler::SomeProcessor, |
485 SomeProcessor(a, p_k, value); | 594 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); |
486 }); | |
487 } | 595 } |
488 | 596 |
489 TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) { | 597 TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) { |
490 GenerateIteratingArrayBuiltinBody( | 598 GenerateIteratingArrayBuiltinBody( |
491 "Array.prototype.some", [=](Node*, Node*) { return FalseConstant(); }, | 599 "Array.prototype.some", |
492 [this](Node* a, Node* p_k, Node* value) { SomeProcessor(a, p_k, value); }, | 600 &ArrayBuiltinCodeStubAssembler::SomeResultGenerator, |
601 &ArrayBuiltinCodeStubAssembler::SomeProcessor, | |
602 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction, | |
493 CodeFactory::ArraySomeLoopContinuation(isolate())); | 603 CodeFactory::ArraySomeLoopContinuation(isolate())); |
494 } | 604 } |
495 | 605 |
496 TF_BUILTIN(ArrayEveryLoopContinuation, ArrayBuiltinCodeStubAssembler) { | 606 TF_BUILTIN(ArrayEveryLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
497 GenerateIteratingArrayBuiltinLoopContinuation( | 607 GenerateIteratingArrayBuiltinLoopContinuation( |
498 [this](Node* a, Node* p_k, Node* value) { | 608 &ArrayBuiltinCodeStubAssembler::EveryProcessor, |
499 EveryProcessor(a, p_k, value); | 609 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); |
500 }); | |
501 } | 610 } |
502 | 611 |
503 TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) { | 612 TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) { |
504 GenerateIteratingArrayBuiltinBody( | 613 GenerateIteratingArrayBuiltinBody( |
505 "Array.prototype.every", [=](Node*, Node*) { return TrueConstant(); }, | 614 "Array.prototype.every", |
506 [this](Node* a, Node* p_k, Node* value) { | 615 &ArrayBuiltinCodeStubAssembler::EveryResultGenerator, |
507 EveryProcessor(a, p_k, value); | 616 &ArrayBuiltinCodeStubAssembler::EveryProcessor, |
508 }, | 617 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction, |
509 CodeFactory::ArrayEveryLoopContinuation(isolate())); | 618 CodeFactory::ArrayEveryLoopContinuation(isolate())); |
510 } | 619 } |
511 | 620 |
621 TF_BUILTIN(ArrayReduceLoopContinuation, ArrayBuiltinCodeStubAssembler) { | |
622 GenerateIteratingArrayBuiltinLoopContinuation( | |
623 &ArrayBuiltinCodeStubAssembler::ReduceProcessor, | |
624 &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction); | |
625 } | |
626 | |
627 TF_BUILTIN(ArrayReduce, ArrayBuiltinCodeStubAssembler) { | |
628 GenerateIteratingArrayBuiltinBody( | |
629 "Array.prototype.reduce", | |
630 &ArrayBuiltinCodeStubAssembler::ReduceResultGenerator, | |
631 &ArrayBuiltinCodeStubAssembler::ReduceProcessor, | |
632 &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction, | |
633 CodeFactory::ArrayReduceLoopContinuation(isolate())); | |
634 } | |
635 | |
512 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { | 636 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { |
513 Node* object = Parameter(1); | 637 Node* object = Parameter(1); |
514 Node* context = Parameter(4); | 638 Node* context = Parameter(4); |
515 | 639 |
516 Label call_runtime(this), return_true(this), return_false(this); | 640 Label call_runtime(this), return_true(this), return_false(this); |
517 | 641 |
518 GotoIf(TaggedIsSmi(object), &return_false); | 642 GotoIf(TaggedIsSmi(object), &return_false); |
519 Node* instance_type = LoadInstanceType(object); | 643 Node* instance_type = LoadInstanceType(object); |
520 | 644 |
521 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), | 645 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), |
(...skipping 1034 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1556 { | 1680 { |
1557 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); | 1681 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); |
1558 CallRuntime(Runtime::kThrowTypeError, context, message, | 1682 CallRuntime(Runtime::kThrowTypeError, context, message, |
1559 HeapConstant(operation)); | 1683 HeapConstant(operation)); |
1560 Unreachable(); | 1684 Unreachable(); |
1561 } | 1685 } |
1562 } | 1686 } |
1563 | 1687 |
1564 } // namespace internal | 1688 } // namespace internal |
1565 } // namespace v8 | 1689 } // namespace v8 |
OLD | NEW |