[builtins] Port %TypedArray%.from to Torque
... in an uintptr index friendly way. Bug: v8:8906, v8:4153 Change-Id: Ib06ac205453fe3ff653b4fb73194e1ab53ca0d00 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1891610 Commit-Queue: Igor Sheludko <ishell@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Cr-Commit-Position: refs/heads/master@{#64731}
This commit is contained in:
parent
b701330857
commit
bff5a05319
1
BUILD.gn
1
BUILD.gn
@ -995,6 +995,7 @@ torque_files = [
|
||||
"src/builtins/typed-array-find.tq",
|
||||
"src/builtins/typed-array-findindex.tq",
|
||||
"src/builtins/typed-array-foreach.tq",
|
||||
"src/builtins/typed-array-from.tq",
|
||||
"src/builtins/typed-array-reduce.tq",
|
||||
"src/builtins/typed-array-reduceright.tq",
|
||||
"src/builtins/typed-array-slice.tq",
|
||||
|
@ -1373,6 +1373,8 @@ const kInvalidArrayBufferLength: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kInvalidArrayBufferLength';
|
||||
const kInvalidArrayLength: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kInvalidArrayLength';
|
||||
const kNotConstructor: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kNotConstructor';
|
||||
const kCalledNonCallable: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kCalledNonCallable';
|
||||
const kCalledOnNullOrUndefined: constexpr MessageTemplate
|
||||
@ -1491,7 +1493,7 @@ extern macro Int32FalseConstant(): bool;
|
||||
extern macro EmptyStringConstant(): EmptyString;
|
||||
extern macro LengthStringConstant(): String;
|
||||
extern macro NanConstant(): NaN;
|
||||
extern macro IteratorSymbolConstant(): Symbol;
|
||||
extern macro IteratorSymbolConstant(): PublicSymbol;
|
||||
extern macro MatchSymbolConstant(): Symbol;
|
||||
|
||||
const TheHole: TheHole = TheHoleConstant();
|
||||
@ -3245,8 +3247,6 @@ operator '[]=' macro StoreFixedArrayDirect(a: FixedArray, i: Smi, v: Object) {
|
||||
}
|
||||
|
||||
extern macro GetNumberDictionaryNumberOfElements(NumberDictionary): Smi;
|
||||
extern macro GetIteratorMethod(implicit context: Context)(HeapObject): JSAny
|
||||
labels IfIteratorUndefined;
|
||||
|
||||
extern macro LoadConstructorOrBackPointer(Map): Object;
|
||||
|
||||
@ -3653,6 +3653,7 @@ extern macro IsName(HeapObject): bool;
|
||||
extern macro IsPrivateSymbol(HeapObject): bool;
|
||||
extern macro IsNumber(Object): bool;
|
||||
extern macro IsNumberNormalized(Number): bool;
|
||||
extern macro IsSafeInteger(Object): bool;
|
||||
extern macro IsOddball(HeapObject): bool;
|
||||
extern macro IsSymbol(HeapObject): bool;
|
||||
extern macro IsJSArrayMap(Map): bool;
|
||||
@ -3826,11 +3827,29 @@ transitioning macro GetLengthProperty(implicit context: Context)(o: JSAny):
|
||||
}
|
||||
|
||||
transitioning macro GetMethod(implicit context: Context)(
|
||||
o: JSAny, name: constexpr string): Callable labels IfNullOrUndefined {
|
||||
o: JSAny, name: AnyName): Callable labels IfNullOrUndefined,
|
||||
IfMethodNotCallable(JSAny) {
|
||||
const value = GetProperty(o, name);
|
||||
// TODO(v8:9933): Consider checking for null/undefined after checking for
|
||||
// callable because the latter seems to be more common.
|
||||
if (value == Undefined || value == Null) goto IfNullOrUndefined;
|
||||
return Cast<Callable>(value)
|
||||
otherwise ThrowTypeError(kPropertyNotFunction, value, name, o);
|
||||
otherwise goto IfMethodNotCallable(value);
|
||||
}
|
||||
|
||||
transitioning macro GetMethod(implicit context: Context)(
|
||||
o: JSAny, name: String): Callable labels IfNullOrUndefined {
|
||||
try {
|
||||
return GetMethod(o, name) otherwise IfNullOrUndefined, IfMethodNotCallable;
|
||||
}
|
||||
label IfMethodNotCallable(value: JSAny) deferred {
|
||||
ThrowTypeError(kPropertyNotFunction, value, name, o);
|
||||
}
|
||||
}
|
||||
|
||||
transitioning macro GetMethod(implicit context: Context)(
|
||||
o: JSAny, name: constexpr string): Callable labels IfNullOrUndefined {
|
||||
return GetMethod(o, StringConstant(name)) otherwise IfNullOrUndefined;
|
||||
}
|
||||
|
||||
extern macro NumberToString(Number): String;
|
||||
|
@ -941,8 +941,6 @@ namespace internal {
|
||||
TFJ(TypedArrayPrototypeMap, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 %TypedArray%.of */ \
|
||||
TFJ(TypedArrayOf, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES6 %TypedArray%.from */ \
|
||||
TFJ(TypedArrayFrom, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
\
|
||||
/* Wasm */ \
|
||||
ASM(WasmCompileLazy, Dummy) \
|
||||
|
@ -231,36 +231,6 @@ TNode<JSFunction> TypedArrayBuiltinsAssembler::GetDefaultConstructor(
|
||||
LoadContextElement(LoadNativeContext(context), context_slot.value()));
|
||||
}
|
||||
|
||||
TNode<JSTypedArray> TypedArrayBuiltinsAssembler::TypedArrayCreateByLength(
|
||||
TNode<Context> context, TNode<Object> constructor, TNode<Smi> len,
|
||||
const char* method_name) {
|
||||
CSA_ASSERT(this, TaggedIsPositiveSmi(len));
|
||||
|
||||
// Let newTypedArray be ? Construct(constructor, argumentList).
|
||||
TNode<Object> new_object = CAST(ConstructJS(CodeFactory::Construct(isolate()),
|
||||
context, constructor, len));
|
||||
|
||||
// Perform ? ValidateTypedArray(newTypedArray).
|
||||
TNode<JSTypedArray> new_typed_array =
|
||||
ValidateTypedArray(context, new_object, method_name);
|
||||
|
||||
ThrowIfLengthLessThan(context, new_typed_array, len);
|
||||
return new_typed_array;
|
||||
}
|
||||
|
||||
void TypedArrayBuiltinsAssembler::ThrowIfLengthLessThan(
|
||||
TNode<Context> context, TNode<JSTypedArray> typed_array,
|
||||
TNode<Smi> min_length) {
|
||||
// If typed_array.[[ArrayLength]] < min_length, throw a TypeError exception.
|
||||
Label if_length_is_not_short(this);
|
||||
TNode<UintPtrT> new_length = LoadJSTypedArrayLength(typed_array);
|
||||
GotoIfNot(UintPtrLessThan(new_length, SmiUntag(min_length)),
|
||||
&if_length_is_not_short);
|
||||
ThrowTypeError(context, MessageTemplate::kTypedArrayTooShort);
|
||||
|
||||
BIND(&if_length_is_not_short);
|
||||
}
|
||||
|
||||
TNode<JSArrayBuffer> TypedArrayBuiltinsAssembler::GetBuffer(
|
||||
TNode<Context> context, TNode<JSTypedArray> array) {
|
||||
Label call_runtime(this), done(this);
|
||||
@ -605,6 +575,23 @@ void TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromNumeric(
|
||||
}
|
||||
}
|
||||
|
||||
void TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromTagged(
|
||||
TNode<Context> context, TNode<JSTypedArray> typed_array,
|
||||
TNode<UintPtrT> index, TNode<Object> value, ElementsKind elements_kind,
|
||||
Label* if_detached) {
|
||||
// |prepared_value| is Word32T or Float64T or Float32T or BigInt.
|
||||
Node* prepared_value =
|
||||
PrepareValueForWriteToTypedArray(value, elements_kind, context);
|
||||
|
||||
// ToNumber/ToBigInt may execute JavaScript code, which could detach
|
||||
// the array's buffer.
|
||||
TNode<JSArrayBuffer> buffer = LoadJSArrayBufferViewBuffer(typed_array);
|
||||
GotoIf(IsDetachedBuffer(buffer), if_detached);
|
||||
|
||||
TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(typed_array);
|
||||
StoreElement(data_ptr, elements_kind, index, prepared_value);
|
||||
}
|
||||
|
||||
// ES #sec-get-%typedarray%.prototype.set
|
||||
TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
|
||||
const char* method_name = "%TypedArray%.prototype.set";
|
||||
@ -790,7 +777,7 @@ TF_BUILTIN(TypedArrayOf, TypedArrayBuiltinsAssembler) {
|
||||
|
||||
// 5. Let newObj be ? TypedArrayCreate(C, len).
|
||||
TNode<JSTypedArray> new_typed_array = TypedArrayCreateByLength(
|
||||
context, receiver, SmiTag(length), "%TypedArray%.of");
|
||||
context, CAST(receiver), SmiTag(length), "%TypedArray%.of");
|
||||
|
||||
TNode<Int32T> elements_kind = LoadElementsKind(new_typed_array);
|
||||
|
||||
@ -836,231 +823,5 @@ TF_BUILTIN(TypedArrayOf, TypedArrayBuiltinsAssembler) {
|
||||
"%TypedArray%.of");
|
||||
}
|
||||
|
||||
// ES6 #sec-%typedarray%.from
|
||||
TF_BUILTIN(TypedArrayFrom, TypedArrayBuiltinsAssembler) {
|
||||
TNode<Int32T> argc =
|
||||
UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
|
||||
Label check_iterator(this), from_array_like(this), fast_path(this),
|
||||
slow_path(this), create_typed_array(this), check_typedarray(this),
|
||||
if_not_constructor(this, Label::kDeferred),
|
||||
if_map_fn_not_callable(this, Label::kDeferred),
|
||||
if_iterator_fn_not_callable(this, Label::kDeferred),
|
||||
if_detached(this, Label::kDeferred);
|
||||
|
||||
CodeStubArguments args(this, argc);
|
||||
TNode<Object> source = args.GetOptionalArgumentValue(0);
|
||||
|
||||
// 5. If thisArg is present, let T be thisArg; else let T be undefined.
|
||||
TNode<Object> this_arg = args.GetOptionalArgumentValue(2);
|
||||
|
||||
// 1. Let C be the this value.
|
||||
// 2. If IsConstructor(C) is false, throw a TypeError exception.
|
||||
TNode<Object> receiver = args.GetReceiver();
|
||||
GotoIf(TaggedIsSmi(receiver), &if_not_constructor);
|
||||
GotoIfNot(IsConstructor(CAST(receiver)), &if_not_constructor);
|
||||
|
||||
// 3. If mapfn is present and mapfn is not undefined, then
|
||||
TNode<Object> map_fn = args.GetOptionalArgumentValue(1);
|
||||
TVARIABLE(BoolT, mapping, Int32FalseConstant());
|
||||
GotoIf(IsUndefined(map_fn), &check_typedarray);
|
||||
|
||||
// a. If IsCallable(mapfn) is false, throw a TypeError exception.
|
||||
// b. Let mapping be true.
|
||||
// 4. Else, let mapping be false.
|
||||
GotoIf(TaggedIsSmi(map_fn), &if_map_fn_not_callable);
|
||||
GotoIfNot(IsCallable(CAST(map_fn)), &if_map_fn_not_callable);
|
||||
mapping = Int32TrueConstant();
|
||||
Goto(&check_typedarray);
|
||||
|
||||
TVARIABLE(Object, final_source);
|
||||
TVARIABLE(Smi, final_length);
|
||||
|
||||
// We split up this builtin differently to the way it is written in the spec.
|
||||
// We already have great code in the elements accessor for copying from a
|
||||
// JSArray into a TypedArray, so we use that when possible. We only avoid
|
||||
// calling into the elements accessor when we have a mapping function, because
|
||||
// we can't handle that. Here, presence of a mapping function is the slow
|
||||
// path. We also combine the two different loops in the specification
|
||||
// (starting at 7.e and 13) because they are essentially identical. We also
|
||||
// save on code-size this way.
|
||||
|
||||
// Get the iterator function
|
||||
BIND(&check_typedarray);
|
||||
TNode<Object> iterator_fn =
|
||||
CAST(GetMethod(context, source, isolate()->factory()->iterator_symbol(),
|
||||
&from_array_like));
|
||||
GotoIf(TaggedIsSmi(iterator_fn), &if_iterator_fn_not_callable);
|
||||
|
||||
{
|
||||
// TypedArrays have iterators, so normally we would go through the
|
||||
// IterableToList case below, which would convert the TypedArray to a
|
||||
// JSArray (boxing the values if they won't fit in a Smi).
|
||||
//
|
||||
// However, if we can guarantee that the source object has the built-in
|
||||
// iterator and that the %ArrayIteratorPrototype%.next method has not been
|
||||
// overridden, then we know the behavior of the iterator: returning the
|
||||
// values in the TypedArray sequentially from index 0 to length-1.
|
||||
//
|
||||
// In this case, we can avoid creating the intermediate array and the
|
||||
// associated HeapNumbers, and use the fast path in TypedArrayCopyElements
|
||||
// which uses the same ordering as the default iterator.
|
||||
//
|
||||
// Drop through to the default check_iterator behavior if any of these
|
||||
// checks fail.
|
||||
|
||||
// Check that the source is a TypedArray
|
||||
GotoIf(TaggedIsSmi(source), &check_iterator);
|
||||
GotoIfNot(IsJSTypedArray(CAST(source)), &check_iterator);
|
||||
TNode<JSArrayBuffer> source_buffer =
|
||||
LoadJSArrayBufferViewBuffer(CAST(source));
|
||||
GotoIf(IsDetachedBuffer(source_buffer), &check_iterator);
|
||||
|
||||
// Check that the iterator function is Builtins::kTypedArrayPrototypeValues
|
||||
GotoIfNot(IsJSFunction(CAST(iterator_fn)), &check_iterator);
|
||||
TNode<SharedFunctionInfo> shared_info = LoadObjectField<SharedFunctionInfo>(
|
||||
CAST(iterator_fn), JSFunction::kSharedFunctionInfoOffset);
|
||||
GotoIfNot(
|
||||
TaggedEqual(LoadObjectField(shared_info,
|
||||
SharedFunctionInfo::kFunctionDataOffset),
|
||||
SmiConstant(Builtins::kTypedArrayPrototypeValues)),
|
||||
&check_iterator);
|
||||
// Check that the ArrayIterator prototype's "next" method hasn't been
|
||||
// overridden
|
||||
TNode<PropertyCell> protector_cell = ArrayIteratorProtectorConstant();
|
||||
GotoIfNot(
|
||||
TaggedEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
|
||||
SmiConstant(Protectors::kProtectorValid)),
|
||||
&check_iterator);
|
||||
|
||||
// Source is a TypedArray with unmodified iterator behavior. Use the
|
||||
// source object directly, taking advantage of the special-case code in
|
||||
// TypedArrayCopyElements
|
||||
// TODO(v8:4153): This needs to be handle to huge TypedArrays.
|
||||
final_length = SmiTag(Signed(LoadJSTypedArrayLength(CAST(source))));
|
||||
final_source = source;
|
||||
Goto(&create_typed_array);
|
||||
}
|
||||
|
||||
BIND(&check_iterator);
|
||||
{
|
||||
// 6. Let usingIterator be ? GetMethod(source, @@iterator).
|
||||
GotoIfNot(IsCallable(CAST(iterator_fn)), &if_iterator_fn_not_callable);
|
||||
|
||||
// We are using the iterator.
|
||||
Label if_length_not_smi(this, Label::kDeferred);
|
||||
// 7. If usingIterator is not undefined, then
|
||||
// a. Let values be ? IterableToList(source, usingIterator).
|
||||
// b. Let len be the number of elements in values.
|
||||
TNode<JSArray> values = CAST(
|
||||
CallBuiltin(Builtins::kIterableToList, context, source, iterator_fn));
|
||||
|
||||
// This is not a spec'd limit, so it doesn't particularly matter when we
|
||||
// throw the range error for typed array length > MaxSmi.
|
||||
TNode<Number> raw_length = LoadJSArrayLength(values);
|
||||
GotoIfNot(TaggedIsSmi(raw_length), &if_length_not_smi);
|
||||
|
||||
final_length = CAST(raw_length);
|
||||
final_source = values;
|
||||
Goto(&create_typed_array);
|
||||
|
||||
BIND(&if_length_not_smi);
|
||||
ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength,
|
||||
raw_length);
|
||||
}
|
||||
|
||||
BIND(&from_array_like);
|
||||
{
|
||||
// TODO(7881): support larger-than-smi typed array lengths
|
||||
Label if_length_not_smi(this, Label::kDeferred);
|
||||
final_source = source;
|
||||
|
||||
// 10. Let len be ? ToLength(? Get(arrayLike, "length")).
|
||||
TNode<Object> raw_length =
|
||||
GetProperty(context, final_source.value(), LengthStringConstant());
|
||||
final_length = ToSmiLength(context, raw_length, &if_length_not_smi);
|
||||
Goto(&create_typed_array);
|
||||
|
||||
BIND(&if_length_not_smi);
|
||||
ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength,
|
||||
raw_length);
|
||||
}
|
||||
|
||||
TVARIABLE(JSTypedArray, target_obj);
|
||||
|
||||
BIND(&create_typed_array);
|
||||
{
|
||||
// 7c/11. Let targetObj be ? TypedArrayCreate(C, «len»).
|
||||
target_obj = TypedArrayCreateByLength(
|
||||
context, receiver, final_length.value(), "%TypedArray%.from");
|
||||
|
||||
Branch(mapping.value(), &slow_path, &fast_path);
|
||||
}
|
||||
|
||||
BIND(&fast_path);
|
||||
{
|
||||
Label done(this);
|
||||
GotoIf(SmiEqual(final_length.value(), SmiConstant(0)), &done);
|
||||
|
||||
CallRuntime(Runtime::kTypedArrayCopyElements, context, target_obj.value(),
|
||||
final_source.value(), final_length.value());
|
||||
Goto(&done);
|
||||
|
||||
BIND(&done);
|
||||
args.PopAndReturn(target_obj.value());
|
||||
}
|
||||
|
||||
BIND(&slow_path);
|
||||
TNode<Int32T> elements_kind = LoadElementsKind(target_obj.value());
|
||||
|
||||
// 7e/13 : Copy the elements
|
||||
BuildFastLoop<Smi>(
|
||||
SmiConstant(0), final_length.value(),
|
||||
[&](TNode<Smi> index) {
|
||||
const TNode<Object> k_value =
|
||||
GetProperty(context, final_source.value(), index);
|
||||
|
||||
const TNode<Object> mapped_value =
|
||||
CallJS(CodeFactory::Call(isolate()), context, map_fn, this_arg,
|
||||
k_value, index);
|
||||
|
||||
DispatchTypedArrayByElementsKind(
|
||||
elements_kind,
|
||||
[&](ElementsKind kind, int size, int typed_array_fun_index) {
|
||||
Node* const final_value =
|
||||
PrepareValueForWriteToTypedArray(mapped_value, kind, context);
|
||||
|
||||
// ToNumber/ToBigInt may execute JavaScript code, which could
|
||||
// detach the array's buffer.
|
||||
TNode<JSArrayBuffer> buffer =
|
||||
LoadJSArrayBufferViewBuffer(target_obj.value());
|
||||
GotoIf(IsDetachedBuffer(buffer), &if_detached);
|
||||
|
||||
// GC may move backing store in map_fn, thus load backing
|
||||
// store in each iteration of this loop.
|
||||
TNode<RawPtrT> data_ptr =
|
||||
LoadJSTypedArrayDataPtr(target_obj.value());
|
||||
StoreElement(data_ptr, kind, index, final_value, SMI_PARAMETERS);
|
||||
});
|
||||
},
|
||||
1, IndexAdvanceMode::kPost);
|
||||
|
||||
args.PopAndReturn(target_obj.value());
|
||||
|
||||
BIND(&if_not_constructor);
|
||||
ThrowTypeError(context, MessageTemplate::kNotConstructor, receiver);
|
||||
|
||||
BIND(&if_map_fn_not_callable);
|
||||
ThrowTypeError(context, MessageTemplate::kCalledNonCallable, map_fn);
|
||||
|
||||
BIND(&if_iterator_fn_not_callable);
|
||||
ThrowTypeError(context, MessageTemplate::kIteratorSymbolNonCallable);
|
||||
|
||||
BIND(&if_detached);
|
||||
ThrowTypeError(context, MessageTemplate::kDetachedOperation,
|
||||
"%TypedArray%.from");
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -50,15 +50,6 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
|
||||
TNode<JSFunction> GetDefaultConstructor(TNode<Context> context,
|
||||
TNode<JSTypedArray> exemplar);
|
||||
|
||||
TNode<JSTypedArray> TypedArrayCreateByLength(TNode<Context> context,
|
||||
TNode<Object> constructor,
|
||||
TNode<Smi> len,
|
||||
const char* method_name);
|
||||
|
||||
void ThrowIfLengthLessThan(TNode<Context> context,
|
||||
TNode<JSTypedArray> typed_array,
|
||||
TNode<Smi> min_length);
|
||||
|
||||
TNode<JSArrayBuffer> GetBuffer(TNode<Context> context,
|
||||
TNode<JSTypedArray> array);
|
||||
|
||||
@ -117,6 +108,12 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
|
||||
TNode<UintPtrT> index_node,
|
||||
TNode<Numeric> value,
|
||||
ElementsKind elements_kind);
|
||||
void StoreJSTypedArrayElementFromTagged(TNode<Context> context,
|
||||
TNode<JSTypedArray> typed_array,
|
||||
TNode<UintPtrT> index_node,
|
||||
TNode<Object> value,
|
||||
ElementsKind elements_kind,
|
||||
Label* if_detached);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -27,8 +27,6 @@ namespace promise {
|
||||
const PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN:
|
||||
constexpr NativeContextSlot
|
||||
generates 'Context::PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN';
|
||||
const kNotConstructor: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kNotConstructor';
|
||||
const kPromiseNonCallable: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kPromiseNonCallable';
|
||||
|
||||
|
@ -283,15 +283,46 @@ namespace typed_array {
|
||||
}
|
||||
}
|
||||
|
||||
// 22.2.4.6 TypedArrayCreate ( constructor, argumentList )
|
||||
// ES #typedarray-create
|
||||
@export
|
||||
transitioning macro TypedArrayCreateByLength(implicit context: Context)(
|
||||
constructor: Constructor, length: Number, methodName: constexpr string):
|
||||
JSTypedArray {
|
||||
assert(IsSafeInteger(length));
|
||||
|
||||
// 1. Let newTypedArray be ? Construct(constructor, argumentList).
|
||||
const newTypedArrayObj = Construct(constructor, length);
|
||||
|
||||
// 2. Perform ? ValidateTypedArray(newTypedArray).
|
||||
// ValidateTypedArray currently returns the array, not the ViewBuffer.
|
||||
const newTypedArray: JSTypedArray =
|
||||
ValidateTypedArray(context, newTypedArrayObj, methodName);
|
||||
|
||||
if (IsDetachedBuffer(newTypedArray.buffer)) deferred {
|
||||
ThrowTypeError(kDetachedOperation, methodName);
|
||||
}
|
||||
|
||||
// 3. If argumentList is a List of a single Number, then
|
||||
// a. If newTypedArray.[[ArrayLength]] < argumentList[0], throw a
|
||||
// TypeError exception.
|
||||
if (newTypedArray.length < Convert<uintptr>(length)) deferred {
|
||||
ThrowTypeError(kTypedArrayTooShort);
|
||||
}
|
||||
|
||||
// 4. Return newTypedArray.
|
||||
return newTypedArray;
|
||||
}
|
||||
|
||||
transitioning macro ConstructByJSReceiver(implicit context:
|
||||
Context)(obj: JSReceiver): never
|
||||
labels IfConstructByArrayLike(JSReceiver, uintptr, JSReceiver) {
|
||||
try {
|
||||
const iteratorMethod: Object =
|
||||
GetIteratorMethod(obj) otherwise IfIteratorUndefined;
|
||||
const iteratorFn: Callable = Cast<Callable>(iteratorMethod)
|
||||
otherwise ThrowTypeError(kIteratorSymbolNonCallable);
|
||||
ConstructByIterable(obj, iteratorFn)
|
||||
// TODO(v8:8906): Use iterator::GetIteratorMethod() once it supports
|
||||
// labels.
|
||||
const iteratorMethod = GetMethod(obj, IteratorSymbolConstant())
|
||||
otherwise IfIteratorUndefined, IfIteratorNotCallable;
|
||||
ConstructByIterable(obj, iteratorMethod)
|
||||
otherwise IfConstructByArrayLike;
|
||||
}
|
||||
label IfIteratorUndefined {
|
||||
@ -307,6 +338,9 @@ namespace typed_array {
|
||||
label IfInvalidLength(length: Number) {
|
||||
ThrowRangeError(kInvalidTypedArrayLength, length);
|
||||
}
|
||||
label IfIteratorNotCallable(_value: JSAny) deferred {
|
||||
ThrowTypeError(kIteratorSymbolNonCallable);
|
||||
}
|
||||
}
|
||||
|
||||
// 22.2.4 The TypedArray Constructors
|
||||
|
186
src/builtins/typed-array-from.tq
Normal file
186
src/builtins/typed-array-from.tq
Normal file
@ -0,0 +1,186 @@
|
||||
// Copyright 2019 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include 'src/builtins/builtins-typed-array-gen.h'
|
||||
|
||||
namespace typed_array {
|
||||
const kBuiltinNameFrom: constexpr string = '%TypedArray%.from';
|
||||
|
||||
type BuiltinsName extends int31 constexpr 'Builtins::Name';
|
||||
const kTypedArrayPrototypeValues: constexpr BuiltinsName
|
||||
generates 'Builtins::kTypedArrayPrototypeValues';
|
||||
|
||||
extern builtin IterableToList(implicit context: Context)(JSAny, JSAny):
|
||||
JSArray;
|
||||
|
||||
// %TypedArray%.from ( source [ , mapfn [ , thisArg ] ] )
|
||||
// https://tc39.github.io/ecma262/#sec-%typedarray%.from
|
||||
transitioning javascript builtin
|
||||
TypedArrayFrom(js-implicit context: Context, receiver: JSAny)(...arguments):
|
||||
JSTypedArray {
|
||||
try {
|
||||
const source: JSAny = arguments[0];
|
||||
|
||||
// 1. Let C be the this value.
|
||||
// 2. If IsConstructor(C) is false, throw a TypeError exception.
|
||||
const constructor = Cast<Constructor>(receiver) otherwise NotConstructor;
|
||||
|
||||
// 3. If mapfn is present and mapfn is not undefined, then
|
||||
// a. If IsCallable(mapfn) is false, throw a TypeError exception.
|
||||
// b. Let mapping be true.
|
||||
// 4. Else, let mapping be false.
|
||||
const mapping: bool = arguments.length > 1;
|
||||
const mapfnObj: JSAny = mapping ? arguments[1] : Undefined;
|
||||
if (mapping && !TaggedIsCallable(mapfnObj)) deferred {
|
||||
ThrowTypeError(kCalledNonCallable, mapfnObj);
|
||||
}
|
||||
|
||||
// 5. If thisArg is present, let T be thisArg; else let T be undefined.
|
||||
const thisArg = arguments.length > 2 ? arguments[2] : Undefined;
|
||||
|
||||
// We split up this builtin differently to the way it is written in the
|
||||
// spec. We already have great code in the elements accessor for copying
|
||||
// from a JSArray into a TypedArray, so we use that when possible. We only
|
||||
// avoid calling into the elements accessor when we have a mapping
|
||||
// function, because we can't handle that. Here, presence of a mapping
|
||||
// function is the slow path. We also combine the two different loops in
|
||||
// the specification (starting at 7.e and 13) because they are essentially
|
||||
// identical. We also save on code-size this way.
|
||||
|
||||
let finalLength: uintptr;
|
||||
let finalSource: JSAny;
|
||||
|
||||
try {
|
||||
// 6. Let usingIterator be ? GetMethod(source, @@iterator).
|
||||
// TODO(v8:8906): Use iterator::GetIteratorMethod() once it supports
|
||||
// labels.
|
||||
const usingIterator = GetMethod(source, IteratorSymbolConstant())
|
||||
otherwise IteratorIsUndefined, IteratorNotCallable;
|
||||
|
||||
try {
|
||||
// TypedArrays have iterators, so normally we would go through the
|
||||
// IterableToList case below, which would convert the TypedArray to a
|
||||
// JSArray (boxing the values if they won't fit in a Smi).
|
||||
//
|
||||
// However, if we can guarantee that the source object has the
|
||||
// built-in iterator and that the %ArrayIteratorPrototype%.next method
|
||||
// has not been overridden, then we know the behavior of the iterator:
|
||||
// returning the values in the TypedArray sequentially from index 0 to
|
||||
// length-1.
|
||||
//
|
||||
// In this case, we can avoid creating the intermediate array and the
|
||||
// associated HeapNumbers, and use the fast path in
|
||||
// TypedArrayCopyElements which uses the same ordering as the default
|
||||
// iterator.
|
||||
//
|
||||
// Drop through to the default check_iterator behavior if any of these
|
||||
// checks fail.
|
||||
const sourceTypedArray =
|
||||
Cast<JSTypedArray>(source) otherwise UseUserProvidedIterator;
|
||||
const sourceBuffer = sourceTypedArray.buffer;
|
||||
if (IsDetachedBuffer(sourceBuffer)) goto UseUserProvidedIterator;
|
||||
|
||||
// Check that the iterator function is exactly
|
||||
// Builtins::kTypedArrayPrototypeValues.
|
||||
const iteratorFn =
|
||||
Cast<JSFunction>(usingIterator) otherwise UseUserProvidedIterator;
|
||||
if (TaggedEqual(
|
||||
iteratorFn.shared_function_info.function_data,
|
||||
SmiConstant(kTypedArrayPrototypeValues)))
|
||||
goto UseUserProvidedIterator;
|
||||
|
||||
// Check that the ArrayIterator prototype's "next" method hasn't been
|
||||
// overridden.
|
||||
if (IsArrayIteratorProtectorCellInvalid())
|
||||
goto UseUserProvidedIterator;
|
||||
|
||||
// Source is a TypedArray with unmodified iterator behavior. Use the
|
||||
// source object directly, taking advantage of the special-case code
|
||||
// in TypedArrayCopyElements
|
||||
finalLength = sourceTypedArray.length;
|
||||
finalSource = source;
|
||||
}
|
||||
label UseUserProvidedIterator {
|
||||
// 7. If usingIterator is not undefined, then
|
||||
// a. Let values be ? IterableToList(source, usingIterator).
|
||||
// b. Let len be the number of elements in values.
|
||||
const values: JSArray = IterableToList(source, usingIterator);
|
||||
|
||||
finalLength = Convert<uintptr>(values.length);
|
||||
finalSource = values;
|
||||
}
|
||||
}
|
||||
label IteratorIsUndefined {
|
||||
// 8. NOTE: source is not an Iterable so assume it is already an
|
||||
// array-like object.
|
||||
|
||||
// 9. Let arrayLike be ! ToObject(source).
|
||||
const arrayLike: JSReceiver = ToObject_Inline(context, source);
|
||||
|
||||
// 10. Let len be ? ToLength(? Get(arrayLike, "length")).
|
||||
finalLength = Convert<uintptr>(GetLengthProperty(arrayLike));
|
||||
finalSource = arrayLike;
|
||||
}
|
||||
label IteratorNotCallable(_value: JSAny) deferred {
|
||||
ThrowTypeError(kIteratorSymbolNonCallable);
|
||||
}
|
||||
|
||||
const finalLengthNum = Convert<Number>(finalLength);
|
||||
|
||||
// 7c/11. Let targetObj be ? TypedArrayCreate(C, «len»).
|
||||
const targetObj = TypedArrayCreateByLength(
|
||||
constructor, finalLengthNum, kBuiltinNameFrom);
|
||||
|
||||
if (!mapping) {
|
||||
// Fast path.
|
||||
if (finalLength != 0) {
|
||||
// Call runtime.
|
||||
TypedArrayCopyElements(
|
||||
context, targetObj, finalSource, finalLengthNum);
|
||||
}
|
||||
return targetObj;
|
||||
}
|
||||
// Slow path.
|
||||
|
||||
const mapfn: Callable = Cast<Callable>(mapfnObj) otherwise unreachable;
|
||||
const accessor: TypedArrayAccessor =
|
||||
GetTypedArrayAccessor(targetObj.elements_kind);
|
||||
|
||||
// 7d-7e and 12-13.
|
||||
// 12. Let k be 0.
|
||||
// 13. Repeat, while k < len
|
||||
for (let k: uintptr = 0; k < finalLength; k++) {
|
||||
// 13a. Let Pk be ! ToString(k).
|
||||
const kNum = Convert<Number>(k);
|
||||
|
||||
// 13b. Let kValue be ? Get(arrayLike, Pk).
|
||||
const kValue: JSAny = GetProperty(finalSource, kNum);
|
||||
|
||||
let mappedValue: JSAny;
|
||||
// 13c. If mapping is true, then
|
||||
if (mapping) {
|
||||
// i. Let mappedValue be ? Call(mapfn, T, « kValue, k »).
|
||||
mappedValue = Call(context, mapfn, thisArg, kValue, kNum);
|
||||
} else {
|
||||
// 13d. Else, let mappedValue be kValue.
|
||||
mappedValue = kValue;
|
||||
}
|
||||
|
||||
// 13e. Perform ? Set(targetObj, Pk, mappedValue, true).
|
||||
// Buffer may be detached during executing ToNumber/ToBigInt.
|
||||
accessor.StoreJSAny(context, targetObj, k, mappedValue)
|
||||
otherwise IfDetached;
|
||||
|
||||
// 13f. Set k to k + 1. (done by the loop).
|
||||
}
|
||||
return targetObj;
|
||||
}
|
||||
label NotConstructor deferred {
|
||||
ThrowTypeError(kNotConstructor, receiver);
|
||||
}
|
||||
label IfDetached deferred {
|
||||
ThrowTypeError(kDetachedOperation, kBuiltinNameFrom);
|
||||
}
|
||||
}
|
||||
}
|
@ -59,7 +59,7 @@ namespace typed_array {
|
||||
// 1. Let O be the this value.
|
||||
// 2. Perform ? ValidateTypedArray(O).
|
||||
const src: JSTypedArray =
|
||||
typed_array::ValidateTypedArray(context, receiver, kBuiltinNameSlice);
|
||||
ValidateTypedArray(context, receiver, kBuiltinNameSlice);
|
||||
|
||||
// 3. Let len be O.[[ArrayLength]].
|
||||
const len: uintptr = src.length;
|
||||
|
@ -79,63 +79,85 @@ namespace typed_array {
|
||||
RawPtr, uintptr, constexpr ElementsKind): Numeric;
|
||||
extern macro TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromNumeric(
|
||||
Context, JSTypedArray, uintptr, Numeric, constexpr ElementsKind);
|
||||
extern macro TypedArrayBuiltinsAssembler::StoreJSTypedArrayElementFromTagged(
|
||||
Context, JSTypedArray, uintptr, JSAny,
|
||||
constexpr ElementsKind) labels IfDetached;
|
||||
|
||||
type LoadNumericFn = builtin(Context, JSTypedArray, uintptr) => Numeric;
|
||||
type StoreNumericFn = builtin(Context, JSTypedArray, uintptr, Numeric) =>
|
||||
JSAny;
|
||||
type StoreNumericFn = builtin(Context, JSTypedArray, uintptr, Numeric) => Smi;
|
||||
type StoreJSAnyFn = builtin(Context, JSTypedArray, uintptr, JSAny) => Smi;
|
||||
|
||||
// The result codes returned by StoreNumericFn and StoreJSAnyFn builtins.
|
||||
const kStoreSucceded: Smi = 0;
|
||||
const kStoreFailureArrayDetached: Smi = 1;
|
||||
|
||||
struct TypedArrayAccessor {
|
||||
LoadNumeric(
|
||||
context: Context, array: JSTypedArray, index: uintptr): Numeric {
|
||||
const loadfn: LoadNumericFn = this.loadNumericFn;
|
||||
return loadfn(context, array, index);
|
||||
}
|
||||
|
||||
StoreNumeric(
|
||||
context: Context, array: JSTypedArray, index: uintptr, value: Numeric) {
|
||||
const storefn: StoreNumericFn = this.storeNumericFn;
|
||||
const result = storefn(context, array, index, value);
|
||||
assert(result == kStoreSucceded);
|
||||
}
|
||||
|
||||
StoreJSAny(
|
||||
context: Context, array: JSTypedArray, index: uintptr, value: JSAny)
|
||||
labels IfDetached {
|
||||
const storefn: StoreJSAnyFn = this.storeJSAnyFn;
|
||||
const result = storefn(context, array, index, value);
|
||||
if (result == kStoreFailureArrayDetached) {
|
||||
goto IfDetached;
|
||||
}
|
||||
assert(result == kStoreSucceded);
|
||||
}
|
||||
|
||||
struct LoadStoreFn {
|
||||
loadNumericFn: LoadNumericFn;
|
||||
storeNumericFn: StoreNumericFn;
|
||||
storeJSAnyFn: StoreJSAnyFn;
|
||||
}
|
||||
|
||||
macro GetLoadStoreFnForElementsKind(elementsKind: ElementsKind): LoadStoreFn {
|
||||
let loadNumericFn: LoadNumericFn;
|
||||
let storeNumericFn: StoreNumericFn;
|
||||
macro GetTypedArrayAccessor<T : type extends ElementsKind>():
|
||||
TypedArrayAccessor {
|
||||
const loadNumericFn = LoadTypedElement<T>;
|
||||
const storeNumericFn = StoreTypedElementNumeric<T>;
|
||||
const storeJSAnyFn = StoreTypedElementJSAny<T>;
|
||||
return TypedArrayAccessor{loadNumericFn, storeNumericFn, storeJSAnyFn};
|
||||
}
|
||||
|
||||
macro GetTypedArrayAccessor(elementsKind: ElementsKind): TypedArrayAccessor {
|
||||
if (IsElementsKindGreaterThan(elementsKind, UINT32_ELEMENTS)) {
|
||||
if (elementsKind == INT32_ELEMENTS) {
|
||||
loadNumericFn = LoadTypedElement<Int32Elements>;
|
||||
storeNumericFn = StoreTypedElementNumeric<Int32Elements>;
|
||||
return GetTypedArrayAccessor<Int32Elements>();
|
||||
} else if (elementsKind == FLOAT32_ELEMENTS) {
|
||||
loadNumericFn = LoadTypedElement<Float32Elements>;
|
||||
storeNumericFn = StoreTypedElementNumeric<Float32Elements>;
|
||||
return GetTypedArrayAccessor<Float32Elements>();
|
||||
} else if (elementsKind == FLOAT64_ELEMENTS) {
|
||||
loadNumericFn = LoadTypedElement<Float64Elements>;
|
||||
storeNumericFn = StoreTypedElementNumeric<Float64Elements>;
|
||||
return GetTypedArrayAccessor<Float64Elements>();
|
||||
} else if (elementsKind == UINT8_CLAMPED_ELEMENTS) {
|
||||
loadNumericFn = LoadTypedElement<Uint8ClampedElements>;
|
||||
storeNumericFn = StoreTypedElementNumeric<Uint8ClampedElements>;
|
||||
return GetTypedArrayAccessor<Uint8ClampedElements>();
|
||||
} else if (elementsKind == BIGUINT64_ELEMENTS) {
|
||||
loadNumericFn = LoadTypedElement<BigUint64Elements>;
|
||||
storeNumericFn = StoreTypedElementNumeric<BigUint64Elements>;
|
||||
return GetTypedArrayAccessor<BigUint64Elements>();
|
||||
} else if (elementsKind == BIGINT64_ELEMENTS) {
|
||||
loadNumericFn = LoadTypedElement<BigInt64Elements>;
|
||||
storeNumericFn = StoreTypedElementNumeric<BigInt64Elements>;
|
||||
} else {
|
||||
unreachable;
|
||||
return GetTypedArrayAccessor<BigInt64Elements>();
|
||||
}
|
||||
} else {
|
||||
if (elementsKind == UINT8_ELEMENTS) {
|
||||
loadNumericFn = LoadTypedElement<Uint8Elements>;
|
||||
storeNumericFn = StoreTypedElementNumeric<Uint8Elements>;
|
||||
return GetTypedArrayAccessor<Uint8Elements>();
|
||||
} else if (elementsKind == INT8_ELEMENTS) {
|
||||
loadNumericFn = LoadTypedElement<Int8Elements>;
|
||||
storeNumericFn = StoreTypedElementNumeric<Int8Elements>;
|
||||
return GetTypedArrayAccessor<Int8Elements>();
|
||||
} else if (elementsKind == UINT16_ELEMENTS) {
|
||||
loadNumericFn = LoadTypedElement<Uint16Elements>;
|
||||
storeNumericFn = StoreTypedElementNumeric<Uint16Elements>;
|
||||
return GetTypedArrayAccessor<Uint16Elements>();
|
||||
} else if (elementsKind == INT16_ELEMENTS) {
|
||||
loadNumericFn = LoadTypedElement<Int16Elements>;
|
||||
storeNumericFn = StoreTypedElementNumeric<Int16Elements>;
|
||||
return GetTypedArrayAccessor<Int16Elements>();
|
||||
} else if (elementsKind == UINT32_ELEMENTS) {
|
||||
loadNumericFn = LoadTypedElement<Uint32Elements>;
|
||||
storeNumericFn = StoreTypedElementNumeric<Uint32Elements>;
|
||||
} else {
|
||||
unreachable;
|
||||
return GetTypedArrayAccessor<Uint32Elements>();
|
||||
}
|
||||
}
|
||||
return LoadStoreFn{loadNumericFn, storeNumericFn};
|
||||
unreachable;
|
||||
}
|
||||
|
||||
extern macro TypedArrayBuiltinsAssembler::SetJSTypedArrayOnHeapDataPtr(
|
||||
@ -179,11 +201,11 @@ namespace typed_array {
|
||||
macro NewAttachedJSTypedArrayWitness(array: AttachedJSTypedArray):
|
||||
AttachedJSTypedArrayWitness {
|
||||
const kind = array.elements_kind;
|
||||
const accessors: LoadStoreFn = GetLoadStoreFnForElementsKind(kind);
|
||||
const accessor: TypedArrayAccessor = GetTypedArrayAccessor(kind);
|
||||
return AttachedJSTypedArrayWitness{
|
||||
stable: array,
|
||||
unstable: array,
|
||||
loadfn: accessors.loadNumericFn
|
||||
loadfn: accessor.loadNumericFn
|
||||
};
|
||||
}
|
||||
|
||||
@ -231,10 +253,25 @@ namespace typed_array {
|
||||
|
||||
builtin StoreTypedElementNumeric<T : type extends ElementsKind>(
|
||||
context: Context, typedArray: JSTypedArray, index: uintptr,
|
||||
value: Numeric): JSAny {
|
||||
value: Numeric): Smi {
|
||||
StoreJSTypedArrayElementFromNumeric(
|
||||
context, typedArray, index, value, KindForArrayType<T>());
|
||||
return Undefined;
|
||||
return kStoreSucceded;
|
||||
}
|
||||
|
||||
// Returns True on sucess or False if the typedArrays was detached.
|
||||
builtin StoreTypedElementJSAny<T : type extends ElementsKind>(
|
||||
context: Context, typedArray: JSTypedArray, index: uintptr,
|
||||
value: JSAny): Smi {
|
||||
try {
|
||||
StoreJSTypedArrayElementFromTagged(
|
||||
context, typedArray, index, value, KindForArrayType<T>())
|
||||
otherwise IfDetached;
|
||||
}
|
||||
label IfDetached {
|
||||
return kStoreFailureArrayDetached;
|
||||
}
|
||||
return kStoreSucceded;
|
||||
}
|
||||
|
||||
transitioning macro CallCompare(
|
||||
@ -345,10 +382,8 @@ namespace typed_array {
|
||||
|
||||
const comparefn: Callable =
|
||||
Cast<Callable>(comparefnObj) otherwise unreachable;
|
||||
const accessors: LoadStoreFn =
|
||||
GetLoadStoreFnForElementsKind(array.elements_kind);
|
||||
const loadfn = accessors.loadNumericFn;
|
||||
const storefn = accessors.storeNumericFn;
|
||||
const accessor: TypedArrayAccessor =
|
||||
GetTypedArrayAccessor(array.elements_kind);
|
||||
|
||||
// Prepare the two work arrays. All numbers are converted to tagged
|
||||
// objects first, and merge sorted between the two FixedArrays.
|
||||
@ -357,7 +392,7 @@ namespace typed_array {
|
||||
const work2: FixedArray = AllocateZeroedFixedArray(Convert<intptr>(len));
|
||||
|
||||
for (let i: uintptr = 0; i < len; ++i) {
|
||||
const element: Numeric = loadfn(context, array, i);
|
||||
const element: Numeric = accessor.LoadNumeric(context, array, i);
|
||||
work1.objects[i] = element;
|
||||
work2.objects[i] = element;
|
||||
}
|
||||
@ -365,8 +400,10 @@ namespace typed_array {
|
||||
TypedArrayMergeSort(work2, 0, len, work1, array, comparefn);
|
||||
|
||||
// work1 contains the sorted numbers. Write them back.
|
||||
for (let i: uintptr = 0; i < len; ++i)
|
||||
storefn(context, array, i, UnsafeCast<Numeric>(work1.objects[i]));
|
||||
for (let i: uintptr = 0; i < len; ++i) {
|
||||
accessor.StoreNumeric(
|
||||
context, array, i, UnsafeCast<Numeric>(work1.objects[i]));
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
@ -7512,44 +7512,6 @@ TNode<JSReceiver> CodeStubAssembler::ToObject_Inline(TNode<Context> context,
|
||||
return result.value();
|
||||
}
|
||||
|
||||
TNode<Smi> CodeStubAssembler::ToSmiLength(TNode<Context> context,
|
||||
TNode<Object> input,
|
||||
Label* range_error) {
|
||||
TVARIABLE(Smi, result);
|
||||
Label to_integer(this), negative_check(this),
|
||||
heap_number_negative_check(this), return_zero(this), done(this);
|
||||
|
||||
GotoIfNot(TaggedIsSmi(input), &to_integer);
|
||||
result = CAST(input);
|
||||
Goto(&negative_check);
|
||||
|
||||
BIND(&to_integer);
|
||||
{
|
||||
TNode<Number> integer_input = CAST(
|
||||
CallBuiltin(Builtins::kToInteger_TruncateMinusZero, context, input));
|
||||
GotoIfNot(TaggedIsSmi(integer_input), &heap_number_negative_check);
|
||||
result = CAST(integer_input);
|
||||
Goto(&negative_check);
|
||||
|
||||
// integer_input can still be a negative HeapNumber here.
|
||||
BIND(&heap_number_negative_check);
|
||||
TNode<HeapNumber> heap_number_input = CAST(integer_input);
|
||||
Branch(IsTrue(CallBuiltin(Builtins::kLessThan, context, heap_number_input,
|
||||
SmiConstant(0))),
|
||||
&return_zero, range_error);
|
||||
}
|
||||
|
||||
BIND(&negative_check);
|
||||
Branch(SmiLessThan(result.value(), SmiConstant(0)), &return_zero, &done);
|
||||
|
||||
BIND(&return_zero);
|
||||
result = SmiConstant(0);
|
||||
Goto(&done);
|
||||
|
||||
BIND(&done);
|
||||
return result.value();
|
||||
}
|
||||
|
||||
TNode<Number> CodeStubAssembler::ToLength_Inline(SloppyTNode<Context> context,
|
||||
SloppyTNode<Object> input) {
|
||||
TNode<Smi> smi_zero = SmiConstant(0);
|
||||
@ -10593,11 +10555,7 @@ TNode<TIndex> CodeStubAssembler::BuildFastLoop(const VariableList& vars,
|
||||
return var.value();
|
||||
}
|
||||
|
||||
// Instantiate BuildFastLoop for Smi and IntPtrT.
|
||||
template TNode<Smi> CodeStubAssembler::BuildFastLoop<Smi>(
|
||||
const VariableList& vars, TNode<Smi> start_index, TNode<Smi> end_index,
|
||||
const FastLoopBody<Smi>& body, int increment,
|
||||
IndexAdvanceMode advance_mode);
|
||||
// Instantiate BuildFastLoop for IntPtrT and UintPtrT.
|
||||
template TNode<IntPtrT> CodeStubAssembler::BuildFastLoop<IntPtrT>(
|
||||
const VariableList& vars, TNode<IntPtrT> start_index,
|
||||
TNode<IntPtrT> end_index, const FastLoopBody<IntPtrT>& body, int increment,
|
||||
|
@ -2659,10 +2659,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
kTruncateMinusZero,
|
||||
};
|
||||
|
||||
// ES6 7.1.15 ToLength, but jumps to range_error if the result is not a Smi.
|
||||
TNode<Smi> ToSmiLength(TNode<Context> context, TNode<Object> input,
|
||||
Label* range_error);
|
||||
|
||||
// ES6 7.1.15 ToLength, but with inlined fast path.
|
||||
TNode<Number> ToLength_Inline(SloppyTNode<Context> context,
|
||||
SloppyTNode<Object> input);
|
||||
|
@ -387,7 +387,7 @@ void PrintTypedArrayElements(std::ostream& os, const ElementType* data_ptr,
|
||||
if (previous_index != i - 1) {
|
||||
ss << '-' << (i - 1);
|
||||
}
|
||||
os << std::setw(12) << ss.str() << ": " << previous_value;
|
||||
os << std::setw(12) << ss.str() << ": " << +previous_value;
|
||||
previous_index = i;
|
||||
previous_value = value;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user