Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: src/builtins/builtins-array-gen.cc

Issue 2752273003: [builtins] Implement Array.prototype.reduce in the CSA (Closed)
Patch Set: Simplify Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-factory.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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), &not_js_array);
135 merged_length.Bind(LoadJSArrayLength(a()));
136 Goto(&has_length);
137 Bind(&not_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), &not_js_array); 217 GotoIf(DoesntHaveInstanceType(o(), JS_ARRAY_TYPE), &not_js_array);
61 merged_length.Bind(LoadJSArrayLength(o)); 218 merged_length.Bind(LoadJSArrayLength(o()));
62 Goto(&has_length); 219 Goto(&has_length);
63 Bind(&not_js_array); 220 Bind(&not_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), &not_js_array);
191 merged_length.Bind(LoadJSArrayLength(a));
192 Goto(&has_length);
193 Bind(&not_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
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
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
OLDNEW
« no previous file with comments | « src/builtins/builtins.h ('k') | src/code-factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698