diff --git a/src/builtins/builtins-sharedarraybuffer-gen.cc b/src/builtins/builtins-sharedarraybuffer-gen.cc index 85cb4f10f7..7953de0ba5 100644 --- a/src/builtins/builtins-sharedarraybuffer-gen.cc +++ b/src/builtins/builtins-sharedarraybuffer-gen.cc @@ -23,18 +23,23 @@ class SharedArrayBufferBuiltinsAssembler : public CodeStubAssembler { Node* base, Node* offset, Node* value, Node* value_high); - void ValidateSharedTypedArray(Node* tagged, Node* context, + void ValidateSharedTypedArray(TNode maybe_array, + TNode context, TNode* out_elements_kind, - Node** out_backing_store); - Node* ConvertTaggedAtomicIndexToWord32(Node* tagged, Node* context, - Node** number_index); - void ValidateAtomicIndex(Node* array, Node* index_word, Node* context); -#if DEBUG - void DebugSanityCheckAtomicIndex(Node* array, Node* index_word, - Node* context); -#endif - void AtomicBinopBuiltinCommon(Node* array, Node* index, Node* value, - Node* context, AssemblerFunction function, + TNode* out_backing_store); + // TODO(v8:4153): Support huge SharedTypedArrays. + TNode ConvertTaggedAtomicIndexToWord32(TNode index, + TNode context, + TNode* number_index); + void ValidateAtomicIndex(TNode array, TNode index, + TNode context); + + inline void DebugSanityCheckAtomicIndex(TNode array, + TNode index); + + void AtomicBinopBuiltinCommon(TNode maybe_array, TNode index, + TNode value, TNode context, + AssemblerFunction function, Runtime::FunctionId runtime_function); // Create a BigInt from the result of a 64-bit atomic operation, using @@ -43,20 +48,22 @@ class SharedArrayBufferBuiltinsAssembler : public CodeStubAssembler { TNode BigIntFromUnsigned64(Node* unsigned64); }; +// https://tc39.es/ecma262/#sec-validatesharedintegertypedarray void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray( - Node* tagged, Node* context, TNode* out_elements_kind, - Node** out_backing_store) { + TNode maybe_array, TNode context, + TNode* out_elements_kind, TNode* out_backing_store) { Label not_float_or_clamped(this), invalid(this); // Fail if it is not a heap object. - GotoIf(TaggedIsSmi(tagged), &invalid); + GotoIf(TaggedIsSmi(maybe_array), &invalid); // Fail if the array's instance type is not JSTypedArray. - TNode tagged_map = LoadMap(tagged); - GotoIfNot(IsJSTypedArrayMap(tagged_map), &invalid); + TNode map = LoadMap(CAST(maybe_array)); + GotoIfNot(IsJSTypedArrayMap(map), &invalid); + TNode array = CAST(maybe_array); // Fail if the array's JSArrayBuffer is not shared. - TNode array_buffer = LoadJSArrayBufferViewBuffer(CAST(tagged)); + TNode array_buffer = LoadJSArrayBufferViewBuffer(array); TNode bitfield = LoadJSArrayBufferBitField(array_buffer); GotoIfNot(IsSetWord32(bitfield), &invalid); @@ -67,7 +74,7 @@ void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray( STATIC_ASSERT(UINT8_ELEMENTS < FLOAT32_ELEMENTS); STATIC_ASSERT(UINT16_ELEMENTS < FLOAT32_ELEMENTS); STATIC_ASSERT(UINT32_ELEMENTS < FLOAT32_ELEMENTS); - TNode elements_kind = LoadMapElementsKind(tagged_map); + TNode elements_kind = LoadMapElementsKind(map); GotoIf(Int32LessThan(elements_kind, Int32Constant(FLOAT32_ELEMENTS)), ¬_float_or_clamped); STATIC_ASSERT(BIGINT64_ELEMENTS > UINT8_CLAMPED_ELEMENTS); @@ -78,21 +85,22 @@ void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray( BIND(&invalid); { ThrowTypeError(context, MessageTemplate::kNotIntegerSharedTypedArray, - tagged); + maybe_array); } BIND(¬_float_or_clamped); *out_elements_kind = elements_kind; TNode backing_store = LoadJSArrayBufferBackingStore(array_buffer); - TNode byte_offset = LoadJSArrayBufferViewByteOffset(CAST(tagged)); - *out_backing_store = IntPtrAdd(backing_store, byte_offset); + TNode byte_offset = LoadJSArrayBufferViewByteOffset(array); + *out_backing_store = RawPtrAdd(backing_store, Signed(byte_offset)); } // https://tc39.github.io/ecma262/#sec-validateatomicaccess -Node* SharedArrayBufferBuiltinsAssembler::ConvertTaggedAtomicIndexToWord32( - Node* tagged, Node* context, Node** number_index) { - VARIABLE(var_result, MachineRepresentation::kWord32); +TNode +SharedArrayBufferBuiltinsAssembler::ConvertTaggedAtomicIndexToWord32( + TNode index, TNode context, TNode* number_index) { + TVARIABLE(Uint32T, var_result); Label done(this), range_error(this); // Returns word32 since index cannot be longer than a TypedArray length, @@ -100,8 +108,9 @@ Node* SharedArrayBufferBuiltinsAssembler::ConvertTaggedAtomicIndexToWord32( // The |number_index| output parameter is used only for architectures that // don't currently have a TF implementation and forward to runtime functions // instead; they expect the value has already been coerced to an integer. - *number_index = ToSmiIndex(CAST(context), CAST(tagged), &range_error); - var_result.Bind(SmiToInt32(*number_index)); + // TODO(v8:4153): Use ToIndex() here. + *number_index = ToSmiIndex(context, index, &range_error); + var_result = Unsigned(SmiToInt32(*number_index)); Goto(&done); BIND(&range_error); @@ -111,12 +120,11 @@ Node* SharedArrayBufferBuiltinsAssembler::ConvertTaggedAtomicIndexToWord32( return var_result.value(); } -void SharedArrayBufferBuiltinsAssembler::ValidateAtomicIndex(Node* array, - Node* index, - Node* context) { +void SharedArrayBufferBuiltinsAssembler::ValidateAtomicIndex( + TNode array, TNode index, TNode context) { // Check if the index is in bounds. If not, throw RangeError. Label check_passed(this); - TNode array_length = LoadJSTypedArrayLength(CAST(array)); + TNode array_length = LoadJSTypedArrayLength(array); // TODO(v8:4153): Use UintPtr for the {index} as well. GotoIf(UintPtrLessThan(ChangeUint32ToWord(index), array_length), &check_passed); @@ -126,17 +134,15 @@ void SharedArrayBufferBuiltinsAssembler::ValidateAtomicIndex(Node* array, BIND(&check_passed); } -#if DEBUG void SharedArrayBufferBuiltinsAssembler::DebugSanityCheckAtomicIndex( - Node* array, Node* index_word, Node* context) { + TNode array, TNode index) { // In Debug mode, we re-validate the index as a sanity check because // ToInteger above calls out to JavaScript. A SharedArrayBuffer can't be // detached and the TypedArray length can't change either, so skipping this // check in Release mode is safe. - CSA_ASSERT(this, UintPtrLessThan(ChangeUint32ToWord(index_word), - LoadJSTypedArrayLength(CAST(array)))); + CSA_ASSERT(this, UintPtrLessThan(ChangeUint32ToWord(index), + LoadJSTypedArrayLength(array))); } -#endif TNode SharedArrayBufferBuiltinsAssembler::BigIntFromSigned64( Node* signed64) { @@ -160,17 +166,20 @@ TNode SharedArrayBufferBuiltinsAssembler::BigIntFromUnsigned64( } } +// https://tc39.es/ecma262/#sec-atomicload TF_BUILTIN(AtomicsLoad, SharedArrayBufferBuiltinsAssembler) { - Node* array = Parameter(Descriptor::kArray); - Node* index = Parameter(Descriptor::kIndex); - Node* context = Parameter(Descriptor::kContext); + TNode maybe_array = CAST(Parameter(Descriptor::kArray)); + TNode index = CAST(Parameter(Descriptor::kIndex)); + TNode context = CAST(Parameter(Descriptor::kContext)); TNode elements_kind; - Node* backing_store; - ValidateSharedTypedArray(array, context, &elements_kind, &backing_store); + TNode backing_store; + ValidateSharedTypedArray(maybe_array, context, &elements_kind, + &backing_store); + TNode array = CAST(maybe_array); - Node* index_integer; - Node* index_word32 = + TNode index_integer; + TNode index_word32 = ConvertTaggedAtomicIndexToWord32(index, context, &index_integer); ValidateAtomicIndex(array, index_word32, context); TNode index_word = ChangeUint32ToWord(index_word32); @@ -231,20 +240,24 @@ TF_BUILTIN(AtomicsLoad, SharedArrayBufferBuiltinsAssembler) { Unreachable(); } +// https://tc39.es/ecma262/#sec-atomics.store TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) { - Node* array = Parameter(Descriptor::kArray); - Node* index = Parameter(Descriptor::kIndex); - Node* value = Parameter(Descriptor::kValue); - Node* context = Parameter(Descriptor::kContext); + TNode maybe_array = CAST(Parameter(Descriptor::kArray)); + TNode index = CAST(Parameter(Descriptor::kIndex)); + TNode value = CAST(Parameter(Descriptor::kValue)); + TNode context = CAST(Parameter(Descriptor::kContext)); TNode elements_kind; - Node* backing_store; - ValidateSharedTypedArray(array, context, &elements_kind, &backing_store); + TNode backing_store; + ValidateSharedTypedArray(maybe_array, context, &elements_kind, + &backing_store); + TNode array = CAST(maybe_array); - Node* index_integer; - Node* index_word32 = + TNode index_integer; + TNode index_word32 = ConvertTaggedAtomicIndexToWord32(index, context, &index_integer); ValidateAtomicIndex(array, index_word32, context); + TNode index_word = ChangeUint32ToWord(index_word32); Label u8(this), u16(this), u32(this), u64(this), other(this); @@ -252,12 +265,10 @@ TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) { STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS); GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &u64); - TNode value_integer = ToInteger_Inline(CAST(context), CAST(value)); + TNode value_integer = ToInteger_Inline(context, value); TNode value_word32 = TruncateTaggedToWord32(context, value_integer); -#if DEBUG - DebugSanityCheckAtomicIndex(array, index_word32, context); -#endif + DebugSanityCheckAtomicIndex(array, index_word32); int32_t case_values[] = { INT8_ELEMENTS, UINT8_ELEMENTS, INT16_ELEMENTS, @@ -287,14 +298,14 @@ TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) { Return(CallRuntime(Runtime::kAtomicsStore64, context, array, index_integer, value)); #else - TNode value_bigint = ToBigInt(CAST(context), CAST(value)); -#if DEBUG - DebugSanityCheckAtomicIndex(array, index_word32, context); -#endif + TNode value_bigint = ToBigInt(context, value); + + DebugSanityCheckAtomicIndex(array, index_word32); + TVARIABLE(UintPtrT, var_low); TVARIABLE(UintPtrT, var_high); BigIntToRawBytes(value_bigint, &var_low, &var_high); - Node* high = Is64() ? nullptr : static_cast(var_high.value()); + TNode high = Is64() ? TNode() : var_high.value(); AtomicStore(MachineRepresentation::kWord64, backing_store, WordShl(index_word, 3), var_low.value(), high); Return(value_bigint); @@ -305,18 +316,21 @@ TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) { Unreachable(); } +// https://tc39.es/ecma262/#sec-atomics.exchange TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) { - Node* array = Parameter(Descriptor::kArray); - Node* index = Parameter(Descriptor::kIndex); - Node* value = Parameter(Descriptor::kValue); - Node* context = Parameter(Descriptor::kContext); + TNode maybe_array = CAST(Parameter(Descriptor::kArray)); + TNode index = CAST(Parameter(Descriptor::kIndex)); + TNode value = CAST(Parameter(Descriptor::kValue)); + TNode context = CAST(Parameter(Descriptor::kContext)); TNode elements_kind; - Node* backing_store; - ValidateSharedTypedArray(array, context, &elements_kind, &backing_store); + TNode backing_store; + ValidateSharedTypedArray(maybe_array, context, &elements_kind, + &backing_store); + TNode array = CAST(maybe_array); - Node* index_integer; - Node* index_word32 = + TNode index_integer; + TNode index_word32 = ConvertTaggedAtomicIndexToWord32(index, context, &index_integer); ValidateAtomicIndex(array, index_word32, context); @@ -332,10 +346,10 @@ TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) { STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS); GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &big); - TNode value_integer = ToInteger_Inline(CAST(context), CAST(value)); -#if DEBUG - DebugSanityCheckAtomicIndex(array, index_word32, context); -#endif + TNode value_integer = ToInteger_Inline(context, value); + + DebugSanityCheckAtomicIndex(array, index_word32); + TNode value_word32 = TruncateTaggedToWord32(context, value_integer); int32_t case_values[] = { @@ -375,14 +389,14 @@ TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) { WordShl(index_word, 2), value_word32))); BIND(&big); - TNode value_bigint = ToBigInt(CAST(context), CAST(value)); -#if DEBUG - DebugSanityCheckAtomicIndex(array, index_word32, context); -#endif + TNode value_bigint = ToBigInt(context, value); + + DebugSanityCheckAtomicIndex(array, index_word32); + TVARIABLE(UintPtrT, var_low); TVARIABLE(UintPtrT, var_high); BigIntToRawBytes(value_bigint, &var_low, &var_high); - Node* high = Is64() ? nullptr : static_cast(var_high.value()); + TNode high = Is64() ? TNode() : var_high.value(); GotoIf(Word32Equal(elements_kind, Int32Constant(BIGINT64_ELEMENTS)), &i64); GotoIf(Word32Equal(elements_kind, Int32Constant(BIGUINT64_ELEMENTS)), &u64); Unreachable(); @@ -406,19 +420,22 @@ TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) { #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 } +// https://tc39.es/ecma262/#sec-atomics.compareexchange TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) { - Node* array = Parameter(Descriptor::kArray); - Node* index = Parameter(Descriptor::kIndex); - Node* old_value = Parameter(Descriptor::kOldValue); - Node* new_value = Parameter(Descriptor::kNewValue); - Node* context = Parameter(Descriptor::kContext); + TNode maybe_array = CAST(Parameter(Descriptor::kArray)); + TNode index = CAST(Parameter(Descriptor::kIndex)); + TNode old_value = CAST(Parameter(Descriptor::kOldValue)); + TNode new_value = CAST(Parameter(Descriptor::kNewValue)); + TNode context = CAST(Parameter(Descriptor::kContext)); TNode elements_kind; - Node* backing_store; - ValidateSharedTypedArray(array, context, &elements_kind, &backing_store); + TNode backing_store; + ValidateSharedTypedArray(maybe_array, context, &elements_kind, + &backing_store); + TNode array = CAST(maybe_array); - Node* index_integer; - Node* index_word32 = + TNode index_integer; + TNode index_word32 = ConvertTaggedAtomicIndexToWord32(index, context, &index_integer); ValidateAtomicIndex(array, index_word32, context); @@ -435,13 +452,11 @@ TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) { STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS); GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &big); - TNode old_value_integer = - ToInteger_Inline(CAST(context), CAST(old_value)); - TNode new_value_integer = - ToInteger_Inline(CAST(context), CAST(new_value)); -#if DEBUG - DebugSanityCheckAtomicIndex(array, index_word32, context); -#endif + TNode old_value_integer = ToInteger_Inline(context, old_value); + TNode new_value_integer = ToInteger_Inline(context, new_value); + + DebugSanityCheckAtomicIndex(array, index_word32); + TNode old_value_word32 = TruncateTaggedToWord32(context, old_value_integer); TNode new_value_word32 = @@ -488,19 +503,19 @@ TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) { old_value_word32, new_value_word32))); BIND(&big); - TNode old_value_bigint = ToBigInt(CAST(context), CAST(old_value)); - TNode new_value_bigint = ToBigInt(CAST(context), CAST(new_value)); -#if DEBUG - DebugSanityCheckAtomicIndex(array, index_word32, context); -#endif + TNode old_value_bigint = ToBigInt(context, old_value); + TNode new_value_bigint = ToBigInt(context, new_value); + + DebugSanityCheckAtomicIndex(array, index_word32); + TVARIABLE(UintPtrT, var_old_low); TVARIABLE(UintPtrT, var_old_high); TVARIABLE(UintPtrT, var_new_low); TVARIABLE(UintPtrT, var_new_high); BigIntToRawBytes(old_value_bigint, &var_old_low, &var_old_high); BigIntToRawBytes(new_value_bigint, &var_new_low, &var_new_high); - Node* old_high = Is64() ? nullptr : static_cast(var_old_high.value()); - Node* new_high = Is64() ? nullptr : static_cast(var_new_high.value()); + TNode old_high = Is64() ? TNode() : var_old_high.value(); + TNode new_high = Is64() ? TNode() : var_new_high.value(); GotoIf(Word32Equal(elements_kind, Int32Constant(BIGINT64_ELEMENTS)), &i64); GotoIf(Word32Equal(elements_kind, Int32Constant(BIGUINT64_ELEMENTS)), &u64); Unreachable(); @@ -525,32 +540,41 @@ TF_BUILTIN(AtomicsCompareExchange, SharedArrayBufferBuiltinsAssembler) { // || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X } -#define BINOP_BUILTIN(op) \ - TF_BUILTIN(Atomics##op, SharedArrayBufferBuiltinsAssembler) { \ - Node* array = Parameter(Descriptor::kArray); \ - Node* index = Parameter(Descriptor::kIndex); \ - Node* value = Parameter(Descriptor::kValue); \ - Node* context = Parameter(Descriptor::kContext); \ - AtomicBinopBuiltinCommon(array, index, value, context, \ - &CodeAssembler::Atomic##op, \ - Runtime::kAtomics##op); \ +#define BINOP_BUILTIN(op) \ + TF_BUILTIN(Atomics##op, SharedArrayBufferBuiltinsAssembler) { \ + TNode array = CAST(Parameter(Descriptor::kArray)); \ + TNode index = CAST(Parameter(Descriptor::kIndex)); \ + TNode value = CAST(Parameter(Descriptor::kValue)); \ + TNode context = CAST(Parameter(Descriptor::kContext)); \ + AtomicBinopBuiltinCommon(array, index, value, context, \ + &CodeAssembler::Atomic##op, \ + Runtime::kAtomics##op); \ } +// https://tc39.es/ecma262/#sec-atomics.add BINOP_BUILTIN(Add) +// https://tc39.es/ecma262/#sec-atomics.sub BINOP_BUILTIN(Sub) +// https://tc39.es/ecma262/#sec-atomics.and BINOP_BUILTIN(And) +// https://tc39.es/ecma262/#sec-atomics.or BINOP_BUILTIN(Or) +// https://tc39.es/ecma262/#sec-atomics.xor BINOP_BUILTIN(Xor) #undef BINOP_BUILTIN +// https://tc39.es/ecma262/#sec-atomicreadmodifywrite void SharedArrayBufferBuiltinsAssembler::AtomicBinopBuiltinCommon( - Node* array, Node* index, Node* value, Node* context, - AssemblerFunction function, Runtime::FunctionId runtime_function) { + TNode maybe_array, TNode index, TNode value, + TNode context, AssemblerFunction function, + Runtime::FunctionId runtime_function) { TNode elements_kind; - Node* backing_store; - ValidateSharedTypedArray(array, context, &elements_kind, &backing_store); + TNode backing_store; + ValidateSharedTypedArray(maybe_array, context, &elements_kind, + &backing_store); + TNode array = CAST(maybe_array); - Node* index_integer; - Node* index_word32 = + TNode index_integer; + TNode index_word32 = ConvertTaggedAtomicIndexToWord32(index, context, &index_integer); ValidateAtomicIndex(array, index_word32, context); @@ -567,10 +591,10 @@ void SharedArrayBufferBuiltinsAssembler::AtomicBinopBuiltinCommon( STATIC_ASSERT(BIGUINT64_ELEMENTS > INT32_ELEMENTS); GotoIf(Int32GreaterThan(elements_kind, Int32Constant(INT32_ELEMENTS)), &big); - TNode value_integer = ToInteger_Inline(CAST(context), CAST(value)); -#if DEBUG - DebugSanityCheckAtomicIndex(array, index_word32, context); -#endif + TNode value_integer = ToInteger_Inline(context, value); + + DebugSanityCheckAtomicIndex(array, index_word32); + TNode value_word32 = TruncateTaggedToWord32(context, value_integer); int32_t case_values[] = { @@ -612,14 +636,14 @@ void SharedArrayBufferBuiltinsAssembler::AtomicBinopBuiltinCommon( WordShl(index_word, 2), value_word32, nullptr))); BIND(&big); - TNode value_bigint = ToBigInt(CAST(context), CAST(value)); -#if DEBUG - DebugSanityCheckAtomicIndex(array, index_word32, context); -#endif + TNode value_bigint = ToBigInt(context, value); + + DebugSanityCheckAtomicIndex(array, index_word32); + TVARIABLE(UintPtrT, var_low); TVARIABLE(UintPtrT, var_high); BigIntToRawBytes(value_bigint, &var_low, &var_high); - Node* high = Is64() ? nullptr : static_cast(var_high.value()); + TNode high = Is64() ? TNode() : var_high.value(); GotoIf(Word32Equal(elements_kind, Int32Constant(BIGINT64_ELEMENTS)), &i64); GotoIf(Word32Equal(elements_kind, Int32Constant(BIGUINT64_ELEMENTS)), &u64); Unreachable(); diff --git a/src/codegen/code-stub-assembler.cc b/src/codegen/code-stub-assembler.cc index f67409f506..197c92faf5 100644 --- a/src/codegen/code-stub-assembler.cc +++ b/src/codegen/code-stub-assembler.cc @@ -7322,8 +7322,8 @@ TNode CodeStubAssembler::ToNumber(SloppyTNode context, return var_result.value(); } -TNode CodeStubAssembler::ToBigInt(SloppyTNode context, - SloppyTNode input) { +TNode CodeStubAssembler::ToBigInt(TNode context, + TNode input) { TVARIABLE(BigInt, var_result); Label if_bigint(this), done(this), if_throw(this); diff --git a/src/codegen/code-stub-assembler.h b/src/codegen/code-stub-assembler.h index bbdbf8d7dd..be7a31dda2 100644 --- a/src/codegen/code-stub-assembler.h +++ b/src/codegen/code-stub-assembler.h @@ -2637,8 +2637,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler // Try to convert an object to a BigInt. Throws on failure (e.g. for Numbers). // https://tc39.github.io/proposal-bigint/#sec-to-bigint - TNode ToBigInt(SloppyTNode context, - SloppyTNode input); + TNode ToBigInt(TNode context, TNode input); // Converts |input| to one of 2^32 integer values in the range 0 through // 2^32-1, inclusive.