summaryrefslogtreecommitdiff
path: root/chromium/v8/src/builtins
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/v8/src/builtins')
-rw-r--r--chromium/v8/src/builtins/builtins-collections-gen.cc9
-rw-r--r--chromium/v8/src/builtins/builtins-definitions.h2
-rw-r--r--chromium/v8/src/builtins/builtins-proxy-gen.cc4
-rw-r--r--chromium/v8/src/builtins/builtins-string-gen.cc29
-rw-r--r--chromium/v8/src/builtins/builtins-string-gen.h2
-rw-r--r--chromium/v8/src/builtins/builtins-typedarray-gen.cc346
-rw-r--r--chromium/v8/src/builtins/builtins-typedarray.cc296
7 files changed, 366 insertions, 322 deletions
diff --git a/chromium/v8/src/builtins/builtins-collections-gen.cc b/chromium/v8/src/builtins/builtins-collections-gen.cc
index a1928632abd..4aa7fa310b1 100644
--- a/chromium/v8/src/builtins/builtins-collections-gen.cc
+++ b/chromium/v8/src/builtins/builtins-collections-gen.cc
@@ -314,10 +314,11 @@ TF_BUILTIN(MapConstructor, CollectionsBuiltinsAssembler) {
BIND(&if_notobject);
{
- Node* const exception = MakeTypeError(
- MessageTemplate::kIteratorValueNotAnObject, context, next_value);
- var_exception.Bind(exception);
- Goto(&if_exception);
+ Node* ret = CallRuntime(
+ Runtime::kThrowTypeError, context,
+ SmiConstant(MessageTemplate::kIteratorValueNotAnObject), next_value);
+ GotoIfException(ret, &if_exception, &var_exception);
+ Unreachable();
}
}
diff --git a/chromium/v8/src/builtins/builtins-definitions.h b/chromium/v8/src/builtins/builtins-definitions.h
index 746051b6cd9..cc89c4e3650 100644
--- a/chromium/v8/src/builtins/builtins-definitions.h
+++ b/chromium/v8/src/builtins/builtins-definitions.h
@@ -1024,7 +1024,7 @@ namespace internal {
/* ES6 #sec-%typedarray%.prototype.reverse */ \
CPP(TypedArrayPrototypeReverse) \
/* ES6 %TypedArray%.prototype.set */ \
- CPP(TypedArrayPrototypeSet) \
+ TFJ(TypedArrayPrototypeSet, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
/* ES6 #sec-%typedarray%.prototype.slice */ \
CPP(TypedArrayPrototypeSlice) \
/* ES6 #sec-get-%typedarray%.prototype-@@tostringtag */ \
diff --git a/chromium/v8/src/builtins/builtins-proxy-gen.cc b/chromium/v8/src/builtins/builtins-proxy-gen.cc
index c4fd34290a8..29c5a4eaeb3 100644
--- a/chromium/v8/src/builtins/builtins-proxy-gen.cc
+++ b/chromium/v8/src/builtins/builtins-proxy-gen.cc
@@ -491,7 +491,7 @@ void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
Node* instance_type = LoadInstanceType(target);
TryGetOwnProperty(context, target, target, map, instance_type, name,
&if_found_value, &var_value, &var_details, &var_raw_value,
- check_passed, &check_in_runtime);
+ check_passed, &check_in_runtime, kReturnAccessorPair);
BIND(&if_found_value);
{
@@ -589,7 +589,7 @@ void ProxiesCodeStubAssembler::CheckHasTrapResult(Node* context, Node* target,
Node* instance_type = LoadInstanceType(target);
TryGetOwnProperty(context, target, target, target_map, instance_type, name,
&if_found_value, &var_value, &var_details, &var_raw_value,
- check_passed, if_bailout);
+ check_passed, if_bailout, kReturnAccessorPair);
// 9.b. If targetDesc is not undefined, then (see 9.b.i. below).
BIND(&if_found_value);
diff --git a/chromium/v8/src/builtins/builtins-string-gen.cc b/chromium/v8/src/builtins/builtins-string-gen.cc
index 9cb0e474e21..8d407b35e61 100644
--- a/chromium/v8/src/builtins/builtins-string-gen.cc
+++ b/chromium/v8/src/builtins/builtins-string-gen.cc
@@ -1052,9 +1052,9 @@ void StringBuiltinsAssembler::RequireObjectCoercible(Node* const context,
}
void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol(
- Node* const context, Node* const object, Handle<Symbol> symbol,
- const NodeFunction0& regexp_call, const NodeFunction1& generic_call,
- CodeStubArguments* args) {
+ Node* const context, Node* const object, Node* const maybe_string,
+ Handle<Symbol> symbol, const NodeFunction0& regexp_call,
+ const NodeFunction1& generic_call, CodeStubArguments* args) {
Label out(this);
// Smis definitely don't have an attached symbol.
@@ -1084,14 +1084,21 @@ void StringBuiltinsAssembler::MaybeCallFunctionAtSymbol(
}
// Take the fast path for RegExps.
+ // There's two conditions: {object} needs to be a fast regexp, and
+ // {maybe_string} must be a string (we can't call ToString on the fast path
+ // since it may mutate {object}).
{
Label stub_call(this), slow_lookup(this);
+ GotoIf(TaggedIsSmi(maybe_string), &slow_lookup);
+ GotoIfNot(IsString(maybe_string), &slow_lookup);
+
RegExpBuiltinsAssembler regexp_asm(state());
regexp_asm.BranchIfFastRegExp(context, object, object_map, &stub_call,
&slow_lookup);
BIND(&stub_call);
+ // TODO(jgruber): Add a no-JS scope once it exists.
Node* const result = regexp_call();
if (args == nullptr) {
Return(result);
@@ -1307,12 +1314,10 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
// Redirect to replacer method if {search[@@replace]} is not undefined.
MaybeCallFunctionAtSymbol(
- context, search, isolate()->factory()->replace_symbol(),
+ context, search, receiver, isolate()->factory()->replace_symbol(),
[=]() {
- Node* const subject_string = ToString_Inline(context, receiver);
-
- return CallBuiltin(Builtins::kRegExpReplace, context, search,
- subject_string, replace);
+ return CallBuiltin(Builtins::kRegExpReplace, context, search, receiver,
+ replace);
},
[=](Node* fn) {
Callable call_callable = CodeFactory::Call(isolate());
@@ -1550,12 +1555,10 @@ TF_BUILTIN(StringPrototypeSplit, StringBuiltinsAssembler) {
// Redirect to splitter method if {separator[@@split]} is not undefined.
MaybeCallFunctionAtSymbol(
- context, separator, isolate()->factory()->split_symbol(),
+ context, separator, receiver, isolate()->factory()->split_symbol(),
[=]() {
- Node* const subject_string = ToString_Inline(context, receiver);
-
- return CallBuiltin(Builtins::kRegExpSplit, context, separator,
- subject_string, limit);
+ return CallBuiltin(Builtins::kRegExpSplit, context, separator, receiver,
+ limit);
},
[=](Node* fn) {
Callable call_callable = CodeFactory::Call(isolate());
diff --git a/chromium/v8/src/builtins/builtins-string-gen.h b/chromium/v8/src/builtins/builtins-string-gen.h
index 607f7b6acb2..c9af3802707 100644
--- a/chromium/v8/src/builtins/builtins-string-gen.h
+++ b/chromium/v8/src/builtins/builtins-string-gen.h
@@ -82,9 +82,11 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
// }
//
// Contains fast paths for Smi and RegExp objects.
+ // Important: {regexp_call} may not contain any code that can call into JS.
typedef std::function<Node*()> NodeFunction0;
typedef std::function<Node*(Node* fn)> NodeFunction1;
void MaybeCallFunctionAtSymbol(Node* const context, Node* const object,
+ Node* const maybe_string,
Handle<Symbol> symbol,
const NodeFunction0& regexp_call,
const NodeFunction1& generic_call,
diff --git a/chromium/v8/src/builtins/builtins-typedarray-gen.cc b/chromium/v8/src/builtins/builtins-typedarray-gen.cc
index a58f3a4093f..07f122b9098 100644
--- a/chromium/v8/src/builtins/builtins-typedarray-gen.cc
+++ b/chromium/v8/src/builtins/builtins-typedarray-gen.cc
@@ -10,6 +10,10 @@
namespace v8 {
namespace internal {
+using compiler::Node;
+template <class T>
+using TNode = compiler::TNode<T>;
+
// This is needed for gc_mole which will compile this file without the full set
// of GN defined macros.
#ifndef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP
@@ -41,9 +45,37 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
Node* CalculateExternalPointer(Node* backing_store, Node* byte_offset);
Node* LoadDataPtr(Node* typed_array);
Node* ByteLengthIsValid(Node* byte_length);
+
+ // Loads the element kind of TypedArray instance.
+ TNode<Word32T> LoadElementsKind(TNode<Object> typed_array);
+
+ // Returns the byte size of an element for a TypedArray elements kind.
+ TNode<IntPtrT> GetTypedArrayElementSize(TNode<Word32T> elements_kind);
+
+ // Fast path for setting a TypedArray (source) onto another TypedArray
+ // (target) at an element offset.
+ void SetTypedArraySource(TNode<Context> context, TNode<JSTypedArray> source,
+ TNode<JSTypedArray> target, TNode<IntPtrT> offset,
+ Label* call_runtime, Label* if_source_too_large);
+
+ void SetJSArraySource(TNode<Context> context, TNode<JSArray> source,
+ TNode<JSTypedArray> target, TNode<IntPtrT> offset,
+ Label* call_runtime, Label* if_source_too_large);
+
+ void CallCMemmove(TNode<IntPtrT> dest_ptr, TNode<IntPtrT> src_ptr,
+ TNode<IntPtrT> byte_length);
+
+ void CallCCopyFastNumberJSArrayElementsToTypedArray(
+ TNode<Context> context, TNode<JSArray> source, TNode<JSTypedArray> dest,
+ TNode<IntPtrT> source_length, TNode<IntPtrT> offset);
+
+ void CallCCopyTypedArrayElementsToTypedArray(TNode<JSTypedArray> source,
+ TNode<JSTypedArray> dest,
+ TNode<IntPtrT> source_length,
+ TNode<IntPtrT> offset);
};
-compiler::Node* TypedArrayBuiltinsAssembler::LoadMapForType(Node* array) {
+Node* TypedArrayBuiltinsAssembler::LoadMapForType(Node* array) {
CSA_ASSERT(this, IsJSTypedArray(array));
Label unreachable(this), done(this);
@@ -96,8 +128,8 @@ compiler::Node* TypedArrayBuiltinsAssembler::LoadMapForType(Node* array) {
// can't allocate an array bigger than our 32-bit arithmetic range anyway. 64
// bit platforms could theoretically have an offset up to 2^35 - 1, so we may
// need to convert the float heap number to an intptr.
-compiler::Node* TypedArrayBuiltinsAssembler::CalculateExternalPointer(
- Node* backing_store, Node* byte_offset) {
+Node* TypedArrayBuiltinsAssembler::CalculateExternalPointer(Node* backing_store,
+ Node* byte_offset) {
return IntPtrAdd(backing_store, ChangeNumberToIntPtr(byte_offset));
}
@@ -518,7 +550,7 @@ TF_BUILTIN(TypedArrayConstructByArrayBuffer, TypedArrayBuiltinsAssembler) {
}
}
-compiler::Node* TypedArrayBuiltinsAssembler::LoadDataPtr(Node* typed_array) {
+Node* TypedArrayBuiltinsAssembler::LoadDataPtr(Node* typed_array) {
CSA_ASSERT(this, IsJSTypedArray(typed_array));
Node* elements = LoadElements(typed_array);
CSA_ASSERT(this, IsFixedTypedArray(elements));
@@ -529,8 +561,7 @@ compiler::Node* TypedArrayBuiltinsAssembler::LoadDataPtr(Node* typed_array) {
return IntPtrAdd(base_pointer, external_pointer);
}
-compiler::Node* TypedArrayBuiltinsAssembler::ByteLengthIsValid(
- Node* byte_length) {
+Node* TypedArrayBuiltinsAssembler::ByteLengthIsValid(Node* byte_length) {
Label smi(this), done(this);
VARIABLE(is_valid, MachineRepresentation::kWord32);
GotoIf(TaggedIsSmi(byte_length), &smi);
@@ -674,6 +705,309 @@ TF_BUILTIN(TypedArrayPrototypeLength, TypedArrayBuiltinsAssembler) {
JSTypedArray::kLengthOffset);
}
+TNode<Word32T> TypedArrayBuiltinsAssembler::LoadElementsKind(
+ TNode<Object> typed_array) {
+ CSA_ASSERT(this, IsJSTypedArray(typed_array));
+ return Int32Sub(LoadMapElementsKind(LoadMap(CAST(typed_array))),
+ Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND));
+}
+
+TNode<IntPtrT> TypedArrayBuiltinsAssembler::GetTypedArrayElementSize(
+ TNode<Word32T> elements_kind) {
+ TVARIABLE(IntPtrT, element_size);
+ Label next(this), if_unknown_type(this, Label::kDeferred);
+
+ size_t const kTypedElementsKindCount = LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
+ FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
+ 1;
+
+ int32_t elements_kinds[kTypedElementsKindCount] = {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ TYPE##_ELEMENTS - FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+ };
+
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ Label if_##type##array(this);
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+
+ Label* elements_kind_labels[kTypedElementsKindCount] = {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) &if_##type##array,
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+ };
+
+ Switch(elements_kind, &if_unknown_type, elements_kinds, elements_kind_labels,
+ kTypedElementsKindCount);
+
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ BIND(&if_##type##array); \
+ { \
+ element_size = IntPtrConstant(size); \
+ Goto(&next); \
+ }
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+
+ BIND(&if_unknown_type);
+ {
+ element_size = IntPtrConstant(0);
+ Goto(&next);
+ }
+ BIND(&next);
+ return element_size;
+}
+
+void TypedArrayBuiltinsAssembler::SetTypedArraySource(
+ TNode<Context> context, TNode<JSTypedArray> source,
+ TNode<JSTypedArray> target, TNode<IntPtrT> offset, Label* call_runtime,
+ Label* if_source_too_large) {
+ CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(
+ LoadObjectField(source, JSTypedArray::kBufferOffset))));
+ CSA_ASSERT(this, Word32BinaryNot(IsDetachedBuffer(
+ LoadObjectField(target, JSTypedArray::kBufferOffset))));
+ CSA_ASSERT(this, IntPtrGreaterThanOrEqual(offset, IntPtrConstant(0)));
+ CSA_ASSERT(this,
+ IntPtrLessThanOrEqual(offset, IntPtrConstant(Smi::kMaxValue)));
+
+ // Check for possible range errors.
+
+ TNode<IntPtrT> source_length =
+ LoadAndUntagObjectField(source, JSTypedArray::kLengthOffset);
+ TNode<IntPtrT> target_length =
+ LoadAndUntagObjectField(target, JSTypedArray::kLengthOffset);
+ TNode<IntPtrT> required_target_length = IntPtrAdd(source_length, offset);
+
+ GotoIf(IntPtrGreaterThan(required_target_length, target_length),
+ if_source_too_large);
+
+ // Grab pointers and byte lengths we need later on.
+
+ TNode<IntPtrT> target_data_ptr = UncheckedCast<IntPtrT>(LoadDataPtr(target));
+ TNode<IntPtrT> source_data_ptr = UncheckedCast<IntPtrT>(LoadDataPtr(source));
+
+ TNode<Word32T> source_el_kind = LoadElementsKind(source);
+ TNode<Word32T> target_el_kind = LoadElementsKind(target);
+
+ TNode<IntPtrT> source_el_size = GetTypedArrayElementSize(source_el_kind);
+ TNode<IntPtrT> target_el_size = GetTypedArrayElementSize(target_el_kind);
+
+ // A note on byte lengths: both source- and target byte lengths must be valid,
+ // i.e. it must be possible to allocate an array of the given length. That
+ // means we're safe from overflows in the following multiplication.
+ TNode<IntPtrT> source_byte_length = IntPtrMul(source_length, source_el_size);
+ CSA_ASSERT(this,
+ IntPtrGreaterThanOrEqual(source_byte_length, IntPtrConstant(0)));
+
+ Label call_memmove(this), fast_c_call(this), out(this);
+ Branch(Word32Equal(source_el_kind, target_el_kind), &call_memmove,
+ &fast_c_call);
+
+ BIND(&call_memmove);
+ {
+ TNode<IntPtrT> target_start =
+ IntPtrAdd(target_data_ptr, IntPtrMul(offset, target_el_size));
+ CallCMemmove(target_start, source_data_ptr, source_byte_length);
+ Goto(&out);
+ }
+
+ BIND(&fast_c_call);
+ {
+ // Overlapping backing stores of different element kinds are handled in
+ // runtime. We're a bit conservative here and bail to runtime if ranges
+ // overlap and element kinds differ.
+
+ TNode<IntPtrT> target_byte_length =
+ IntPtrMul(target_length, target_el_size);
+ CSA_ASSERT(this,
+ IntPtrGreaterThanOrEqual(target_byte_length, IntPtrConstant(0)));
+
+ TNode<IntPtrT> target_data_end_ptr =
+ IntPtrAdd(target_data_ptr, target_byte_length);
+ TNode<IntPtrT> source_data_end_ptr =
+ IntPtrAdd(source_data_ptr, source_byte_length);
+
+ GotoIfNot(
+ Word32Or(IntPtrLessThanOrEqual(target_data_end_ptr, source_data_ptr),
+ IntPtrLessThanOrEqual(source_data_end_ptr, target_data_ptr)),
+ call_runtime);
+
+ TNode<IntPtrT> source_length =
+ LoadAndUntagObjectField(source, JSTypedArray::kLengthOffset);
+ CallCCopyTypedArrayElementsToTypedArray(source, target, source_length,
+ offset);
+ Goto(&out);
+ }
+
+ BIND(&out);
+}
+
+void TypedArrayBuiltinsAssembler::SetJSArraySource(
+ TNode<Context> context, TNode<JSArray> source, TNode<JSTypedArray> target,
+ TNode<IntPtrT> offset, Label* call_runtime, Label* if_source_too_large) {
+ CSA_ASSERT(this, IntPtrGreaterThanOrEqual(offset, IntPtrConstant(0)));
+ CSA_ASSERT(this,
+ IntPtrLessThanOrEqual(offset, IntPtrConstant(Smi::kMaxValue)));
+
+ TNode<IntPtrT> source_length = SmiUntag(LoadFastJSArrayLength(source));
+ TNode<IntPtrT> target_length =
+ LoadAndUntagObjectField(target, JSTypedArray::kLengthOffset);
+
+ // Maybe out of bounds?
+ GotoIf(IntPtrGreaterThan(IntPtrAdd(source_length, offset), target_length),
+ if_source_too_large);
+
+ // Nothing to do if {source} is empty.
+ Label out(this), fast_c_call(this);
+ GotoIf(IntPtrEqual(source_length, IntPtrConstant(0)), &out);
+
+ // Dispatch based on the source elements kind.
+ {
+ // These are the supported elements kinds in TryCopyElementsFastNumber.
+ int32_t values[] = {
+ PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS, PACKED_DOUBLE_ELEMENTS,
+ HOLEY_DOUBLE_ELEMENTS,
+ };
+ Label* labels[] = {
+ &fast_c_call, &fast_c_call, &fast_c_call, &fast_c_call,
+ };
+ STATIC_ASSERT(arraysize(values) == arraysize(labels));
+
+ TNode<Int32T> source_elements_kind = LoadMapElementsKind(LoadMap(source));
+ Switch(source_elements_kind, call_runtime, values, labels,
+ arraysize(values));
+ }
+
+ BIND(&fast_c_call);
+ CallCCopyFastNumberJSArrayElementsToTypedArray(context, source, target,
+ source_length, offset);
+ Goto(&out);
+ BIND(&out);
+}
+
+void TypedArrayBuiltinsAssembler::CallCMemmove(TNode<IntPtrT> dest_ptr,
+ TNode<IntPtrT> src_ptr,
+ TNode<IntPtrT> byte_length) {
+ TNode<ExternalReference> memmove =
+ ExternalConstant(ExternalReference::libc_memmove_function(isolate()));
+ CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
+ MachineType::Pointer(), MachineType::UintPtr(), memmove,
+ dest_ptr, src_ptr, byte_length);
+}
+
+void TypedArrayBuiltinsAssembler::
+ CallCCopyFastNumberJSArrayElementsToTypedArray(TNode<Context> context,
+ TNode<JSArray> source,
+ TNode<JSTypedArray> dest,
+ TNode<IntPtrT> source_length,
+ TNode<IntPtrT> offset) {
+ TNode<ExternalReference> f = ExternalConstant(
+ ExternalReference::copy_fast_number_jsarray_elements_to_typed_array(
+ isolate()));
+ CallCFunction5(MachineType::AnyTagged(), MachineType::AnyTagged(),
+ MachineType::AnyTagged(), MachineType::AnyTagged(),
+ MachineType::UintPtr(), MachineType::UintPtr(), f, context,
+ source, dest, source_length, offset);
+}
+
+void TypedArrayBuiltinsAssembler::CallCCopyTypedArrayElementsToTypedArray(
+ TNode<JSTypedArray> source, TNode<JSTypedArray> dest,
+ TNode<IntPtrT> source_length, TNode<IntPtrT> offset) {
+ TNode<ExternalReference> f = ExternalConstant(
+ ExternalReference::copy_typed_array_elements_to_typed_array(isolate()));
+ CallCFunction4(MachineType::AnyTagged(), MachineType::AnyTagged(),
+ MachineType::AnyTagged(), MachineType::UintPtr(),
+ MachineType::UintPtr(), f, source, dest, source_length,
+ offset);
+}
+
+// ES #sec-get-%typedarray%.prototype.set
+TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
+ TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
+ CodeStubArguments args(
+ this, ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount)));
+
+ 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.
+ TNode<Object> receiver = args.GetReceiver();
+ GotoIf(TaggedIsSmi(receiver), &if_receiver_is_not_typedarray);
+ GotoIfNot(IsJSTypedArray(receiver), &if_receiver_is_not_typedarray);
+
+ // Normalize offset argument (using ToInteger) and handle heap number cases.
+ TNode<Object> offset = args.GetOptionalArgumentValue(1, SmiConstant(0));
+ TNode<Object> offset_num = ToInteger(context, offset, kTruncateMinusZero);
+ CSA_ASSERT(this, IsNumberNormalized(offset_num));
+
+ // Since ToInteger always returns a Smi if the given value is within Smi
+ // range, and the only corner case of -0.0 has already been truncated to 0.0,
+ // we can simply throw unless the offset is a non-negative Smi.
+ // TODO(jgruber): It's an observable spec violation to throw here if
+ // {offset_num} is a positive number outside the Smi range. Per spec, we need
+ // to check for detached buffers and call the observable ToObject/ToLength
+ // operations first.
+ GotoIfNot(TaggedIsPositiveSmi(offset_num), &if_offset_is_out_of_bounds);
+ 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);
+
+ // Check the source argument is valid and whether a fast path can be taken.
+ Label call_runtime(this);
+ TNode<Object> source = args.GetOptionalArgumentValue(0);
+ GotoIf(TaggedIsSmi(source), &call_runtime);
+ GotoIf(IsJSTypedArray(source), &if_source_is_typed_array);
+ BranchIfFastJSArray(source, context, &if_source_is_fast_jsarray,
+ &call_runtime);
+
+ // Fast path for a typed array source argument.
+ 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);
+
+ SetTypedArraySource(context, CAST(source), CAST(receiver),
+ SmiUntag(offset_smi), &call_runtime,
+ &if_source_too_large);
+ args.PopAndReturn(UndefinedConstant());
+ }
+
+ // Fast path for a fast JSArray source argument.
+ BIND(&if_source_is_fast_jsarray);
+ {
+ SetJSArraySource(context, CAST(source), CAST(receiver),
+ SmiUntag(offset_smi), &call_runtime, &if_source_too_large);
+ args.PopAndReturn(UndefinedConstant());
+ }
+
+ BIND(&call_runtime);
+ args.PopAndReturn(CallRuntime(Runtime::kTypedArraySet, context, receiver,
+ source, offset_smi));
+
+ BIND(&if_offset_is_out_of_bounds);
+ ThrowRangeError(context, MessageTemplate::kTypedArraySetOffsetOutOfBounds);
+
+ 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);
+}
+
// ES #sec-get-%typedarray%.prototype-@@tostringtag
TF_BUILTIN(TypedArrayPrototypeToStringTag, TypedArrayBuiltinsAssembler) {
Node* receiver = Parameter(Descriptor::kReceiver);
diff --git a/chromium/v8/src/builtins/builtins-typedarray.cc b/chromium/v8/src/builtins/builtins-typedarray.cc
index 3d40d3755f8..176a79965b2 100644
--- a/chromium/v8/src/builtins/builtins-typedarray.cc
+++ b/chromium/v8/src/builtins/builtins-typedarray.cc
@@ -277,302 +277,6 @@ BUILTIN(TypedArrayPrototypeReverse) {
return *array;
}
-namespace {
-Object* TypedArrayCopyElements(Handle<JSTypedArray> target,
- Handle<JSReceiver> source, Object* length_obj) {
- size_t length;
- CHECK(TryNumberToSize(length_obj, &length));
-
- ElementsAccessor* accessor = target->GetElementsAccessor();
- return accessor->CopyElements(source, target, length);
-}
-
-enum class TypedArraySetResultCodes {
- // Set from typed array of the same type.
- // This is processed by TypedArraySetFastCases
- SAME_TYPE,
- // Set from typed array of the different type, overlapping in memory.
- OVERLAPPING,
- // Set from typed array of the different type, non-overlapping.
- NONOVERLAPPING,
- // Set from non-typed array.
- NON_TYPED_ARRAY
-};
-
-MaybeHandle<Object> TypedArraySetFromArrayLike(Isolate* isolate,
- Handle<JSTypedArray> target,
- Handle<Object> source,
- int source_length, int offset) {
- DCHECK_GE(source_length, 0);
- DCHECK_GE(offset, 0);
-
- for (int i = 0; i < source_length; i++) {
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
- Object::GetElement(isolate, source, i), Object);
- ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
- Object::SetElement(isolate, target, offset + i,
- value, LanguageMode::STRICT),
- Object);
- }
-
- return target;
-}
-
-MaybeHandle<Object> TypedArraySetFromOverlapping(Isolate* isolate,
- Handle<JSTypedArray> target,
- Handle<JSTypedArray> source,
- int offset) {
- DCHECK_GE(offset, 0);
-
- size_t sourceElementSize = source->element_size();
- size_t targetElementSize = target->element_size();
-
- uint32_t source_length = source->length_value();
- if (source_length == 0) return target;
-
- // Copy left part.
-
- // First un-mutated byte after the next write
- uint32_t target_ptr = 0;
- CHECK(target->byte_offset()->ToUint32(&target_ptr));
- target_ptr += (offset + 1) * targetElementSize;
-
- // Next read at sourcePtr. We do not care for memory changing before
- // sourcePtr - we have already copied it.
- uint32_t source_ptr = 0;
- CHECK(source->byte_offset()->ToUint32(&source_ptr));
-
- uint32_t left_index;
- for (left_index = 0; left_index < source_length && target_ptr <= source_ptr;
- left_index++) {
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
- Object::GetElement(isolate, source, left_index),
- Object);
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, value,
- Object::SetElement(isolate, target, offset + left_index, value,
- LanguageMode::STRICT),
- Object);
-
- target_ptr += targetElementSize;
- source_ptr += sourceElementSize;
- }
-
- // Copy right part;
- // First unmutated byte before the next write
- CHECK(target->byte_offset()->ToUint32(&target_ptr));
- target_ptr += (offset + source_length - 1) * targetElementSize;
-
- // Next read before sourcePtr. We do not care for memory changing after
- // sourcePtr - we have already copied it.
- CHECK(target->byte_offset()->ToUint32(&source_ptr));
- source_ptr += source_length * sourceElementSize;
-
- uint32_t right_index;
- DCHECK_GE(source_length, 1);
- for (right_index = source_length - 1;
- right_index > left_index && target_ptr >= source_ptr; right_index--) {
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
- Object::GetElement(isolate, source, right_index),
- Object);
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, value,
- Object::SetElement(isolate, target, offset + right_index, value,
- LanguageMode::STRICT),
- Object);
-
- target_ptr -= targetElementSize;
- source_ptr -= sourceElementSize;
- }
-
- std::vector<Handle<Object>> temp(right_index + 1 - left_index);
-
- for (uint32_t i = left_index; i <= right_index; i++) {
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
- Object::GetElement(isolate, source, i), Object);
- temp[i - left_index] = value;
- }
-
- for (uint32_t i = left_index; i <= right_index; i++) {
- Handle<Object> value;
-
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, value,
- Object::SetElement(isolate, target, offset + i, temp[i - left_index],
- LanguageMode::STRICT),
- Object);
- }
-
- return target;
-}
-
-MaybeHandle<Smi> TypedArraySetFastCases(Isolate* isolate,
- Handle<JSTypedArray> target,
- Handle<Object> source_obj,
- Handle<Object> offset_obj) {
- if (!source_obj->IsJSTypedArray()) {
- return MaybeHandle<Smi>(
- Smi::FromEnum(TypedArraySetResultCodes::NON_TYPED_ARRAY), isolate);
- }
-
- Handle<JSTypedArray> source = Handle<JSTypedArray>::cast(source_obj);
-
- size_t offset = 0;
- CHECK(TryNumberToSize(*offset_obj, &offset));
- size_t target_length = target->length_value();
- size_t source_length = source->length_value();
- size_t target_byte_length = NumberToSize(target->byte_length());
- size_t source_byte_length = NumberToSize(source->byte_length());
- if (offset > target_length || offset + source_length > target_length ||
- offset + source_length < offset) { // overflow
- THROW_NEW_ERROR(
- isolate, NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge),
- Smi);
- }
-
- size_t target_offset = NumberToSize(target->byte_offset());
- size_t source_offset = NumberToSize(source->byte_offset());
- uint8_t* target_base =
- static_cast<uint8_t*>(target->GetBuffer()->backing_store()) +
- target_offset;
- uint8_t* source_base =
- static_cast<uint8_t*>(source->GetBuffer()->backing_store()) +
- source_offset;
-
- // Typed arrays of the same type: use memmove.
- if (target->type() == source->type()) {
- memmove(target_base + offset * target->element_size(), source_base,
- source_byte_length);
- return MaybeHandle<Smi>(Smi::FromEnum(TypedArraySetResultCodes::SAME_TYPE),
- isolate);
- }
-
- // Typed arrays of different types over the same backing store
- if ((source_base <= target_base &&
- source_base + source_byte_length > target_base) ||
- (target_base <= source_base &&
- target_base + target_byte_length > source_base)) {
- // We do not support overlapping ArrayBuffers
- DCHECK(target->GetBuffer()->backing_store() ==
- source->GetBuffer()->backing_store());
- return MaybeHandle<Smi>(
- Smi::FromEnum(TypedArraySetResultCodes::OVERLAPPING), isolate);
- } else { // Non-overlapping typed arrays
- return MaybeHandle<Smi>(
- Smi::FromEnum(TypedArraySetResultCodes::NONOVERLAPPING), isolate);
- }
-}
-
-} // anonymous namespace
-
-// 22.2.3.23%TypedArray%.prototype.set ( overloaded [ , offset ] )
-BUILTIN(TypedArrayPrototypeSet) {
- HandleScope scope(isolate);
-
- Handle<Object> target = args.receiver();
- Handle<Object> obj = args.atOrUndefined(isolate, 1);
- Handle<Object> offset = args.atOrUndefined(isolate, 2);
-
- if (offset->IsUndefined(isolate)) {
- offset = Handle<Object>(Smi::kZero, isolate);
- } else {
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, offset,
- Object::ToInteger(isolate, offset));
- }
-
- if (offset->Number() < 0) {
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate, NewRangeError(MessageTemplate::kTypedArraySetNegativeOffset));
- }
-
- if (offset->Number() > Smi::kMaxValue) {
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate, NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge));
- }
-
- if (!target->IsJSTypedArray()) {
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate, NewTypeError(MessageTemplate::kNotTypedArray));
- }
- auto int_offset = static_cast<int>(offset->Number());
-
- Handle<Smi> result_code;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, result_code,
- TypedArraySetFastCases(isolate, Handle<JSTypedArray>::cast(target), obj,
- offset));
-
- switch (static_cast<TypedArraySetResultCodes>(result_code->value())) {
- case TypedArraySetResultCodes::SAME_TYPE: {
- break;
- }
- case TypedArraySetResultCodes::OVERLAPPING: {
- RETURN_FAILURE_ON_EXCEPTION(
- isolate, TypedArraySetFromOverlapping(
- isolate, Handle<JSTypedArray>::cast(target),
- Handle<JSTypedArray>::cast(obj), int_offset));
- break;
- }
- case TypedArraySetResultCodes::NONOVERLAPPING: {
- if (int_offset == 0) {
- TypedArrayCopyElements(Handle<JSTypedArray>::cast(target),
- Handle<JSTypedArray>::cast(obj),
- Handle<JSTypedArray>::cast(obj)->length());
- } else {
- RETURN_FAILURE_ON_EXCEPTION(
- isolate,
- TypedArraySetFromArrayLike(
- isolate, Handle<JSTypedArray>::cast(target), obj,
- Handle<JSTypedArray>::cast(obj)->length_value(), int_offset));
- }
- break;
- }
- case TypedArraySetResultCodes::NON_TYPED_ARRAY: {
- if (obj->IsNumber()) {
- // For number as a first argument, throw TypeError
- // instead of silently ignoring the call, so that
- // users know they did something wrong.
- // (Consistent with Firefox and Blink/WebKit)
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate, NewTypeError(MessageTemplate::kInvalidArgument));
- }
-
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, obj,
- Object::ToObject(isolate, obj));
-
- Handle<Object> len;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, len,
- Object::GetProperty(obj, isolate->factory()->length_string()));
- if (len->IsUndefined(isolate)) {
- break;
- }
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len,
- Object::ToLength(isolate, len));
-
- DCHECK_GE(int_offset, 0);
- if (int_offset + len->Number() >
- Handle<JSTypedArray>::cast(target)->length_value()) {
- THROW_NEW_ERROR_RETURN_FAILURE(
- isolate,
- NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge));
- }
- uint32_t int_l;
- CHECK(DoubleToUint32IfEqualToSelf(len->Number(), &int_l));
- RETURN_FAILURE_ON_EXCEPTION(
- isolate, TypedArraySetFromArrayLike(
- isolate, Handle<JSTypedArray>::cast(target), obj, int_l,
- int_offset));
- } break;
- }
-
- return *isolate->factory()->undefined_value();
-}
-
BUILTIN(TypedArrayPrototypeSlice) {
HandleScope scope(isolate);