[csa][cleanup] TNodify PrepareValueForWriteToTypedArray
Using templates seems like the best way to go. We are duplicating code but seems like a fair trade-off. Bug: v8:6949 Change-Id: I22b3d5e2e74bfc2bf46f95656782aae4944d72de Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2727816 Reviewed-by: Dan Elphick <delphick@chromium.org> Commit-Queue: Santiago Aboy Solanes <solanes@chromium.org> Cr-Commit-Position: refs/heads/master@{#73126}
This commit is contained in:
parent
4db38b0c9e
commit
eb976c3ef9
@ -10260,34 +10260,6 @@ TNode<UntaggedT> CodeStubAssembler::PrepareValueForWriteToTypedArray(
|
||||
}
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::PrepareValueForWriteToTypedArray(
|
||||
TNode<Object> input, ElementsKind elements_kind, TNode<Context> context) {
|
||||
DCHECK(IsTypedArrayElementsKind(elements_kind));
|
||||
|
||||
switch (elements_kind) {
|
||||
case UINT8_ELEMENTS:
|
||||
case INT8_ELEMENTS:
|
||||
case UINT16_ELEMENTS:
|
||||
case INT16_ELEMENTS:
|
||||
case UINT32_ELEMENTS:
|
||||
case INT32_ELEMENTS:
|
||||
case UINT8_CLAMPED_ELEMENTS:
|
||||
return PrepareValueForWriteToTypedArray<Word32T>(input, elements_kind,
|
||||
context);
|
||||
case FLOAT32_ELEMENTS:
|
||||
return PrepareValueForWriteToTypedArray<Float32T>(input, elements_kind,
|
||||
context);
|
||||
case FLOAT64_ELEMENTS:
|
||||
return PrepareValueForWriteToTypedArray<Float64T>(input, elements_kind,
|
||||
context);
|
||||
case BIGINT64_ELEMENTS:
|
||||
case BIGUINT64_ELEMENTS:
|
||||
return ToBigInt(context, input);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void CodeStubAssembler::BigIntToRawBytes(TNode<BigInt> bigint,
|
||||
TVariable<UintPtrT>* var_low,
|
||||
TVariable<UintPtrT>* var_high) {
|
||||
@ -10321,6 +10293,134 @@ void CodeStubAssembler::BigIntToRawBytes(TNode<BigInt> bigint,
|
||||
BIND(&done);
|
||||
}
|
||||
|
||||
template <>
|
||||
void CodeStubAssembler::EmitElementStoreTypedArrayUpdateValue(
|
||||
TNode<Object> value, ElementsKind elements_kind,
|
||||
TNode<Word32T> converted_value, TVariable<Object>* maybe_converted_value) {
|
||||
switch (elements_kind) {
|
||||
case UINT8_ELEMENTS:
|
||||
case INT8_ELEMENTS:
|
||||
case UINT16_ELEMENTS:
|
||||
case INT16_ELEMENTS:
|
||||
case UINT8_CLAMPED_ELEMENTS:
|
||||
*maybe_converted_value =
|
||||
SmiFromInt32(UncheckedCast<Int32T>(converted_value));
|
||||
break;
|
||||
case UINT32_ELEMENTS:
|
||||
*maybe_converted_value =
|
||||
ChangeUint32ToTagged(UncheckedCast<Uint32T>(converted_value));
|
||||
break;
|
||||
case INT32_ELEMENTS:
|
||||
*maybe_converted_value =
|
||||
ChangeInt32ToTagged(UncheckedCast<Int32T>(converted_value));
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void CodeStubAssembler::EmitElementStoreTypedArrayUpdateValue(
|
||||
TNode<Object> value, ElementsKind elements_kind,
|
||||
TNode<Float32T> converted_value, TVariable<Object>* maybe_converted_value) {
|
||||
Label dont_allocate_heap_number(this), end(this);
|
||||
GotoIf(TaggedIsSmi(value), &dont_allocate_heap_number);
|
||||
GotoIf(IsHeapNumber(CAST(value)), &dont_allocate_heap_number);
|
||||
{
|
||||
*maybe_converted_value =
|
||||
AllocateHeapNumberWithValue(ChangeFloat32ToFloat64(converted_value));
|
||||
Goto(&end);
|
||||
}
|
||||
BIND(&dont_allocate_heap_number);
|
||||
{
|
||||
*maybe_converted_value = value;
|
||||
Goto(&end);
|
||||
}
|
||||
BIND(&end);
|
||||
}
|
||||
|
||||
template <>
|
||||
void CodeStubAssembler::EmitElementStoreTypedArrayUpdateValue(
|
||||
TNode<Object> value, ElementsKind elements_kind,
|
||||
TNode<Float64T> converted_value, TVariable<Object>* maybe_converted_value) {
|
||||
Label dont_allocate_heap_number(this), end(this);
|
||||
GotoIf(TaggedIsSmi(value), &dont_allocate_heap_number);
|
||||
GotoIf(IsHeapNumber(CAST(value)), &dont_allocate_heap_number);
|
||||
{
|
||||
*maybe_converted_value = AllocateHeapNumberWithValue(converted_value);
|
||||
Goto(&end);
|
||||
}
|
||||
BIND(&dont_allocate_heap_number);
|
||||
{
|
||||
*maybe_converted_value = value;
|
||||
Goto(&end);
|
||||
}
|
||||
BIND(&end);
|
||||
}
|
||||
|
||||
template <>
|
||||
void CodeStubAssembler::EmitElementStoreTypedArrayUpdateValue(
|
||||
TNode<Object> value, ElementsKind elements_kind,
|
||||
TNode<BigInt> converted_value, TVariable<Object>* maybe_converted_value) {
|
||||
*maybe_converted_value = converted_value;
|
||||
}
|
||||
|
||||
template <typename TValue>
|
||||
void CodeStubAssembler::EmitElementStoreTypedArray(
|
||||
TNode<JSTypedArray> typed_array, TNode<IntPtrT> key, TNode<Object> value,
|
||||
ElementsKind elements_kind, KeyedAccessStoreMode store_mode, Label* bailout,
|
||||
TNode<Context> context, TVariable<Object>* maybe_converted_value) {
|
||||
Label done(this), update_value_and_bailout(this, Label::kDeferred);
|
||||
|
||||
TNode<TValue> converted_value =
|
||||
PrepareValueForWriteToTypedArray<TValue>(value, elements_kind, context);
|
||||
|
||||
// There must be no allocations between the buffer load and
|
||||
// and the actual store to backing store, because GC may decide that
|
||||
// the buffer is not alive or move the elements.
|
||||
// TODO(ishell): introduce DisallowGarbageCollectionCode scope here.
|
||||
|
||||
// Check if buffer has been detached.
|
||||
TNode<JSArrayBuffer> buffer = LoadJSArrayBufferViewBuffer(typed_array);
|
||||
if (maybe_converted_value) {
|
||||
GotoIf(IsDetachedBuffer(buffer), &update_value_and_bailout);
|
||||
} else {
|
||||
GotoIf(IsDetachedBuffer(buffer), bailout);
|
||||
}
|
||||
|
||||
// Bounds check.
|
||||
TNode<UintPtrT> length = LoadJSTypedArrayLength(typed_array);
|
||||
|
||||
if (store_mode == STORE_IGNORE_OUT_OF_BOUNDS) {
|
||||
// Skip the store if we write beyond the length or
|
||||
// to a property with a negative integer index.
|
||||
GotoIfNot(UintPtrLessThan(key, length), &done);
|
||||
} else {
|
||||
DCHECK_EQ(store_mode, STANDARD_STORE);
|
||||
GotoIfNot(UintPtrLessThan(key, length), &update_value_and_bailout);
|
||||
}
|
||||
|
||||
TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(typed_array);
|
||||
StoreElement(data_ptr, elements_kind, key, converted_value);
|
||||
Goto(&done);
|
||||
|
||||
BIND(&update_value_and_bailout);
|
||||
// We already prepared the incoming value for storing into a typed array.
|
||||
// This might involve calling ToNumber in some cases. We shouldn't call
|
||||
// ToNumber again in the runtime so pass the converted value to the runtime.
|
||||
// The prepared value is an untagged value. Convert it to a tagged value
|
||||
// to pass it to runtime. It is not possible to do the detached buffer check
|
||||
// before we prepare the value, since ToNumber can detach the ArrayBuffer.
|
||||
// The spec specifies the order of these operations.
|
||||
if (maybe_converted_value != nullptr) {
|
||||
EmitElementStoreTypedArrayUpdateValue(value, elements_kind, converted_value,
|
||||
maybe_converted_value);
|
||||
}
|
||||
Goto(bailout);
|
||||
|
||||
BIND(&done);
|
||||
}
|
||||
|
||||
void CodeStubAssembler::EmitElementStore(
|
||||
TNode<JSObject> object, TNode<Object> key, TNode<Object> value,
|
||||
ElementsKind elements_kind, KeyedAccessStoreMode store_mode, Label* bailout,
|
||||
@ -10342,111 +10442,38 @@ void CodeStubAssembler::EmitElementStore(
|
||||
// TODO(rmcilroy): TNodify the converted value once this funciton and
|
||||
// StoreElement are templated based on the type elements_kind type.
|
||||
if (IsTypedArrayElementsKind(elements_kind)) {
|
||||
Label done(this), update_value_and_bailout(this, Label::kDeferred);
|
||||
|
||||
// IntegerIndexedElementSet converts value to a Number/BigInt prior to the
|
||||
// bounds check.
|
||||
Node* converted_value =
|
||||
PrepareValueForWriteToTypedArray(value, elements_kind, context);
|
||||
TNode<JSTypedArray> typed_array = CAST(object);
|
||||
|
||||
// There must be no allocations between the buffer load and
|
||||
// and the actual store to backing store, because GC may decide that
|
||||
// the buffer is not alive or move the elements.
|
||||
// TODO(ishell): introduce DisallowGarbageCollectionCode scope here.
|
||||
|
||||
// Check if buffer has been detached.
|
||||
TNode<JSArrayBuffer> buffer = LoadJSArrayBufferViewBuffer(typed_array);
|
||||
if (maybe_converted_value) {
|
||||
GotoIf(IsDetachedBuffer(buffer), &update_value_and_bailout);
|
||||
} else {
|
||||
GotoIf(IsDetachedBuffer(buffer), bailout);
|
||||
switch (elements_kind) {
|
||||
case UINT8_ELEMENTS:
|
||||
case INT8_ELEMENTS:
|
||||
case UINT16_ELEMENTS:
|
||||
case INT16_ELEMENTS:
|
||||
case UINT32_ELEMENTS:
|
||||
case INT32_ELEMENTS:
|
||||
case UINT8_CLAMPED_ELEMENTS:
|
||||
EmitElementStoreTypedArray<Word32T>(typed_array, intptr_key, value,
|
||||
elements_kind, store_mode, bailout,
|
||||
context, maybe_converted_value);
|
||||
break;
|
||||
case FLOAT32_ELEMENTS:
|
||||
EmitElementStoreTypedArray<Float32T>(typed_array, intptr_key, value,
|
||||
elements_kind, store_mode, bailout,
|
||||
context, maybe_converted_value);
|
||||
break;
|
||||
case FLOAT64_ELEMENTS:
|
||||
EmitElementStoreTypedArray<Float64T>(typed_array, intptr_key, value,
|
||||
elements_kind, store_mode, bailout,
|
||||
context, maybe_converted_value);
|
||||
break;
|
||||
case BIGINT64_ELEMENTS:
|
||||
case BIGUINT64_ELEMENTS:
|
||||
EmitElementStoreTypedArray<BigInt>(typed_array, intptr_key, value,
|
||||
elements_kind, store_mode, bailout,
|
||||
context, maybe_converted_value);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
// Bounds check.
|
||||
TNode<UintPtrT> length = LoadJSTypedArrayLength(typed_array);
|
||||
|
||||
if (store_mode == STORE_IGNORE_OUT_OF_BOUNDS) {
|
||||
// Skip the store if we write beyond the length or
|
||||
// to a property with a negative integer index.
|
||||
GotoIfNot(UintPtrLessThan(intptr_key, length), &done);
|
||||
} else {
|
||||
DCHECK_EQ(store_mode, STANDARD_STORE);
|
||||
GotoIfNot(UintPtrLessThan(intptr_key, length), &update_value_and_bailout);
|
||||
}
|
||||
|
||||
TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(typed_array);
|
||||
StoreElement(data_ptr, elements_kind, intptr_key, converted_value);
|
||||
Goto(&done);
|
||||
|
||||
BIND(&update_value_and_bailout);
|
||||
// We already prepared the incoming value for storing into a typed array.
|
||||
// This might involve calling ToNumber in some cases. We shouldn't call
|
||||
// ToNumber again in the runtime so pass the converted value to the runtime.
|
||||
// The prepared value is an untagged value. Convert it to a tagged value
|
||||
// to pass it to runtime. It is not possible to do the detached buffer check
|
||||
// before we prepare the value, since ToNumber can detach the ArrayBuffer.
|
||||
// The spec specifies the order of these operations.
|
||||
if (maybe_converted_value != nullptr) {
|
||||
switch (elements_kind) {
|
||||
case UINT8_ELEMENTS:
|
||||
case INT8_ELEMENTS:
|
||||
case UINT16_ELEMENTS:
|
||||
case INT16_ELEMENTS:
|
||||
case UINT8_CLAMPED_ELEMENTS:
|
||||
*maybe_converted_value = SmiFromInt32(converted_value);
|
||||
break;
|
||||
case UINT32_ELEMENTS:
|
||||
*maybe_converted_value = ChangeUint32ToTagged(converted_value);
|
||||
break;
|
||||
case INT32_ELEMENTS:
|
||||
*maybe_converted_value = ChangeInt32ToTagged(converted_value);
|
||||
break;
|
||||
case FLOAT32_ELEMENTS: {
|
||||
Label dont_allocate_heap_number(this), end(this);
|
||||
GotoIf(TaggedIsSmi(value), &dont_allocate_heap_number);
|
||||
GotoIf(IsHeapNumber(CAST(value)), &dont_allocate_heap_number);
|
||||
{
|
||||
*maybe_converted_value = AllocateHeapNumberWithValue(
|
||||
ChangeFloat32ToFloat64(converted_value));
|
||||
Goto(&end);
|
||||
}
|
||||
BIND(&dont_allocate_heap_number);
|
||||
{
|
||||
*maybe_converted_value = value;
|
||||
Goto(&end);
|
||||
}
|
||||
BIND(&end);
|
||||
break;
|
||||
}
|
||||
case FLOAT64_ELEMENTS: {
|
||||
Label dont_allocate_heap_number(this), end(this);
|
||||
GotoIf(TaggedIsSmi(value), &dont_allocate_heap_number);
|
||||
GotoIf(IsHeapNumber(CAST(value)), &dont_allocate_heap_number);
|
||||
{
|
||||
*maybe_converted_value =
|
||||
AllocateHeapNumberWithValue(converted_value);
|
||||
Goto(&end);
|
||||
}
|
||||
BIND(&dont_allocate_heap_number);
|
||||
{
|
||||
*maybe_converted_value = value;
|
||||
Goto(&end);
|
||||
}
|
||||
BIND(&end);
|
||||
break;
|
||||
}
|
||||
case BIGINT64_ELEMENTS:
|
||||
case BIGUINT64_ELEMENTS:
|
||||
*maybe_converted_value = CAST(converted_value);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
Goto(bailout);
|
||||
|
||||
BIND(&done);
|
||||
return;
|
||||
}
|
||||
DCHECK(IsFastElementsKind(elements_kind) ||
|
||||
|
@ -3203,10 +3203,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
TNode<Uint8T> Int32ToUint8Clamped(TNode<Int32T> int32_value);
|
||||
TNode<Uint8T> Float64ToUint8Clamped(TNode<Float64T> float64_value);
|
||||
|
||||
Node* PrepareValueForWriteToTypedArray(TNode<Object> input,
|
||||
ElementsKind elements_kind,
|
||||
TNode<Context> context);
|
||||
|
||||
template <typename T>
|
||||
TNode<T> PrepareValueForWriteToTypedArray(TNode<Object> input,
|
||||
ElementsKind elements_kind,
|
||||
@ -3828,6 +3824,19 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
void TryPlainPrimitiveNonNumberToNumber(TNode<HeapObject> input,
|
||||
TVariable<Number>* var_result,
|
||||
Label* if_bailout);
|
||||
|
||||
template <typename TValue>
|
||||
void EmitElementStoreTypedArray(TNode<JSTypedArray> typed_array,
|
||||
TNode<IntPtrT> key, TNode<Object> value,
|
||||
ElementsKind elements_kind,
|
||||
KeyedAccessStoreMode store_mode,
|
||||
Label* bailout, TNode<Context> context,
|
||||
TVariable<Object>* maybe_converted_value);
|
||||
|
||||
template <typename TValue>
|
||||
void EmitElementStoreTypedArrayUpdateValue(
|
||||
TNode<Object> value, ElementsKind elements_kind,
|
||||
TNode<TValue> converted_value, TVariable<Object>* maybe_converted_value);
|
||||
};
|
||||
|
||||
class V8_EXPORT_PRIVATE CodeStubArguments {
|
||||
|
Loading…
Reference in New Issue
Block a user