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-string-gen.h" | 5 #include "src/builtins/builtins-string-gen.h" |
6 #include "src/builtins/builtins-utils-gen.h" | 6 #include "src/builtins/builtins-utils-gen.h" |
7 #include "src/builtins/builtins.h" | 7 #include "src/builtins/builtins.h" |
8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 to_.Bind(NumberInc(to_.value())); | 157 to_.Bind(NumberInc(to_.value())); |
158 Goto(&false_continue); | 158 Goto(&false_continue); |
159 } | 159 } |
160 } | 160 } |
161 BIND(&false_continue); | 161 BIND(&false_continue); |
162 return a(); | 162 return a(); |
163 } | 163 } |
164 | 164 |
165 void MapResultGenerator() { ArraySpeciesCreate(len_); } | 165 void MapResultGenerator() { ArraySpeciesCreate(len_); } |
166 | 166 |
| 167 void TypedArrayMapResultGenerator() { |
| 168 // 6. Let A be ? TypedArraySpeciesCreate(O, len). |
| 169 Node* a = TypedArraySpeciesCreateByLength(context(), o(), len_); |
| 170 // In the Spec and our current implementation, the length check is already |
| 171 // performed in TypedArraySpeciesCreate. Repeating the check here to |
| 172 // keep this invariant local. |
| 173 // TODO(tebbi): Change this to a release mode check. |
| 174 CSA_ASSERT( |
| 175 this, WordEqual(len_, LoadObjectField(a, JSTypedArray::kLengthOffset))); |
| 176 fast_typed_array_target_ = Word32Equal(LoadInstanceType(LoadElements(o_)), |
| 177 LoadInstanceType(LoadElements(a))); |
| 178 a_.Bind(a); |
| 179 } |
| 180 |
167 Node* SpecCompliantMapProcessor(Node* k_value, Node* k) { | 181 Node* SpecCompliantMapProcessor(Node* k_value, Node* k) { |
168 // i. Let kValue be ? Get(O, Pk). Performed by the caller of | 182 // i. Let kValue be ? Get(O, Pk). Performed by the caller of |
169 // SpecCompliantMapProcessor. | 183 // SpecCompliantMapProcessor. |
170 // ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O). | 184 // ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O). |
171 Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(), | 185 Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(), |
172 callbackfn(), this_arg(), k_value, k, o()); | 186 callbackfn(), this_arg(), k_value, k, o()); |
173 | 187 |
174 // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). | 188 // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). |
175 CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mappedValue); | 189 CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mappedValue); |
176 return a(); | 190 return a(); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 { | 245 { |
232 // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). | 246 // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). |
233 CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mappedValue); | 247 CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mappedValue); |
234 Goto(&finished); | 248 Goto(&finished); |
235 } | 249 } |
236 | 250 |
237 BIND(&finished); | 251 BIND(&finished); |
238 return a(); | 252 return a(); |
239 } | 253 } |
240 | 254 |
| 255 // See tc39.github.io/ecma262/#sec-%typedarray%.prototype.map. |
| 256 Node* TypedArrayMapProcessor(Node* k_value, Node* k) { |
| 257 // 8. c. Let mappedValue be ? Call(callbackfn, T, « kValue, k, O »). |
| 258 Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(), |
| 259 callbackfn(), this_arg(), k_value, k, o()); |
| 260 Label fast(this), slow(this), done(this), detached(this, Label::kDeferred); |
| 261 |
| 262 // 8. d. Perform ? Set(A, Pk, mappedValue, true). |
| 263 // Since we know that A is a TypedArray, this always ends up in |
| 264 // #sec-integer-indexed-exotic-objects-set-p-v-receiver and then |
| 265 // tc39.github.io/ecma262/#sec-integerindexedelementset . |
| 266 Branch(fast_typed_array_target_, &fast, &slow); |
| 267 |
| 268 BIND(&fast); |
| 269 // #sec-integerindexedelementset 3. Let numValue be ? ToNumber(value). |
| 270 Node* num_value = ToNumber(context(), mappedValue); |
| 271 // The only way how this can bailout is because of a detached buffer. |
| 272 EmitElementStore( |
| 273 a(), k, num_value, false, source_elements_kind_, |
| 274 KeyedAccessStoreMode::STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS, |
| 275 &detached); |
| 276 Goto(&done); |
| 277 |
| 278 BIND(&slow); |
| 279 CallRuntime(Runtime::kSetProperty, context(), a(), k, mappedValue, |
| 280 SmiConstant(STRICT)); |
| 281 Goto(&done); |
| 282 |
| 283 BIND(&detached); |
| 284 { |
| 285 // tc39.github.io/ecma262/#sec-integerindexedelementset |
| 286 // 5. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. |
| 287 CallRuntime(Runtime::kThrowTypeError, context_, |
| 288 SmiConstant(MessageTemplate::kDetachedOperation), |
| 289 name_string_); |
| 290 Unreachable(); |
| 291 } |
| 292 |
| 293 BIND(&done); |
| 294 return a(); |
| 295 } |
| 296 |
241 void NullPostLoopAction() {} | 297 void NullPostLoopAction() {} |
242 | 298 |
243 protected: | 299 protected: |
244 Node* context() { return context_; } | 300 Node* context() { return context_; } |
245 Node* receiver() { return receiver_; } | 301 Node* receiver() { return receiver_; } |
246 Node* new_target() { return new_target_; } | 302 Node* new_target() { return new_target_; } |
247 Node* argc() { return argc_; } | 303 Node* argc() { return argc_; } |
248 Node* o() { return o_; } | 304 Node* o() { return o_; } |
249 Node* len() { return len_; } | 305 Node* len() { return len_; } |
250 Node* callbackfn() { return callbackfn_; } | 306 Node* callbackfn() { return callbackfn_; } |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 k_.Bind(initial_k); | 425 k_.Bind(initial_k); |
370 o_ = o; | 426 o_ = o; |
371 len_ = len; | 427 len_ = len; |
372 to_.Bind(to); | 428 to_.Bind(to); |
373 } | 429 } |
374 | 430 |
375 void GenerateIteratingTypedArrayBuiltinBody( | 431 void GenerateIteratingTypedArrayBuiltinBody( |
376 const char* name, const BuiltinResultGenerator& generator, | 432 const char* name, const BuiltinResultGenerator& generator, |
377 const CallResultProcessor& processor, const PostLoopAction& action, | 433 const CallResultProcessor& processor, const PostLoopAction& action, |
378 ForEachDirection direction = ForEachDirection::kForward) { | 434 ForEachDirection direction = ForEachDirection::kForward) { |
379 Node* name_string = | 435 name_string_ = |
380 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked(name)); | 436 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked(name)); |
381 | 437 |
382 // ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray | 438 // ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray |
383 | 439 |
384 Label throw_not_typed_array(this, Label::kDeferred), | 440 Label throw_not_typed_array(this, Label::kDeferred), |
385 throw_detached(this, Label::kDeferred); | 441 throw_detached(this, Label::kDeferred); |
386 | 442 |
387 GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array); | 443 GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array); |
388 GotoIfNot(HasInstanceType(receiver_, JS_TYPED_ARRAY_TYPE), | 444 GotoIfNot(HasInstanceType(receiver_, JS_TYPED_ARRAY_TYPE), |
389 &throw_not_typed_array); | 445 &throw_not_typed_array); |
(...skipping 14 matching lines...) Expand all Loading... |
404 { | 460 { |
405 CallRuntime(Runtime::kThrowTypeError, context_, | 461 CallRuntime(Runtime::kThrowTypeError, context_, |
406 SmiConstant(MessageTemplate::kNotTypedArray)); | 462 SmiConstant(MessageTemplate::kNotTypedArray)); |
407 Unreachable(); | 463 Unreachable(); |
408 } | 464 } |
409 | 465 |
410 BIND(&throw_detached); | 466 BIND(&throw_detached); |
411 { | 467 { |
412 CallRuntime(Runtime::kThrowTypeError, context_, | 468 CallRuntime(Runtime::kThrowTypeError, context_, |
413 SmiConstant(MessageTemplate::kDetachedOperation), | 469 SmiConstant(MessageTemplate::kDetachedOperation), |
414 name_string); | 470 name_string_); |
415 Unreachable(); | 471 Unreachable(); |
416 } | 472 } |
417 | 473 |
418 BIND(&throw_not_callable); | 474 BIND(&throw_not_callable); |
419 { | 475 { |
420 CallRuntime(Runtime::kThrowTypeError, context_, | 476 CallRuntime(Runtime::kThrowTypeError, context_, |
421 SmiConstant(MessageTemplate::kCalledNonCallable), | 477 SmiConstant(MessageTemplate::kCalledNonCallable), |
422 callbackfn_); | 478 callbackfn_); |
423 Unreachable(); | 479 Unreachable(); |
424 } | 480 } |
(...skipping 16 matching lines...) Expand all Loading... |
441 label_ptrs.push_back(&label); | 497 label_ptrs.push_back(&label); |
442 } | 498 } |
443 | 499 |
444 BIND(&distinguish_types); | 500 BIND(&distinguish_types); |
445 | 501 |
446 if (direction == ForEachDirection::kForward) { | 502 if (direction == ForEachDirection::kForward) { |
447 k_.Bind(SmiConstant(0)); | 503 k_.Bind(SmiConstant(0)); |
448 } else { | 504 } else { |
449 k_.Bind(NumberDec(len())); | 505 k_.Bind(NumberDec(len())); |
450 } | 506 } |
451 generator(this); | 507 Node* instance_type = LoadInstanceType(LoadElements(o_)); |
452 Node* elements_type = LoadInstanceType(LoadElements(o_)); | 508 Switch(instance_type, &unexpected_instance_type, instance_types.data(), |
453 Switch(elements_type, &unexpected_instance_type, instance_types.data(), | |
454 label_ptrs.data(), labels.size()); | 509 label_ptrs.data(), labels.size()); |
455 | 510 |
456 for (size_t i = 0; i < labels.size(); ++i) { | 511 for (size_t i = 0; i < labels.size(); ++i) { |
457 BIND(&labels[i]); | 512 BIND(&labels[i]); |
458 Label done(this); | 513 Label done(this); |
| 514 source_elements_kind_ = ElementsKindForInstanceType( |
| 515 static_cast<InstanceType>(instance_types[i])); |
| 516 generator(this); |
459 // TODO(tebbi): Silently cancelling the loop on buffer detachment is a | 517 // TODO(tebbi): Silently cancelling the loop on buffer detachment is a |
460 // spec violation. Should go to &detached and throw a TypeError instead. | 518 // spec violation. Should go to &throw_detached and throw a TypeError |
461 VisitAllTypedArrayElements( | 519 // instead. |
462 ElementsKindForInstanceType( | 520 VisitAllTypedArrayElements(array_buffer, processor, &done, direction); |
463 static_cast<InstanceType>(instance_types[i])), | |
464 array_buffer, processor, &done, direction); | |
465 Goto(&done); | 521 Goto(&done); |
466 // No exception, return success | 522 // No exception, return success |
467 BIND(&done); | 523 BIND(&done); |
468 action(this); | 524 action(this); |
469 ReturnFromBuiltin(a_.value()); | 525 ReturnFromBuiltin(a_.value()); |
470 } | 526 } |
471 } | 527 } |
472 | 528 |
473 void GenerateIteratingArrayBuiltinLoopContinuation( | 529 void GenerateIteratingArrayBuiltinLoopContinuation( |
474 const CallResultProcessor& processor, const PostLoopAction& action, | 530 const CallResultProcessor& processor, const PostLoopAction& action, |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 | 589 |
534 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENTS_KIND) | 590 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENTS_KIND) |
535 #undef INSTANCE_TYPE_TO_ELEMENTS_KIND | 591 #undef INSTANCE_TYPE_TO_ELEMENTS_KIND |
536 | 592 |
537 default: | 593 default: |
538 UNREACHABLE(); | 594 UNREACHABLE(); |
539 return static_cast<ElementsKind>(-1); | 595 return static_cast<ElementsKind>(-1); |
540 } | 596 } |
541 } | 597 } |
542 | 598 |
543 void VisitAllTypedArrayElements(ElementsKind kind, Node* array_buffer, | 599 void VisitAllTypedArrayElements(Node* array_buffer, |
544 const CallResultProcessor& processor, | 600 const CallResultProcessor& processor, |
545 Label* detached, ForEachDirection direction) { | 601 Label* detached, ForEachDirection direction) { |
546 VariableList list({&a_, &k_, &to_}, zone()); | 602 VariableList list({&a_, &k_, &to_}, zone()); |
547 | 603 |
548 FastLoopBody body = [&](Node* index) { | 604 FastLoopBody body = [&](Node* index) { |
549 GotoIf(IsDetachedBuffer(array_buffer), detached); | 605 GotoIf(IsDetachedBuffer(array_buffer), detached); |
550 Node* elements = LoadElements(o_); | 606 Node* elements = LoadElements(o_); |
551 Node* base_ptr = | 607 Node* base_ptr = |
552 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); | 608 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); |
553 Node* external_ptr = | 609 Node* external_ptr = |
554 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, | 610 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, |
555 MachineType::Pointer()); | 611 MachineType::Pointer()); |
556 Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr); | 612 Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr); |
557 Node* value = LoadFixedTypedArrayElementAsTagged(data_ptr, index, kind, | 613 Node* value = LoadFixedTypedArrayElementAsTagged( |
558 SMI_PARAMETERS); | 614 data_ptr, index, source_elements_kind_, SMI_PARAMETERS); |
559 k_.Bind(index); | 615 k_.Bind(index); |
560 a_.Bind(processor(this, value, index)); | 616 a_.Bind(processor(this, value, index)); |
561 }; | 617 }; |
562 Node* start = SmiConstant(0); | 618 Node* start = SmiConstant(0); |
563 Node* end = len_; | 619 Node* end = len_; |
564 IndexAdvanceMode advance_mode = IndexAdvanceMode::kPost; | 620 IndexAdvanceMode advance_mode = IndexAdvanceMode::kPost; |
565 int incr = 1; | 621 int incr = 1; |
566 if (direction == ForEachDirection::kReverse) { | 622 if (direction == ForEachDirection::kReverse) { |
567 std::swap(start, end); | 623 std::swap(start, end); |
568 advance_mode = IndexAdvanceMode::kPre; | 624 advance_mode = IndexAdvanceMode::kPre; |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
733 } | 789 } |
734 | 790 |
735 Node* callbackfn_ = nullptr; | 791 Node* callbackfn_ = nullptr; |
736 Node* o_ = nullptr; | 792 Node* o_ = nullptr; |
737 Node* this_arg_ = nullptr; | 793 Node* this_arg_ = nullptr; |
738 Node* len_ = nullptr; | 794 Node* len_ = nullptr; |
739 Node* context_ = nullptr; | 795 Node* context_ = nullptr; |
740 Node* receiver_ = nullptr; | 796 Node* receiver_ = nullptr; |
741 Node* new_target_ = nullptr; | 797 Node* new_target_ = nullptr; |
742 Node* argc_ = nullptr; | 798 Node* argc_ = nullptr; |
| 799 Node* fast_typed_array_target_ = nullptr; |
| 800 Node* name_string_ = nullptr; |
743 Variable k_; | 801 Variable k_; |
744 Variable a_; | 802 Variable a_; |
745 Variable to_; | 803 Variable to_; |
746 Label fully_spec_compliant_; | 804 Label fully_spec_compliant_; |
| 805 ElementsKind source_elements_kind_ = ElementsKind::NO_ELEMENTS; |
747 }; | 806 }; |
748 | 807 |
749 TF_BUILTIN(FastArrayPop, CodeStubAssembler) { | 808 TF_BUILTIN(FastArrayPop, CodeStubAssembler) { |
750 Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount); | 809 Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount); |
751 Node* context = Parameter(BuiltinDescriptor::kContext); | 810 Node* context = Parameter(BuiltinDescriptor::kContext); |
752 CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget), | 811 CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget), |
753 UndefinedConstant())); | 812 UndefinedConstant())); |
754 | 813 |
755 CodeStubArguments args(this, ChangeInt32ToIntPtr(argc)); | 814 CodeStubArguments args(this, ChangeInt32ToIntPtr(argc)); |
756 Node* receiver = args.GetReceiver(); | 815 Node* receiver = args.GetReceiver(); |
(...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1341 InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, | 1400 InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, |
1342 new_target, argc); | 1401 new_target, argc); |
1343 | 1402 |
1344 GenerateIteratingArrayBuiltinBody( | 1403 GenerateIteratingArrayBuiltinBody( |
1345 "Array.prototype.map", &ArrayBuiltinCodeStubAssembler::MapResultGenerator, | 1404 "Array.prototype.map", &ArrayBuiltinCodeStubAssembler::MapResultGenerator, |
1346 &ArrayBuiltinCodeStubAssembler::FastMapProcessor, | 1405 &ArrayBuiltinCodeStubAssembler::FastMapProcessor, |
1347 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction, | 1406 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction, |
1348 Builtins::CallableFor(isolate(), Builtins::kArrayMapLoopContinuation)); | 1407 Builtins::CallableFor(isolate(), Builtins::kArrayMapLoopContinuation)); |
1349 } | 1408 } |
1350 | 1409 |
| 1410 TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinCodeStubAssembler) { |
| 1411 Node* argc = |
| 1412 ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount)); |
| 1413 CodeStubArguments args(this, argc); |
| 1414 Node* context = Parameter(BuiltinDescriptor::kContext); |
| 1415 Node* new_target = Parameter(BuiltinDescriptor::kNewTarget); |
| 1416 Node* receiver = args.GetReceiver(); |
| 1417 Node* callbackfn = args.GetOptionalArgumentValue(0, UndefinedConstant()); |
| 1418 Node* this_arg = args.GetOptionalArgumentValue(1, UndefinedConstant()); |
| 1419 |
| 1420 InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, |
| 1421 new_target, argc); |
| 1422 |
| 1423 GenerateIteratingTypedArrayBuiltinBody( |
| 1424 "%TypedArray%.prototype.map", |
| 1425 &ArrayBuiltinCodeStubAssembler::TypedArrayMapResultGenerator, |
| 1426 &ArrayBuiltinCodeStubAssembler::TypedArrayMapProcessor, |
| 1427 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); |
| 1428 } |
| 1429 |
1351 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { | 1430 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { |
1352 Node* object = Parameter(Descriptor::kArg); | 1431 Node* object = Parameter(Descriptor::kArg); |
1353 Node* context = Parameter(Descriptor::kContext); | 1432 Node* context = Parameter(Descriptor::kContext); |
1354 | 1433 |
1355 Label call_runtime(this), return_true(this), return_false(this); | 1434 Label call_runtime(this), return_true(this), return_false(this); |
1356 | 1435 |
1357 GotoIf(TaggedIsSmi(object), &return_false); | 1436 GotoIf(TaggedIsSmi(object), &return_false); |
1358 Node* instance_type = LoadInstanceType(object); | 1437 Node* instance_type = LoadInstanceType(object); |
1359 | 1438 |
1360 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), | 1439 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), |
(...skipping 857 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2218 { | 2297 { |
2219 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); | 2298 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); |
2220 CallRuntime(Runtime::kThrowTypeError, context, message, | 2299 CallRuntime(Runtime::kThrowTypeError, context, message, |
2221 HeapConstant(operation)); | 2300 HeapConstant(operation)); |
2222 Unreachable(); | 2301 Unreachable(); |
2223 } | 2302 } |
2224 } | 2303 } |
2225 | 2304 |
2226 } // namespace internal | 2305 } // namespace internal |
2227 } // namespace v8 | 2306 } // namespace v8 |
OLD | NEW |