[typedarray] Migrate %TypedArray%.of to CSA
- Remove %TypedArray%.of in js/typedarray.js - Implement %TypedArray%.of in builtins/builtins-typedarray-gen.cc - This CL makes TA.of 1.5x faster Bug: v8:5929 Change-Id: Ie165114a0ab9b4ec9ed70840c4c6a42d1eeed101 Reviewed-on: https://chromium-review.googlesource.com/897227 Commit-Queue: Peter Marshall <petermarshall@chromium.org> Reviewed-by: Peter Marshall <petermarshall@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#51141}
This commit is contained in:
parent
f4e42f9d31
commit
756c8c4e1b
@ -3004,6 +3004,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
|||||||
InstallSpeciesGetter(typed_array_fun);
|
InstallSpeciesGetter(typed_array_fun);
|
||||||
native_context()->set_typed_array_function(*typed_array_fun);
|
native_context()->set_typed_array_function(*typed_array_fun);
|
||||||
|
|
||||||
|
SimpleInstallFunction(typed_array_fun, "of", Builtins::kTypedArrayOf, 0,
|
||||||
|
false);
|
||||||
|
|
||||||
// Setup %TypedArrayPrototype%.
|
// Setup %TypedArrayPrototype%.
|
||||||
Handle<JSObject> prototype(
|
Handle<JSObject> prototype(
|
||||||
JSObject::cast(typed_array_fun->instance_prototype()));
|
JSObject::cast(typed_array_fun->instance_prototype()));
|
||||||
|
@ -1125,6 +1125,8 @@ namespace internal {
|
|||||||
/* ES6 %TypedArray%.prototype.forEach */ \
|
/* ES6 %TypedArray%.prototype.forEach */ \
|
||||||
TFJ(TypedArrayPrototypeForEach, \
|
TFJ(TypedArrayPrototypeForEach, \
|
||||||
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||||
|
/* ES6 %TypedArray%.of */ \
|
||||||
|
TFJ(TypedArrayOf, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||||
\
|
\
|
||||||
/* Wasm */ \
|
/* Wasm */ \
|
||||||
ASM(WasmCompileLazy) \
|
ASM(WasmCompileLazy) \
|
||||||
|
@ -926,6 +926,12 @@ TNode<JSTypedArray> TypedArrayBuiltinsAssembler::SpeciesCreateByLength(
|
|||||||
TNode<Object> constructor = TypedArraySpeciesConstructor(context, exemplar);
|
TNode<Object> constructor = TypedArraySpeciesConstructor(context, exemplar);
|
||||||
CSA_ASSERT(this, IsJSFunction(constructor));
|
CSA_ASSERT(this, IsJSFunction(constructor));
|
||||||
|
|
||||||
|
return CreateByLength(context, constructor, len, method_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
TNode<JSTypedArray> TypedArrayBuiltinsAssembler::CreateByLength(
|
||||||
|
TNode<Context> context, TNode<Object> constructor, TNode<Smi> len,
|
||||||
|
const char* method_name) {
|
||||||
// Let newTypedArray be ? Construct(constructor, argumentList).
|
// Let newTypedArray be ? Construct(constructor, argumentList).
|
||||||
TNode<Object> new_object = CAST(ConstructJS(CodeFactory::Construct(isolate()),
|
TNode<Object> new_object = CAST(ConstructJS(CodeFactory::Construct(isolate()),
|
||||||
context, constructor, len));
|
context, constructor, len));
|
||||||
@ -1544,6 +1550,89 @@ TF_BUILTIN(TypedArrayPrototypeKeys, TypedArrayBuiltinsAssembler) {
|
|||||||
context, receiver, "%TypedArray%.prototype.keys()", IterationKind::kKeys);
|
context, receiver, "%TypedArray%.prototype.keys()", IterationKind::kKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TypedArrayBuiltinsAssembler::DebugSanityCheckTypedArrayIndex(
|
||||||
|
TNode<JSTypedArray> array, SloppyTNode<Smi> index) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
TNode<JSArrayBuffer> buffer =
|
||||||
|
LoadObjectField<JSArrayBuffer>(array, JSArrayBufferView::kBufferOffset);
|
||||||
|
CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(buffer)));
|
||||||
|
TNode<Smi> array_length =
|
||||||
|
LoadObjectField<Smi>(array, JSTypedArray::kLengthOffset);
|
||||||
|
CSA_ASSERT(this, SmiLessThan(index, array_length));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// ES6 #sec-%typedarray%.of
|
||||||
|
TF_BUILTIN(TypedArrayOf, TypedArrayBuiltinsAssembler) {
|
||||||
|
TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
|
||||||
|
|
||||||
|
// 1. Let len be the actual number of arguments passed to this function.
|
||||||
|
TNode<Int32T> argc =
|
||||||
|
UncheckedCast<Int32T>(Parameter(BuiltinDescriptor::kArgumentsCount));
|
||||||
|
TNode<Smi> length = SmiFromWord32(argc);
|
||||||
|
// 2. Let items be the List of arguments passed to this function.
|
||||||
|
CodeStubArguments args(this, length, nullptr, ParameterMode::SMI_PARAMETERS,
|
||||||
|
CodeStubArguments::ReceiverMode::kHasReceiver);
|
||||||
|
|
||||||
|
Label if_not_constructor(this, Label::kDeferred),
|
||||||
|
unreachable(this, Label::kDeferred);
|
||||||
|
|
||||||
|
// 3. Let C be the this value.
|
||||||
|
// 4. If IsConstructor(C) is false, throw a TypeError exception.
|
||||||
|
TNode<Object> receiver = args.GetReceiver();
|
||||||
|
GotoIf(TaggedIsSmi(receiver), &if_not_constructor);
|
||||||
|
GotoIfNot(IsConstructor(receiver), &if_not_constructor);
|
||||||
|
|
||||||
|
// 5. Let newObj be ? TypedArrayCreate(C, len).
|
||||||
|
TNode<JSTypedArray> new_typed_array =
|
||||||
|
CreateByLength(context, receiver, length, "%TypedArray%.of");
|
||||||
|
|
||||||
|
TNode<Word32T> elements_kind = LoadElementsKind(new_typed_array);
|
||||||
|
|
||||||
|
// 6. Let k be 0.
|
||||||
|
// 7. Repeat, while k < len
|
||||||
|
// a. Let kValue be items[k].
|
||||||
|
// b. Let Pk be ! ToString(k).
|
||||||
|
// c. Perform ? Set(newObj, Pk, kValue, true).
|
||||||
|
// d. Increase k by 1.
|
||||||
|
DispatchTypedArrayByElementsKind(
|
||||||
|
elements_kind,
|
||||||
|
[&](ElementsKind kind, int size, int typed_array_fun_index) {
|
||||||
|
BuildFastLoop(
|
||||||
|
SmiConstant(0), length,
|
||||||
|
[&](Node* index) {
|
||||||
|
TNode<Object> item =
|
||||||
|
args.AtIndex(index, ParameterMode::SMI_PARAMETERS);
|
||||||
|
TNode<Number> number = ToNumber_Inline(context, item);
|
||||||
|
|
||||||
|
// ToNumber may execute JavaScript code, but it cannot access
|
||||||
|
// arguments array and new typed array.
|
||||||
|
DebugSanityCheckTypedArrayIndex(new_typed_array, index);
|
||||||
|
|
||||||
|
// Since we can guarantee that "number" is Number type,
|
||||||
|
// PrepareValueForWriteToTypedArray cannot bail out.
|
||||||
|
Node* value =
|
||||||
|
PrepareValueForWriteToTypedArray(number, kind, &unreachable);
|
||||||
|
|
||||||
|
// GC may move backing store in ToNumber, thus load backing store
|
||||||
|
// everytime in this loop.
|
||||||
|
TNode<IntPtrT> backing_store =
|
||||||
|
UncheckedCast<IntPtrT>(LoadDataPtr(new_typed_array));
|
||||||
|
StoreElement(backing_store, kind, index, value, SMI_PARAMETERS);
|
||||||
|
},
|
||||||
|
1, ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 8. Return newObj.
|
||||||
|
args.PopAndReturn(new_typed_array);
|
||||||
|
|
||||||
|
BIND(&unreachable);
|
||||||
|
Unreachable();
|
||||||
|
|
||||||
|
BIND(&if_not_constructor);
|
||||||
|
ThrowTypeError(context, MessageTemplate::kNotConstructor, receiver);
|
||||||
|
}
|
||||||
|
|
||||||
#undef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
|
#undef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
@ -80,6 +80,10 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
|
|||||||
TNode<Smi> len,
|
TNode<Smi> len,
|
||||||
const char* method_name);
|
const char* method_name);
|
||||||
|
|
||||||
|
TNode<JSTypedArray> CreateByLength(TNode<Context> context,
|
||||||
|
TNode<Object> constructor, TNode<Smi> len,
|
||||||
|
const char* method_name);
|
||||||
|
|
||||||
TNode<JSArrayBuffer> GetBuffer(TNode<Context> context,
|
TNode<JSArrayBuffer> GetBuffer(TNode<Context> context,
|
||||||
TNode<JSTypedArray> array);
|
TNode<JSTypedArray> array);
|
||||||
|
|
||||||
@ -113,6 +117,9 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
|
|||||||
|
|
||||||
void DispatchTypedArrayByElementsKind(
|
void DispatchTypedArrayByElementsKind(
|
||||||
TNode<Word32T> elements_kind, const TypedArraySwitchCase& case_function);
|
TNode<Word32T> elements_kind, const TypedArraySwitchCase& case_function);
|
||||||
|
|
||||||
|
void DebugSanityCheckTypedArrayIndex(TNode<JSTypedArray> array,
|
||||||
|
SloppyTNode<Smi> index);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
@ -5611,6 +5611,30 @@ TNode<Numeric> CodeStubAssembler::NonNumberToNumeric(
|
|||||||
return UncheckedCast<Numeric>(result);
|
return UncheckedCast<Numeric>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TNode<Number> CodeStubAssembler::ToNumber_Inline(TNode<Context> context,
|
||||||
|
TNode<Object> input) {
|
||||||
|
TVARIABLE(Number, var_result);
|
||||||
|
Label end(this), not_smi(this, Label::kDeferred);
|
||||||
|
|
||||||
|
GotoIfNot(TaggedIsSmi(input), ¬_smi);
|
||||||
|
var_result = CAST(input);
|
||||||
|
Goto(&end);
|
||||||
|
|
||||||
|
BIND(¬_smi);
|
||||||
|
{
|
||||||
|
var_result = Select<Number>(
|
||||||
|
IsHeapNumber(input), [=] { return CAST(input); },
|
||||||
|
[=] {
|
||||||
|
return CallBuiltin(Builtins::kNonNumberToNumeric, context, input);
|
||||||
|
},
|
||||||
|
MachineRepresentation::kTagged);
|
||||||
|
Goto(&end);
|
||||||
|
}
|
||||||
|
|
||||||
|
BIND(&end);
|
||||||
|
return var_result;
|
||||||
|
}
|
||||||
|
|
||||||
TNode<Number> CodeStubAssembler::ToNumber(SloppyTNode<Context> context,
|
TNode<Number> CodeStubAssembler::ToNumber(SloppyTNode<Context> context,
|
||||||
SloppyTNode<Object> input,
|
SloppyTNode<Object> input,
|
||||||
BigIntHandling bigint_handling) {
|
BigIntHandling bigint_handling) {
|
||||||
|
@ -1240,6 +1240,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
|||||||
TNode<Number> ToNumber(
|
TNode<Number> ToNumber(
|
||||||
SloppyTNode<Context> context, SloppyTNode<Object> input,
|
SloppyTNode<Context> context, SloppyTNode<Object> input,
|
||||||
BigIntHandling bigint_handling = BigIntHandling::kThrow);
|
BigIntHandling bigint_handling = BigIntHandling::kThrow);
|
||||||
|
TNode<Number> ToNumber_Inline(TNode<Context> context, TNode<Object> input);
|
||||||
|
|
||||||
// Converts |input| to one of 2^32 integer values in the range 0 through
|
// Converts |input| to one of 2^32 integer values in the range 0 through
|
||||||
// 2^32-1, inclusive.
|
// 2^32-1, inclusive.
|
||||||
|
@ -203,20 +203,6 @@ DEFINE_METHOD(
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// ES6 draft 08-24-14, section 22.2.2.2
|
|
||||||
DEFINE_METHOD(
|
|
||||||
GlobalTypedArray,
|
|
||||||
of() {
|
|
||||||
var length = arguments.length;
|
|
||||||
var array = TypedArrayCreate(this, length);
|
|
||||||
for (var i = 0; i < length; i++) {
|
|
||||||
array[i] = arguments[i];
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// ES#sec-iterabletoarraylike Runtime Semantics: IterableToArrayLike( items )
|
// ES#sec-iterabletoarraylike Runtime Semantics: IterableToArrayLike( items )
|
||||||
function IterableToArrayLike(items) {
|
function IterableToArrayLike(items) {
|
||||||
var iterable = GetMethod(items, iteratorSymbol);
|
var iterable = GetMethod(items, iteratorSymbol);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
//
|
||||||
|
// Flags: --expose-gc
|
||||||
|
|
||||||
// Based on Mozilla Array.of() tests at http://dxr.mozilla.org/mozilla-central/source/js/src/jit-test/tests/collections
|
// Based on Mozilla Array.of() tests at http://dxr.mozilla.org/mozilla-central/source/js/src/jit-test/tests/collections
|
||||||
|
|
||||||
@ -130,6 +132,20 @@ function TestTypedArrayOf(constructor) {
|
|||||||
for (var x of [undefined, null, false, true, "cow", 42, 3.14]) {
|
for (var x of [undefined, null, false, true, "cow", 42, 3.14]) {
|
||||||
assertThrows(function () { constructor.of.call(x); }, TypeError);
|
assertThrows(function () { constructor.of.call(x); }, TypeError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if it's correctly accessing new typed array elements even after
|
||||||
|
// garbage collection is invoked in ToNumber.
|
||||||
|
var not_number = {
|
||||||
|
[Symbol.toPrimitive]() {
|
||||||
|
gc();
|
||||||
|
return 123;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var dangerous_array = new Array(64).fill(not_number);
|
||||||
|
var a = constructor.of(...dangerous_array);
|
||||||
|
for (var i = 0; i < 64; i++) {
|
||||||
|
assertEquals(123, a[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var constructor of typedArrayConstructors) {
|
for (var constructor of typedArrayConstructors) {
|
||||||
|
Loading…
Reference in New Issue
Block a user