Chromium Code Reviews| Index: src/builtins/builtins-array-gen.cc |
| diff --git a/src/builtins/builtins-array-gen.cc b/src/builtins/builtins-array-gen.cc |
| index aad31db8a17d8bbb65347533377e61299e455279..d5b4865124d5243548ef84a1227a731d93314c7d 100644 |
| --- a/src/builtins/builtins-array-gen.cc |
| +++ b/src/builtins/builtins-array-gen.cc |
| @@ -154,6 +154,19 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| return ArraySpeciesCreate(context(), o(), len_); |
| } |
| + Node* TypedArrayMapResultGenerator() { |
| + // 6. Let A be ? TypedArraySpeciesCreate(O, len). |
| + Node* A = TypedArraySpeciesCreateByLength(context(), o(), len_); |
| + // In the Spec and our current implementation, the length check is already |
| + // performed in TypedArraySpeciesCreate. Repeating the check here to |
| + // keep this invariant local. |
| + fast_typed_array_target_ = WordAnd( |
| + WordEqual(LoadInstanceType(LoadElements(o_)), |
| + LoadInstanceType(LoadElements(A))), |
| + WordEqual(len_, LoadObjectField(A, JSTypedArray::kLengthOffset))); |
| + return A; |
| + } |
| + |
| Node* MapProcessor(Node* k_value, Node* k) { |
| // i. Let kValue be ? Get(O, Pk). Performed by the caller of MapProcessor. |
| // ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O). |
| @@ -165,6 +178,48 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| return a(); |
| } |
| + // See tc39.github.io/ecma262/#sec-%typedarray%.prototype.map. |
| + Node* TypedArrayMapProcessor(Node* k_value, Node* k) { |
| + // 8. c. Let mappedValue be ? Call(callbackfn, T, « kValue, k, O »). |
| + Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(), |
| + callbackfn(), this_arg(), k_value, k, o()); |
| + Label fast(this), slow(this), done(this), detached(this, Label::kDeferred); |
| + |
| + // 8. d. Perform ? Set(A, Pk, mappedValue, true). |
| + // Since we know that A is a TypedArray, this always ends up in |
| + // #sec-integer-indexed-exotic-objects-set-p-v-receiver and then |
| + // tc39.github.io/ecma262/#sec-integerindexedelementset . |
| + Branch(fast_typed_array_target_, &fast, &slow); |
| + |
| + Bind(&fast); |
|
Camillo Bruni
2017/04/11 13:16:06
drive-by-comment: Could you upgrade your implement
|
| + // #sec-integerindexedelementset 3. Let numValue be ? ToNumber(value). |
| + Node* num_value = ToNumber(context(), mappedValue); |
| + // The only way how this can bailout is because of a detached buffer. |
| + EmitElementStore( |
| + a(), k, num_value, false, source_elements_kind_, |
| + KeyedAccessStoreMode::STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS, |
| + &detached); |
| + Goto(&done); |
| + |
| + Bind(&slow); |
| + CallRuntime(Runtime::kSetProperty, context(), a(), k, mappedValue, |
| + SmiConstant(STRICT)); |
| + Goto(&done); |
| + |
| + Bind(&detached); |
| + { |
| + // tc39.github.io/ecma262/#sec-integerindexedelementset |
| + // 5. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. |
| + CallRuntime(Runtime::kThrowTypeError, context_, |
| + SmiConstant(MessageTemplate::kDetachedOperation), |
| + name_string_); |
| + Unreachable(); |
| + } |
| + |
| + Bind(&done); |
| + return a(); |
| + } |
| + |
| void NullPostLoopAction() {} |
| protected: |
| @@ -295,7 +350,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| const char* name, const BuiltinResultGenerator& generator, |
| const CallResultProcessor& processor, const PostLoopAction& action, |
| ForEachDirection direction = ForEachDirection::kForward) { |
| - Node* name_string = |
| + name_string_ = |
| HeapConstant(isolate()->factory()->NewStringFromAsciiChecked(name)); |
| // ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray |
| @@ -330,7 +385,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| { |
| CallRuntime(Runtime::kThrowTypeError, context_, |
| SmiConstant(MessageTemplate::kDetachedOperation), |
| - name_string); |
| + name_string_); |
| Unreachable(); |
| } |
| @@ -367,20 +422,20 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| } else { |
| k_.Bind(NumberDec(len())); |
| } |
| - a_.Bind(generator(this)); |
| - Node* elements_type = LoadInstanceType(LoadElements(o_)); |
| - Switch(elements_type, &unexpected_instance_type, instance_types.data(), |
| + Node* instance_type = LoadInstanceType(LoadElements(o_)); |
| + Switch(instance_type, &unexpected_instance_type, instance_types.data(), |
| label_ptrs.data(), labels.size()); |
| for (size_t i = 0; i < labels.size(); ++i) { |
| BIND(&labels[i]); |
| Label done(this); |
| + source_elements_kind_ = ElementsKindForInstanceType( |
| + static_cast<InstanceType>(instance_types[i])); |
| + a_.Bind(generator(this)); |
| // TODO(tebbi): Silently cancelling the loop on buffer detachment is a |
| - // spec violation. Should go to &detached and throw a TypeError instead. |
| - VisitAllTypedArrayElements( |
| - ElementsKindForInstanceType( |
| - static_cast<InstanceType>(instance_types[i])), |
| - array_buffer, processor, &done, direction); |
| + // spec violation. Should go to &throw_detached_ and throw a TypeError |
| + // instead. |
| + VisitAllTypedArrayElements(array_buffer, processor, &done, direction); |
| Goto(&done); |
| // No exception, return success |
| BIND(&done); |
| @@ -459,7 +514,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| } |
| } |
| - void VisitAllTypedArrayElements(ElementsKind kind, Node* array_buffer, |
| + void VisitAllTypedArrayElements(Node* array_buffer, |
| const CallResultProcessor& processor, |
| Label* detached, ForEachDirection direction) { |
| VariableList list({&a_, &k_, &to_}, zone()); |
| @@ -473,8 +528,8 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, |
| MachineType::Pointer()); |
| Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr); |
| - Node* value = LoadFixedTypedArrayElementAsTagged(data_ptr, index, kind, |
| - SMI_PARAMETERS); |
| + Node* value = LoadFixedTypedArrayElementAsTagged( |
| + data_ptr, index, source_elements_kind_, SMI_PARAMETERS); |
| k_.Bind(index); |
| a_.Bind(processor(this, value, index)); |
| }; |
| @@ -613,9 +668,12 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| Node* context_ = nullptr; |
| Node* receiver_ = nullptr; |
| Node* new_target_ = nullptr; |
| + Node* fast_typed_array_target_ = nullptr; |
| + Node* name_string_ = nullptr; |
| Variable k_; |
| Variable a_; |
| Variable to_; |
| + ElementsKind source_elements_kind_ = ElementsKind::NO_ELEMENTS; |
| }; |
| TF_BUILTIN(FastArrayPush, CodeStubAssembler) { |
| @@ -1110,6 +1168,23 @@ TF_BUILTIN(ArrayMap, ArrayBuiltinCodeStubAssembler) { |
| CodeFactory::ArrayMapLoopContinuation(isolate())); |
| } |
| +TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinCodeStubAssembler) { |
| + Node* context = Parameter(Descriptor::kContext); |
| + Node* receiver = Parameter(Descriptor::kReceiver); |
| + Node* callbackfn = Parameter(Descriptor::kCallbackFn); |
| + Node* this_arg = Parameter(Descriptor::kThisArg); |
| + Node* new_target = Parameter(Descriptor::kNewTarget); |
| + |
| + InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, |
| + new_target); |
| + |
| + GenerateIteratingTypedArrayBuiltinBody( |
| + "%TypedArray%.prototype.map", |
| + &ArrayBuiltinCodeStubAssembler::TypedArrayMapResultGenerator, |
| + &ArrayBuiltinCodeStubAssembler::TypedArrayMapProcessor, |
| + &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); |
| +} |
| + |
| TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { |
| Node* object = Parameter(Descriptor::kArg); |
| Node* context = Parameter(Descriptor::kContext); |