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), to_(this, MachineRepresentation::kTagged) { | 15 : CodeStubAssembler(state), |
16 to_.Bind(SmiConstant(0)); | 16 k_(this, MachineRepresentation::kTagged, SmiConstant(0)), |
17 a_(this, MachineRepresentation::kTagged, SmiConstant(0)), | |
18 to_(this, MachineRepresentation::kTagged, SmiConstant(0)) {} | |
19 | |
20 typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm)> | |
21 BuiltinResultGenerator; | |
22 | |
23 typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)> | |
24 BuiltinResultIndexInitializer; | |
25 | |
26 typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm, | |
27 Node* k_value, Node* k)> | |
28 CallResultProcessor; | |
29 | |
30 typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)> | |
31 PostLoopAction; | |
32 | |
33 Node* ForEachResultGenerator() { return UndefinedConstant(); } | |
34 | |
35 Node* ForEachProcessor(Node* k_value, Node* k) { | |
36 CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(), | |
37 k_value, k, o()); | |
38 return a(); | |
17 } | 39 } |
18 | 40 |
19 typedef std::function<Node*(Node* context, Node* o, Node* len)> | 41 Node* SomeResultGenerator() { return FalseConstant(); } |
20 BuiltinResultGenerator; | 42 |
21 typedef std::function<void(Node* context, Node* a)> | 43 Node* SomeProcessor(Node* k_value, Node* k) { |
22 BuiltinResultIndexInitializer; | 44 Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), |
23 typedef std::function<void(Node* context, Node* value, Node* a, | 45 this_arg(), k_value, k, o()); |
24 Node* callback_result)> | 46 Label false_continue(this), return_true(this); |
25 CallResultProcessor; | 47 BranchIfToBooleanIsTrue(value, &return_true, &false_continue); |
48 Bind(&return_true); | |
49 Return(TrueConstant()); | |
50 Bind(&false_continue); | |
51 return a(); | |
52 } | |
53 | |
54 Node* EveryResultGenerator() { return TrueConstant(); } | |
55 | |
56 Node* EveryProcessor(Node* k_value, Node* k) { | |
57 Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), | |
58 this_arg(), k_value, k, o()); | |
59 Label true_continue(this), return_false(this); | |
60 BranchIfToBooleanIsTrue(value, &true_continue, &return_false); | |
61 Bind(&return_false); | |
62 Return(FalseConstant()); | |
63 Bind(&true_continue); | |
64 return a(); | |
65 } | |
66 | |
67 Node* ReduceResultGenerator() { | |
68 Variable a(this, MachineRepresentation::kTagged, UndefinedConstant()); | |
69 Label no_initial_value(this), has_initial_value(this), done(this, {&a}); | |
70 | |
71 // 8. If initialValue is present, then | |
72 Node* parent_frame_ptr = LoadParentFramePointer(); | |
73 Node* marker_or_function = LoadBufferObject( | |
74 parent_frame_ptr, CommonFrameConstants::kContextOrFrameTypeOffset); | |
75 GotoIf( | |
76 MarkerIsNotFrameType(marker_or_function, StackFrame::ARGUMENTS_ADAPTOR), | |
77 &has_initial_value); | |
78 | |
79 // Has arguments adapter, check count. | |
80 Node* adapted_parameter_count = LoadBufferObject( | |
81 parent_frame_ptr, ArgumentsAdaptorFrameConstants::kLengthOffset); | |
82 Branch(SmiLessThan(adapted_parameter_count, | |
83 SmiConstant(IteratingArrayBuiltinDescriptor::kThisArg)), | |
84 &no_initial_value, &has_initial_value); | |
85 | |
86 // a. Set accumulator to initialValue. | |
87 Bind(&has_initial_value); | |
88 a.Bind(this_arg()); | |
89 Goto(&done); | |
90 | |
91 // 9. Else initialValue is not present, | |
92 Bind(&no_initial_value); | |
93 | |
94 // a. Let kPresent be false. | |
95 a.Bind(TheHoleConstant()); | |
96 Goto(&done); | |
97 Bind(&done); | |
98 return a.value(); | |
99 } | |
100 | |
101 Node* ReduceProcessor(Node* k_value, Node* k) { | |
102 Variable result(this, MachineRepresentation::kTagged); | |
103 Label done(this, {&result}), initial(this); | |
104 GotoIf(WordEqual(a(), TheHoleConstant()), &initial); | |
105 result.Bind(CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), | |
106 UndefinedConstant(), a(), k_value, k, o())); | |
107 Goto(&done); | |
108 | |
109 Bind(&initial); | |
110 result.Bind(k_value); | |
111 Goto(&done); | |
112 | |
113 Bind(&done); | |
114 return result.value(); | |
115 } | |
116 | |
117 void ReducePostLoopAction() { | |
118 Label ok(this); | |
119 GotoIf(WordNotEqual(a(), TheHoleConstant()), &ok); | |
120 CallRuntime(Runtime::kThrowTypeError, context(), | |
121 SmiConstant(MessageTemplate::kReduceNoInitial)); | |
122 Unreachable(); | |
123 Bind(&ok); | |
124 } | |
125 | |
126 Node* FilterResultGenerator() { | |
127 // 7. Let A be ArraySpeciesCreate(O, 0). | |
128 return ArraySpeciesCreate(context(), o(), SmiConstant(0)); | |
129 } | |
130 | |
131 void FilterResultIndexReinitializer() { | |
132 Variable merged_length(this, MachineRepresentation::kTagged); | |
133 Label has_length(this, &merged_length), not_js_array(this); | |
134 GotoIf(DoesntHaveInstanceType(a(), JS_ARRAY_TYPE), ¬_js_array); | |
135 merged_length.Bind(LoadJSArrayLength(a())); | |
136 Goto(&has_length); | |
137 Bind(¬_js_array); | |
138 Node* len_property = | |
139 GetProperty(context(), a(), isolate()->factory()->length_string()); | |
140 merged_length.Bind( | |
141 CallStub(CodeFactory::ToLength(isolate()), context(), len_property)); | |
142 Goto(&has_length); | |
143 Bind(&has_length); | |
144 Node* len = merged_length.value(); | |
145 | |
146 to_.Bind(len); | |
147 } | |
148 | |
149 Node* FilterProcessor(Node* k_value, Node* k) { | |
150 Node* callback_result = CallJS(CodeFactory::Call(isolate()), context(), | |
151 callbackfn(), this_arg(), k_value, k, o()); | |
152 Label true_continue(this, &to_), false_continue(this); | |
153 BranchIfToBooleanIsTrue(callback_result, &true_continue, &false_continue); | |
154 Bind(&true_continue); | |
155 | |
156 // 1. let status be CreateDataPropertyOrThrow(A, ToString(to), kValue). | |
157 // 2. ReturnIfAbrupt(status) | |
158 Node* const p_to = ToString(context(), to_.value()); | |
159 CallRuntime(Runtime::kCreateDataProperty, context(), a(), p_to, k_value); | |
160 | |
161 // 3. Increase to by 1. | |
162 to_.Bind(NumberInc(to_.value())); | |
163 Goto(&false_continue); | |
164 Bind(&false_continue); | |
165 return a(); | |
166 } | |
167 | |
168 void NullPostLoopAction() {} | |
169 | |
170 void NullResultIndexReinitializer() {} | |
171 | |
172 protected: | |
173 Node* context() { return context_; } | |
174 Node* o() { return o_; } | |
175 Node* len() { return len_; } | |
176 Node* callbackfn() { return callbackfn_; } | |
177 Node* this_arg() { return this_arg_; } | |
178 Node* k() { return k_.value(); } | |
179 Node* a() { return a_.value(); } | |
26 | 180 |
27 void GenerateIteratingArrayBuiltinBody( | 181 void GenerateIteratingArrayBuiltinBody( |
28 const char* name, const BuiltinResultGenerator& generator, | 182 const char* name, const BuiltinResultGenerator& generator, |
29 const CallResultProcessor& processor, | 183 const CallResultProcessor& processor, const PostLoopAction& action, |
30 const Callable& slow_case_continuation) { | 184 const Callable& slow_case_continuation) { |
31 // TODO(ishell): use constants from Descriptor once the JSFunction linkage | 185 // TODO(ishell): use constants from Descriptor once the JSFunction linkage |
32 // arguments are reordered. | 186 // arguments are reordered. |
33 Node* receiver = Parameter(IteratingArrayBuiltinDescriptor::kReceiver); | 187 Node* receiver = Parameter(IteratingArrayBuiltinDescriptor::kReceiver); |
34 Node* callbackfn = Parameter(IteratingArrayBuiltinDescriptor::kCallback); | 188 callbackfn_ = Parameter(IteratingArrayBuiltinDescriptor::kCallback); |
35 Node* this_arg = Parameter(IteratingArrayBuiltinDescriptor::kThisArg); | 189 this_arg_ = Parameter(IteratingArrayBuiltinDescriptor::kThisArg); |
36 Node* context = Parameter(IteratingArrayBuiltinDescriptor::kContext); | 190 context_ = Parameter(IteratingArrayBuiltinDescriptor::kContext); |
37 Node* new_target = Parameter(IteratingArrayBuiltinDescriptor::kNewTarget); | 191 Node* new_target = Parameter(IteratingArrayBuiltinDescriptor::kNewTarget); |
38 | 192 |
39 Variable k(this, MachineRepresentation::kTagged, SmiConstant(0)); | 193 k_.Bind(SmiConstant(0)); |
40 Label non_array(this), slow(this, &k), array_changes(this, &k); | 194 a_.Bind(UndefinedConstant()); |
195 | |
196 Label non_array(this), slow(this, {&k_, &a_, &to_}), | |
197 array_changes(this, {&k_, &a_, &to_}); | |
41 | 198 |
42 // TODO(danno): Seriously? Do we really need to throw the exact error | 199 // TODO(danno): Seriously? Do we really need to throw the exact error |
43 // message on null and undefined so that the webkit tests pass? | 200 // message on null and undefined so that the webkit tests pass? |
44 Label throw_null_undefined_exception(this, Label::kDeferred); | 201 Label throw_null_undefined_exception(this, Label::kDeferred); |
45 GotoIf(WordEqual(receiver, NullConstant()), | 202 GotoIf(WordEqual(receiver, NullConstant()), |
46 &throw_null_undefined_exception); | 203 &throw_null_undefined_exception); |
47 GotoIf(WordEqual(receiver, UndefinedConstant()), | 204 GotoIf(WordEqual(receiver, UndefinedConstant()), |
48 &throw_null_undefined_exception); | 205 &throw_null_undefined_exception); |
49 | 206 |
50 // By the book: taken directly from the ECMAScript 2015 specification | 207 // By the book: taken directly from the ECMAScript 2015 specification |
51 | 208 |
52 // 1. Let O be ToObject(this value). | 209 // 1. Let O be ToObject(this value). |
53 // 2. ReturnIfAbrupt(O) | 210 // 2. ReturnIfAbrupt(O) |
54 Node* o = CallStub(CodeFactory::ToObject(isolate()), context, receiver); | 211 o_ = CallStub(CodeFactory::ToObject(isolate()), context(), receiver); |
55 | 212 |
56 // 3. Let len be ToLength(Get(O, "length")). | 213 // 3. Let len be ToLength(Get(O, "length")). |
57 // 4. ReturnIfAbrupt(len). | 214 // 4. ReturnIfAbrupt(len). |
58 Variable merged_length(this, MachineRepresentation::kTagged); | 215 Variable merged_length(this, MachineRepresentation::kTagged); |
59 Label has_length(this, &merged_length), not_js_array(this); | 216 Label has_length(this, &merged_length), not_js_array(this); |
60 GotoIf(DoesntHaveInstanceType(o, JS_ARRAY_TYPE), ¬_js_array); | 217 GotoIf(DoesntHaveInstanceType(o(), JS_ARRAY_TYPE), ¬_js_array); |
61 merged_length.Bind(LoadJSArrayLength(o)); | 218 merged_length.Bind(LoadJSArrayLength(o())); |
62 Goto(&has_length); | 219 Goto(&has_length); |
63 Bind(¬_js_array); | 220 Bind(¬_js_array); |
64 Node* len_property = | 221 Node* len_property = |
65 GetProperty(context, o, isolate()->factory()->length_string()); | 222 GetProperty(context(), o(), isolate()->factory()->length_string()); |
66 merged_length.Bind( | 223 merged_length.Bind( |
67 CallStub(CodeFactory::ToLength(isolate()), context, len_property)); | 224 CallStub(CodeFactory::ToLength(isolate()), context(), len_property)); |
68 Goto(&has_length); | 225 Goto(&has_length); |
69 Bind(&has_length); | 226 Bind(&has_length); |
70 Node* len = merged_length.value(); | 227 len_ = merged_length.value(); |
71 | 228 |
72 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. | 229 // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. |
73 Label type_exception(this, Label::kDeferred); | 230 Label type_exception(this, Label::kDeferred); |
74 Label done(this); | 231 Label done(this); |
75 GotoIf(TaggedIsSmi(callbackfn), &type_exception); | 232 GotoIf(TaggedIsSmi(callbackfn()), &type_exception); |
76 Branch(IsCallableMap(LoadMap(callbackfn)), &done, &type_exception); | 233 Branch(IsCallableMap(LoadMap(callbackfn())), &done, &type_exception); |
77 | 234 |
78 Bind(&throw_null_undefined_exception); | 235 Bind(&throw_null_undefined_exception); |
79 { | 236 { |
80 CallRuntime( | 237 CallRuntime( |
81 Runtime::kThrowTypeError, context, | 238 Runtime::kThrowTypeError, context(), |
82 SmiConstant(MessageTemplate::kCalledOnNullOrUndefined), | 239 SmiConstant(MessageTemplate::kCalledOnNullOrUndefined), |
83 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked(name))); | 240 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked(name))); |
84 Unreachable(); | 241 Unreachable(); |
85 } | 242 } |
86 | 243 |
87 Bind(&type_exception); | 244 Bind(&type_exception); |
88 { | 245 { |
89 CallRuntime(Runtime::kThrowTypeError, context, | 246 CallRuntime(Runtime::kThrowTypeError, context(), |
90 SmiConstant(MessageTemplate::kCalledNonCallable), callbackfn); | 247 SmiConstant(MessageTemplate::kCalledNonCallable), |
248 callbackfn()); | |
91 Unreachable(); | 249 Unreachable(); |
92 } | 250 } |
93 | 251 |
94 Bind(&done); | 252 Bind(&done); |
95 | 253 |
96 Node* a = generator(context, o, len); | |
97 | |
98 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. | 254 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. |
99 // [Already done by the arguments adapter] | 255 // [Already done by the arguments adapter] |
100 | 256 |
101 HandleFastElements(context, this_arg, o, len, callbackfn, processor, a, k, | 257 // 7. Let k be 0. |
102 &slow); | 258 // [Already done in code assembler initialization] |
103 | 259 |
104 // 7. Let k be 0. | 260 a_.Bind(generator(this)); |
105 // Already done above in initialization of the Variable k | 261 |
262 HandleFastElements(processor, action, &slow); | |
106 | 263 |
107 Bind(&slow); | 264 Bind(&slow); |
108 | 265 |
109 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, | 266 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, |
110 MachineType::TaggedPointer()); | 267 MachineType::TaggedPointer()); |
111 TailCallStub( | 268 TailCallStub( |
112 slow_case_continuation, context, target, new_target, | 269 slow_case_continuation, context(), target, new_target, |
113 Int32Constant(IteratingArrayBuiltinLoopContinuationDescriptor::kArity), | 270 Int32Constant(IteratingArrayBuiltinLoopContinuationDescriptor::kArity), |
114 receiver, callbackfn, this_arg, a, o, k.value(), len); | 271 receiver, callbackfn(), this_arg(), a_.value(), o(), k_.value(), len_); |
115 } | 272 } |
116 | 273 |
117 void GenerateIteratingArrayBuiltinLoopContinuation( | 274 void GenerateIteratingArrayBuiltinLoopContinuation( |
118 const BuiltinResultIndexInitializer& index_initializer, | 275 const BuiltinResultIndexInitializer& index_initializer, |
119 const CallResultProcessor& processor) { | 276 const CallResultProcessor& processor, const PostLoopAction& action) { |
120 // TODO(ishell): use constants from Descriptor once the JSFunction linkage | 277 // TODO(ishell): use constants from Descriptor once the JSFunction linkage |
121 // arguments are reordered. | 278 // arguments are reordered. |
122 Node* callbackfn = | 279 this_arg_ = |
280 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kThisArg); | |
281 callbackfn_ = | |
123 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kCallback); | 282 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kCallback); |
124 Node* this_arg = | 283 a_.Bind(Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kArray)); |
125 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kThisArg); | 284 k_.Bind( |
126 Node* a = | 285 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kInitialK)); |
127 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kArray); | 286 o_ = Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kObject); |
128 Node* o = | 287 len_ = Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kLength); |
129 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kObject); | 288 context_ = |
130 Node* initial_k = | |
131 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kInitialK); | |
132 Node* len = | |
133 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kLength); | |
134 Node* context = | |
135 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kContext); | 289 Parameter(IteratingArrayBuiltinLoopContinuationDescriptor::kContext); |
136 | 290 |
137 index_initializer(context, a); | 291 index_initializer(this); |
138 | 292 |
139 // 8. Repeat, while k < len | 293 // 8. Repeat, while k < len |
140 Variable k(this, MachineRepresentation::kTagged, initial_k); | 294 Label loop(this, {&k_, &a_, &to_}); |
141 VariableList list({&k, &to_}, zone()); | |
142 Label loop(this, list); | |
143 Label after_loop(this); | 295 Label after_loop(this); |
144 Goto(&loop); | 296 Goto(&loop); |
145 Bind(&loop); | 297 Bind(&loop); |
146 { | 298 { |
147 GotoUnlessNumberLessThan(k.value(), len, &after_loop); | 299 GotoUnlessNumberLessThan(k(), len_, &after_loop); |
148 | 300 |
149 Label done_element(this, &to_); | 301 Label done_element(this, &to_); |
150 // a. Let Pk be ToString(k). | 302 // a. Let Pk be ToString(k). |
151 Node* p_k = ToString(context, k.value()); | 303 Node* p_k = ToString(context(), k()); |
152 | 304 |
153 // b. Let kPresent be HasProperty(O, Pk). | 305 // b. Let kPresent be HasProperty(O, Pk). |
154 // c. ReturnIfAbrupt(kPresent). | 306 // c. ReturnIfAbrupt(kPresent). |
155 Node* k_present = HasProperty(o, p_k, context); | 307 Node* k_present = HasProperty(o(), p_k, context()); |
156 | 308 |
157 // d. If kPresent is true, then | 309 // d. If kPresent is true, then |
158 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); | 310 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); |
159 | 311 |
160 // i. Let kValue be Get(O, Pk). | 312 // i. Let kValue be Get(O, Pk). |
161 // ii. ReturnIfAbrupt(kValue). | 313 // ii. ReturnIfAbrupt(kValue). |
162 Node* k_value = GetProperty(context, o, k.value()); | 314 Node* k_value = GetProperty(context(), o(), k()); |
163 | 315 |
164 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). | 316 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). |
165 // iv. ReturnIfAbrupt(funcResult). | 317 // iv. ReturnIfAbrupt(funcResult). |
166 Node* callback_result = | 318 a_.Bind(processor(this, k_value, k())); |
167 CallJS(CodeFactory::Call(isolate()), context, callbackfn, this_arg, | 319 Goto(&done_element); |
168 k_value, k.value(), o); | |
169 | 320 |
170 processor(context, k_value, a, callback_result); | |
171 Goto(&done_element); | |
172 Bind(&done_element); | 321 Bind(&done_element); |
173 | 322 |
174 // e. Increase k by 1. | 323 // e. Increase k by 1. |
175 k.Bind(NumberInc(k.value())); | 324 k_.Bind(NumberInc(k_.value())); |
176 Goto(&loop); | 325 Goto(&loop); |
177 } | 326 } |
178 Bind(&after_loop); | 327 Bind(&after_loop); |
179 Return(a); | |
180 } | |
181 | 328 |
182 Node* FilterResultGenerator(Node* context, Node* o, Node* len) { | 329 action(this); |
183 // 7. Let A be ArraySpeciesCreate(O, 0). | 330 Return(a_.value()); |
184 return ArraySpeciesCreate(context, o, SmiConstant(0)); | |
185 } | |
186 | |
187 void FilterResultIndexReinitializer(Node* context, Node* a) { | |
188 Variable merged_length(this, MachineRepresentation::kTagged); | |
189 Label has_length(this, &merged_length), not_js_array(this); | |
190 GotoIf(DoesntHaveInstanceType(a, JS_ARRAY_TYPE), ¬_js_array); | |
191 merged_length.Bind(LoadJSArrayLength(a)); | |
192 Goto(&has_length); | |
193 Bind(¬_js_array); | |
194 Node* len_property = | |
195 GetProperty(context, a, isolate()->factory()->length_string()); | |
196 merged_length.Bind( | |
197 CallStub(CodeFactory::ToLength(isolate()), context, len_property)); | |
198 Goto(&has_length); | |
199 Bind(&has_length); | |
200 Node* len = merged_length.value(); | |
201 | |
202 to_.Bind(len); | |
203 } | |
204 | |
205 void ForEachProcessor(Node* context, Node* value, Node* a, | |
206 Node* callback_result) {} | |
207 | |
208 void SomeProcessor(Node* context, Node* value, Node* a, | |
209 Node* callback_result) { | |
210 Label false_continue(this), return_true(this); | |
211 BranchIfToBooleanIsTrue(callback_result, &return_true, &false_continue); | |
212 Bind(&return_true); | |
213 Return(TrueConstant()); | |
214 Bind(&false_continue); | |
215 } | |
216 | |
217 void EveryProcessor(Node* context, Node* value, Node* a, | |
218 Node* callback_result) { | |
219 Label true_continue(this), return_false(this); | |
220 BranchIfToBooleanIsTrue(callback_result, &true_continue, &return_false); | |
221 Bind(&return_false); | |
222 Return(FalseConstant()); | |
223 Bind(&true_continue); | |
224 } | |
225 | |
226 void FilterProcessor(Node* context, Node* value, Node* a, | |
227 Node* callback_result) { | |
228 Label true_continue(this, &to_), false_continue(this); | |
229 BranchIfToBooleanIsTrue(callback_result, &true_continue, &false_continue); | |
230 Bind(&true_continue); | |
231 | |
232 // 1. let status be CreateDataPropertyOrThrow(A, ToString(to), kValue). | |
233 // 2. ReturnIfAbrupt(status) | |
234 Node* const p_to = ToString(context, to_.value()); | |
235 CallRuntime(Runtime::kCreateDataProperty, context, a, p_to, value); | |
236 | |
237 // 3. Increase to by 1. | |
238 to_.Bind(NumberInc(to_.value())); | |
239 Goto(&false_continue); | |
240 Bind(&false_continue); | |
241 } | 331 } |
242 | 332 |
243 private: | 333 private: |
244 Node* VisitAllFastElementsOneKind(Node* context, ElementsKind kind, | 334 void VisitAllFastElementsOneKind(ElementsKind kind, |
245 Node* this_arg, Node* o, Node* len, | 335 const CallResultProcessor& processor, |
246 Node* callbackfn, | 336 Label* array_changed, ParameterMode mode) { |
247 const CallResultProcessor& processor, | |
248 Node* a, Label* array_changed, | |
249 ParameterMode mode) { | |
250 Comment("begin VisitAllFastElementsOneKind"); | 337 Comment("begin VisitAllFastElementsOneKind"); |
251 Variable original_map(this, MachineRepresentation::kTagged); | 338 Variable original_map(this, MachineRepresentation::kTagged); |
252 original_map.Bind(LoadMap(o)); | 339 original_map.Bind(LoadMap(o())); |
253 VariableList list({&original_map, &to_}, zone()); | 340 VariableList list({&original_map, &a_, &k_, &to_}, zone()); |
254 Node* last_index = nullptr; | |
255 BuildFastLoop( | 341 BuildFastLoop( |
256 list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len, mode), | 342 list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len(), mode), |
257 [=, &original_map, &last_index](Node* index) { | 343 [=, &original_map](Node* index) { |
258 last_index = index; | 344 k_.Bind(ParameterToTagged(index, mode)); |
259 Label one_element_done(this), hole_element(this); | 345 Label one_element_done(this), hole_element(this); |
260 | 346 |
261 // Check if o's map has changed during the callback. If so, we have to | 347 // Check if o's map has changed during the callback. If so, we have to |
262 // fall back to the slower spec implementation for the rest of the | 348 // fall back to the slower spec implementation for the rest of the |
263 // iteration. | 349 // iteration. |
264 Node* o_map = LoadMap(o); | 350 Node* o_map = LoadMap(o()); |
265 GotoIf(WordNotEqual(o_map, original_map.value()), array_changed); | 351 GotoIf(WordNotEqual(o_map, original_map.value()), array_changed); |
266 | 352 |
267 // Check if o's length has changed during the callback and if the | 353 // Check if o's length has changed during the callback and if the |
268 // index is now out of range of the new length. | 354 // index is now out of range of the new length. |
269 Node* tagged_index = ParameterToTagged(index, mode); | 355 GotoIf(SmiGreaterThanOrEqual(k_.value(), LoadJSArrayLength(o())), |
270 GotoIf(SmiGreaterThanOrEqual(tagged_index, LoadJSArrayLength(o)), | |
271 array_changed); | 356 array_changed); |
272 | 357 |
273 // Re-load the elements array. If may have been resized. | 358 // Re-load the elements array. If may have been resized. |
274 Node* elements = LoadElements(o); | 359 Node* elements = LoadElements(o()); |
275 | 360 |
276 // Fast case: load the element directly from the elements FixedArray | 361 // Fast case: load the element directly from the elements FixedArray |
277 // and call the callback if the element is not the hole. | 362 // and call the callback if the element is not the hole. |
278 DCHECK(kind == FAST_ELEMENTS || kind == FAST_DOUBLE_ELEMENTS); | 363 DCHECK(kind == FAST_ELEMENTS || kind == FAST_DOUBLE_ELEMENTS); |
279 int base_size = kind == FAST_ELEMENTS | 364 int base_size = kind == FAST_ELEMENTS |
280 ? FixedArray::kHeaderSize | 365 ? FixedArray::kHeaderSize |
281 : (FixedArray::kHeaderSize - kHeapObjectTag); | 366 : (FixedArray::kHeaderSize - kHeapObjectTag); |
282 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); | 367 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); |
283 Node* value = nullptr; | 368 Node* value = nullptr; |
284 if (kind == FAST_ELEMENTS) { | 369 if (kind == FAST_ELEMENTS) { |
285 value = LoadObjectField(elements, offset); | 370 value = LoadObjectField(elements, offset); |
286 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); | 371 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); |
287 } else { | 372 } else { |
288 Node* double_value = | 373 Node* double_value = |
289 LoadDoubleWithHoleCheck(elements, offset, &hole_element); | 374 LoadDoubleWithHoleCheck(elements, offset, &hole_element); |
290 value = AllocateHeapNumberWithValue(double_value); | 375 value = AllocateHeapNumberWithValue(double_value); |
291 } | 376 } |
292 Node* callback_result = | 377 a_.Bind(processor(this, value, k())); |
293 CallJS(CodeFactory::Call(isolate()), context, callbackfn, | |
294 this_arg, value, tagged_index, o); | |
295 processor(context, value, a, callback_result); | |
296 Goto(&one_element_done); | 378 Goto(&one_element_done); |
297 | 379 |
298 Bind(&hole_element); | 380 Bind(&hole_element); |
299 // Check if o's prototype change unexpectedly has elements after the | 381 // Check if o's prototype change unexpectedly has elements after the |
300 // callback in the case of a hole. | 382 // callback in the case of a hole. |
301 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, | 383 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, |
302 array_changed); | 384 array_changed); |
303 | 385 |
304 Bind(&one_element_done); | 386 Bind(&one_element_done); |
305 }, | 387 }, |
306 1, mode, IndexAdvanceMode::kPost); | 388 1, mode, IndexAdvanceMode::kPost); |
307 Comment("end VisitAllFastElementsOneKind"); | 389 Comment("end VisitAllFastElementsOneKind"); |
308 return last_index; | |
309 } | 390 } |
310 | 391 |
311 void HandleFastElements(Node* context, Node* this_arg, Node* o, Node* len, | 392 void HandleFastElements(const CallResultProcessor& processor, |
312 Node* callbackfn, CallResultProcessor processor, | 393 const PostLoopAction& action, Label* slow) { |
313 Node* a, Variable& k, Label* slow) { | |
314 Label switch_on_elements_kind(this), fast_elements(this), | 394 Label switch_on_elements_kind(this), fast_elements(this), |
315 maybe_double_elements(this), fast_double_elements(this); | 395 maybe_double_elements(this), fast_double_elements(this); |
316 | 396 |
317 Comment("begin HandleFastElements"); | 397 Comment("begin HandleFastElements"); |
318 // Non-smi lengths must use the slow path. | 398 // Non-smi lengths must use the slow path. |
319 GotoIf(TaggedIsNotSmi(len), slow); | 399 GotoIf(TaggedIsNotSmi(len()), slow); |
320 | 400 |
321 BranchIfFastJSArray(o, context, | 401 BranchIfFastJSArray(o(), context(), |
322 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, | 402 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, |
323 &switch_on_elements_kind, slow); | 403 &switch_on_elements_kind, slow); |
324 | 404 |
325 Bind(&switch_on_elements_kind); | 405 Bind(&switch_on_elements_kind); |
326 // Select by ElementsKind | 406 // Select by ElementsKind |
327 Node* o_map = LoadMap(o); | 407 Node* o_map = LoadMap(o()); |
328 Node* bit_field2 = LoadMapBitField2(o_map); | 408 Node* bit_field2 = LoadMapBitField2(o_map); |
329 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); | 409 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); |
330 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | 410 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), |
331 &maybe_double_elements, &fast_elements); | 411 &maybe_double_elements, &fast_elements); |
332 | 412 |
333 ParameterMode mode = OptimalParameterMode(); | 413 ParameterMode mode = OptimalParameterMode(); |
334 Bind(&fast_elements); | 414 Bind(&fast_elements); |
335 { | 415 { |
336 Label array_changed(this, Label::kDeferred); | 416 VisitAllFastElementsOneKind(FAST_ELEMENTS, processor, slow, mode); |
337 Node* last_index = VisitAllFastElementsOneKind( | 417 |
338 context, FAST_ELEMENTS, this_arg, o, len, callbackfn, processor, a, | 418 action(this); |
339 &array_changed, mode); | |
340 | 419 |
341 // No exception, return success | 420 // No exception, return success |
342 Return(a); | 421 Return(a_.value()); |
343 | |
344 Bind(&array_changed); | |
345 k.Bind(ParameterToTagged(last_index, mode)); | |
346 Goto(slow); | |
347 } | 422 } |
348 | 423 |
349 Bind(&maybe_double_elements); | 424 Bind(&maybe_double_elements); |
350 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)), | 425 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)), |
351 slow, &fast_double_elements); | 426 slow, &fast_double_elements); |
352 | 427 |
353 Bind(&fast_double_elements); | 428 Bind(&fast_double_elements); |
354 { | 429 { |
355 Label array_changed(this, Label::kDeferred); | 430 VisitAllFastElementsOneKind(FAST_DOUBLE_ELEMENTS, processor, slow, mode); |
356 Node* last_index = VisitAllFastElementsOneKind( | 431 |
357 context, FAST_DOUBLE_ELEMENTS, this_arg, o, len, callbackfn, | 432 action(this); |
358 processor, a, &array_changed, mode); | |
359 | 433 |
360 // No exception, return success | 434 // No exception, return success |
361 Return(a); | 435 Return(a_.value()); |
362 | |
363 Bind(&array_changed); | |
364 k.Bind(ParameterToTagged(last_index, mode)); | |
365 Goto(slow); | |
366 } | 436 } |
367 } | 437 } |
368 | 438 |
439 Node* callbackfn_; | |
440 Node* o_; | |
441 Node* this_arg_; | |
442 Node* len_; | |
443 Node* context_; | |
444 Variable k_; | |
445 Variable a_; | |
369 Variable to_; | 446 Variable to_; |
370 }; | 447 }; |
371 | 448 |
372 TF_BUILTIN(FastArrayPush, CodeStubAssembler) { | 449 TF_BUILTIN(FastArrayPush, CodeStubAssembler) { |
373 Variable arg_index(this, MachineType::PointerRepresentation()); | 450 Variable arg_index(this, MachineType::PointerRepresentation()); |
374 Label default_label(this, &arg_index); | 451 Label default_label(this, &arg_index); |
375 Label smi_transition(this); | 452 Label smi_transition(this); |
376 Label object_push_pre(this); | 453 Label object_push_pre(this); |
377 Label object_push(this, &arg_index); | 454 Label object_push(this, &arg_index); |
378 Label double_push(this, &arg_index); | 455 Label double_push(this, &arg_index); |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
520 { | 597 { |
521 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, | 598 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, |
522 MachineType::TaggedPointer()); | 599 MachineType::TaggedPointer()); |
523 TailCallStub(CodeFactory::ArrayPush(isolate()), context, target, new_target, | 600 TailCallStub(CodeFactory::ArrayPush(isolate()), context, target, new_target, |
524 argc); | 601 argc); |
525 } | 602 } |
526 } | 603 } |
527 | 604 |
528 TF_BUILTIN(ArrayForEachLoopContinuation, ArrayBuiltinCodeStubAssembler) { | 605 TF_BUILTIN(ArrayForEachLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
529 GenerateIteratingArrayBuiltinLoopContinuation( | 606 GenerateIteratingArrayBuiltinLoopContinuation( |
530 [](Node* context, Node* a) {}, | 607 &ArrayBuiltinCodeStubAssembler::NullResultIndexReinitializer, |
531 [this](Node* context, Node* value, Node* a, Node* callback_result) { | 608 &ArrayBuiltinCodeStubAssembler::ForEachProcessor, |
532 ForEachProcessor(context, value, a, callback_result); | 609 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); |
533 }); | |
534 } | |
535 | |
536 TF_BUILTIN(ArrayFilter, ArrayBuiltinCodeStubAssembler) { | |
537 GenerateIteratingArrayBuiltinBody( | |
538 "Array.prototype.filter", | |
539 [=](Node* context, Node* o, Node* len) { | |
540 return FilterResultGenerator(context, o, len); | |
541 }, | |
542 [this](Node* context, Node* value, Node* a, Node* callback_result) { | |
543 FilterProcessor(context, value, a, callback_result); | |
544 }, | |
545 CodeFactory::ArrayFilterLoopContinuation(isolate())); | |
546 } | |
547 | |
548 TF_BUILTIN(ArrayFilterLoopContinuation, ArrayBuiltinCodeStubAssembler) { | |
549 GenerateIteratingArrayBuiltinLoopContinuation( | |
550 [this](Node* context, Node* a) { | |
551 FilterResultIndexReinitializer(context, a); | |
552 }, | |
553 [this](Node* context, Node* value, Node* a, Node* callback_result) { | |
554 FilterProcessor(context, value, a, callback_result); | |
555 }); | |
556 } | 610 } |
557 | 611 |
558 TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) { | 612 TF_BUILTIN(ArrayForEach, ArrayBuiltinCodeStubAssembler) { |
559 GenerateIteratingArrayBuiltinBody( | 613 GenerateIteratingArrayBuiltinBody( |
560 "Array.prototype.forEach", | 614 "Array.prototype.forEach", |
561 [=](Node*, Node*, Node*) { return UndefinedConstant(); }, | 615 &ArrayBuiltinCodeStubAssembler::ForEachResultGenerator, |
562 [this](Node* context, Node* value, Node* a, Node* callback_result) { | 616 &ArrayBuiltinCodeStubAssembler::ForEachProcessor, |
563 ForEachProcessor(context, value, a, callback_result); | 617 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction, |
564 }, | |
565 CodeFactory::ArrayForEachLoopContinuation(isolate())); | 618 CodeFactory::ArrayForEachLoopContinuation(isolate())); |
Igor Sheludko
2017/03/21 14:20:28
FYI: We have a Builtins::CallableFor(), so there's
danno
2017/03/21 15:55:29
To land quickly, will do this in a follow-on CL.
| |
566 } | 619 } |
567 | 620 |
568 TF_BUILTIN(ArraySomeLoopContinuation, ArrayBuiltinCodeStubAssembler) { | 621 TF_BUILTIN(ArraySomeLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
569 GenerateIteratingArrayBuiltinLoopContinuation( | 622 GenerateIteratingArrayBuiltinLoopContinuation( |
570 [](Node* context, Node* a) {}, | 623 &ArrayBuiltinCodeStubAssembler::NullResultIndexReinitializer, |
571 [this](Node* context, Node* value, Node* a, Node* callback_result) { | 624 &ArrayBuiltinCodeStubAssembler::SomeProcessor, |
572 SomeProcessor(context, value, a, callback_result); | 625 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); |
573 }); | |
574 } | 626 } |
575 | 627 |
576 TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) { | 628 TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) { |
577 GenerateIteratingArrayBuiltinBody( | 629 GenerateIteratingArrayBuiltinBody( |
578 "Array.prototype.some", | 630 "Array.prototype.some", |
579 [=](Node*, Node*, Node*) { return FalseConstant(); }, | 631 &ArrayBuiltinCodeStubAssembler::SomeResultGenerator, |
580 [this](Node* context, Node* value, Node* a, Node* callback_result) { | 632 &ArrayBuiltinCodeStubAssembler::SomeProcessor, |
581 SomeProcessor(context, value, a, callback_result); | 633 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction, |
582 }, | |
583 CodeFactory::ArraySomeLoopContinuation(isolate())); | 634 CodeFactory::ArraySomeLoopContinuation(isolate())); |
584 } | 635 } |
585 | 636 |
586 TF_BUILTIN(ArrayEveryLoopContinuation, ArrayBuiltinCodeStubAssembler) { | 637 TF_BUILTIN(ArrayEveryLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
587 GenerateIteratingArrayBuiltinLoopContinuation( | 638 GenerateIteratingArrayBuiltinLoopContinuation( |
588 [](Node* context, Node* a) {}, | 639 &ArrayBuiltinCodeStubAssembler::NullResultIndexReinitializer, |
589 [this](Node* context, Node* value, Node* a, Node* callback_result) { | 640 &ArrayBuiltinCodeStubAssembler::EveryProcessor, |
590 EveryProcessor(context, value, a, callback_result); | 641 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); |
591 }); | |
592 } | 642 } |
593 | 643 |
594 TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) { | 644 TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) { |
595 GenerateIteratingArrayBuiltinBody( | 645 GenerateIteratingArrayBuiltinBody( |
596 "Array.prototype.every", | 646 "Array.prototype.every", |
597 [=](Node*, Node*, Node*) { return TrueConstant(); }, | 647 &ArrayBuiltinCodeStubAssembler::EveryResultGenerator, |
598 [this](Node* context, Node* value, Node* a, Node* callback_result) { | 648 &ArrayBuiltinCodeStubAssembler::EveryProcessor, |
599 EveryProcessor(context, value, a, callback_result); | 649 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction, |
600 }, | |
601 CodeFactory::ArrayEveryLoopContinuation(isolate())); | 650 CodeFactory::ArrayEveryLoopContinuation(isolate())); |
602 } | 651 } |
603 | 652 |
653 TF_BUILTIN(ArrayReduceLoopContinuation, ArrayBuiltinCodeStubAssembler) { | |
654 GenerateIteratingArrayBuiltinLoopContinuation( | |
655 &ArrayBuiltinCodeStubAssembler::NullResultIndexReinitializer, | |
656 &ArrayBuiltinCodeStubAssembler::ReduceProcessor, | |
657 &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction); | |
658 } | |
659 | |
660 TF_BUILTIN(ArrayReduce, ArrayBuiltinCodeStubAssembler) { | |
661 GenerateIteratingArrayBuiltinBody( | |
662 "Array.prototype.reduce", | |
663 &ArrayBuiltinCodeStubAssembler::ReduceResultGenerator, | |
664 &ArrayBuiltinCodeStubAssembler::ReduceProcessor, | |
665 &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction, | |
666 CodeFactory::ArrayReduceLoopContinuation(isolate())); | |
667 } | |
668 | |
669 TF_BUILTIN(ArrayFilterLoopContinuation, ArrayBuiltinCodeStubAssembler) { | |
670 GenerateIteratingArrayBuiltinLoopContinuation( | |
671 &ArrayBuiltinCodeStubAssembler::FilterResultIndexReinitializer, | |
672 &ArrayBuiltinCodeStubAssembler::FilterProcessor, | |
673 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); | |
674 } | |
675 | |
676 TF_BUILTIN(ArrayFilter, ArrayBuiltinCodeStubAssembler) { | |
677 GenerateIteratingArrayBuiltinBody( | |
678 "Array.prototype.reduce", | |
679 &ArrayBuiltinCodeStubAssembler::FilterResultGenerator, | |
680 &ArrayBuiltinCodeStubAssembler::FilterProcessor, | |
681 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction, | |
682 CodeFactory::ArrayFilterLoopContinuation(isolate())); | |
683 } | |
684 | |
604 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { | 685 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { |
605 Node* object = Parameter(Descriptor::kArg); | 686 Node* object = Parameter(Descriptor::kArg); |
606 Node* context = Parameter(Descriptor::kContext); | 687 Node* context = Parameter(Descriptor::kContext); |
607 | 688 |
608 Label call_runtime(this), return_true(this), return_false(this); | 689 Label call_runtime(this), return_true(this), return_false(this); |
609 | 690 |
610 GotoIf(TaggedIsSmi(object), &return_false); | 691 GotoIf(TaggedIsSmi(object), &return_false); |
611 Node* instance_type = LoadInstanceType(object); | 692 Node* instance_type = LoadInstanceType(object); |
612 | 693 |
613 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), | 694 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), |
(...skipping 1041 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1655 { | 1736 { |
1656 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); | 1737 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); |
1657 CallRuntime(Runtime::kThrowTypeError, context, message, | 1738 CallRuntime(Runtime::kThrowTypeError, context, message, |
1658 HeapConstant(operation)); | 1739 HeapConstant(operation)); |
1659 Unreachable(); | 1740 Unreachable(); |
1660 } | 1741 } |
1661 } | 1742 } |
1662 | 1743 |
1663 } // namespace internal | 1744 } // namespace internal |
1664 } // namespace v8 | 1745 } // namespace v8 |
OLD | NEW |