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

[builtins] Implement %TypedArray%.prototype.{some,every} in the CSA

R=mvstanton@chromium.org,danno@chromium.org

Review-Url: https://codereview.chromium.org/2775203002
Cr-Commit-Position: refs/heads/master@{#44274}
parent e8034487
......@@ -216,7 +216,7 @@ class Genesis BASE_EMBEDDED {
HARMONY_SHIPPING(DECLARE_FEATURE_INITIALIZATION)
#undef DECLARE_FEATURE_INITIALIZATION
void InstallOneBuiltinFunction(const char* object, const char* method,
void InstallOneBuiltinFunction(Handle<Object> prototype, const char* method,
Builtins::Name name);
void InitializeGlobal_experimental_fast_array_builtins();
......@@ -3827,35 +3827,38 @@ void InstallPublicSymbol(Factory* factory, Handle<Context> native_context,
JSObject::AddProperty(symbol, name_string, value, attributes);
}
void Genesis::InstallOneBuiltinFunction(const char* object_name,
void Genesis::InstallOneBuiltinFunction(Handle<Object> prototype,
const char* method_name,
Builtins::Name builtin_name) {
Handle<JSGlobalObject> global(native_context()->global_object());
Isolate* isolate = global->GetIsolate();
Factory* factory = isolate->factory();
LookupIterator it1(global, factory->NewStringFromAsciiChecked(object_name),
LookupIterator::OWN_SKIP_INTERCEPTOR);
Handle<Object> object = Object::GetProperty(&it1).ToHandleChecked();
LookupIterator it2(object, factory->NewStringFromAsciiChecked("prototype"),
LookupIterator::OWN_SKIP_INTERCEPTOR);
Handle<Object> prototype = Object::GetProperty(&it2).ToHandleChecked();
LookupIterator it3(prototype, factory->NewStringFromAsciiChecked(method_name),
LookupIterator::OWN_SKIP_INTERCEPTOR);
Handle<Object> function = Object::GetProperty(&it3).ToHandleChecked();
LookupIterator it(
prototype, isolate()->factory()->NewStringFromAsciiChecked(method_name),
LookupIterator::OWN_SKIP_INTERCEPTOR);
Handle<Object> function = Object::GetProperty(&it).ToHandleChecked();
Handle<JSFunction>::cast(function)->set_code(
isolate->builtins()->builtin(builtin_name));
isolate()->builtins()->builtin(builtin_name));
Handle<JSFunction>::cast(function)->shared()->set_code(
isolate->builtins()->builtin(builtin_name));
isolate()->builtins()->builtin(builtin_name));
}
void Genesis::InitializeGlobal_experimental_fast_array_builtins() {
if (!FLAG_experimental_fast_array_builtins) return;
// Insert experimental fast array builtins here.
InstallOneBuiltinFunction("Array", "filter", Builtins::kArrayFilter);
InstallOneBuiltinFunction("Array", "map", Builtins::kArrayMap);
{
Handle<JSFunction> array_constructor(native_context()->array_function());
Handle<Object> array_prototype(array_constructor->prototype(), isolate());
// Insert experimental fast Array builtins here.
InstallOneBuiltinFunction(array_prototype, "filter",
Builtins::kArrayFilter);
InstallOneBuiltinFunction(array_prototype, "map", Builtins::kArrayMap);
}
{
Handle<Object> typed_array_prototype(
native_context()->typed_array_prototype(), isolate());
// Insert experimental fast TypedArray builtins here.
InstallOneBuiltinFunction(typed_array_prototype, "every",
Builtins::kTypedArrayPrototypeEvery);
InstallOneBuiltinFunction(typed_array_prototype, "some",
Builtins::kTypedArrayPrototypeSome);
}
}
void Genesis::InitializeGlobal_harmony_sharedarraybuffer() {
......
......@@ -295,6 +295,97 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
to_.Bind(to);
}
void GenerateIteratingTypedArrayBuiltinBody(
const char* name, const BuiltinResultGenerator& generator,
const CallResultProcessor& processor, const PostLoopAction& action) {
Node* name_string =
HeapConstant(isolate()->factory()->NewStringFromAsciiChecked(name));
// ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray
Label throw_not_typed_array(this, Label::kDeferred),
throw_detached(this, Label::kDeferred);
GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array);
GotoIfNot(HasInstanceType(receiver_, JS_TYPED_ARRAY_TYPE),
&throw_not_typed_array);
o_ = receiver_;
Node* array_buffer = LoadObjectField(o_, JSTypedArray::kBufferOffset);
GotoIf(IsDetachedBuffer(array_buffer), &throw_detached);
len_ = LoadObjectField(o_, JSTypedArray::kLengthOffset);
Label throw_not_callable(this, Label::kDeferred);
Label distinguish_types(this);
GotoIf(TaggedIsSmi(callbackfn_), &throw_not_callable);
Branch(IsCallableMap(LoadMap(callbackfn_)), &distinguish_types,
&throw_not_callable);
Bind(&throw_not_typed_array);
{
CallRuntime(Runtime::kThrowTypeError, context_,
SmiConstant(MessageTemplate::kNotTypedArray));
Unreachable();
}
Bind(&throw_detached);
{
CallRuntime(Runtime::kThrowTypeError, context_,
SmiConstant(MessageTemplate::kDetachedOperation),
name_string);
Unreachable();
}
Bind(&throw_not_callable);
{
CallRuntime(Runtime::kThrowTypeError, context_,
SmiConstant(MessageTemplate::kCalledNonCallable),
callbackfn_);
Unreachable();
}
Label unexpected_instance_type(this);
Bind(&unexpected_instance_type);
Unreachable();
std::vector<int32_t> instance_types = {
#define INSTANCE_TYPE(Type, type, TYPE, ctype, size) FIXED_##TYPE##_ARRAY_TYPE,
TYPED_ARRAYS(INSTANCE_TYPE)
#undef INSTANCE_TYPE
};
std::vector<Label> labels;
for (size_t i = 0; i < instance_types.size(); ++i) {
labels.push_back(Label(this));
}
std::vector<Label*> label_ptrs;
for (Label& label : labels) {
label_ptrs.push_back(&label);
}
Bind(&distinguish_types);
a_.Bind(generator(this));
Node* elements_type = LoadInstanceType(LoadElements(o_));
Switch(elements_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);
// 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);
Goto(&done);
action(this);
// No exception, return success
Bind(&done);
Return(a_.value());
}
}
void GenerateIteratingArrayBuiltinLoopContinuation(
const CallResultProcessor& processor, const PostLoopAction& action,
ForEachDirection direction = ForEachDirection::kForward) {
......@@ -350,6 +441,44 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
}
private:
static ElementsKind ElementsKindForInstanceType(InstanceType type) {
switch (type) {
#define INSTANCE_TYPE_TO_ELEMENTS_KIND(Type, type, TYPE, ctype, size) \
case FIXED_##TYPE##_ARRAY_TYPE: \
return TYPE##_ELEMENTS;
TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENTS_KIND)
#undef INSTANCE_TYPE_TO_ELEMENTS_KIND
default:
UNREACHABLE();
return static_cast<ElementsKind>(-1);
}
}
void VisitAllTypedArrayElements(ElementsKind kind, Node* array_buffer,
const CallResultProcessor& processor,
Label* detached) {
VariableList list({&a_, &k_, &to_}, zone());
FastLoopBody body = [&](Node* index) {
GotoIf(IsDetachedBuffer(array_buffer), detached);
Node* elements = LoadElements(o_);
Node* base_ptr =
LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
Node* external_ptr =
LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
MachineType::Pointer());
Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr);
Node* value = LoadFixedTypedArrayElementAsTagged(data_ptr, index, kind,
SMI_PARAMETERS);
k_.Bind(index);
a_.Bind(processor(this, value, index));
};
BuildFastLoop(list, SmiConstant(0), len_, body, 1,
ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost);
}
void VisitAllFastElementsOneKind(ElementsKind kind,
const CallResultProcessor& processor,
Label* array_changed, ParameterMode mode,
......@@ -709,6 +838,23 @@ TF_BUILTIN(ArraySome, ArrayBuiltinCodeStubAssembler) {
CodeFactory::ArraySomeLoopContinuation(isolate()));
}
TF_BUILTIN(TypedArrayPrototypeSome, 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.some",
&ArrayBuiltinCodeStubAssembler::SomeResultGenerator,
&ArrayBuiltinCodeStubAssembler::SomeProcessor,
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
}
TF_BUILTIN(ArrayEveryLoopContinuation, ArrayBuiltinCodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
Node* receiver = Parameter(Descriptor::kReceiver);
......@@ -747,6 +893,23 @@ TF_BUILTIN(ArrayEvery, ArrayBuiltinCodeStubAssembler) {
CodeFactory::ArrayEveryLoopContinuation(isolate()));
}
TF_BUILTIN(TypedArrayPrototypeEvery, 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.every",
&ArrayBuiltinCodeStubAssembler::EveryResultGenerator,
&ArrayBuiltinCodeStubAssembler::EveryProcessor,
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
}
TF_BUILTIN(ArrayReduceLoopContinuation, ArrayBuiltinCodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
Node* receiver = Parameter(Descriptor::kReceiver);
......
......@@ -889,6 +889,10 @@ namespace internal {
CPP(TypedArrayPrototypeLastIndexOf) \
/* ES6 #sec-%typedarray%.prototype.reverse */ \
CPP(TypedArrayPrototypeReverse) \
/* ES6 %TypedArray%.prototype.every */ \
TFJ(TypedArrayPrototypeEvery, 2, kCallbackFn, kThisArg) \
/* ES6 %TypedArray%.prototype.some */ \
TFJ(TypedArrayPrototypeSome, 2, kCallbackFn, kThisArg) \
\
/* Wasm */ \
ASM(WasmCompileLazy) \
......
......@@ -1241,6 +1241,32 @@ Node* CodeStubAssembler::LoadFixedTypedArrayElement(
return Load(type, data_pointer, offset);
}
Node* CodeStubAssembler::LoadFixedTypedArrayElementAsTagged(
Node* data_pointer, Node* index_node, ElementsKind elements_kind,
ParameterMode parameter_mode) {
Node* value = LoadFixedTypedArrayElement(data_pointer, index_node,
elements_kind, parameter_mode);
switch (elements_kind) {
case ElementsKind::INT8_ELEMENTS:
case ElementsKind::UINT8_CLAMPED_ELEMENTS:
case ElementsKind::UINT8_ELEMENTS:
case ElementsKind::INT16_ELEMENTS:
case ElementsKind::UINT16_ELEMENTS:
return SmiFromWord32(value);
case ElementsKind::INT32_ELEMENTS:
return ChangeInt32ToTagged(value);
case ElementsKind::UINT32_ELEMENTS:
return ChangeUint32ToTagged(value);
case ElementsKind::FLOAT32_ELEMENTS:
return AllocateHeapNumberWithValue(ChangeFloat32ToFloat64(value));
case ElementsKind::FLOAT64_ELEMENTS:
return AllocateHeapNumberWithValue(value);
default:
UNREACHABLE();
return nullptr;
}
}
Node* CodeStubAssembler::LoadAndUntagToWord32FixedArrayElement(
Node* object, Node* index_node, int additional_offset,
ParameterMode parameter_mode) {
......
......@@ -447,6 +447,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* LoadFixedTypedArrayElement(
Node* data_pointer, Node* index_node, ElementsKind elements_kind,
ParameterMode parameter_mode = INTPTR_PARAMETERS);
Node* LoadFixedTypedArrayElementAsTagged(
Node* data_pointer, Node* index_node, ElementsKind elements_kind,
ParameterMode parameter_mode = INTPTR_PARAMETERS);
// Context manipulation
Node* LoadContextElement(Node* context, int slot_index);
......
......@@ -98,6 +98,20 @@ function TestTypedArrayForEach(constructor) {
CheckTypedArrayIsNeutered(a);
assertEquals(undefined, a[0]);
// Calling array.buffer midway can change the backing store.
a = new constructor(5);
a[0] = 42;
result = a.every(function (n, index, array) {
assertSame(a, array);
if (index == 2) {
(new constructor(array.buffer))[(index + 1) % 5] = 42;
} else {
a[(index+1)%5] = 42
}
return n == 42;
});
assertEquals(true, result);
// The method must work for typed arrays created from ArrayBuffer.
// The length of the ArrayBuffer is chosen so it is a multiple of
// all lengths of the typed array items.
......
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