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 { |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 callbackfn_ = callbackfn; | 187 callbackfn_ = callbackfn; |
188 this_arg_ = this_arg; | 188 this_arg_ = this_arg; |
189 | 189 |
190 k_.Bind(SmiConstant(0)); | 190 k_.Bind(SmiConstant(0)); |
191 a_.Bind(UndefinedConstant()); | 191 a_.Bind(UndefinedConstant()); |
192 } | 192 } |
193 | 193 |
194 void GenerateIteratingArrayBuiltinBody( | 194 void GenerateIteratingArrayBuiltinBody( |
195 const char* name, const BuiltinResultGenerator& generator, | 195 const char* name, const BuiltinResultGenerator& generator, |
196 const CallResultProcessor& processor, const PostLoopAction& action, | 196 const CallResultProcessor& processor, const PostLoopAction& action, |
197 const Callable& slow_case_continuation) { | 197 const Callable& slow_case_continuation, |
| 198 ForEachDirection direction = ForEachDirection::kForward) { |
198 Label non_array(this), slow(this, {&k_, &a_, &to_}), | 199 Label non_array(this), slow(this, {&k_, &a_, &to_}), |
199 array_changes(this, {&k_, &a_, &to_}); | 200 array_changes(this, {&k_, &a_, &to_}); |
200 | 201 |
201 // TODO(danno): Seriously? Do we really need to throw the exact error | 202 // TODO(danno): Seriously? Do we really need to throw the exact error |
202 // message on null and undefined so that the webkit tests pass? | 203 // message on null and undefined so that the webkit tests pass? |
203 Label throw_null_undefined_exception(this, Label::kDeferred); | 204 Label throw_null_undefined_exception(this, Label::kDeferred); |
204 GotoIf(WordEqual(receiver(), NullConstant()), | 205 GotoIf(WordEqual(receiver(), NullConstant()), |
205 &throw_null_undefined_exception); | 206 &throw_null_undefined_exception); |
206 GotoIf(WordEqual(receiver(), UndefinedConstant()), | 207 GotoIf(WordEqual(receiver(), UndefinedConstant()), |
207 &throw_null_undefined_exception); | 208 &throw_null_undefined_exception); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
249 SmiConstant(MessageTemplate::kCalledNonCallable), | 250 SmiConstant(MessageTemplate::kCalledNonCallable), |
250 callbackfn()); | 251 callbackfn()); |
251 Unreachable(); | 252 Unreachable(); |
252 } | 253 } |
253 | 254 |
254 Bind(&done); | 255 Bind(&done); |
255 | 256 |
256 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. | 257 // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. |
257 // [Already done by the arguments adapter] | 258 // [Already done by the arguments adapter] |
258 | 259 |
259 // 7. Let k be 0. | 260 if (direction == ForEachDirection::kForward) { |
260 // [Already done in code assembler initialization] | 261 // 7. Let k be 0. |
| 262 k_.Bind(SmiConstant(0)); |
| 263 } else { |
| 264 k_.Bind(len()); |
| 265 k_.Bind(NumberDec(k_.value())); |
| 266 } |
261 | 267 |
262 a_.Bind(generator(this)); | 268 a_.Bind(generator(this)); |
263 | 269 |
264 HandleFastElements(processor, action, &slow); | 270 HandleFastElements(processor, action, &slow, direction); |
265 | 271 |
266 Bind(&slow); | 272 Bind(&slow); |
267 | 273 |
268 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, | 274 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, |
269 MachineType::TaggedPointer()); | 275 MachineType::TaggedPointer()); |
270 TailCallStub( | 276 TailCallStub( |
271 slow_case_continuation, context(), target, new_target(), | 277 slow_case_continuation, context(), target, new_target(), |
272 Int32Constant(IteratingArrayBuiltinLoopContinuationDescriptor::kArity), | 278 Int32Constant(IteratingArrayBuiltinLoopContinuationDescriptor::kArity), |
273 receiver(), callbackfn(), this_arg(), a_.value(), o(), k_.value(), | 279 receiver(), callbackfn(), this_arg(), a_.value(), o(), k_.value(), |
274 len(), to_.value()); | 280 len(), to_.value()); |
275 } | 281 } |
276 | 282 |
277 void InitIteratingArrayBuiltinLoopContinuation(Node* context, Node* receiver, | 283 void InitIteratingArrayBuiltinLoopContinuation(Node* context, Node* receiver, |
278 Node* callbackfn, | 284 Node* callbackfn, |
279 Node* this_arg, Node* a, | 285 Node* this_arg, Node* a, |
280 Node* o, Node* initial_k, | 286 Node* o, Node* initial_k, |
281 Node* len, Node* to) { | 287 Node* len, Node* to) { |
282 context_ = context; | 288 context_ = context; |
283 this_arg_ = this_arg; | 289 this_arg_ = this_arg; |
284 callbackfn_ = callbackfn; | 290 callbackfn_ = callbackfn; |
285 a_.Bind(a); | 291 a_.Bind(a); |
286 k_.Bind(initial_k); | 292 k_.Bind(initial_k); |
287 o_ = o; | 293 o_ = o; |
288 len_ = len; | 294 len_ = len; |
289 to_.Bind(to); | 295 to_.Bind(to); |
290 } | 296 } |
291 | 297 |
292 void GenerateIteratingArrayBuiltinLoopContinuation( | 298 void GenerateIteratingArrayBuiltinLoopContinuation( |
293 const CallResultProcessor& processor, const PostLoopAction& action) { | 299 const CallResultProcessor& processor, const PostLoopAction& action, |
294 // 8. Repeat, while k < len | 300 ForEachDirection direction = ForEachDirection::kForward) { |
295 Label loop(this, {&k_, &a_, &to_}); | 301 Label loop(this, {&k_, &a_, &to_}); |
296 Label after_loop(this); | 302 Label after_loop(this); |
297 Goto(&loop); | 303 Goto(&loop); |
298 Bind(&loop); | 304 Bind(&loop); |
299 { | 305 { |
300 GotoUnlessNumberLessThan(k(), len_, &after_loop); | 306 if (direction == ForEachDirection::kForward) { |
| 307 // 8. Repeat, while k < len |
| 308 GotoUnlessNumberLessThan(k(), len_, &after_loop); |
| 309 } else { |
| 310 // OR |
| 311 // 10. Repeat, while k >= 0 |
| 312 GotoUnlessNumberLessThan(SmiConstant(-1), k(), &after_loop); |
| 313 } |
301 | 314 |
302 Label done_element(this, &to_); | 315 Label done_element(this, &to_); |
303 // a. Let Pk be ToString(k). | 316 // a. Let Pk be ToString(k). |
304 Node* p_k = ToString(context(), k()); | 317 Node* p_k = ToString(context(), k()); |
305 | 318 |
306 // b. Let kPresent be HasProperty(O, Pk). | 319 // b. Let kPresent be HasProperty(O, Pk). |
307 // c. ReturnIfAbrupt(kPresent). | 320 // c. ReturnIfAbrupt(kPresent). |
308 Node* k_present = HasProperty(o(), p_k, context()); | 321 Node* k_present = HasProperty(o(), p_k, context()); |
309 | 322 |
310 // d. If kPresent is true, then | 323 // d. If kPresent is true, then |
311 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); | 324 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); |
312 | 325 |
313 // i. Let kValue be Get(O, Pk). | 326 // i. Let kValue be Get(O, Pk). |
314 // ii. ReturnIfAbrupt(kValue). | 327 // ii. ReturnIfAbrupt(kValue). |
315 Node* k_value = GetProperty(context(), o(), k()); | 328 Node* k_value = GetProperty(context(), o(), k()); |
316 | 329 |
317 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). | 330 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). |
318 // iv. ReturnIfAbrupt(funcResult). | 331 // iv. ReturnIfAbrupt(funcResult). |
319 a_.Bind(processor(this, k_value, k())); | 332 a_.Bind(processor(this, k_value, k())); |
320 Goto(&done_element); | 333 Goto(&done_element); |
321 | 334 |
322 Bind(&done_element); | 335 Bind(&done_element); |
323 | 336 |
324 // e. Increase k by 1. | 337 if (direction == ForEachDirection::kForward) { |
325 k_.Bind(NumberInc(k_.value())); | 338 // e. Increase k by 1. |
| 339 k_.Bind(NumberInc(k())); |
| 340 } else { |
| 341 // e. Decrease k by 1. |
| 342 k_.Bind(NumberDec(k())); |
| 343 } |
326 Goto(&loop); | 344 Goto(&loop); |
327 } | 345 } |
328 Bind(&after_loop); | 346 Bind(&after_loop); |
329 | 347 |
330 action(this); | 348 action(this); |
331 Return(a_.value()); | 349 Return(a_.value()); |
332 } | 350 } |
333 | 351 |
334 private: | 352 private: |
335 void VisitAllFastElementsOneKind(ElementsKind kind, | 353 void VisitAllFastElementsOneKind(ElementsKind kind, |
336 const CallResultProcessor& processor, | 354 const CallResultProcessor& processor, |
337 Label* array_changed, ParameterMode mode) { | 355 Label* array_changed, ParameterMode mode, |
| 356 ForEachDirection direction) { |
338 Comment("begin VisitAllFastElementsOneKind"); | 357 Comment("begin VisitAllFastElementsOneKind"); |
339 Variable original_map(this, MachineRepresentation::kTagged); | 358 Variable original_map(this, MachineRepresentation::kTagged); |
340 original_map.Bind(LoadMap(o())); | 359 original_map.Bind(LoadMap(o())); |
341 VariableList list({&original_map, &a_, &k_, &to_}, zone()); | 360 VariableList list({&original_map, &a_, &k_, &to_}, zone()); |
| 361 Node* start = IntPtrOrSmiConstant(0, mode); |
| 362 Node* end = TaggedToParameter(len(), mode); |
| 363 IndexAdvanceMode advance_mode = direction == ForEachDirection::kReverse |
| 364 ? IndexAdvanceMode::kPre |
| 365 : IndexAdvanceMode::kPost; |
| 366 if (direction == ForEachDirection::kReverse) std::swap(start, end); |
342 BuildFastLoop( | 367 BuildFastLoop( |
343 list, IntPtrOrSmiConstant(0, mode), TaggedToParameter(len(), mode), | 368 list, start, end, |
344 [=, &original_map](Node* index) { | 369 [=, &original_map](Node* index) { |
345 k_.Bind(ParameterToTagged(index, mode)); | 370 k_.Bind(ParameterToTagged(index, mode)); |
346 Label one_element_done(this), hole_element(this); | 371 Label one_element_done(this), hole_element(this); |
347 | 372 |
348 // Check if o's map has changed during the callback. If so, we have to | 373 // Check if o's map has changed during the callback. If so, we have to |
349 // fall back to the slower spec implementation for the rest of the | 374 // fall back to the slower spec implementation for the rest of the |
350 // iteration. | 375 // iteration. |
351 Node* o_map = LoadMap(o()); | 376 Node* o_map = LoadMap(o()); |
352 GotoIf(WordNotEqual(o_map, original_map.value()), array_changed); | 377 GotoIf(WordNotEqual(o_map, original_map.value()), array_changed); |
353 | 378 |
(...skipping 25 matching lines...) Expand all Loading... |
379 Goto(&one_element_done); | 404 Goto(&one_element_done); |
380 | 405 |
381 Bind(&hole_element); | 406 Bind(&hole_element); |
382 // Check if o's prototype change unexpectedly has elements after the | 407 // Check if o's prototype change unexpectedly has elements after the |
383 // callback in the case of a hole. | 408 // callback in the case of a hole. |
384 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, | 409 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, |
385 array_changed); | 410 array_changed); |
386 | 411 |
387 Bind(&one_element_done); | 412 Bind(&one_element_done); |
388 }, | 413 }, |
389 1, mode, IndexAdvanceMode::kPost); | 414 1, mode, advance_mode); |
390 Comment("end VisitAllFastElementsOneKind"); | 415 Comment("end VisitAllFastElementsOneKind"); |
391 } | 416 } |
392 | 417 |
393 void HandleFastElements(const CallResultProcessor& processor, | 418 void HandleFastElements(const CallResultProcessor& processor, |
394 const PostLoopAction& action, Label* slow) { | 419 const PostLoopAction& action, Label* slow, |
| 420 ForEachDirection direction) { |
395 Label switch_on_elements_kind(this), fast_elements(this), | 421 Label switch_on_elements_kind(this), fast_elements(this), |
396 maybe_double_elements(this), fast_double_elements(this); | 422 maybe_double_elements(this), fast_double_elements(this); |
397 | 423 |
398 Comment("begin HandleFastElements"); | 424 Comment("begin HandleFastElements"); |
399 // Non-smi lengths must use the slow path. | 425 // Non-smi lengths must use the slow path. |
400 GotoIf(TaggedIsNotSmi(len()), slow); | 426 GotoIf(TaggedIsNotSmi(len()), slow); |
401 | 427 |
402 BranchIfFastJSArray(o(), context(), | 428 BranchIfFastJSArray(o(), context(), |
403 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, | 429 CodeStubAssembler::FastJSArrayAccessMode::INBOUNDS_READ, |
404 &switch_on_elements_kind, slow); | 430 &switch_on_elements_kind, slow); |
405 | 431 |
406 Bind(&switch_on_elements_kind); | 432 Bind(&switch_on_elements_kind); |
407 // Select by ElementsKind | 433 // Select by ElementsKind |
408 Node* o_map = LoadMap(o()); | 434 Node* o_map = LoadMap(o()); |
409 Node* bit_field2 = LoadMapBitField2(o_map); | 435 Node* bit_field2 = LoadMapBitField2(o_map); |
410 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); | 436 Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); |
411 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | 437 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), |
412 &maybe_double_elements, &fast_elements); | 438 &maybe_double_elements, &fast_elements); |
413 | 439 |
414 ParameterMode mode = OptimalParameterMode(); | 440 ParameterMode mode = OptimalParameterMode(); |
415 Bind(&fast_elements); | 441 Bind(&fast_elements); |
416 { | 442 { |
417 VisitAllFastElementsOneKind(FAST_ELEMENTS, processor, slow, mode); | 443 VisitAllFastElementsOneKind(FAST_ELEMENTS, processor, slow, mode, |
| 444 direction); |
418 | 445 |
419 action(this); | 446 action(this); |
420 | 447 |
421 // No exception, return success | 448 // No exception, return success |
422 Return(a_.value()); | 449 Return(a_.value()); |
423 } | 450 } |
424 | 451 |
425 Bind(&maybe_double_elements); | 452 Bind(&maybe_double_elements); |
426 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)), | 453 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_DOUBLE_ELEMENTS)), |
427 slow, &fast_double_elements); | 454 slow, &fast_double_elements); |
428 | 455 |
429 Bind(&fast_double_elements); | 456 Bind(&fast_double_elements); |
430 { | 457 { |
431 VisitAllFastElementsOneKind(FAST_DOUBLE_ELEMENTS, processor, slow, mode); | 458 VisitAllFastElementsOneKind(FAST_DOUBLE_ELEMENTS, processor, slow, mode, |
| 459 direction); |
432 | 460 |
433 action(this); | 461 action(this); |
434 | 462 |
435 // No exception, return success | 463 // No exception, return success |
436 Return(a_.value()); | 464 Return(a_.value()); |
437 } | 465 } |
438 } | 466 } |
439 | 467 |
440 Node* callbackfn_ = nullptr; | 468 Node* callbackfn_ = nullptr; |
441 Node* o_ = nullptr; | 469 Node* o_ = nullptr; |
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
750 new_target); | 778 new_target); |
751 | 779 |
752 GenerateIteratingArrayBuiltinBody( | 780 GenerateIteratingArrayBuiltinBody( |
753 "Array.prototype.reduce", | 781 "Array.prototype.reduce", |
754 &ArrayBuiltinCodeStubAssembler::ReduceResultGenerator, | 782 &ArrayBuiltinCodeStubAssembler::ReduceResultGenerator, |
755 &ArrayBuiltinCodeStubAssembler::ReduceProcessor, | 783 &ArrayBuiltinCodeStubAssembler::ReduceProcessor, |
756 &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction, | 784 &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction, |
757 CodeFactory::ArrayReduceLoopContinuation(isolate())); | 785 CodeFactory::ArrayReduceLoopContinuation(isolate())); |
758 } | 786 } |
759 | 787 |
| 788 TF_BUILTIN(ArrayReduceRightLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
| 789 Node* context = Parameter(Descriptor::kContext); |
| 790 Node* receiver = Parameter(Descriptor::kReceiver); |
| 791 Node* callbackfn = Parameter(Descriptor::kCallbackFn); |
| 792 Node* this_arg = Parameter(Descriptor::kThisArg); |
| 793 Node* accumulator = Parameter(Descriptor::kAccumulator); |
| 794 Node* object = Parameter(Descriptor::kObject); |
| 795 Node* initial_k = Parameter(Descriptor::kInitialK); |
| 796 Node* len = Parameter(Descriptor::kLength); |
| 797 Node* to = Parameter(Descriptor::kTo); |
| 798 |
| 799 InitIteratingArrayBuiltinLoopContinuation(context, receiver, callbackfn, |
| 800 this_arg, accumulator, object, |
| 801 initial_k, len, to); |
| 802 |
| 803 GenerateIteratingArrayBuiltinLoopContinuation( |
| 804 &ArrayBuiltinCodeStubAssembler::ReduceProcessor, |
| 805 &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction, |
| 806 ForEachDirection::kReverse); |
| 807 } |
| 808 |
| 809 TF_BUILTIN(ArrayReduceRight, ArrayBuiltinCodeStubAssembler) { |
| 810 Node* context = Parameter(Descriptor::kContext); |
| 811 Node* receiver = Parameter(Descriptor::kReceiver); |
| 812 Node* callbackfn = Parameter(Descriptor::kCallbackFn); |
| 813 Node* initial_value = Parameter(Descriptor::kInitialValue); |
| 814 Node* new_target = Parameter(Descriptor::kNewTarget); |
| 815 |
| 816 InitIteratingArrayBuiltinBody(context, receiver, callbackfn, initial_value, |
| 817 new_target); |
| 818 |
| 819 GenerateIteratingArrayBuiltinBody( |
| 820 "Array.prototype.reduceRight", |
| 821 &ArrayBuiltinCodeStubAssembler::ReduceResultGenerator, |
| 822 &ArrayBuiltinCodeStubAssembler::ReduceProcessor, |
| 823 &ArrayBuiltinCodeStubAssembler::ReducePostLoopAction, |
| 824 CodeFactory::ArrayReduceRightLoopContinuation(isolate()), |
| 825 ForEachDirection::kReverse); |
| 826 } |
| 827 |
760 TF_BUILTIN(ArrayFilterLoopContinuation, ArrayBuiltinCodeStubAssembler) { | 828 TF_BUILTIN(ArrayFilterLoopContinuation, ArrayBuiltinCodeStubAssembler) { |
761 Node* context = Parameter(Descriptor::kContext); | 829 Node* context = Parameter(Descriptor::kContext); |
762 Node* receiver = Parameter(Descriptor::kReceiver); | 830 Node* receiver = Parameter(Descriptor::kReceiver); |
763 Node* callbackfn = Parameter(Descriptor::kCallbackFn); | 831 Node* callbackfn = Parameter(Descriptor::kCallbackFn); |
764 Node* this_arg = Parameter(Descriptor::kThisArg); | 832 Node* this_arg = Parameter(Descriptor::kThisArg); |
765 Node* array = Parameter(Descriptor::kArray); | 833 Node* array = Parameter(Descriptor::kArray); |
766 Node* object = Parameter(Descriptor::kObject); | 834 Node* object = Parameter(Descriptor::kObject); |
767 Node* initial_k = Parameter(Descriptor::kInitialK); | 835 Node* initial_k = Parameter(Descriptor::kInitialK); |
768 Node* len = Parameter(Descriptor::kLength); | 836 Node* len = Parameter(Descriptor::kLength); |
769 Node* to = Parameter(Descriptor::kTo); | 837 Node* to = Parameter(Descriptor::kTo); |
(...skipping 1116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1886 { | 1954 { |
1887 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); | 1955 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); |
1888 CallRuntime(Runtime::kThrowTypeError, context, message, | 1956 CallRuntime(Runtime::kThrowTypeError, context, message, |
1889 HeapConstant(operation)); | 1957 HeapConstant(operation)); |
1890 Unreachable(); | 1958 Unreachable(); |
1891 } | 1959 } |
1892 } | 1960 } |
1893 | 1961 |
1894 } // namespace internal | 1962 } // namespace internal |
1895 } // namespace v8 | 1963 } // namespace v8 |
OLD | NEW |