Commit d4f80f4c authored by tebbi's avatar tebbi Committed by Commit bot

[builtins] Implement %TypedArray%.prototype.map in the CSA

R=danno@chromium.org

Review-Url: https://codereview.chromium.org/2814683002
Cr-Commit-Position: refs/heads/master@{#45380}
parent f1e82a2e
......@@ -3899,6 +3899,8 @@ void Genesis::InitializeGlobal_experimental_fast_array_builtins() {
Builtins::kTypedArrayPrototypeReduce);
InstallOneBuiltinFunction(typed_array_prototype, "reduceRight",
Builtins::kTypedArrayPrototypeReduceRight);
InstallOneBuiltinFunction(typed_array_prototype, "map",
Builtins::kTypedArrayPrototypeMap);
}
}
......
......@@ -164,6 +164,20 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
void MapResultGenerator() { ArraySpeciesCreate(len_); }
void 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.
// TODO(tebbi): Change this to a release mode check.
CSA_ASSERT(
this, WordEqual(len_, LoadObjectField(a, JSTypedArray::kLengthOffset)));
fast_typed_array_target_ = Word32Equal(LoadInstanceType(LoadElements(o_)),
LoadInstanceType(LoadElements(a)));
a_.Bind(a);
}
Node* SpecCompliantMapProcessor(Node* k_value, Node* k) {
// i. Let kValue be ? Get(O, Pk). Performed by the caller of
// SpecCompliantMapProcessor.
......@@ -238,6 +252,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);
// #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:
......@@ -376,7 +432,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
......@@ -411,7 +467,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
{
CallRuntime(Runtime::kThrowTypeError, context_,
SmiConstant(MessageTemplate::kDetachedOperation),
name_string);
name_string_);
Unreachable();
}
......@@ -448,20 +504,20 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
} else {
k_.Bind(NumberDec(len()));
}
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]));
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);
......@@ -540,7 +596,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());
......@@ -554,8 +610,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));
};
......@@ -740,10 +796,13 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
Node* receiver_ = nullptr;
Node* new_target_ = nullptr;
Node* argc_ = nullptr;
Node* fast_typed_array_target_ = nullptr;
Node* name_string_ = nullptr;
Variable k_;
Variable a_;
Variable to_;
Label fully_spec_compliant_;
ElementsKind source_elements_kind_ = ElementsKind::NO_ELEMENTS;
};
TF_BUILTIN(FastArrayPop, CodeStubAssembler) {
......@@ -1496,6 +1555,26 @@ TF_BUILTIN(ArrayMap, ArrayBuiltinCodeStubAssembler) {
Builtins::CallableFor(isolate(), Builtins::kArrayMapLoopContinuation));
}
TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinCodeStubAssembler) {
Node* argc =
ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
CodeStubArguments args(this, argc);
Node* context = Parameter(BuiltinDescriptor::kContext);
Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
Node* receiver = args.GetReceiver();
Node* callbackfn = args.GetOptionalArgumentValue(0, UndefinedConstant());
Node* this_arg = args.GetOptionalArgumentValue(1, UndefinedConstant());
InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg,
new_target, argc);
GenerateIteratingTypedArrayBuiltinBody(
"%TypedArray%.prototype.map",
&ArrayBuiltinCodeStubAssembler::TypedArrayMapResultGenerator,
&ArrayBuiltinCodeStubAssembler::TypedArrayMapProcessor,
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
}
TF_BUILTIN(ArrayIsArray, CodeStubAssembler) {
Node* object = Parameter(Descriptor::kArg);
Node* context = Parameter(Descriptor::kContext);
......
......@@ -950,6 +950,8 @@ namespace internal {
/* ES6 %TypedArray%.prototype.reduceRight */ \
TFJ(TypedArrayPrototypeReduceRight, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 %TypedArray%.prototype.map */ \
TFJ(TypedArrayPrototypeMap, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
\
/* Wasm */ \
ASM(WasmCompileLazy) \
......
......@@ -42,81 +42,14 @@ int64_t CapRelativeIndex(Handle<Object> num, int64_t minimum, int64_t maximum) {
: std::min<int64_t>(relative, maximum);
}
// ES7 section 22.2.4.6 TypedArrayCreate ( constructor, argumentList )
MaybeHandle<JSTypedArray> TypedArrayCreate(Isolate* isolate,
Handle<JSFunction> default_ctor,
int argc, Handle<Object>* argv,
const char* method_name) {
// 1. Let newTypedArray be ? Construct(constructor, argumentList).
Handle<Object> new_obj;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, new_obj, Execution::New(default_ctor, argc, argv), JSTypedArray);
// 2. Perform ? ValidateTypedArray(newTypedArray).
Handle<JSTypedArray> new_array;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, new_array, JSTypedArray::Validate(isolate, new_obj, method_name),
JSTypedArray);
// 3. If argumentList is a List of a single Number, then
// If newTypedArray.[[ArrayLength]] < size, throw a TypeError exception.
DCHECK_IMPLIES(argc == 1, argv[0]->IsSmi());
if (argc == 1 && new_array->length_value() < argv[0]->Number()) {
const MessageTemplate::Template message =
MessageTemplate::kTypedArrayTooShort;
THROW_NEW_ERROR(isolate, NewTypeError(message), JSTypedArray);
}
// 4. Return newTypedArray.
return new_array;
}
// ES7 section 22.2.4.7 TypedArraySpeciesCreate ( exemplar, argumentList )
MaybeHandle<JSTypedArray> TypedArraySpeciesCreate(Isolate* isolate,
Handle<JSTypedArray> exemplar,
int argc,
Handle<Object>* argv,
const char* method_name) {
// 1. Assert: exemplar is an Object that has a [[TypedArrayName]] internal
// slot.
DCHECK(exemplar->IsJSTypedArray());
// 2. Let defaultConstructor be the intrinsic object listed in column one of
// Table 51 for exemplar.[[TypedArrayName]].
Handle<JSFunction> default_ctor = isolate->uint8_array_fun();
switch (exemplar->type()) {
#define TYPED_ARRAY_CTOR(Type, type, TYPE, ctype, size) \
case kExternal##Type##Array: { \
default_ctor = isolate->type##_array_fun(); \
break; \
}
TYPED_ARRAYS(TYPED_ARRAY_CTOR)
#undef TYPED_ARRAY_CTOR
default:
UNREACHABLE();
}
// 3. Let constructor be ? SpeciesConstructor(exemplar, defaultConstructor).
Handle<Object> ctor;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, ctor,
Object::SpeciesConstructor(isolate, exemplar, default_ctor),
JSTypedArray);
// 4. Return ? TypedArrayCreate(constructor, argumentList).
return TypedArrayCreate(isolate, Handle<JSFunction>::cast(ctor), argc, argv,
method_name);
}
MaybeHandle<JSTypedArray> TypedArraySpeciesCreateByLength(
Isolate* isolate, Handle<JSTypedArray> exemplar, const char* method_name,
int64_t length) {
const int argc = 1;
ScopedVector<Handle<Object>> argv(argc);
argv[0] = isolate->factory()->NewNumberFromInt64(length);
return TypedArraySpeciesCreate(isolate, exemplar, argc, argv.start(),
method_name);
return JSTypedArray::SpeciesCreate(isolate, exemplar, argc, argv.start(),
method_name);
}
} // namespace
......
......@@ -8969,6 +8969,15 @@ Node* CodeStubAssembler::AllocateJSArrayIterator(Node* array, Node* array_map,
return iterator;
}
Node* CodeStubAssembler::TypedArraySpeciesCreateByLength(Node* context,
Node* originalArray,
Node* len) {
// TODO(tebbi): Install a fast path as well, which avoids the runtime
// call.
return CallRuntime(Runtime::kTypedArraySpeciesCreateByLength, context,
UndefinedConstant(), originalArray, len);
}
Node* CodeStubAssembler::IsDetachedBuffer(Node* buffer) {
CSA_ASSERT(this, HasInstanceType(buffer, JS_ARRAY_BUFFER_TYPE));
......
......@@ -621,6 +621,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* AllocateJSArrayIterator(Node* array, Node* array_map, Node* map);
Node* TypedArraySpeciesCreateByLength(Node* context, Node* originalArray,
Node* len);
void FillFixedArrayWithValue(ElementsKind kind, Node* array, Node* from_index,
Node* to_index,
Heap::RootListIndex value_root_index,
......
......@@ -17193,6 +17193,70 @@ size_t JSTypedArray::element_size() {
}
}
// static
MaybeHandle<JSTypedArray> JSTypedArray::Create(Isolate* isolate,
Handle<JSFunction> default_ctor,
int argc, Handle<Object>* argv,
const char* method_name) {
// 1. Let newTypedArray be ? Construct(constructor, argumentList).
Handle<Object> new_obj;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, new_obj, Execution::New(default_ctor, argc, argv), JSTypedArray);
// 2. Perform ? ValidateTypedArray(newTypedArray).
Handle<JSTypedArray> new_array;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, new_array, JSTypedArray::Validate(isolate, new_obj, method_name),
JSTypedArray);
// 3. If argumentList is a List of a single Number, then
// If newTypedArray.[[ArrayLength]] < size, throw a TypeError exception.
DCHECK_IMPLIES(argc == 1, argv[0]->IsSmi());
if (argc == 1 && new_array->length_value() < argv[0]->Number()) {
const MessageTemplate::Template message =
MessageTemplate::kTypedArrayTooShort;
THROW_NEW_ERROR(isolate, NewTypeError(message), JSTypedArray);
}
// 4. Return newTypedArray.
return new_array;
}
// static
MaybeHandle<JSTypedArray> JSTypedArray::SpeciesCreate(
Isolate* isolate, Handle<JSTypedArray> exemplar, int argc,
Handle<Object>* argv, const char* method_name) {
// 1. Assert: exemplar is an Object that has a [[TypedArrayName]] internal
// slot.
DCHECK(exemplar->IsJSTypedArray());
// 2. Let defaultConstructor be the intrinsic object listed in column one of
// Table 51 for exemplar.[[TypedArrayName]].
Handle<JSFunction> default_ctor = isolate->uint8_array_fun();
switch (exemplar->type()) {
#define TYPED_ARRAY_CTOR(Type, type, TYPE, ctype, size) \
case kExternal##Type##Array: { \
default_ctor = isolate->type##_array_fun(); \
break; \
}
TYPED_ARRAYS(TYPED_ARRAY_CTOR)
#undef TYPED_ARRAY_CTOR
default:
UNREACHABLE();
}
// 3. Let constructor be ? SpeciesConstructor(exemplar, defaultConstructor).
Handle<Object> ctor;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, ctor,
Object::SpeciesConstructor(isolate, exemplar, default_ctor),
JSTypedArray);
// 4. Return ? TypedArrayCreate(constructor, argumentList).
return Create(isolate, Handle<JSFunction>::cast(ctor), argc, argv,
method_name);
}
void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
Handle<Name> name) {
......
......@@ -8631,6 +8631,16 @@ class JSTypedArray: public JSArrayBufferView {
static inline MaybeHandle<JSTypedArray> Validate(Isolate* isolate,
Handle<Object> receiver,
const char* method_name);
// ES7 section 22.2.4.6 Create ( constructor, argumentList )
static MaybeHandle<JSTypedArray> Create(Isolate* isolate,
Handle<JSFunction> default_ctor,
int argc, Handle<Object>* argv,
const char* method_name);
// ES7 section 22.2.4.7 TypedArraySpeciesCreate ( exemplar, argumentList )
static MaybeHandle<JSTypedArray> SpeciesCreate(Isolate* isolate,
Handle<JSTypedArray> exemplar,
int argc, Handle<Object>* argv,
const char* method_name);
// Dispatched behavior.
DECLARE_PRINTER(JSTypedArray)
......
......@@ -281,5 +281,21 @@ RUNTIME_FUNCTION(Runtime_IsSharedInteger32TypedArray) {
obj->type() == kExternalInt32Array);
}
RUNTIME_FUNCTION(Runtime_TypedArraySpeciesCreateByLength) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
Handle<JSTypedArray> exemplar = args.at<JSTypedArray>(1);
Handle<Object> length = args.at(2);
int argc = 1;
ScopedVector<Handle<Object>> argv(argc);
argv[0] = length;
Handle<JSTypedArray> result_array;
// TODO(tebbi): Pass correct method name.
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result_array,
JSTypedArray::SpeciesCreate(isolate, exemplar, argc, argv.start(), ""));
return *result_array;
}
} // namespace internal
} // namespace v8
......@@ -649,7 +649,8 @@ namespace internal {
F(IsTypedArray, 1, 1) \
F(IsSharedTypedArray, 1, 1) \
F(IsSharedIntegerTypedArray, 1, 1) \
F(IsSharedInteger32TypedArray, 1, 1)
F(IsSharedInteger32TypedArray, 1, 1) \
F(TypedArraySpeciesCreateByLength, 2, 1)
#define FOR_EACH_INTRINSIC_WASM(F) \
F(WasmGrowMemory, 1, 1) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment