Commit 756c8c4e authored by Choongwoo Han's avatar Choongwoo Han Committed by Commit Bot

[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: 's avatarPeter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51141}
parent f4e42f9d
......@@ -3004,6 +3004,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
InstallSpeciesGetter(typed_array_fun);
native_context()->set_typed_array_function(*typed_array_fun);
SimpleInstallFunction(typed_array_fun, "of", Builtins::kTypedArrayOf, 0,
false);
// Setup %TypedArrayPrototype%.
Handle<JSObject> prototype(
JSObject::cast(typed_array_fun->instance_prototype()));
......
......@@ -1125,6 +1125,8 @@ namespace internal {
/* ES6 %TypedArray%.prototype.forEach */ \
TFJ(TypedArrayPrototypeForEach, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 %TypedArray%.of */ \
TFJ(TypedArrayOf, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
\
/* Wasm */ \
ASM(WasmCompileLazy) \
......
......@@ -926,6 +926,12 @@ TNode<JSTypedArray> TypedArrayBuiltinsAssembler::SpeciesCreateByLength(
TNode<Object> constructor = TypedArraySpeciesConstructor(context, exemplar);
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).
TNode<Object> new_object = CAST(ConstructJS(CodeFactory::Construct(isolate()),
context, constructor, len));
......@@ -1544,6 +1550,89 @@ TF_BUILTIN(TypedArrayPrototypeKeys, TypedArrayBuiltinsAssembler) {
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
} // namespace internal
......
......@@ -80,6 +80,10 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
TNode<Smi> len,
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<JSTypedArray> array);
......@@ -113,6 +117,9 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
void DispatchTypedArrayByElementsKind(
TNode<Word32T> elements_kind, const TypedArraySwitchCase& case_function);
void DebugSanityCheckTypedArrayIndex(TNode<JSTypedArray> array,
SloppyTNode<Smi> index);
};
} // namespace internal
......
......@@ -5611,6 +5611,30 @@ TNode<Numeric> CodeStubAssembler::NonNumberToNumeric(
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), &not_smi);
var_result = CAST(input);
Goto(&end);
BIND(&not_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,
SloppyTNode<Object> input,
BigIntHandling bigint_handling) {
......
......@@ -1240,6 +1240,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
TNode<Number> ToNumber(
SloppyTNode<Context> context, SloppyTNode<Object> input,
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
// 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 )
function IterableToArrayLike(items) {
var iterable = GetMethod(items, iteratorSymbol);
......
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// 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
......@@ -130,6 +132,20 @@ function TestTypedArrayOf(constructor) {
for (var x of [undefined, null, false, true, "cow", 42, 3.14]) {
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) {
......
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