Commit b0a5217f authored by peterwmwong's avatar peterwmwong Committed by Commit Bot

[builtins] Port TypedArray CreateTypedArray to Torque

This is part of an effort to improve the performance of TA#subarray.

Bug: v8:7161
Change-Id: Iffd469ca6528710c28cc454604a725ca9748359d
Reviewed-on: https://chromium-review.googlesource.com/c/1435768
Commit-Queue: Peter Wong <peter.wm.wong@gmail.com>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59105}
parent 2e3fca43
......@@ -291,6 +291,8 @@ const kInvalidOffset: constexpr MessageTemplate
generates 'MessageTemplate::kInvalidOffset';
const kInvalidTypedArrayLength: constexpr MessageTemplate
generates 'MessageTemplate::kInvalidTypedArrayLength';
const kIteratorSymbolNonCallable: constexpr MessageTemplate
generates 'MessageTemplate::kIteratorSymbolNonCallable';
const kIteratorValueNotAnObject: constexpr MessageTemplate
generates 'MessageTemplate::kIteratorValueNotAnObject';
const kNotIterable: constexpr MessageTemplate
......@@ -635,6 +637,8 @@ extern macro IsValidPositiveSmi(intptr): bool;
extern macro HeapObjectToJSDataView(HeapObject): JSDataView
labels CastError;
extern macro HeapObjectToJSArrayBuffer(HeapObject): JSArrayBuffer
labels CastError;
extern macro HeapObjectToJSTypedArray(HeapObject): JSTypedArray
labels CastError;
extern macro TaggedToHeapObject(Object): HeapObject
......@@ -707,6 +711,11 @@ CastHeapObject<JSArray>(o: HeapObject): JSArray
return HeapObjectToJSArray(o) otherwise CastError;
}
CastHeapObject<JSArrayBuffer>(o: HeapObject): JSArrayBuffer
labels CastError {
return HeapObjectToJSArrayBuffer(o) otherwise CastError;
}
CastHeapObject<Context>(o: HeapObject): Context
labels CastError {
if (IsContext(o)) return %RawDownCast<Context>(o);
......@@ -1128,6 +1137,10 @@ TypedArrayBuiltinsAssembler::LoadTypedArrayBuffer(JSTypedArray): JSArrayBuffer;
extern operator '.data_ptr' macro TypedArrayBuiltinsAssembler::LoadDataPtr(
JSTypedArray): RawPtr;
extern operator '.byte_length' macro LoadByteLength(JSArrayBuffer): uintptr;
extern operator '.byte_length=' macro StoreByteLength(
JSTypedArray, uintptr): void;
extern operator '.byte_offset=' macro StoreByteOffset(
JSTypedArray, uintptr): void;
extern operator '.elements_kind' macro LoadMapElementsKind(Map): ElementsKind;
extern operator '.elements_kind' macro LoadElementsKind(JSTypedArray):
......@@ -1177,6 +1190,8 @@ macro StoreFixedDoubleArrayElementWithSmiIndex(
StoreFixedDoubleArrayElement(array, index, value, SMI_PARAMETERS);
}
extern macro GetNumberDictionaryNumberOfElements(NumberDictionary): Smi;
extern macro GetIteratorMethod(implicit context: Context)(HeapObject): Object
labels IfIteratorUndefined;
extern macro BasicLoadNumberDictionaryElement(NumberDictionary, intptr): Object
labels NotData, IfHole;
......@@ -1356,6 +1371,7 @@ extern macro TransitionElementsKind(
constexpr ElementsKind): void labels Bailout;
extern macro IsCallable(HeapObject): bool;
extern macro IsConstructor(HeapObject): bool;
extern macro IsJSArray(HeapObject): bool;
extern macro IsMap(HeapObject): bool;
extern macro IsJSFunction(HeapObject): bool;
......
......@@ -1160,7 +1160,6 @@ namespace internal {
TFS(TypedArrayInitializeWithBuffer, kHolder, kLength, kBuffer, kElementSize, \
kByteOffset) \
/* ES #sec-typedarray-constructors */ \
TFS(CreateTypedArray, kTarget, kNewTarget, kArg1, kArg2, kArg3) \
TFJ(TypedArrayBaseConstructor, 0, kReceiver) \
TFJ(GenericConstructorLazyDeoptContinuation, 1, kReceiver, kResult) \
TFJ(TypedArrayConstructor, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
......
......@@ -354,109 +354,6 @@ TF_BUILTIN(TypedArrayBaseConstructor, TypedArrayBuiltinsAssembler) {
"TypedArray");
}
// ES #sec-typedarray-constructors
TF_BUILTIN(CreateTypedArray, TypedArrayBuiltinsAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<JSFunction> target = CAST(Parameter(Descriptor::kTarget));
TNode<JSReceiver> new_target = CAST(Parameter(Descriptor::kNewTarget));
TNode<Object> arg1 = CAST(Parameter(Descriptor::kArg1));
TNode<Object> arg2 = CAST(Parameter(Descriptor::kArg2));
TNode<Object> arg3 = CAST(Parameter(Descriptor::kArg3));
CSA_ASSERT(this, IsConstructor(target));
CSA_ASSERT(this, IsJSReceiver(new_target));
Label if_arg1isbuffer(this), if_arg1istypedarray(this),
if_arg1isreceiver(this), if_arg1isnumber(this), return_result(this);
ConstructorBuiltinsAssembler constructor_assembler(this->state());
TNode<JSTypedArray> result = CAST(
constructor_assembler.EmitFastNewObject(context, target, new_target));
// We need to set the byte_offset / byte_length to some sane values
// to keep the heap verifier happy.
// TODO(bmeurer): Fix this initialization to not use EmitFastNewObject,
// which causes the problem, since it puts Undefined into all slots of
// the object even though that doesn't make any sense for these fields.
StoreObjectFieldNoWriteBarrier(result, JSTypedArray::kByteOffsetOffset,
UintPtrConstant(0),
MachineType::PointerRepresentation());
StoreObjectFieldNoWriteBarrier(result, JSTypedArray::kByteLengthOffset,
UintPtrConstant(0),
MachineType::PointerRepresentation());
TNode<Smi> element_size =
SmiTag(GetTypedArrayElementSize(LoadElementsKind(result)));
GotoIf(TaggedIsSmi(arg1), &if_arg1isnumber);
TNode<HeapObject> arg1_heap_object = UncheckedCast<HeapObject>(arg1);
GotoIf(IsJSArrayBuffer(arg1_heap_object), &if_arg1isbuffer);
GotoIf(IsJSTypedArray(arg1_heap_object), &if_arg1istypedarray);
GotoIf(IsJSReceiver(arg1_heap_object), &if_arg1isreceiver);
Goto(&if_arg1isnumber);
// https://tc39.github.io/ecma262/#sec-typedarray-buffer-byteoffset-length
BIND(&if_arg1isbuffer);
{
TypedArrayBuiltinsFromDSLAssembler(state()).ConstructByArrayBuffer(
context, result, CAST(arg1), arg2, arg3, element_size);
Goto(&return_result);
}
// https://tc39.github.io/ecma262/#sec-typedarray-typedarray
BIND(&if_arg1istypedarray);
{
TNode<JSTypedArray> typed_array = CAST(arg1_heap_object);
TypedArrayBuiltinsFromDSLAssembler(state()).ConstructByTypedArray(
context, result, typed_array, element_size);
Goto(&return_result);
}
// https://tc39.github.io/ecma262/#sec-typedarray-object
BIND(&if_arg1isreceiver);
{
Label if_iteratorundefined(this), if_iteratornotcallable(this);
// Get iterator symbol
TNode<Object> iteratorFn = CAST(GetMethod(
context, arg1_heap_object, isolate()->factory()->iterator_symbol(),
&if_iteratorundefined));
GotoIf(TaggedIsSmi(iteratorFn), &if_iteratornotcallable);
GotoIfNot(IsCallable(CAST(iteratorFn)), &if_iteratornotcallable);
TypedArrayBuiltinsFromDSLAssembler(state()).ConstructByIterable(
context, result, CAST(arg1_heap_object), CAST(iteratorFn),
element_size);
Goto(&return_result);
BIND(&if_iteratorundefined);
{
TNode<HeapObject> array_like = arg1_heap_object;
TNode<Object> initial_length =
GetProperty(context, arg1, LengthStringConstant());
TNode<JSFunction> default_constructor = CAST(LoadContextElement(
LoadNativeContext(context), Context::ARRAY_BUFFER_FUN_INDEX));
TypedArrayBuiltinsFromDSLAssembler(state()).ConstructByArrayLike(
context, result, array_like, initial_length, element_size,
default_constructor);
Goto(&return_result);
}
BIND(&if_iteratornotcallable);
{ ThrowTypeError(context, MessageTemplate::kIteratorSymbolNonCallable); }
}
// The first argument was a number or fell through and is treated as
// a number. https://tc39.github.io/ecma262/#sec-typedarray-length
BIND(&if_arg1isnumber);
{
TypedArrayBuiltinsFromDSLAssembler(state()).ConstructByLength(
context, result, arg1, element_size);
Goto(&return_result);
}
BIND(&return_result);
Return(result);
}
// ES #sec-typedarray-constructors
TF_BUILTIN(TypedArrayConstructor, TypedArrayBuiltinsAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include 'src/builtins/builtins-constructor-gen.h'
namespace typed_array {
extern builtin IterableToListMayPreserveHoles(Context, Object, Callable):
JSArray;
......@@ -10,9 +12,13 @@ namespace typed_array {
extern builtin TypedArrayInitializeWithBuffer(implicit context: Context)(
JSTypedArray, PositiveSmi, JSArrayBuffer, PositiveSmi, Number): void;
extern macro ConstructorBuiltinsAssembler::EmitFastNewObject(
implicit context: Context)(JSFunction, JSReceiver): JSTypedArray;
extern macro TypedArrayBuiltinsAssembler::ByteLengthIsValid(Number): bool;
extern macro TypedArrayBuiltinsAssembler::CallCMemcpy(
RawPtr, RawPtr, uintptr): void;
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementSize(
ElementsKind): intptr;
extern macro TypedArrayBuiltinsAssembler::IsSharedArrayBuffer(JSArrayBuffer):
bool;
......@@ -202,4 +208,74 @@ namespace typed_array {
ThrowRangeError(context, kInvalidOffset, byteOffset);
}
}
transitioning macro ConstructByJSReceiver(implicit context: Context)(
array: JSTypedArray, obj: JSReceiver, elementSize: Smi) {
try {
const iteratorMethod: Object =
GetIteratorMethod(obj) otherwise IfIteratorUndefined;
const iteratorFn: Callable = Cast<Callable>(iteratorMethod)
otherwise ThrowTypeError(context, kIteratorSymbolNonCallable);
ConstructByIterable(array, obj, iteratorFn, elementSize);
}
label IfIteratorUndefined {
const lengthObj: Object = GetProperty(obj, kLengthString);
const length: Smi = ToSmiLength(lengthObj)
otherwise goto IfInvalidLength(lengthObj);
ConstructByArrayLike(
array, obj, length, elementSize, GetArrayBufferFunction());
}
label IfInvalidLength(length: Object) {
ThrowRangeError(context, kInvalidTypedArrayLength, length);
}
}
// 22.2.4 The TypedArray Constructors
// ES #sec-typedarray-constructors
transitioning builtin CreateTypedArray(
context: Context, target: JSFunction, newTarget: JSReceiver, arg1: Object,
arg2: Object, arg3: Object): Object {
assert(IsConstructor(target));
// 4. Let O be ? AllocateTypedArray(constructorName, NewTarget,
// "%TypedArrayPrototype%").
const array: JSTypedArray = EmitFastNewObject(target, newTarget);
// We need to set the byte_offset / byte_length to some sane values
// to keep the heap verifier happy.
// TODO(bmeurer): Fix this initialization to not use EmitFastNewObject,
// which causes the problem, since it puts Undefined into all slots of
// the object even though that doesn't make any sense for these fields.
array.byte_offset = 0;
array.byte_length = 0;
// 5. Let elementSize be the Number value of the Element Size value in Table
// 56 for constructorName.
const elementSize: Smi =
Convert<Smi>(GetTypedArrayElementSize(array.elements_kind));
try {
typeswitch (arg1) {
case (length: Smi): {
goto IfConstructByLength(length);
}
case (buffer: JSArrayBuffer): {
ConstructByArrayBuffer(array, buffer, arg2, arg3, elementSize);
}
case (typedArray: JSTypedArray): {
ConstructByTypedArray(array, typedArray, elementSize);
}
case (obj: JSReceiver): {
ConstructByJSReceiver(array, obj, elementSize);
}
// The first argument was a number or fell through and is treated as
// a number. https://tc39.github.io/ecma262/#sec-typedarray-length
case (lengthObj: HeapObject): {
goto IfConstructByLength(lengthObj);
}
}
}
label IfConstructByLength(length: Object) {
ConstructByLength(array, length, elementSize);
}
return array;
}
}
......@@ -9147,6 +9147,14 @@ Node* CodeStubAssembler::GetMethod(Node* context, Node* object,
return method;
}
TNode<Object> CodeStubAssembler::GetIteratorMethod(
TNode<Context> context, TNode<HeapObject> heap_obj,
Label* if_iteratorundefined) {
return CAST(GetMethod(context, heap_obj,
isolate()->factory()->iterator_symbol(),
if_iteratorundefined));
}
void CodeStubAssembler::LoadPropertyFromFastObject(
Node* object, Node* map, TNode<DescriptorArray> descriptors,
Node* name_index, Variable* var_details, Variable* var_value) {
......@@ -13088,6 +13096,18 @@ TNode<Smi> CodeStubAssembler::LoadJSTypedArrayLength(
return LoadObjectField<Smi>(typed_array, JSTypedArray::kLengthOffset);
}
void CodeStubAssembler::StoreByteOffset(TNode<JSTypedArray> typed_array,
TNode<UintPtrT> byte_offset) {
StoreObjectFieldNoWriteBarrier<UintPtrT>(
typed_array, JSTypedArray::kByteOffsetOffset, byte_offset);
}
void CodeStubAssembler::StoreByteLength(TNode<JSTypedArray> typed_array,
TNode<UintPtrT> byte_length) {
StoreObjectFieldNoWriteBarrier<UintPtrT>(
typed_array, JSTypedArray::kByteLengthOffset, byte_length);
}
CodeStubArguments::CodeStubArguments(
CodeStubAssembler* assembler, Node* argc, Node* fp,
CodeStubAssembler::ParameterMode param_mode, ReceiverMode receiver_mode)
......
......@@ -338,6 +338,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
return UncheckedCast<JSArray>(heap_object);
}
TNode<JSArrayBuffer> HeapObjectToJSArrayBuffer(TNode<HeapObject> heap_object,
Label* fail) {
GotoIfNot(IsJSArrayBuffer(heap_object), fail);
return UncheckedCast<JSArrayBuffer>(heap_object);
}
TNode<JSArray> TaggedToFastJSArray(TNode<Context> context,
TNode<Object> value, Label* fail) {
GotoIf(TaggedIsSmi(value), fail);
......@@ -1205,6 +1211,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
StoreObjectFieldNoWriteBarrier(object, offset, value,
MachineRepresentationOf<T>::value);
}
template <class T = Object>
void StoreObjectFieldNoWriteBarrier(TNode<HeapObject> object, int offset,
TNode<T> value) {
StoreObjectFieldNoWriteBarrier(object, offset, value,
MachineRepresentationOf<T>::value);
}
// Store the Map of an HeapObject.
void StoreMap(Node* object, Node* map);
......@@ -2634,6 +2646,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
Node* GetMethod(Node* context, Node* object, Handle<Name> name,
Label* if_null_or_undefined);
TNode<Object> GetIteratorMethod(TNode<Context> context,
TNode<HeapObject> heap_obj,
Label* if_iteratorundefined);
template <class... TArgs>
TNode<Object> CallBuiltin(Builtins::Name id, SloppyTNode<Object> context,
TArgs... args) {
......@@ -3042,6 +3058,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// JSTypedArray helpers
TNode<Smi> LoadJSTypedArrayLength(TNode<JSTypedArray> typed_array);
void StoreByteOffset(TNode<JSTypedArray> typed_array,
TNode<UintPtrT> byte_offset);
void StoreByteLength(TNode<JSTypedArray> typed_array,
TNode<UintPtrT> byte_length);
TNode<IntPtrT> ElementOffsetFromIndex(Node* index, ElementsKind kind,
ParameterMode mode, int base_size = 0);
......
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