[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:
peterwmwong 2019-02-01 09:35:18 -06:00 committed by Commit Bot
parent 9eba56162f
commit bf9a7c524c
9 changed files with 259 additions and 210 deletions

View File

@ -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>(

View File

@ -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) \

View File

@ -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,

View File

@ -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);

View File

@ -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();

View File

@ -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(

View File

@ -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()) {

View File

@ -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);

View File

@ -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);