Commit 4f0e9d6c authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[csa] Introduce ThrowIfArrayBufferIsDetached() helper.

This adds new CSA helpers ThrowIfArrayBufferIsDetached() and
ThrowIfArrayBufferViewBufferIsDetached() which check whether
ArrayBuffers or ArrayBufferViews have been detached. This
improves readability of the code that has to deal with typed
arrays.

Bug: v8:8015
Change-Id: Iafab86c418bd0e12bb7d7ec803151a1f6b786400
Reviewed-on: https://chromium-review.googlesource.com/1183422
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55273}
parent 60cbde18
......@@ -501,8 +501,7 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
// ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray
Label throw_not_typed_array(this, Label::kDeferred),
throw_detached(this, Label::kDeferred);
Label throw_not_typed_array(this, Label::kDeferred);
GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array);
GotoIfNot(HasInstanceType(CAST(receiver_), JS_TYPED_ARRAY_TYPE),
......@@ -511,9 +510,8 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
TNode<JSTypedArray> typed_array = CAST(receiver_);
o_ = typed_array;
Node* array_buffer =
LoadObjectField(typed_array, JSTypedArray::kBufferOffset);
GotoIf(IsDetachedBuffer(array_buffer), &throw_detached);
TNode<JSArrayBuffer> array_buffer = LoadArrayBufferViewBuffer(typed_array);
ThrowIfArrayBufferIsDetached(context_, array_buffer, name_);
len_ = LoadTypedArrayLength(typed_array);
......@@ -526,9 +524,6 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
BIND(&throw_not_typed_array);
ThrowTypeError(context_, MessageTemplate::kNotTypedArray);
BIND(&throw_detached);
ThrowTypeError(context_, MessageTemplate::kDetachedOperation, name_);
BIND(&throw_not_callable);
ThrowTypeError(context_, MessageTemplate::kCalledNonCallable, callbackfn_);
......@@ -3500,7 +3495,6 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
Label allocate_entry_if_needed(this);
Label allocate_iterator_result(this);
Label if_detached(this, Label::kDeferred);
Label if_typedarray(this), if_other(this, Label::kDeferred), if_array(this),
if_generic(this, Label::kDeferred);
Label set_done(this, Label::kDeferred);
......@@ -3678,8 +3672,7 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
BIND(&if_typedarray);
{
// Check that the {array}s buffer wasn't neutered.
TNode<JSArrayBuffer> buffer = LoadArrayBufferViewBuffer(CAST(array));
GotoIf(IsDetachedBuffer(buffer), &if_detached);
ThrowIfArrayBufferViewBufferIsDetached(context, CAST(array), method_name);
// If we go outside of the {length}, we don't need to update the
// [[ArrayIteratorNextIndex]] anymore, since a JSTypedArray's
......@@ -3710,9 +3703,6 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
var_value.Bind(LoadFixedTypedArrayElementAsTagged(data_ptr, CAST(index),
elements_kind));
Goto(&allocate_entry_if_needed);
BIND(&if_detached);
ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name);
}
BIND(&allocate_entry_if_needed);
......
......@@ -361,8 +361,7 @@ void TypedArrayBuiltinsAssembler::ConstructByArrayBuffer(
invalid_offset_error(this, Label::kDeferred);
Label offset_is_smi(this), offset_not_smi(this, Label::kDeferred),
check_length(this), call_init(this), invalid_length(this),
length_undefined(this), length_defined(this), detached_error(this),
done(this);
length_undefined(this), length_defined(this), done(this);
GotoIf(IsUndefined(byte_offset), &check_length);
......@@ -399,7 +398,7 @@ void TypedArrayBuiltinsAssembler::ConstructByArrayBuffer(
BIND(&length_undefined);
{
GotoIf(IsDetachedBuffer(buffer), &detached_error);
ThrowIfArrayBufferIsDetached(context, buffer, "Construct");
Node* buffer_byte_length =
LoadObjectField(buffer, JSArrayBuffer::kByteLengthOffset);
......@@ -421,7 +420,7 @@ void TypedArrayBuiltinsAssembler::ConstructByArrayBuffer(
BIND(&length_defined);
{
TNode<Smi> new_length = ToSmiIndex(length, context, &invalid_length);
GotoIf(IsDetachedBuffer(buffer), &detached_error);
ThrowIfArrayBufferIsDetached(context, buffer, "Construct");
new_byte_length.Bind(SmiMul(new_length, element_size));
// Reading the byte length must come after the ToIndex operation, which
// could cause the buffer to become detached.
......@@ -476,9 +475,6 @@ void TypedArrayBuiltinsAssembler::ConstructByArrayBuffer(
ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength, length);
}
BIND(&detached_error);
{ ThrowTypeError(context, MessageTemplate::kDetachedOperation, "Construct"); }
BIND(&done);
}
......@@ -573,7 +569,7 @@ void TypedArrayBuiltinsAssembler::ConstructByArrayLike(
TNode<HeapObject> array_like, TNode<Object> initial_length,
TNode<Smi> element_size, TNode<JSReceiver> buffer_constructor) {
Label invalid_length(this, Label::kDeferred), fill(this), fast_copy(this),
detached_check(this), done(this), detached_error(this, Label::kDeferred);
detached_check(this), done(this);
// The caller has looked up length on array_like, which is observable.
TNode<Smi> length = ToSmiLength(initial_length, context, &invalid_length);
......@@ -586,9 +582,8 @@ void TypedArrayBuiltinsAssembler::ConstructByArrayLike(
Goto(&fill);
BIND(&detached_check);
GotoIf(IsDetachedBuffer(
LoadObjectField(array_like, JSTypedArray::kBufferOffset)),
&detached_error);
ThrowIfArrayBufferViewBufferIsDetached(context, CAST(array_like),
"Construct");
Goto(&fill);
BIND(&fill);
......@@ -629,9 +624,6 @@ void TypedArrayBuiltinsAssembler::ConstructByArrayLike(
Goto(&done);
}
BIND(&detached_error);
{ ThrowTypeError(context, MessageTemplate::kDetachedOperation, "Construct"); }
BIND(&invalid_length);
{
ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength,
......@@ -964,18 +956,12 @@ TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::GetBuffer(
TNode<JSTypedArray> TypedArrayBuiltinsAssembler::ValidateTypedArray(
TNode<Context> context, TNode<Object> obj, const char* method_name) {
Label validation_done(this);
// If it is not a typed array, throw
ThrowIfNotInstanceType(context, obj, JS_TYPED_ARRAY_TYPE, method_name);
// If the typed array's buffer is detached, throw
TNode<Object> buffer =
LoadObjectField(CAST(obj), JSTypedArray::kBufferOffset);
GotoIfNot(IsDetachedBuffer(buffer), &validation_done);
ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name);
ThrowIfArrayBufferViewBufferIsDetached(context, CAST(obj), method_name);
BIND(&validation_done);
return CAST(obj);
}
......@@ -1189,6 +1175,7 @@ void TypedArrayBuiltinsAssembler::DispatchTypedArrayByElementsKind(
// ES #sec-get-%typedarray%.prototype.set
TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
const char* method_name = "%TypedArray%.prototype.set";
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
CodeStubArguments args(
this,
......@@ -1197,7 +1184,6 @@ TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
Label if_source_is_typed_array(this), if_source_is_fast_jsarray(this),
if_offset_is_out_of_bounds(this, Label::kDeferred),
if_source_too_large(this, Label::kDeferred),
if_typed_array_is_neutered(this, Label::kDeferred),
if_receiver_is_not_typedarray(this, Label::kDeferred);
// Check the receiver is a typed array.
......@@ -1221,9 +1207,7 @@ TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
TNode<Smi> offset_smi = CAST(offset_num);
// Check the receiver is not neutered.
TNode<Object> receiver_buffer =
LoadObjectField(CAST(receiver), JSTypedArray::kBufferOffset);
GotoIf(IsDetachedBuffer(receiver_buffer), &if_typed_array_is_neutered);
ThrowIfArrayBufferViewBufferIsDetached(context, CAST(receiver), method_name);
// Check the source argument is valid and whether a fast path can be taken.
Label call_runtime(this);
......@@ -1237,9 +1221,7 @@ TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
BIND(&if_source_is_typed_array);
{
// Check the source argument is not neutered.
TNode<Object> source_buffer =
LoadObjectField(CAST(source), JSTypedArray::kBufferOffset);
GotoIf(IsDetachedBuffer(source_buffer), &if_typed_array_is_neutered);
ThrowIfArrayBufferViewBufferIsDetached(context, CAST(source), method_name);
SetTypedArraySource(context, CAST(source), CAST(receiver),
SmiUntag(offset_smi), &call_runtime,
......@@ -1265,10 +1247,6 @@ TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
BIND(&if_source_too_large);
ThrowRangeError(context, MessageTemplate::kTypedArraySetSourceTooLarge);
BIND(&if_typed_array_is_neutered);
ThrowTypeError(context, MessageTemplate::kDetachedOperation,
"%TypedArray%.prototype.set");
BIND(&if_receiver_is_not_typedarray);
ThrowTypeError(context, MessageTemplate::kNotTypedArray);
}
......@@ -1277,7 +1255,6 @@ TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
TF_BUILTIN(TypedArrayPrototypeSlice, TypedArrayBuiltinsAssembler) {
const char* method_name = "%TypedArray%.prototype.slice";
Label call_c(this), call_memmove(this), if_count_is_not_zero(this),
if_typed_array_is_neutered(this, Label::kDeferred),
if_bigint_mixed_types(this, Label::kDeferred);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
......@@ -1321,9 +1298,9 @@ TF_BUILTIN(TypedArrayPrototypeSlice, TypedArrayBuiltinsAssembler) {
// result array is neutered or not since TypedArraySpeciesCreate checked it.
CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(LoadObjectField(
result_array, JSTypedArray::kBufferOffset))));
TNode<Object> receiver_buffer =
LoadObjectField(CAST(receiver), JSTypedArray::kBufferOffset);
GotoIf(IsDetachedBuffer(receiver_buffer), &if_typed_array_is_neutered);
TNode<JSArrayBuffer> receiver_buffer =
LoadArrayBufferViewBuffer(CAST(receiver));
ThrowIfArrayBufferIsDetached(context, receiver_buffer, method_name);
// result_array could be a different type from source or share the same
// buffer with the source because of custom species constructor.
......@@ -1390,9 +1367,6 @@ TF_BUILTIN(TypedArrayPrototypeSlice, TypedArrayBuiltinsAssembler) {
args.PopAndReturn(result_array);
}
BIND(&if_typed_array_is_neutered);
ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name);
BIND(&if_bigint_mixed_types);
ThrowTypeError(context, MessageTemplate::kBigIntMixedTypes);
}
......@@ -1520,18 +1494,12 @@ void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeIterationMethod(
GotoIfNot(IsJSTypedArray(CAST(receiver)), &throw_bad_receiver);
// Check if the {receiver}'s JSArrayBuffer was neutered.
TNode<JSArrayBuffer> receiver_buffer = LoadObjectField<JSArrayBuffer>(
CAST(receiver), JSTypedArray::kBufferOffset);
Label if_receiverisneutered(this, Label::kDeferred);
GotoIf(IsDetachedBuffer(receiver_buffer), &if_receiverisneutered);
ThrowIfArrayBufferViewBufferIsDetached(context, CAST(receiver), method_name);
Return(CreateArrayIterator(context, receiver, kind));
BIND(&throw_bad_receiver);
ThrowTypeError(context, MessageTemplate::kNotTypedArray, method_name);
BIND(&if_receiverisneutered);
ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name);
}
// ES #sec-%typedarray%.prototype.values
......
......@@ -11979,6 +11979,23 @@ Node* CodeStubAssembler::IsDetachedBuffer(Node* buffer) {
return IsSetWord32<JSArrayBuffer::WasNeutered>(buffer_bit_field);
}
void CodeStubAssembler::ThrowIfArrayBufferIsDetached(
SloppyTNode<Context> context, TNode<JSArrayBuffer> array_buffer,
const char* method_name) {
Label if_detached(this, Label::kDeferred), if_not_detached(this);
Branch(IsDetachedBuffer(array_buffer), &if_detached, &if_not_detached);
BIND(&if_detached);
ThrowTypeError(context, MessageTemplate::kDetachedOperation, method_name);
BIND(&if_not_detached);
}
void CodeStubAssembler::ThrowIfArrayBufferViewBufferIsDetached(
SloppyTNode<Context> context, TNode<JSArrayBufferView> array_buffer_view,
const char* method_name) {
TNode<JSArrayBuffer> buffer = LoadArrayBufferViewBuffer(array_buffer_view);
ThrowIfArrayBufferIsDetached(context, buffer, method_name);
}
TNode<JSArrayBuffer> CodeStubAssembler::LoadArrayBufferViewBuffer(
TNode<JSArrayBufferView> array_buffer_view) {
return LoadObjectField<JSArrayBuffer>(array_buffer_view,
......
......@@ -2722,6 +2722,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
// TypedArray/ArrayBuffer helpers
Node* IsDetachedBuffer(Node* buffer);
void ThrowIfArrayBufferIsDetached(SloppyTNode<Context> context,
TNode<JSArrayBuffer> array_buffer,
const char* method_name);
void ThrowIfArrayBufferViewBufferIsDetached(
SloppyTNode<Context> context, TNode<JSArrayBufferView> array_buffer_view,
const char* method_name);
TNode<JSArrayBuffer> LoadArrayBufferViewBuffer(
TNode<JSArrayBufferView> array_buffer_view);
TNode<RawPtrT> LoadArrayBufferBackingStore(TNode<JSArrayBuffer> array_buffer);
......
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