diff --git a/BUILD.gn b/BUILD.gn index cc9b7a906a..2a8c47542c 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -876,6 +876,7 @@ torque_files = [ "src/builtins/object-fromentries.tq", "src/builtins/iterator.tq", "src/builtins/typed-array.tq", + "src/builtins/typed-array-createtypedarray.tq", "test/torque/test-torque.tq", "third_party/v8/builtins/array-sort.tq", ] diff --git a/src/builtins/base.tq b/src/builtins/base.tq index a13b2e1d7c..b007fe8680 100644 --- a/src/builtins/base.tq +++ b/src/builtins/base.tq @@ -18,6 +18,9 @@ type never; type Tagged generates 'TNode' constexpr 'ObjectPtr'; type Smi extends Tagged generates 'TNode' constexpr 'Smi'; +// A Smi that is greater than or equal to 0. See TaggedIsPositiveSmi. +type PositiveSmi extends Smi generates 'TNode'; + class HeapObject extends Tagged { map_untyped: Tagged; } @@ -147,6 +150,8 @@ intrinsic %RawPointerCast(p: RawPtr): A; intrinsic %RawConstexprCast(f: From): To; type NativeContextSlot generates 'TNode' constexpr 'int32_t'; +const ARRAY_BUFFER_FUN_INDEX: constexpr NativeContextSlot + generates 'Context::ARRAY_BUFFER_FUN_INDEX'; const ARRAY_JOIN_STACK_INDEX: constexpr NativeContextSlot generates 'Context::ARRAY_JOIN_STACK_INDEX'; const OBJECT_FUNCTION_INDEX: constexpr NativeContextSlot @@ -265,6 +270,8 @@ const kCalledNonCallable: constexpr MessageTemplate generates 'MessageTemplate::kCalledNonCallable'; const kCalledOnNullOrUndefined: constexpr MessageTemplate generates 'MessageTemplate::kCalledOnNullOrUndefined'; +const kInvalidTypedArrayLength: constexpr MessageTemplate + generates 'MessageTemplate::kInvalidTypedArrayLength'; const kIteratorValueNotAnObject: constexpr MessageTemplate generates 'MessageTemplate::kIteratorValueNotAnObject'; const kNotIterable: constexpr MessageTemplate @@ -376,6 +383,7 @@ extern transitioning macro HasProperty_Inline(implicit context: Context)( JSReceiver, Object): Boolean; extern macro ThrowRangeError(Context, constexpr MessageTemplate): never; +extern macro ThrowRangeError(Context, constexpr MessageTemplate, Object): never; extern macro ThrowTypeError(Context, constexpr MessageTemplate): never; extern macro ThrowTypeError(Context, constexpr MessageTemplate, Object): never; extern macro ThrowTypeError( @@ -595,6 +603,8 @@ extern macro TaggedToHeapObject(Object): HeapObject labels CastError; extern macro TaggedToSmi(Object): Smi labels CastError; +extern macro TaggedToPositiveSmi(Object): PositiveSmi + labels CastError; extern macro HeapObjectToJSArray(HeapObject): JSArray labels CastError; extern macro HeapObjectToCallable(HeapObject): Callable @@ -805,6 +815,11 @@ Cast(o: Object): Smi return TaggedToSmi(o) otherwise CastError; } +Cast(o: Object): PositiveSmi + labels CastError { + return TaggedToPositiveSmi(o) otherwise CastError; +} + Cast(o: Object): Number labels CastError { return TaggedToNumber(o) otherwise CastError; @@ -1178,6 +1193,10 @@ macro GetObjectFunction(implicit context: Context)(): JSFunction { return UnsafeCast( LoadNativeContext(context)[OBJECT_FUNCTION_INDEX]); } +macro GetArrayBufferFunction(implicit context: Context)(): JSFunction { + return UnsafeCast( + LoadNativeContext(context)[ARRAY_BUFFER_FUN_INDEX]); +} macro GetFastPackedSmiElementsJSArrayMap(implicit context: Context)(): Map { return UnsafeCast( diff --git a/src/builtins/builtins-typed-array-gen.cc b/src/builtins/builtins-typed-array-gen.cc index 8688c3c791..6a9f2b5508 100644 --- a/src/builtins/builtins-typed-array-gen.cc +++ b/src/builtins/builtins-typed-array-gen.cc @@ -10,6 +10,7 @@ #include "src/builtins/growable-fixed-array-gen.h" #include "src/handles-inl.h" #include "src/heap/factory-inl.h" +#include "torque-generated/builtins-typed-array-from-dsl-gen.h" namespace v8 { namespace internal { @@ -317,44 +318,6 @@ TF_BUILTIN(TypedArrayInitialize, TypedArrayBuiltinsAssembler) { Return(UndefinedConstant()); } -// ES6 #sec-typedarray-length -void TypedArrayBuiltinsAssembler::ConstructByLength(TNode context, - TNode holder, - TNode length, - TNode element_size) { - // TODO(7881): support larger-than-smi typed array lengths - CSA_ASSERT(this, TaggedIsPositiveSmi(element_size)); - - Label invalid_length(this, Label::kDeferred), done(this); - - TNode converted_length = - ToInteger_Inline(context, length, CodeStubAssembler::kTruncateMinusZero); - - // The maximum length of a TypedArray is MaxSmi(). - // Note: this is not per spec, but rather a constraint of our current - // representation (which uses Smis). - // TODO(7881): support larger-than-smi typed array lengths - GotoIf(TaggedIsNotSmi(converted_length), &invalid_length); - // The goto above ensures that byte_length is a Smi. - TNode smi_converted_length = CAST(converted_length); - GotoIf(SmiLessThan(smi_converted_length, SmiConstant(0)), &invalid_length); - - Node* initialize = TrueConstant(); - TNode default_constructor = CAST(LoadContextElement( - LoadNativeContext(context), Context::ARRAY_BUFFER_FUN_INDEX)); - CallBuiltin(Builtins::kTypedArrayInitialize, context, holder, - converted_length, element_size, initialize, default_constructor); - Goto(&done); - - BIND(&invalid_length); - { - ThrowRangeError(context, MessageTemplate::kInvalidTypedArrayLength, - converted_length); - } - - BIND(&done); -} - // ES6 #sec-typedarray-buffer-byteoffset-length void TypedArrayBuiltinsAssembler::ConstructByArrayBuffer( TNode context, TNode holder, @@ -758,7 +721,8 @@ TF_BUILTIN(CreateTypedArray, TypedArrayBuiltinsAssembler) { // a number. https://tc39.github.io/ecma262/#sec-typedarray-length BIND(&if_arg1isnumber); { - ConstructByLength(context, result, arg1, element_size); + TypedArrayBuiltinsFromDSLAssembler(this->state()) + .ConstructByLength(context, result, arg1, element_size); Goto(&return_result); } diff --git a/src/builtins/builtins-typed-array-gen.h b/src/builtins/builtins-typed-array-gen.h index b3665e26d3..2a77a981cf 100644 --- a/src/builtins/builtins-typed-array-gen.h +++ b/src/builtins/builtins-typed-array-gen.h @@ -30,8 +30,6 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler { const char* method_name, IterationKind iteration_kind); - void ConstructByLength(TNode context, TNode holder, - TNode length, TNode element_size); void ConstructByArrayBuffer(TNode context, TNode holder, TNode buffer, diff --git a/src/builtins/typed-array-createtypedarray.tq b/src/builtins/typed-array-createtypedarray.tq new file mode 100644 index 0000000000..d711b0479a --- /dev/null +++ b/src/builtins/typed-array-createtypedarray.tq @@ -0,0 +1,29 @@ +// 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. + +namespace typed_array { + extern builtin TypedArrayInitialize(implicit context: Context)( + JSTypedArray, PositiveSmi, PositiveSmi, Boolean, JSReceiver): void; + + // 22.2.4.2 TypedArray ( length ) + // ES #sec-typedarray-length + macro ConstructByLength(implicit context: Context)( + typedArray: JSTypedArray, length: Object, elementSize: Smi): void { + const positiveElementSize: PositiveSmi = + Cast(elementSize) otherwise unreachable; + const convertedLength: Number = + ToInteger_Inline(context, length, kTruncateMinusZero); + // The maximum length of a TypedArray is MaxSmi(). + // Note: this is not per spec, but rather a constraint of our current + // representation (which uses Smis). + // TODO(7881): support larger-than-smi typed array lengths + const positiveLength: PositiveSmi = Cast(convertedLength) + otherwise ThrowRangeError(context, kInvalidTypedArrayLength, length); + const defaultConstructor: JSFunction = GetArrayBufferFunction(); + const initialize: Boolean = True; + TypedArrayInitialize( + typedArray, positiveLength, positiveElementSize, initialize, + defaultConstructor); + } +} diff --git a/src/code-stub-assembler.h b/src/code-stub-assembler.h index 9c23144ea0..42deeae78c 100644 --- a/src/code-stub-assembler.h +++ b/src/code-stub-assembler.h @@ -317,6 +317,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler return UncheckedCast(value); } + TNode TaggedToPositiveSmi(TNode value, Label* fail) { + GotoIfNot(TaggedIsPositiveSmi(value), fail); + return UncheckedCast(value); + } + TNode TaggedToNumber(TNode value, Label* fail) { GotoIfNot(IsNumber(value), fail); return UncheckedCast(value);