[builtins] Port TypedArrayInitialize to Torque
The parts that deal with allocating on heap buffers and typed array elements (FixedTypedArrayBase) remain in CSA, as it is assumed to eventually be expressed with Torque classes. This reduces overall builtins size by 508 bytes (Mac x64.release) - TypedArrayInitialize 2332 -> 1824 Bug: v8:7161 Change-Id: I5d0648b4dd79a687f77d6f4b01b236f4a0508c54 Reviewed-on: https://chromium-review.googlesource.com/c/1445215 Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Simon Zünd <szuend@chromium.org> Commit-Queue: Peter Wong <peter.wm.wong@gmail.com> Cr-Commit-Position: refs/heads/master@{#59337}
This commit is contained in:
parent
9eba56162f
commit
bf9a7c524c
@ -189,6 +189,10 @@ intrinsic %RawConstexprCast<To: type, From: type>(f: From): To;
|
||||
type NativeContextSlot generates 'TNode<IntPtrT>' constexpr 'int32_t';
|
||||
const ARRAY_BUFFER_FUN_INDEX: constexpr NativeContextSlot
|
||||
generates 'Context::ARRAY_BUFFER_FUN_INDEX';
|
||||
const ARRAY_BUFFER_NOINIT_FUN_INDEX: constexpr NativeContextSlot
|
||||
generates 'Context::ARRAY_BUFFER_NOINIT_FUN_INDEX';
|
||||
const ARRAY_BUFFER_MAP_INDEX: constexpr NativeContextSlot
|
||||
generates 'Context::ARRAY_BUFFER_MAP_INDEX';
|
||||
const ARRAY_JOIN_STACK_INDEX: constexpr NativeContextSlot
|
||||
generates 'Context::ARRAY_JOIN_STACK_INDEX';
|
||||
const OBJECT_FUNCTION_INDEX: constexpr NativeContextSlot
|
||||
@ -322,10 +326,16 @@ const kMaxArrayIndex:
|
||||
constexpr uint32 generates 'JSArray::kMaxArrayIndex';
|
||||
const kTypedArrayMaxByteLength:
|
||||
constexpr uintptr generates 'FixedTypedArrayBase::kMaxByteLength';
|
||||
const V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP:
|
||||
constexpr int31 generates 'V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP';
|
||||
const kMaxSafeInteger: constexpr float64 generates 'kMaxSafeInteger';
|
||||
const kStringMaxLength: constexpr int31 generates 'String::kMaxLength';
|
||||
const kFixedArrayMaxLength:
|
||||
constexpr int31 generates 'FixedArray::kMaxLength';
|
||||
const kFixedTypedArrayBaseHeaderSize: constexpr intptr
|
||||
generates 'FixedTypedArrayBase::kHeaderSize';
|
||||
const kObjectAlignmentMask: constexpr intptr
|
||||
generates 'kObjectAlignmentMask';
|
||||
|
||||
const kMaxRegularHeapObjectSize: constexpr int31
|
||||
generates 'kMaxRegularHeapObjectSize';
|
||||
@ -452,6 +462,10 @@ extern macro Construct(implicit context: Context)(
|
||||
Constructor, Object, Object): JSReceiver;
|
||||
extern macro Construct(implicit context: Context)(
|
||||
Constructor, Object, Object, Object): JSReceiver;
|
||||
extern macro ConstructWithTarget(implicit context: Context)(
|
||||
Constructor, JSReceiver): JSReceiver;
|
||||
extern macro ConstructWithTarget(implicit context: Context)(
|
||||
Constructor, JSReceiver, Object): JSReceiver;
|
||||
extern macro SpeciesConstructor(implicit context: Context)(
|
||||
Object, JSReceiver): JSReceiver;
|
||||
|
||||
@ -471,6 +485,7 @@ extern transitioning runtime CreateDataProperty(implicit context: Context)(
|
||||
extern macro LoadBufferObject(RawPtr, constexpr int32): Object;
|
||||
extern macro LoadBufferPointer(RawPtr, constexpr int32): RawPtr;
|
||||
extern macro LoadBufferSmi(RawPtr, constexpr int32): Smi;
|
||||
extern macro LoadFixedTypedArrayOnHeapBackingStore(FixedTypedArrayBase): RawPtr;
|
||||
|
||||
extern macro LoadRoot(constexpr RootIndex): Object;
|
||||
extern macro StoreRoot(constexpr RootIndex, Object): Object;
|
||||
@ -536,6 +551,11 @@ extern operator '<=' macro IntPtrLessThanOrEqual(intptr, intptr): bool;
|
||||
extern operator '<=' macro UintPtrLessThanOrEqual(uintptr, uintptr): bool;
|
||||
extern operator '>=' macro IntPtrGreaterThanOrEqual(intptr, intptr): bool;
|
||||
extern operator '>=' macro UintPtrGreaterThanOrEqual(uintptr, uintptr): bool;
|
||||
extern operator '~' macro WordNot(intptr): intptr;
|
||||
extern operator '~' macro WordNot(uintptr): uintptr;
|
||||
extern operator '~' macro ConstexprWordNot(constexpr intptr): constexpr intptr;
|
||||
extern operator '~' macro ConstexprWordNot(constexpr uintptr):
|
||||
constexpr uintptr;
|
||||
|
||||
extern operator '==' macro Float64Equal(float64, float64): bool;
|
||||
extern operator '!=' macro Float64NotEqual(float64, float64): bool;
|
||||
@ -575,6 +595,10 @@ extern operator '<<' macro SmiShl(Smi, constexpr int31): Smi;
|
||||
extern operator '>>' macro SmiSar(Smi, constexpr int31): Smi;
|
||||
|
||||
extern operator '+' macro IntPtrAdd(intptr, intptr): intptr;
|
||||
extern operator '+' macro ConstexprIntPtrAdd(
|
||||
constexpr intptr, constexpr intptr): constexpr intptr;
|
||||
extern operator '+' macro ConstexprUintPtrAdd(
|
||||
constexpr uintptr, constexpr uintptr): constexpr intptr;
|
||||
extern operator '-' macro IntPtrSub(intptr, intptr): intptr;
|
||||
extern operator '*' macro IntPtrMul(intptr, intptr): intptr;
|
||||
extern operator '/' macro IntPtrDiv(intptr, intptr): intptr;
|
||||
@ -636,6 +660,7 @@ extern operator '>>>' macro ConstexprUintPtrShr(
|
||||
extern macro SmiMax(Smi, Smi): Smi;
|
||||
extern macro SmiMin(Smi, Smi): Smi;
|
||||
extern macro SmiMul(Smi, Smi): Number;
|
||||
extern macro SmiMod(Smi, Smi): Number;
|
||||
|
||||
extern operator '!' macro ConstexprBoolNot(constexpr bool): constexpr bool;
|
||||
extern operator '!' macro Word32BinaryNot(bool): bool;
|
||||
@ -1071,6 +1096,11 @@ Convert<uint32, uintptr>(ui: uintptr): uint32 {
|
||||
Convert<intptr, Smi>(s: Smi): intptr {
|
||||
return SmiUntag(s);
|
||||
}
|
||||
Convert<intptr, uintptr>(ui: uintptr): intptr {
|
||||
const i = Signed(ui);
|
||||
assert(i >= 0);
|
||||
return i;
|
||||
}
|
||||
Convert<int32, Smi>(s: Smi): int32 {
|
||||
return SmiToInt32(s);
|
||||
}
|
||||
@ -1294,10 +1324,14 @@ macro GetObjectFunction(implicit context: Context)(): JSFunction {
|
||||
return UnsafeCast<JSFunction>(
|
||||
LoadNativeContext(context)[OBJECT_FUNCTION_INDEX]);
|
||||
}
|
||||
macro GetArrayBufferFunction(implicit context: Context)(): JSFunction {
|
||||
return UnsafeCast<JSFunction>(
|
||||
macro GetArrayBufferFunction(implicit context: Context)(): Constructor {
|
||||
return UnsafeCast<Constructor>(
|
||||
LoadNativeContext(context)[ARRAY_BUFFER_FUN_INDEX]);
|
||||
}
|
||||
macro GetArrayBufferNoInitFunction(implicit context: Context)(): JSFunction {
|
||||
return UnsafeCast<JSFunction>(
|
||||
LoadNativeContext(context)[ARRAY_BUFFER_NOINIT_FUN_INDEX]);
|
||||
}
|
||||
|
||||
macro GetFastPackedSmiElementsJSArrayMap(implicit context: Context)(): Map {
|
||||
return UnsafeCast<Map>(
|
||||
|
@ -1155,8 +1155,6 @@ namespace internal {
|
||||
TFJ(SymbolPrototypeValueOf, 0, kReceiver) \
|
||||
\
|
||||
/* TypedArray */ \
|
||||
TFS(TypedArrayInitialize, kHolder, kLength, kElementSize, kInitialize, \
|
||||
kBufferConstructor) \
|
||||
/* ES #sec-typedarray-constructors */ \
|
||||
TFJ(TypedArrayBaseConstructor, 0, kReceiver) \
|
||||
TFJ(GenericConstructorLazyDeoptContinuation, 1, kReceiver, kResult) \
|
||||
|
@ -66,6 +66,7 @@ void TypedArrayBuiltinsAssembler::SetupTypedArray(TNode<JSTypedArray> holder,
|
||||
TNode<Smi> length,
|
||||
TNode<UintPtrT> byte_offset,
|
||||
TNode<UintPtrT> byte_length) {
|
||||
CSA_ASSERT(this, TaggedIsPositiveSmi(length));
|
||||
StoreObjectField(holder, JSTypedArray::kLengthOffset, length);
|
||||
StoreObjectFieldNoWriteBarrier(holder, JSArrayBufferView::kByteOffsetOffset,
|
||||
byte_offset,
|
||||
@ -85,6 +86,7 @@ void TypedArrayBuiltinsAssembler::AttachBuffer(TNode<JSTypedArray> holder,
|
||||
TNode<Map> map,
|
||||
TNode<Smi> length,
|
||||
TNode<Number> byte_offset) {
|
||||
CSA_ASSERT(this, TaggedIsPositiveSmi(length));
|
||||
StoreObjectField(holder, JSArrayBufferView::kBufferOffset, buffer);
|
||||
|
||||
Node* elements = Allocate(FixedTypedArrayBase::kHeaderSize);
|
||||
@ -105,198 +107,85 @@ void TypedArrayBuiltinsAssembler::AttachBuffer(TNode<JSTypedArray> holder,
|
||||
StoreObjectField(holder, JSObject::kElementsOffset, elements);
|
||||
}
|
||||
|
||||
TF_BUILTIN(TypedArrayInitialize, TypedArrayBuiltinsAssembler) {
|
||||
TNode<JSTypedArray> holder = CAST(Parameter(Descriptor::kHolder));
|
||||
TNode<Smi> length = CAST(Parameter(Descriptor::kLength));
|
||||
TNode<Smi> element_size = CAST(Parameter(Descriptor::kElementSize));
|
||||
Node* initialize = Parameter(Descriptor::kInitialize);
|
||||
TNode<JSReceiver> buffer_constructor =
|
||||
CAST(Parameter(Descriptor::kBufferConstructor));
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
// Allocate a new ArrayBuffer and initialize it with empty properties and
|
||||
// elements.
|
||||
TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer(
|
||||
TNode<Context> context, TNode<JSTypedArray> holder,
|
||||
TNode<UintPtrT> byte_length) {
|
||||
TNode<Context> native_context = LoadNativeContext(context);
|
||||
TNode<Map> map =
|
||||
CAST(LoadContextElement(native_context, Context::ARRAY_BUFFER_MAP_INDEX));
|
||||
TNode<FixedArray> empty_fixed_array =
|
||||
CAST(LoadRoot(RootIndex::kEmptyFixedArray));
|
||||
|
||||
CSA_ASSERT(this, TaggedIsPositiveSmi(length));
|
||||
CSA_ASSERT(this, TaggedIsPositiveSmi(element_size));
|
||||
CSA_ASSERT(this, IsBoolean(initialize));
|
||||
TNode<JSArrayBuffer> buffer = UncheckedCast<JSArrayBuffer>(
|
||||
Allocate(JSArrayBuffer::kSizeWithEmbedderFields));
|
||||
StoreMapNoWriteBarrier(buffer, map);
|
||||
StoreObjectFieldNoWriteBarrier(buffer, JSArray::kPropertiesOrHashOffset,
|
||||
empty_fixed_array);
|
||||
StoreObjectFieldNoWriteBarrier(buffer, JSArray::kElementsOffset,
|
||||
empty_fixed_array);
|
||||
// Setup the ArrayBuffer.
|
||||
// - Set BitField to 0.
|
||||
// - Set IsExternal and IsDetachable bits of BitFieldSlot.
|
||||
// - Set the byte_length field to byte_length.
|
||||
// - Set backing_store to null/Smi(0).
|
||||
// - Set all embedder fields to Smi(0).
|
||||
if (FIELD_SIZE(JSArrayBuffer::kOptionalPaddingOffset) != 0) {
|
||||
DCHECK_EQ(4, FIELD_SIZE(JSArrayBuffer::kOptionalPaddingOffset));
|
||||
StoreObjectFieldNoWriteBarrier(
|
||||
buffer, JSArrayBuffer::kOptionalPaddingOffset, Int32Constant(0),
|
||||
MachineRepresentation::kWord32);
|
||||
}
|
||||
int32_t bitfield_value = (1 << JSArrayBuffer::IsExternalBit::kShift) |
|
||||
(1 << JSArrayBuffer::IsDetachableBit::kShift);
|
||||
StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBitFieldOffset,
|
||||
Int32Constant(bitfield_value),
|
||||
MachineRepresentation::kWord32);
|
||||
|
||||
TNode<Smi> byte_offset = SmiConstant(0);
|
||||
StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kByteLengthOffset,
|
||||
byte_length,
|
||||
MachineType::PointerRepresentation());
|
||||
StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBackingStoreOffset,
|
||||
SmiConstant(0));
|
||||
for (int offset = JSArrayBuffer::kHeaderSize;
|
||||
offset < JSArrayBuffer::kSizeWithEmbedderFields; offset += kTaggedSize) {
|
||||
StoreObjectFieldNoWriteBarrier(buffer, offset, SmiConstant(0));
|
||||
}
|
||||
|
||||
static const int32_t fta_base_data_offset =
|
||||
StoreObjectField(holder, JSArrayBufferView::kBufferOffset, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
TNode<FixedTypedArrayBase> TypedArrayBuiltinsAssembler::AllocateOnHeapElements(
|
||||
TNode<Map> map, TNode<IntPtrT> total_size, TNode<Number> length) {
|
||||
static const intptr_t fta_base_data_offset =
|
||||
FixedTypedArrayBase::kDataOffset - kHeapObjectTag;
|
||||
|
||||
Label setup_holder(this), allocate_on_heap(this), aligned(this),
|
||||
allocate_elements(this), allocate_off_heap(this),
|
||||
allocate_off_heap_custom_constructor(this),
|
||||
allocate_off_heap_no_init(this), attach_buffer(this), done(this);
|
||||
TVARIABLE(IntPtrT, var_total_size);
|
||||
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(total_size, IntPtrConstant(0)));
|
||||
|
||||
// SmiMul returns a heap number in case of Smi overflow.
|
||||
TNode<Number> byte_length = SmiMul(length, element_size);
|
||||
// Allocate a FixedTypedArray and set the length, base pointer and external
|
||||
// pointer.
|
||||
CSA_ASSERT(this, IsRegularHeapObjectSize(total_size));
|
||||
|
||||
TNode<Map> fixed_typed_map = LoadMapForType(holder);
|
||||
TNode<Object> elements;
|
||||
|
||||
// If target and new_target for the buffer differ, allocate off-heap.
|
||||
TNode<JSFunction> default_constructor = CAST(LoadContextElement(
|
||||
LoadNativeContext(context), Context::ARRAY_BUFFER_FUN_INDEX));
|
||||
GotoIfNot(WordEqual(buffer_constructor, default_constructor),
|
||||
&allocate_off_heap_custom_constructor);
|
||||
|
||||
// For buffers with byte_length over the threshold, allocate off-heap.
|
||||
GotoIf(TaggedIsNotSmi(byte_length), &allocate_off_heap);
|
||||
TNode<Smi> smi_byte_length = CAST(byte_length);
|
||||
GotoIf(SmiGreaterThan(smi_byte_length,
|
||||
SmiConstant(V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP)),
|
||||
&allocate_off_heap);
|
||||
TNode<IntPtrT> word_byte_length = SmiToIntPtr(smi_byte_length);
|
||||
Goto(&allocate_on_heap);
|
||||
|
||||
BIND(&allocate_on_heap);
|
||||
{
|
||||
CSA_ASSERT(this, TaggedIsPositiveSmi(byte_length));
|
||||
// Allocate a new ArrayBuffer and initialize it with empty properties and
|
||||
// elements.
|
||||
Node* native_context = LoadNativeContext(context);
|
||||
Node* map =
|
||||
LoadContextElement(native_context, Context::ARRAY_BUFFER_MAP_INDEX);
|
||||
Node* empty_fixed_array = LoadRoot(RootIndex::kEmptyFixedArray);
|
||||
|
||||
Node* buffer = Allocate(JSArrayBuffer::kSizeWithEmbedderFields);
|
||||
StoreMapNoWriteBarrier(buffer, map);
|
||||
StoreObjectFieldNoWriteBarrier(buffer, JSArray::kPropertiesOrHashOffset,
|
||||
empty_fixed_array);
|
||||
StoreObjectFieldNoWriteBarrier(buffer, JSArray::kElementsOffset,
|
||||
empty_fixed_array);
|
||||
// Setup the ArrayBuffer.
|
||||
// - Set BitField to 0.
|
||||
// - Set IsExternal and IsDetachable bits of BitFieldSlot.
|
||||
// - Set the byte_length field to byte_length.
|
||||
// - Set backing_store to null/Smi(0).
|
||||
// - Set all embedder fields to Smi(0).
|
||||
if (FIELD_SIZE(JSArrayBuffer::kOptionalPaddingOffset) != 0) {
|
||||
DCHECK_EQ(4, FIELD_SIZE(JSArrayBuffer::kOptionalPaddingOffset));
|
||||
StoreObjectFieldNoWriteBarrier(
|
||||
buffer, JSArrayBuffer::kOptionalPaddingOffset, Int32Constant(0),
|
||||
MachineRepresentation::kWord32);
|
||||
}
|
||||
int32_t bitfield_value = (1 << JSArrayBuffer::IsExternalBit::kShift) |
|
||||
(1 << JSArrayBuffer::IsDetachableBit::kShift);
|
||||
StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBitFieldOffset,
|
||||
Int32Constant(bitfield_value),
|
||||
MachineRepresentation::kWord32);
|
||||
|
||||
StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kByteLengthOffset,
|
||||
SmiToIntPtr(CAST(byte_length)),
|
||||
MachineType::PointerRepresentation());
|
||||
StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBackingStoreOffset,
|
||||
SmiConstant(0));
|
||||
for (int offset = JSArrayBuffer::kHeaderSize;
|
||||
offset < JSArrayBuffer::kSizeWithEmbedderFields;
|
||||
offset += kTaggedSize) {
|
||||
StoreObjectFieldNoWriteBarrier(buffer, offset, SmiConstant(0));
|
||||
}
|
||||
|
||||
StoreObjectField(holder, JSArrayBufferView::kBufferOffset, buffer);
|
||||
|
||||
// Check the alignment.
|
||||
// TODO(ishell): remove <Object, Object>
|
||||
GotoIf(WordEqual<Object, Object>(
|
||||
SmiMod(element_size, SmiConstant(kObjectAlignment)),
|
||||
SmiConstant(0)),
|
||||
&aligned);
|
||||
|
||||
// Fix alignment if needed.
|
||||
DCHECK_EQ(0, FixedTypedArrayBase::kHeaderSize & kObjectAlignmentMask);
|
||||
TNode<IntPtrT> aligned_header_size =
|
||||
IntPtrConstant(FixedTypedArrayBase::kHeaderSize + kObjectAlignmentMask);
|
||||
TNode<IntPtrT> size = IntPtrAdd(word_byte_length, aligned_header_size);
|
||||
var_total_size = WordAnd(size, IntPtrConstant(~kObjectAlignmentMask));
|
||||
Goto(&allocate_elements);
|
||||
if (UnalignedLoadSupported(MachineRepresentation::kFloat64) &&
|
||||
UnalignedStoreSupported(MachineRepresentation::kFloat64)) {
|
||||
elements = AllocateInNewSpace(total_size);
|
||||
} else {
|
||||
elements = AllocateInNewSpace(total_size, kDoubleAlignment);
|
||||
}
|
||||
|
||||
BIND(&aligned);
|
||||
{
|
||||
TNode<IntPtrT> header_size =
|
||||
IntPtrConstant(FixedTypedArrayBase::kHeaderSize);
|
||||
var_total_size = IntPtrAdd(word_byte_length, header_size);
|
||||
Goto(&allocate_elements);
|
||||
}
|
||||
|
||||
BIND(&allocate_elements);
|
||||
{
|
||||
// Allocate a FixedTypedArray and set the length, base pointer and external
|
||||
// pointer.
|
||||
CSA_ASSERT(this, IsRegularHeapObjectSize(var_total_size.value()));
|
||||
|
||||
Node* elements;
|
||||
|
||||
if (UnalignedLoadSupported(MachineRepresentation::kFloat64) &&
|
||||
UnalignedStoreSupported(MachineRepresentation::kFloat64)) {
|
||||
elements = AllocateInNewSpace(var_total_size.value());
|
||||
} else {
|
||||
elements = AllocateInNewSpace(var_total_size.value(), kDoubleAlignment);
|
||||
}
|
||||
|
||||
StoreMapNoWriteBarrier(elements, fixed_typed_map);
|
||||
StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
|
||||
StoreObjectFieldNoWriteBarrier(
|
||||
elements, FixedTypedArrayBase::kBasePointerOffset, elements);
|
||||
StoreObjectFieldNoWriteBarrier(elements,
|
||||
FixedTypedArrayBase::kExternalPointerOffset,
|
||||
IntPtrConstant(fta_base_data_offset),
|
||||
MachineType::PointerRepresentation());
|
||||
|
||||
StoreObjectField(holder, JSObject::kElementsOffset, elements);
|
||||
|
||||
GotoIf(IsFalse(initialize), &done);
|
||||
// Initialize the backing store by filling it with 0s.
|
||||
Node* backing_store = IntPtrAdd(BitcastTaggedToWord(elements),
|
||||
IntPtrConstant(fta_base_data_offset));
|
||||
// Call out to memset to perform initialization.
|
||||
Node* memset = ExternalConstant(ExternalReference::libc_memset_function());
|
||||
CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
|
||||
MachineType::IntPtr(), MachineType::UintPtr(), memset,
|
||||
backing_store, IntPtrConstant(0), word_byte_length);
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
TVARIABLE(JSArrayBuffer, var_buffer);
|
||||
|
||||
BIND(&allocate_off_heap);
|
||||
{
|
||||
GotoIf(IsFalse(initialize), &allocate_off_heap_no_init);
|
||||
var_buffer = CAST(Construct(context, default_constructor, byte_length));
|
||||
Goto(&attach_buffer);
|
||||
}
|
||||
|
||||
BIND(&allocate_off_heap_custom_constructor);
|
||||
{
|
||||
var_buffer =
|
||||
CAST(CallStub(CodeFactory::Construct(isolate()), context,
|
||||
default_constructor, buffer_constructor, Int32Constant(1),
|
||||
UndefinedConstant(), byte_length));
|
||||
Goto(&attach_buffer);
|
||||
}
|
||||
|
||||
BIND(&allocate_off_heap_no_init);
|
||||
{
|
||||
Node* buffer_constructor_noinit = LoadContextElement(
|
||||
LoadNativeContext(context), Context::ARRAY_BUFFER_NOINIT_FUN_INDEX);
|
||||
var_buffer = CAST(CallJS(CodeFactory::Call(isolate()), context,
|
||||
buffer_constructor_noinit, UndefinedConstant(),
|
||||
byte_length));
|
||||
Goto(&attach_buffer);
|
||||
}
|
||||
|
||||
BIND(&attach_buffer);
|
||||
{
|
||||
AttachBuffer(holder, var_buffer.value(), fixed_typed_map, length,
|
||||
byte_offset);
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&done);
|
||||
SetupTypedArray(holder, length, ChangeNonnegativeNumberToUintPtr(byte_offset),
|
||||
ChangeNonnegativeNumberToUintPtr(byte_length));
|
||||
Return(UndefinedConstant());
|
||||
StoreMapNoWriteBarrier(elements, map);
|
||||
StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
|
||||
StoreObjectFieldNoWriteBarrier(
|
||||
elements, FixedTypedArrayBase::kBasePointerOffset, elements);
|
||||
StoreObjectFieldNoWriteBarrier(elements,
|
||||
FixedTypedArrayBase::kExternalPointerOffset,
|
||||
IntPtrConstant(fta_base_data_offset),
|
||||
MachineType::PointerRepresentation());
|
||||
return CAST(elements);
|
||||
}
|
||||
|
||||
Node* TypedArrayBuiltinsAssembler::LoadDataPtr(Node* typed_array) {
|
||||
@ -751,6 +640,16 @@ void TypedArrayBuiltinsAssembler::CallCMemcpy(TNode<RawPtrT> dest_ptr,
|
||||
dest_ptr, src_ptr, byte_length);
|
||||
}
|
||||
|
||||
void TypedArrayBuiltinsAssembler::CallCMemset(TNode<RawPtrT> dest_ptr,
|
||||
TNode<IntPtrT> value,
|
||||
TNode<UintPtrT> length) {
|
||||
TNode<ExternalReference> memset =
|
||||
ExternalConstant(ExternalReference::libc_memset_function());
|
||||
CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
|
||||
MachineType::IntPtr(), MachineType::UintPtr(), memset,
|
||||
dest_ptr, value, length);
|
||||
}
|
||||
|
||||
void TypedArrayBuiltinsAssembler::
|
||||
CallCCopyFastNumberJSArrayElementsToTypedArray(TNode<Context> context,
|
||||
TNode<JSArray> source,
|
||||
|
@ -13,6 +13,8 @@ namespace internal {
|
||||
|
||||
class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
|
||||
public:
|
||||
using ElementsInfo =
|
||||
TypedArrayBuiltinsFromDSLAssembler::TypedArrayElementsInfo;
|
||||
explicit TypedArrayBuiltinsAssembler(compiler::CodeAssemblerState* state)
|
||||
: CodeStubAssembler(state) {}
|
||||
|
||||
@ -38,6 +40,14 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
|
||||
TNode<Map> map, TNode<Smi> length,
|
||||
TNode<Number> byte_offset);
|
||||
|
||||
TNode<JSArrayBuffer> AllocateEmptyOnHeapBuffer(TNode<Context> context,
|
||||
TNode<JSTypedArray> holder,
|
||||
TNode<UintPtrT> byte_length);
|
||||
|
||||
TNode<FixedTypedArrayBase> AllocateOnHeapElements(TNode<Map> map,
|
||||
TNode<IntPtrT> byte_length,
|
||||
TNode<Number> length);
|
||||
|
||||
TNode<Map> LoadMapForType(TNode<JSTypedArray> array);
|
||||
TNode<UintPtrT> CalculateExternalPointer(TNode<UintPtrT> backing_store,
|
||||
TNode<Number> byte_offset);
|
||||
@ -54,8 +64,7 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
|
||||
TNode<IntPtrT> GetTypedArrayElementSize(TNode<Word32T> elements_kind);
|
||||
|
||||
// Returns information (byte size and map) about a TypedArray's elements.
|
||||
TypedArrayBuiltinsFromDSLAssembler::TypedArrayElementsInfo
|
||||
GetTypedArrayElementsInfo(TNode<JSTypedArray> typed_array);
|
||||
ElementsInfo GetTypedArrayElementsInfo(TNode<JSTypedArray> typed_array);
|
||||
|
||||
TNode<JSArrayBuffer> LoadTypedArrayBuffer(TNode<JSTypedArray> typed_array) {
|
||||
return LoadObjectField<JSArrayBuffer>(typed_array,
|
||||
@ -97,6 +106,9 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
|
||||
void CallCMemcpy(TNode<RawPtrT> dest_ptr, TNode<RawPtrT> src_ptr,
|
||||
TNode<UintPtrT> byte_length);
|
||||
|
||||
void CallCMemset(TNode<RawPtrT> dest_ptr, TNode<IntPtrT> value,
|
||||
TNode<UintPtrT> length);
|
||||
|
||||
void CallCCopyFastNumberJSArrayElementsToTypedArray(
|
||||
TNode<Context> context, TNode<JSArray> source, TNode<JSTypedArray> dest,
|
||||
TNode<IntPtrT> source_length, TNode<IntPtrT> offset);
|
||||
|
@ -7,26 +7,85 @@
|
||||
namespace typed_array_createtypedarray {
|
||||
extern builtin IterableToListMayPreserveHoles(Context, Object, Callable):
|
||||
JSArray;
|
||||
extern builtin TypedArrayInitialize(implicit context: Context)(
|
||||
JSTypedArray, PositiveSmi, PositiveSmi, Boolean, JSReceiver): void;
|
||||
|
||||
extern macro ConstructorBuiltinsAssembler::EmitFastNewObject(
|
||||
implicit context: Context)(JSFunction, JSReceiver): JSTypedArray;
|
||||
extern macro TypedArrayBuiltinsAssembler::AllocateEmptyOnHeapBuffer(
|
||||
implicit context: Context)(JSTypedArray, uintptr): JSArrayBuffer;
|
||||
extern macro TypedArrayBuiltinsAssembler::AllocateOnHeapElements(
|
||||
Map, intptr, Number): FixedTypedArrayBase;
|
||||
extern macro TypedArrayBuiltinsAssembler::ByteLengthIsValid(Number): bool;
|
||||
extern macro TypedArrayBuiltinsAssembler::CallCMemcpy(
|
||||
RawPtr, RawPtr, uintptr): void;
|
||||
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
|
||||
ElementsKind): typed_array::TypedArrayElementsInfo;
|
||||
extern macro TypedArrayBuiltinsAssembler::IsSharedArrayBuffer(JSArrayBuffer):
|
||||
bool;
|
||||
extern macro TypedArrayBuiltinsAssembler::SetupTypedArray(
|
||||
JSTypedArray, PositiveSmi, uintptr, uintptr): void;
|
||||
JSTypedArray, Smi, uintptr, uintptr): void;
|
||||
extern macro TypedArrayBuiltinsAssembler::AttachBuffer(
|
||||
JSTypedArray, JSArrayBuffer, Map, PositiveSmi, Number): void;
|
||||
JSTypedArray, JSArrayBuffer, Map, Smi, Number): void;
|
||||
|
||||
extern runtime ThrowInvalidTypedArrayAlignment(implicit context: Context)(
|
||||
Map, String): never;
|
||||
extern runtime TypedArrayCopyElements(Context, JSTypedArray, Object, Number):
|
||||
void;
|
||||
|
||||
macro CalculateTotalElementsByteSize(byteLength: intptr): intptr {
|
||||
return (kFixedTypedArrayBaseHeaderSize + kObjectAlignmentMask +
|
||||
byteLength) &
|
||||
~kObjectAlignmentMask;
|
||||
}
|
||||
|
||||
transitioning builtin TypedArrayInitialize(implicit context: Context)(
|
||||
initialize: Boolean, typedArray: JSTypedArray, length: Smi,
|
||||
elementMap: Map, elementSize: Smi,
|
||||
bufferConstructor: JSReceiver): Object {
|
||||
assert(Is<PositiveSmi>(length));
|
||||
assert(Is<PositiveSmi>(elementSize));
|
||||
|
||||
const byteLengthNum = SmiMul(length, elementSize);
|
||||
const byteLength = Convert<uintptr>(byteLengthNum);
|
||||
const defaultConstructor = GetArrayBufferFunction();
|
||||
|
||||
try {
|
||||
if (bufferConstructor != defaultConstructor) {
|
||||
goto AttachBuffer(ConstructWithTarget(
|
||||
defaultConstructor, bufferConstructor, byteLengthNum));
|
||||
}
|
||||
|
||||
if (byteLength > V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP) goto AllocateOffHeap;
|
||||
|
||||
AllocateEmptyOnHeapBuffer(typedArray, byteLength);
|
||||
|
||||
const totalSize =
|
||||
CalculateTotalElementsByteSize(Convert<intptr>(byteLength));
|
||||
const elements = AllocateOnHeapElements(elementMap, totalSize, length);
|
||||
typedArray.elements = elements;
|
||||
|
||||
if (initialize == True) {
|
||||
const backingStore = LoadFixedTypedArrayOnHeapBackingStore(elements);
|
||||
typed_array::CallCMemset(backingStore, 0, byteLength);
|
||||
}
|
||||
}
|
||||
label AllocateOffHeap {
|
||||
if (initialize == True) {
|
||||
goto AttachBuffer(Construct(defaultConstructor, byteLengthNum));
|
||||
} else {
|
||||
goto AttachBuffer(Call(
|
||||
context, GetArrayBufferNoInitFunction(), Undefined, byteLengthNum));
|
||||
}
|
||||
}
|
||||
label AttachBuffer(bufferObj: Object) {
|
||||
const buffer = Cast<JSArrayBuffer>(bufferObj) otherwise unreachable;
|
||||
const byteOffset: Smi = 0;
|
||||
AttachBuffer(typedArray, buffer, elementMap, length, byteOffset);
|
||||
}
|
||||
|
||||
const byteOffset: uintptr = 0;
|
||||
SetupTypedArray(typedArray, length, byteOffset, byteLength);
|
||||
|
||||
return Undefined;
|
||||
}
|
||||
|
||||
macro TypedArrayInitializeWithBuffer(
|
||||
typedArray: JSTypedArray, length: PositiveSmi, buffer: JSArrayBuffer,
|
||||
elementsInfo: typed_array::TypedArrayElementsInfo, byteOffset: Number) {
|
||||
@ -41,7 +100,7 @@ namespace typed_array_createtypedarray {
|
||||
|
||||
// 22.2.4.2 TypedArray ( length )
|
||||
// ES #sec-typedarray-length
|
||||
macro ConstructByLength(implicit context: Context)(
|
||||
transitioning macro ConstructByLength(implicit context: Context)(
|
||||
typedArray: JSTypedArray, length: Object,
|
||||
elementsInfo: typed_array::TypedArrayElementsInfo): void {
|
||||
const convertedLength: Number =
|
||||
@ -52,25 +111,26 @@ namespace typed_array_createtypedarray {
|
||||
// TODO(7881): support larger-than-smi typed array lengths
|
||||
const positiveLength: PositiveSmi = Cast<PositiveSmi>(convertedLength)
|
||||
otherwise ThrowRangeError(context, kInvalidTypedArrayLength, length);
|
||||
const defaultConstructor: JSFunction = GetArrayBufferFunction();
|
||||
const initialize: Boolean = True;
|
||||
const defaultConstructor: Constructor = GetArrayBufferFunction();
|
||||
const initialize = True;
|
||||
TypedArrayInitialize(
|
||||
typedArray, positiveLength, elementsInfo.size, initialize,
|
||||
defaultConstructor);
|
||||
initialize, typedArray, positiveLength, elementsInfo.map,
|
||||
elementsInfo.size, defaultConstructor);
|
||||
}
|
||||
|
||||
// 22.2.4.4 TypedArray ( object )
|
||||
// ES #sec-typedarray-object
|
||||
macro ConstructByArrayLike(implicit context: Context)(
|
||||
transitioning macro ConstructByArrayLike(implicit context: Context)(
|
||||
typedArray: JSTypedArray, arrayLike: HeapObject, initialLength: Object,
|
||||
elementsInfo: typed_array::TypedArrayElementsInfo,
|
||||
bufferConstructor: JSReceiver): void {
|
||||
// The caller has looked up length on arrayLike, which is observable.
|
||||
const length: PositiveSmi = ToSmiLength(initialLength)
|
||||
otherwise ThrowRangeError(context, kInvalidTypedArrayLength, initialLength);
|
||||
const initialize: Boolean = False;
|
||||
const initialize = False;
|
||||
TypedArrayInitialize(
|
||||
typedArray, length, elementsInfo.size, initialize, bufferConstructor);
|
||||
initialize, typedArray, length, elementsInfo.map, elementsInfo.size,
|
||||
bufferConstructor);
|
||||
|
||||
try {
|
||||
const src: JSTypedArray = Cast<JSTypedArray>(arrayLike) otherwise IfSlow;
|
||||
@ -84,7 +144,7 @@ namespace typed_array_createtypedarray {
|
||||
} else if (length > 0) {
|
||||
const byteLength: Number = SmiMul(length, elementsInfo.size);
|
||||
assert(ByteLengthIsValid(byteLength));
|
||||
CallCMemcpy(
|
||||
typed_array::CallCMemcpy(
|
||||
typedArray.data_ptr, src.data_ptr, Convert<uintptr>(byteLength));
|
||||
}
|
||||
}
|
||||
@ -97,7 +157,7 @@ namespace typed_array_createtypedarray {
|
||||
|
||||
// 22.2.4.4 TypedArray ( object )
|
||||
// ES #sec-typedarray-object
|
||||
macro ConstructByIterable(implicit context: Context)(
|
||||
transitioning macro ConstructByIterable(implicit context: Context)(
|
||||
typedArray: JSTypedArray, iterable: JSReceiver, iteratorFn: Callable,
|
||||
elementsInfo: typed_array::TypedArrayElementsInfo): void {
|
||||
const array: JSArray =
|
||||
@ -109,7 +169,7 @@ namespace typed_array_createtypedarray {
|
||||
|
||||
// 22.2.4.3 TypedArray ( typedArray )
|
||||
// ES #sec-typedarray-typedarray
|
||||
macro ConstructByTypedArray(implicit context: Context)(
|
||||
transitioning macro ConstructByTypedArray(implicit context: Context)(
|
||||
typedArray: JSTypedArray, srcTypedArray: JSTypedArray,
|
||||
elementsInfo: typed_array::TypedArrayElementsInfo): void {
|
||||
let bufferConstructor: JSReceiver = GetArrayBufferFunction();
|
||||
|
@ -15,6 +15,10 @@ namespace typed_array {
|
||||
extern macro TypedArrayBuiltinsAssembler::ValidateTypedArray(
|
||||
Context, Object, constexpr string): JSTypedArray;
|
||||
|
||||
extern macro TypedArrayBuiltinsAssembler::CallCMemcpy(
|
||||
RawPtr, RawPtr, uintptr): void;
|
||||
extern macro TypedArrayBuiltinsAssembler::CallCMemset(
|
||||
RawPtr, intptr, uintptr): void;
|
||||
extern macro TypedArrayBuiltinsAssembler::GetTypedArrayElementsInfo(
|
||||
JSTypedArray): TypedArrayElementsInfo;
|
||||
extern macro LoadFixedTypedArrayElementAsTagged(
|
||||
|
@ -2003,6 +2003,28 @@ TNode<RawPtrT> CodeStubAssembler::LoadFixedTypedArrayBackingStore(
|
||||
IntPtrAdd(external_pointer, BitcastTaggedToWord(base_pointer)));
|
||||
}
|
||||
|
||||
TNode<RawPtrT> CodeStubAssembler::LoadFixedTypedArrayOnHeapBackingStore(
|
||||
TNode<FixedTypedArrayBase> typed_array) {
|
||||
// This is specialized method of retrieving the backing store pointer for on
|
||||
// heap allocated typed array buffer. On heap allocated buffer's backing
|
||||
// stores are a fixed offset from the pointer to a typed array's elements. See
|
||||
// TypedArrayBuiltinsAssembler::AllocateOnHeapElements().
|
||||
static const intptr_t fta_base_data_offset =
|
||||
FixedTypedArrayBase::kDataOffset - kHeapObjectTag;
|
||||
|
||||
TNode<WordT> backing_store = IntPtrAdd(BitcastTaggedToWord(typed_array),
|
||||
IntPtrConstant(fta_base_data_offset));
|
||||
|
||||
#ifdef DEBUG
|
||||
// Verify that this is an on heap backing store.
|
||||
TNode<RawPtrT> expected_backing_store_pointer =
|
||||
LoadFixedTypedArrayBackingStore(typed_array);
|
||||
CSA_ASSERT(this, WordEqual(backing_store, expected_backing_store_pointer));
|
||||
#endif
|
||||
|
||||
return UncheckedCast<RawPtrT>(backing_store);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::LoadFixedBigInt64ArrayElementAsTagged(
|
||||
Node* data_pointer, Node* offset) {
|
||||
if (Is64()) {
|
||||
|
@ -402,6 +402,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
|
||||
uintptr_t ConstexprUintPtrShl(uintptr_t a, int32_t b) { return a << b; }
|
||||
uintptr_t ConstexprUintPtrShr(uintptr_t a, int32_t b) { return a >> b; }
|
||||
intptr_t ConstexprIntPtrAdd(intptr_t a, intptr_t b) { return a + b; }
|
||||
uintptr_t ConstexprUintPtrAdd(uintptr_t a, uintptr_t b) { return a + b; }
|
||||
intptr_t ConstexprWordNot(intptr_t a) { return ~a; }
|
||||
uintptr_t ConstexprWordNot(uintptr_t a) { return ~a; }
|
||||
|
||||
TNode<Object> NoContextConstant();
|
||||
|
||||
@ -667,11 +671,19 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
callable, receiver, args...));
|
||||
}
|
||||
|
||||
template <class... TArgs>
|
||||
TNode<JSReceiver> ConstructWithTarget(TNode<Context> context,
|
||||
TNode<JSReceiver> target,
|
||||
TNode<JSReceiver> new_target,
|
||||
TArgs... args) {
|
||||
return CAST(ConstructJSWithTarget(CodeFactory::Construct(isolate()),
|
||||
context, target, new_target,
|
||||
implicit_cast<TNode<Object>>(args)...));
|
||||
}
|
||||
template <class... TArgs>
|
||||
TNode<JSReceiver> Construct(TNode<Context> context,
|
||||
TNode<JSReceiver> new_target, TArgs... args) {
|
||||
return CAST(ConstructJS(CodeFactory::Construct(isolate()), context,
|
||||
new_target, implicit_cast<TNode<Object>>(args)...));
|
||||
return ConstructWithTarget(context, new_target, new_target, args...);
|
||||
}
|
||||
|
||||
template <class A, class F, class G>
|
||||
@ -1119,6 +1131,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
MachineType machine_type = MachineType::Float64());
|
||||
TNode<RawPtrT> LoadFixedTypedArrayBackingStore(
|
||||
TNode<FixedTypedArrayBase> typed_array);
|
||||
TNode<RawPtrT> LoadFixedTypedArrayOnHeapBackingStore(
|
||||
TNode<FixedTypedArrayBase> typed_array);
|
||||
Node* LoadFixedTypedArrayElementAsTagged(
|
||||
Node* data_pointer, Node* index_node, ElementsKind elements_kind,
|
||||
ParameterMode parameter_mode = INTPTR_PARAMETERS);
|
||||
|
@ -1275,16 +1275,22 @@ class V8_EXPORT_PRIVATE CodeAssembler {
|
||||
}
|
||||
|
||||
template <class... TArgs>
|
||||
Node* ConstructJS(Callable const& callable, Node* context, Node* new_target,
|
||||
TArgs... args) {
|
||||
Node* ConstructJSWithTarget(Callable const& callable, Node* context,
|
||||
Node* target, Node* new_target, TArgs... args) {
|
||||
int argc = static_cast<int>(sizeof...(args));
|
||||
Node* arity = Int32Constant(argc);
|
||||
Node* receiver = LoadRoot(RootIndex::kUndefinedValue);
|
||||
|
||||
// Construct(target, new_target, arity, receiver, arguments...)
|
||||
return CallStub(callable, context, new_target, new_target, arity, receiver,
|
||||
return CallStub(callable, context, target, new_target, arity, receiver,
|
||||
args...);
|
||||
}
|
||||
template <class... TArgs>
|
||||
Node* ConstructJS(Callable const& callable, Node* context, Node* new_target,
|
||||
TArgs... args) {
|
||||
return ConstructJSWithTarget(callable, context, new_target, new_target,
|
||||
args...);
|
||||
}
|
||||
|
||||
Node* CallCFunctionN(Signature<MachineType>* signature, int input_count,
|
||||
Node* const* inputs);
|
||||
|
Loading…
Reference in New Issue
Block a user