diff options
Diffstat (limited to 'chromium/v8/src/objects')
147 files changed, 5754 insertions, 4147 deletions
diff --git a/chromium/v8/src/objects/OWNERS b/chromium/v8/src/objects/OWNERS new file mode 100644 index 00000000000..450423f8785 --- /dev/null +++ b/chromium/v8/src/objects/OWNERS @@ -0,0 +1,3 @@ +file://COMMON_OWNERS + +# COMPONENT: Blink>JavaScript>Runtime diff --git a/chromium/v8/src/objects/api-callbacks-inl.h b/chromium/v8/src/objects/api-callbacks-inl.h index 041247637a1..c327a35746c 100644 --- a/chromium/v8/src/objects/api-callbacks-inl.h +++ b/chromium/v8/src/objects/api-callbacks-inl.h @@ -13,6 +13,7 @@ #include "src/objects/js-objects-inl.h" #include "src/objects/name.h" #include "src/objects/templates.h" +#include "torque-generated/class-definitions-tq-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -23,12 +24,12 @@ namespace internal { OBJECT_CONSTRUCTORS_IMPL(AccessCheckInfo, Struct) OBJECT_CONSTRUCTORS_IMPL(AccessorInfo, Struct) OBJECT_CONSTRUCTORS_IMPL(InterceptorInfo, Struct) -OBJECT_CONSTRUCTORS_IMPL(CallHandlerInfo, Tuple3) + +TQ_OBJECT_CONSTRUCTORS_IMPL(CallHandlerInfo) CAST_ACCESSOR(AccessorInfo) CAST_ACCESSOR(AccessCheckInfo) CAST_ACCESSOR(InterceptorInfo) -CAST_ACCESSOR(CallHandlerInfo) ACCESSORS(AccessorInfo, name, Name, kNameOffset) SMI_ACCESSORS(AccessorInfo, flags, kFlagsOffset) @@ -119,9 +120,6 @@ BOOL_ACCESSORS(InterceptorInfo, flags, non_masking, kNonMasking) BOOL_ACCESSORS(InterceptorInfo, flags, is_named, kNamed) BOOL_ACCESSORS(InterceptorInfo, flags, has_no_side_effect, kHasNoSideEffect) -ACCESSORS(CallHandlerInfo, callback, Object, kCallbackOffset) -ACCESSORS(CallHandlerInfo, js_callback, Object, kJsCallbackOffset) -ACCESSORS(CallHandlerInfo, data, Object, kDataOffset) bool CallHandlerInfo::IsSideEffectFreeCallHandlerInfo() const { ReadOnlyRoots roots = GetReadOnlyRoots(); diff --git a/chromium/v8/src/objects/api-callbacks.h b/chromium/v8/src/objects/api-callbacks.h index 1d8b456a8e0..518339f7d4a 100644 --- a/chromium/v8/src/objects/api-callbacks.h +++ b/chromium/v8/src/objects/api-callbacks.h @@ -6,6 +6,7 @@ #define V8_OBJECTS_API_CALLBACKS_H_ #include "src/objects/struct.h" +#include "torque-generated/class-definitions-tq.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -159,14 +160,9 @@ class InterceptorInfo : public Struct { OBJECT_CONSTRUCTORS(InterceptorInfo, Struct); }; -class CallHandlerInfo : public Tuple3 { +class CallHandlerInfo + : public TorqueGeneratedCallHandlerInfo<CallHandlerInfo, Struct> { public: - DECL_ACCESSORS(callback, Object) - DECL_ACCESSORS(js_callback, Object) - DECL_ACCESSORS(data, Object) - - DECL_CAST(CallHandlerInfo) - inline bool IsSideEffectFreeCallHandlerInfo() const; inline bool IsSideEffectCallHandlerInfo() const; inline void SetNextCallHasNoSideEffect(); @@ -180,11 +176,7 @@ class CallHandlerInfo : public Tuple3 { Address redirected_callback() const; - static const int kCallbackOffset = kValue1Offset; - static const int kJsCallbackOffset = kValue2Offset; - static const int kDataOffset = kValue3Offset; - - OBJECT_CONSTRUCTORS(CallHandlerInfo, Tuple3); + TQ_OBJECT_CONSTRUCTORS(CallHandlerInfo) }; } // namespace internal diff --git a/chromium/v8/src/objects/arguments-inl.h b/chromium/v8/src/objects/arguments-inl.h index c2ef59a8968..2931c5b0a02 100644 --- a/chromium/v8/src/objects/arguments-inl.h +++ b/chromium/v8/src/objects/arguments-inl.h @@ -29,12 +29,14 @@ CAST_ACCESSOR(JSArgumentsObject) SMI_ACCESSORS(AliasedArgumentsEntry, aliased_context_slot, kAliasedContextSlotOffset) -Context SloppyArgumentsElements::context() { - return Context::cast(get(kContextIndex)); +DEF_GETTER(SloppyArgumentsElements, context, Context) { + return TaggedField<Context>::load(isolate, *this, + OffsetOfElementAt(kContextIndex)); } -FixedArray SloppyArgumentsElements::arguments() { - return FixedArray::cast(get(kArgumentsIndex)); +DEF_GETTER(SloppyArgumentsElements, arguments, FixedArray) { + return TaggedField<FixedArray>::load(isolate, *this, + OffsetOfElementAt(kArgumentsIndex)); } void SloppyArgumentsElements::set_arguments(FixedArray arguments) { diff --git a/chromium/v8/src/objects/arguments.h b/chromium/v8/src/objects/arguments.h index a1d39f1f36d..79d2e604bd2 100644 --- a/chromium/v8/src/objects/arguments.h +++ b/chromium/v8/src/objects/arguments.h @@ -102,8 +102,8 @@ class SloppyArgumentsElements : public FixedArray { static const int kArgumentsIndex = 1; static const uint32_t kParameterMapStart = 2; - inline Context context(); - inline FixedArray arguments(); + DECL_GETTER(context, Context) + DECL_GETTER(arguments, FixedArray) inline void set_arguments(FixedArray arguments); inline uint32_t parameter_map_length(); inline Object get_mapped_entry(uint32_t entry); diff --git a/chromium/v8/src/objects/bigint.cc b/chromium/v8/src/objects/bigint.cc index 92b78f88216..b02c0f29d6f 100644 --- a/chromium/v8/src/objects/bigint.cc +++ b/chromium/v8/src/objects/bigint.cc @@ -46,6 +46,8 @@ class MutableBigInt : public FreshlyAllocatedBigInt { static MaybeHandle<BigInt> MakeImmutable(MaybeHandle<MutableBigInt> maybe); static Handle<BigInt> MakeImmutable(Handle<MutableBigInt> result); + static void Canonicalize(MutableBigInt result); + // Allocation helpers. static MaybeHandle<MutableBigInt> New( Isolate* isolate, int length, @@ -64,6 +66,10 @@ class MutableBigInt : public FreshlyAllocatedBigInt { SLOW_DCHECK(bigint->IsBigInt()); return Handle<MutableBigInt>::cast(bigint); } + static MutableBigInt cast(Object o) { + SLOW_DCHECK(o.IsBigInt()); + return MutableBigInt(o.ptr()); + } static MutableBigInt unchecked_cast(Object o) { return MutableBigInt(o.ptr()); } @@ -87,8 +93,13 @@ class MutableBigInt : public FreshlyAllocatedBigInt { static MaybeHandle<BigInt> AbsoluteAdd(Isolate* isolate, Handle<BigInt> x, Handle<BigInt> y, bool result_sign); + + static void AbsoluteAdd(MutableBigInt result, BigInt x, BigInt y); + static Handle<BigInt> AbsoluteSub(Isolate* isolate, Handle<BigInt> x, Handle<BigInt> y, bool result_sign); + static void AbsoluteSub(MutableBigInt result, BigInt x, BigInt y); + static MaybeHandle<MutableBigInt> AbsoluteAddOne( Isolate* isolate, Handle<BigIntBase> x, bool sign, MutableBigInt result_storage = MutableBigInt()); @@ -120,6 +131,8 @@ class MutableBigInt : public FreshlyAllocatedBigInt { static int AbsoluteCompare(Handle<BigIntBase> x, Handle<BigIntBase> y); + static int AbsoluteCompare(BigIntBase x, BigIntBase y); + static void MultiplyAccumulate(Handle<BigIntBase> multiplicand, digit_t multiplier, Handle<MutableBigInt> accumulator, @@ -223,11 +236,24 @@ NEVER_READ_ONLY_SPACE_IMPL(MutableBigInt) #include "src/objects/object-macros-undef.h" +template <typename T> +MaybeHandle<T> ThrowBigIntTooBig(Isolate* isolate) { + // If the result of a BigInt computation is truncated to 64 bit, Turbofan + // can sometimes truncate intermediate results already, which can prevent + // those from exceeding the maximum length, effectively preventing a + // RangeError from being thrown. As this is a performance optimization, this + // behavior is accepted. To prevent the correctness fuzzer from detecting this + // difference, we crash the program. + if (FLAG_correctness_fuzzer_suppressions) { + FATAL("Aborting on invalid BigInt length"); + } + THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig), T); +} + MaybeHandle<MutableBigInt> MutableBigInt::New(Isolate* isolate, int length, AllocationType allocation) { if (length > BigInt::kMaxLength) { - THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig), - MutableBigInt); + return ThrowBigIntTooBig<MutableBigInt>(isolate); } Handle<MutableBigInt> result = Cast(isolate->factory()->NewBigInt(length, allocation)); @@ -347,32 +373,36 @@ MaybeHandle<BigInt> MutableBigInt::MakeImmutable( } Handle<BigInt> MutableBigInt::MakeImmutable(Handle<MutableBigInt> result) { + MutableBigInt::Canonicalize(*result); + return Handle<BigInt>::cast(result); +} + +void MutableBigInt::Canonicalize(MutableBigInt result) { // Check if we need to right-trim any leading zero-digits. - int old_length = result->length(); + int old_length = result.length(); int new_length = old_length; - while (new_length > 0 && result->digit(new_length - 1) == 0) new_length--; + while (new_length > 0 && result.digit(new_length - 1) == 0) new_length--; int to_trim = old_length - new_length; if (to_trim != 0) { - int size_delta = to_trim * kDigitSize; - Address new_end = result->address() + BigInt::SizeFor(new_length); - Heap* heap = result->GetHeap(); - if (!heap->IsLargeObject(*result)) { + int size_delta = to_trim * MutableBigInt::kDigitSize; + Address new_end = result.address() + BigInt::SizeFor(new_length); + Heap* heap = result.GetHeap(); + if (!heap->IsLargeObject(result)) { // We do not create a filler for objects in large object space. // TODO(hpayer): We should shrink the large object page if the size // of the object changed significantly. heap->CreateFillerObjectAt(new_end, size_delta, ClearRecordedSlots::kNo); } - result->synchronized_set_length(new_length); + result.synchronized_set_length(new_length); // Canonicalize -0n. if (new_length == 0) { - result->set_sign(false); + result.set_sign(false); // TODO(jkummerow): If we cache a canonical 0n, return that here. } } - DCHECK_IMPLIES(result->length() > 0, - result->digit(result->length() - 1) != 0); // MSD is non-zero. - return Handle<BigInt>(result.location()); + DCHECK_IMPLIES(result.length() > 0, + result.digit(result.length() - 1) != 0); // MSD is non-zero. } Handle<BigInt> BigInt::Zero(Isolate* isolate) { @@ -428,14 +458,12 @@ MaybeHandle<BigInt> BigInt::Exponentiate(Isolate* isolate, Handle<BigInt> base, // results. STATIC_ASSERT(kMaxLengthBits < std::numeric_limits<digit_t>::max()); if (exponent->length() > 1) { - THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig), - BigInt); + return ThrowBigIntTooBig<BigInt>(isolate); } digit_t exp_value = exponent->digit(0); if (exp_value == 1) return base; if (exp_value >= kMaxLengthBits) { - THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig), - BigInt); + return ThrowBigIntTooBig<BigInt>(isolate); } STATIC_ASSERT(kMaxLengthBits <= kMaxInt); int n = static_cast<int>(exp_value); @@ -1130,6 +1158,26 @@ void BigInt::BigIntShortPrint(std::ostream& os) { // Internal helpers. +void MutableBigInt::AbsoluteAdd(MutableBigInt result, BigInt x, BigInt y) { + DisallowHeapAllocation no_gc; + digit_t carry = 0; + int i = 0; + for (; i < y.length(); i++) { + digit_t new_carry = 0; + digit_t sum = digit_add(x.digit(i), y.digit(i), &new_carry); + sum = digit_add(sum, carry, &new_carry); + result.set_digit(i, sum); + carry = new_carry; + } + for (; i < x.length(); i++) { + digit_t new_carry = 0; + digit_t sum = digit_add(x.digit(i), carry, &new_carry); + result.set_digit(i, sum); + carry = new_carry; + } + result.set_digit(i, carry); +} + MaybeHandle<BigInt> MutableBigInt::AbsoluteAdd(Isolate* isolate, Handle<BigInt> x, Handle<BigInt> y, @@ -1146,22 +1194,9 @@ MaybeHandle<BigInt> MutableBigInt::AbsoluteAdd(Isolate* isolate, if (!New(isolate, x->length() + 1).ToHandle(&result)) { return MaybeHandle<BigInt>(); } - digit_t carry = 0; - int i = 0; - for (; i < y->length(); i++) { - digit_t new_carry = 0; - digit_t sum = digit_add(x->digit(i), y->digit(i), &new_carry); - sum = digit_add(sum, carry, &new_carry); - result->set_digit(i, sum); - carry = new_carry; - } - for (; i < x->length(); i++) { - digit_t new_carry = 0; - digit_t sum = digit_add(x->digit(i), carry, &new_carry); - result->set_digit(i, sum); - carry = new_carry; - } - result->set_digit(i, carry); + + AbsoluteAdd(*result, *x, *y); + result->set_sign(result_sign); return MakeImmutable(result); } @@ -1178,24 +1213,31 @@ Handle<BigInt> MutableBigInt::AbsoluteSub(Isolate* isolate, Handle<BigInt> x, return result_sign == x->sign() ? x : BigInt::UnaryMinus(isolate, x); } Handle<MutableBigInt> result = New(isolate, x->length()).ToHandleChecked(); + + AbsoluteSub(*result, *x, *y); + + result->set_sign(result_sign); + return MakeImmutable(result); +} + +void MutableBigInt::AbsoluteSub(MutableBigInt result, BigInt x, BigInt y) { + DisallowHeapAllocation no_gc; digit_t borrow = 0; int i = 0; - for (; i < y->length(); i++) { + for (; i < y.length(); i++) { digit_t new_borrow = 0; - digit_t difference = digit_sub(x->digit(i), y->digit(i), &new_borrow); + digit_t difference = digit_sub(x.digit(i), y.digit(i), &new_borrow); difference = digit_sub(difference, borrow, &new_borrow); - result->set_digit(i, difference); + result.set_digit(i, difference); borrow = new_borrow; } - for (; i < x->length(); i++) { + for (; i < x.length(); i++) { digit_t new_borrow = 0; - digit_t difference = digit_sub(x->digit(i), borrow, &new_borrow); - result->set_digit(i, difference); + digit_t difference = digit_sub(x.digit(i), borrow, &new_borrow); + result.set_digit(i, difference); borrow = new_borrow; } DCHECK_EQ(0, borrow); - result->set_sign(result_sign); - return MakeImmutable(result); } // Adds 1 to the absolute value of {x} and sets the result's sign to {sign}. @@ -1375,12 +1417,17 @@ Handle<MutableBigInt> MutableBigInt::AbsoluteXor(Isolate* isolate, // Returns a positive value if abs(x) > abs(y), a negative value if // abs(x) < abs(y), or zero if abs(x) == abs(y). int MutableBigInt::AbsoluteCompare(Handle<BigIntBase> x, Handle<BigIntBase> y) { - int diff = x->length() - y->length(); + return MutableBigInt::AbsoluteCompare(*x, *y); +} + +int MutableBigInt::AbsoluteCompare(BigIntBase x, BigIntBase y) { + DisallowHeapAllocation no_gc; + int diff = x.length() - y.length(); if (diff != 0) return diff; - int i = x->length() - 1; - while (i >= 0 && x->digit(i) == y->digit(i)) i--; + int i = x.length() - 1; + while (i >= 0 && x.digit(i) == y.digit(i)) i--; if (i < 0) return 0; - return x->digit(i) > y->digit(i) ? 1 : -1; + return x.digit(i) > y.digit(i) ? 1 : -1; } // Multiplies {multiplicand} with {multiplier} and adds the result to @@ -1716,8 +1763,7 @@ MaybeHandle<BigInt> MutableBigInt::LeftShiftByAbsolute(Isolate* isolate, Handle<BigIntBase> y) { Maybe<digit_t> maybe_shift = ToShiftAmount(y); if (maybe_shift.IsNothing()) { - THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig), - BigInt); + return ThrowBigIntTooBig<BigInt>(isolate); } digit_t shift = maybe_shift.FromJust(); int digit_shift = static_cast<int>(shift / kDigitBits); @@ -1727,8 +1773,7 @@ MaybeHandle<BigInt> MutableBigInt::LeftShiftByAbsolute(Isolate* isolate, (x->digit(length - 1) >> (kDigitBits - bits_shift)) != 0; int result_length = length + digit_shift + grow; if (result_length > kMaxLength) { - THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig), - BigInt); + return ThrowBigIntTooBig<BigInt>(isolate); } Handle<MutableBigInt> result; if (!New(isolate, result_length).ToHandle(&result)) { @@ -1887,8 +1932,7 @@ MaybeHandle<FreshlyAllocatedBigInt> BigInt::AllocateFor( } // All the overflow/maximum checks above fall through to here. if (should_throw == kThrowOnError) { - THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig), - FreshlyAllocatedBigInt); + return ThrowBigIntTooBig<FreshlyAllocatedBigInt>(isolate); } else { return MaybeHandle<FreshlyAllocatedBigInt>(); } @@ -2155,10 +2199,6 @@ MaybeHandle<String> MutableBigInt::ToStringGeneric(Isolate* isolate, // the raw characters pointer (as the string might have moved). chars = result->GetChars(no_gc); } - if (interrupt_check.InterruptRequested() && - isolate->stack_guard()->HandleInterrupts().IsException(isolate)) { - return MaybeHandle<String>(); - } } } while (nonzero_digit > 0); last_digit = rest->digit(0); @@ -2250,8 +2290,7 @@ MaybeHandle<BigInt> BigInt::AsUintN(Isolate* isolate, uint64_t n, // If {x} is negative, simulate two's complement representation. if (x->sign()) { if (n > kMaxLengthBits) { - THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig), - BigInt); + return ThrowBigIntTooBig<BigInt>(isolate); } return MutableBigInt::TruncateAndSubFromPowerOfTwo( isolate, static_cast<int>(n), x, false); @@ -2395,8 +2434,7 @@ MaybeHandle<BigInt> BigInt::FromWords64(Isolate* isolate, int sign_bit, int words64_count, const uint64_t* words) { if (words64_count < 0 || words64_count > kMaxLength / (64 / kDigitBits)) { - THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig), - BigInt); + return ThrowBigIntTooBig<BigInt>(isolate); } if (words64_count == 0) return MutableBigInt::Zero(isolate); STATIC_ASSERT(kDigitBits == 64 || kDigitBits == 32); @@ -2674,5 +2712,32 @@ void BigInt::BigIntPrint(std::ostream& os) { } #endif // OBJECT_PRINT +void MutableBigInt_AbsoluteAddAndCanonicalize(Address result_addr, + Address x_addr, Address y_addr) { + BigInt x = BigInt::cast(Object(x_addr)); + BigInt y = BigInt::cast(Object(y_addr)); + MutableBigInt result = MutableBigInt::cast(Object(result_addr)); + + MutableBigInt::AbsoluteAdd(result, x, y); + MutableBigInt::Canonicalize(result); +} + +int32_t MutableBigInt_AbsoluteCompare(Address x_addr, Address y_addr) { + BigInt x = BigInt::cast(Object(x_addr)); + BigInt y = BigInt::cast(Object(y_addr)); + + return MutableBigInt::AbsoluteCompare(x, y); +} + +void MutableBigInt_AbsoluteSubAndCanonicalize(Address result_addr, + Address x_addr, Address y_addr) { + BigInt x = BigInt::cast(Object(x_addr)); + BigInt y = BigInt::cast(Object(y_addr)); + MutableBigInt result = MutableBigInt::cast(Object(result_addr)); + + MutableBigInt::AbsoluteSub(result, x, y); + MutableBigInt::Canonicalize(result); +} + } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/objects/bigint.h b/chromium/v8/src/objects/bigint.h index 3f5d35878bc..a5ca5148679 100644 --- a/chromium/v8/src/objects/bigint.h +++ b/chromium/v8/src/objects/bigint.h @@ -16,6 +16,12 @@ namespace v8 { namespace internal { +void MutableBigInt_AbsoluteAddAndCanonicalize(Address result_addr, + Address x_addr, Address y_addr); +int32_t MutableBigInt_AbsoluteCompare(Address x_addr, Address y_addr); +void MutableBigInt_AbsoluteSubAndCanonicalize(Address result_addr, + Address x_addr, Address y_addr); + class BigInt; class ValueDeserializer; class ValueSerializer; @@ -66,6 +72,10 @@ class BigIntBase : public HeapObject { DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, BIGINT_FIELDS) #undef BIGINT_FIELDS + static constexpr bool HasOptionalPadding() { + return FIELD_SIZE(kOptionalPaddingOffset) > 0; + } + private: friend class ::v8::internal::BigInt; // MSVC wants full namespace. friend class MutableBigInt; diff --git a/chromium/v8/src/objects/code-inl.h b/chromium/v8/src/objects/code-inl.h index 0877746d110..e6f00b0fb2b 100644 --- a/chromium/v8/src/objects/code-inl.h +++ b/chromium/v8/src/objects/code-inl.h @@ -7,8 +7,8 @@ #include "src/objects/code.h" +#include "src/base/memory.h" #include "src/codegen/code-desc.h" -#include "src/common/v8memory.h" #include "src/execution/isolate.h" #include "src/interpreter/bytecode-register.h" #include "src/objects/dictionary.h" @@ -29,7 +29,7 @@ OBJECT_CONSTRUCTORS_IMPL(BytecodeArray, FixedArrayBase) OBJECT_CONSTRUCTORS_IMPL(AbstractCode, HeapObject) OBJECT_CONSTRUCTORS_IMPL(DependentCode, WeakFixedArray) OBJECT_CONSTRUCTORS_IMPL(CodeDataContainer, HeapObject) -OBJECT_CONSTRUCTORS_IMPL(SourcePositionTableWithFrameCache, Struct) +TQ_OBJECT_CONSTRUCTORS_IMPL(SourcePositionTableWithFrameCache) NEVER_READ_ONLY_SPACE_IMPL(AbstractCode) @@ -39,12 +39,6 @@ CAST_ACCESSOR(Code) CAST_ACCESSOR(CodeDataContainer) CAST_ACCESSOR(DependentCode) CAST_ACCESSOR(DeoptimizationData) -CAST_ACCESSOR(SourcePositionTableWithFrameCache) - -ACCESSORS(SourcePositionTableWithFrameCache, source_position_table, ByteArray, - kSourcePositionTableOffset) -ACCESSORS(SourcePositionTableWithFrameCache, stack_frame_cache, - SimpleNumberDictionary, kStackFrameCacheOffset) int AbstractCode::raw_instruction_size() { if (IsCode()) { @@ -331,7 +325,9 @@ int Code::SizeIncludingMetadata() const { } ByteArray Code::unchecked_relocation_info() const { - return ByteArray::unchecked_cast(READ_FIELD(*this, kRelocationInfoOffset)); + Isolate* isolate = GetIsolateForPtrCompr(*this); + return ByteArray::unchecked_cast( + TaggedField<HeapObject, kRelocationInfoOffset>::load(isolate, *this)); } byte* Code::relocation_start() const { @@ -575,7 +571,7 @@ Code Code::GetCodeFromTargetAddress(Address address) { } Code Code::GetObjectFromEntryAddress(Address location_of_address) { - Address code_entry = Memory<Address>(location_of_address); + Address code_entry = base::Memory<Address>(location_of_address); HeapObject code = HeapObject::FromAddress(code_entry - Code::kHeaderSize); // Unchecked cast because we can't rely on the map currently // not being a forwarding pointer. @@ -622,32 +618,32 @@ void BytecodeArray::set(int index, byte value) { WriteField<byte>(kHeaderSize + index * kCharSize, value); } -void BytecodeArray::set_frame_size(int frame_size) { +void BytecodeArray::set_frame_size(int32_t frame_size) { DCHECK_GE(frame_size, 0); DCHECK(IsAligned(frame_size, kSystemPointerSize)); - WriteField<int>(kFrameSizeOffset, frame_size); + WriteField<int32_t>(kFrameSizeOffset, frame_size); } -int BytecodeArray::frame_size() const { - return ReadField<int>(kFrameSizeOffset); +int32_t BytecodeArray::frame_size() const { + return ReadField<int32_t>(kFrameSizeOffset); } int BytecodeArray::register_count() const { - return frame_size() / kSystemPointerSize; + return static_cast<int>(frame_size()) / kSystemPointerSize; } -void BytecodeArray::set_parameter_count(int number_of_parameters) { +void BytecodeArray::set_parameter_count(int32_t number_of_parameters) { DCHECK_GE(number_of_parameters, 0); // Parameter count is stored as the size on stack of the parameters to allow // it to be used directly by generated code. - WriteField<int>(kParameterSizeOffset, + WriteField<int32_t>(kParameterSizeOffset, (number_of_parameters << kSystemPointerSizeLog2)); } interpreter::Register BytecodeArray::incoming_new_target_or_generator_register() const { - int register_operand = - ReadField<int>(kIncomingNewTargetOrGeneratorRegisterOffset); + int32_t register_operand = + ReadField<int32_t>(kIncomingNewTargetOrGeneratorRegisterOffset); if (register_operand == 0) { return interpreter::Register::invalid_value(); } else { @@ -658,24 +654,24 @@ interpreter::Register BytecodeArray::incoming_new_target_or_generator_register() void BytecodeArray::set_incoming_new_target_or_generator_register( interpreter::Register incoming_new_target_or_generator_register) { if (!incoming_new_target_or_generator_register.is_valid()) { - WriteField<int>(kIncomingNewTargetOrGeneratorRegisterOffset, 0); + WriteField<int32_t>(kIncomingNewTargetOrGeneratorRegisterOffset, 0); } else { DCHECK(incoming_new_target_or_generator_register.index() < register_count()); DCHECK_NE(0, incoming_new_target_or_generator_register.ToOperand()); - WriteField<int>(kIncomingNewTargetOrGeneratorRegisterOffset, + WriteField<int32_t>(kIncomingNewTargetOrGeneratorRegisterOffset, incoming_new_target_or_generator_register.ToOperand()); } } int BytecodeArray::osr_loop_nesting_level() const { - return ReadField<int8_t>(kOSRNestingLevelOffset); + return ReadField<int8_t>(kOsrNestingLevelOffset); } void BytecodeArray::set_osr_loop_nesting_level(int depth) { DCHECK(0 <= depth && depth <= AbstractCode::kMaxLoopNestingMarker); STATIC_ASSERT(AbstractCode::kMaxLoopNestingMarker < kMaxInt8); - WriteField<int8_t>(kOSRNestingLevelOffset, depth); + WriteField<int8_t>(kOsrNestingLevelOffset, depth); } BytecodeArray::Age BytecodeArray::bytecode_age() const { @@ -691,10 +687,10 @@ void BytecodeArray::set_bytecode_age(BytecodeArray::Age age) { RELAXED_WRITE_INT8_FIELD(*this, kBytecodeAgeOffset, static_cast<int8_t>(age)); } -int BytecodeArray::parameter_count() const { +int32_t BytecodeArray::parameter_count() const { // Parameter count is stored as the size on stack of the parameters to allow // it to be used directly by generated code. - return ReadField<int>(kParameterSizeOffset) >> kSystemPointerSizeLog2; + return ReadField<int32_t>(kParameterSizeOffset) >> kSystemPointerSizeLog2; } ACCESSORS(BytecodeArray, constant_pool, FixedArray, kConstantPoolOffset) @@ -745,7 +741,9 @@ ByteArray BytecodeArray::SourcePositionTableIfCollected() const { void BytecodeArray::ClearFrameCacheFromSourcePositionTable() { Object maybe_table = source_position_table(); - if (maybe_table.IsUndefined() || maybe_table.IsByteArray()) return; + if (maybe_table.IsUndefined() || maybe_table.IsByteArray() || + maybe_table.IsException()) + return; DCHECK(maybe_table.IsSourcePositionTableWithFrameCache()); set_source_position_table(SourcePositionTableWithFrameCache::cast(maybe_table) .source_position_table()); diff --git a/chromium/v8/src/objects/code.cc b/chromium/v8/src/objects/code.cc index 89180693a52..a51a8c5b79d 100644 --- a/chromium/v8/src/objects/code.cc +++ b/chromium/v8/src/objects/code.cc @@ -352,7 +352,8 @@ bool Code::Inlines(SharedFunctionInfo sfi) { Code::OptimizedCodeIterator::OptimizedCodeIterator(Isolate* isolate) { isolate_ = isolate; Object list = isolate->heap()->native_contexts_list(); - next_context_ = list.IsUndefined(isolate_) ? Context() : Context::cast(list); + next_context_ = + list.IsUndefined(isolate_) ? NativeContext() : NativeContext::cast(list); } Code Code::OptimizedCodeIterator::Next() { @@ -366,8 +367,8 @@ Code Code::OptimizedCodeIterator::Next() { next = next_context_.OptimizedCodeListHead(); Object next_context = next_context_.next_context_link(); next_context_ = next_context.IsUndefined(isolate_) - ? Context() - : Context::cast(next_context); + ? NativeContext() + : NativeContext::cast(next_context); } else { // Exhausted contexts. return Code(); @@ -830,7 +831,8 @@ void BytecodeArray::Disassemble(std::ostream& os) { os << reinterpret_cast<const void*>(current_address) << " @ " << std::setw(4) << iterator.current_offset() << " : "; interpreter::BytecodeDecoder::Decode( - os, reinterpret_cast<byte*>(current_address), parameter_count()); + os, reinterpret_cast<byte*>(current_address), + static_cast<int>(parameter_count())); if (interpreter::Bytecodes::IsJump(iterator.current_bytecode())) { Address jump_target = base_address + iterator.GetJumpTargetOffset(); os << " (" << reinterpret_cast<void*>(jump_target) << " @ " @@ -856,7 +858,7 @@ void BytecodeArray::Disassemble(std::ostream& os) { os << "Constant pool (size = " << constant_pool().length() << ")\n"; #ifdef OBJECT_PRINT if (constant_pool().length() > 0) { - constant_pool().Print(); + constant_pool().Print(os); } #endif @@ -1084,5 +1086,15 @@ const char* DependentCode::DependencyGroupName(DependencyGroup group) { UNREACHABLE(); } +bool BytecodeArray::IsBytecodeEqual(const BytecodeArray other) const { + if (length() != other.length()) return false; + + for (int i = 0; i < length(); ++i) { + if (get(i) != other.get(i)) return false; + } + + return true; +} + } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/objects/code.h b/chromium/v8/src/objects/code.h index a9502611035..2f85d4ac7b3 100644 --- a/chromium/v8/src/objects/code.h +++ b/chromium/v8/src/objects/code.h @@ -476,7 +476,7 @@ class Code::OptimizedCodeIterator { Code Next(); private: - Context next_context_; + NativeContext next_context_; Code current_code_; Isolate* isolate_; @@ -741,15 +741,15 @@ class BytecodeArray : public FixedArrayBase { inline Address GetFirstBytecodeAddress(); // Accessors for frame size. - inline int frame_size() const; - inline void set_frame_size(int frame_size); + inline int32_t frame_size() const; + inline void set_frame_size(int32_t frame_size); // Accessor for register count (derived from frame_size). inline int register_count() const; // Accessors for parameter count (including implicit 'this' receiver). - inline int parameter_count() const; - inline void set_parameter_count(int number_of_parameters); + inline int32_t parameter_count() const; + inline void set_parameter_count(int32_t number_of_parameters); // Register used to pass the incoming new.target or generator object from the // fucntion call. @@ -828,28 +828,15 @@ class BytecodeArray : public FixedArrayBase { // Compares only the bytecode array but not any of the header fields. bool IsBytecodeEqual(const BytecodeArray other) const; -// Layout description. -#define BYTECODE_ARRAY_FIELDS(V) \ - /* Pointer fields. */ \ - V(kConstantPoolOffset, kTaggedSize) \ - V(kHandlerTableOffset, kTaggedSize) \ - V(kSourcePositionTableOffset, kTaggedSize) \ - V(kFrameSizeOffset, kIntSize) \ - V(kParameterSizeOffset, kIntSize) \ - V(kIncomingNewTargetOrGeneratorRegisterOffset, kIntSize) \ - V(kOSRNestingLevelOffset, kCharSize) \ - V(kBytecodeAgeOffset, kCharSize) \ - /* Total size. */ \ - V(kHeaderSize, 0) - + // Layout description. DEFINE_FIELD_OFFSET_CONSTANTS(FixedArrayBase::kHeaderSize, - BYTECODE_ARRAY_FIELDS) -#undef BYTECODE_ARRAY_FIELDS + TORQUE_GENERATED_BYTECODE_ARRAY_FIELDS) + static constexpr int kHeaderSize = kSize; // InterpreterEntryTrampoline expects these fields to be next to each other // and writes a 16-bit value to reset them. STATIC_ASSERT(BytecodeArray::kBytecodeAgeOffset == - kOSRNestingLevelOffset + kCharSize); + kOsrNestingLevelOffset + kCharSize); // Maximal memory consumption for a single BytecodeArray. static const int kMaxSize = 512 * MB; @@ -948,22 +935,11 @@ class DeoptimizationData : public FixedArray { OBJECT_CONSTRUCTORS(DeoptimizationData, FixedArray); }; -class SourcePositionTableWithFrameCache : public Struct { +class SourcePositionTableWithFrameCache + : public TorqueGeneratedSourcePositionTableWithFrameCache< + SourcePositionTableWithFrameCache, Struct> { public: - DECL_ACCESSORS(source_position_table, ByteArray) - DECL_ACCESSORS(stack_frame_cache, SimpleNumberDictionary) - - DECL_CAST(SourcePositionTableWithFrameCache) - - DECL_PRINTER(SourcePositionTableWithFrameCache) - DECL_VERIFIER(SourcePositionTableWithFrameCache) - - // Layout description. - DEFINE_FIELD_OFFSET_CONSTANTS( - Struct::kHeaderSize, - TORQUE_GENERATED_SOURCE_POSITION_TABLE_WITH_FRAME_CACHE_FIELDS) - - OBJECT_CONSTRUCTORS(SourcePositionTableWithFrameCache, Struct); + TQ_OBJECT_CONSTRUCTORS(SourcePositionTableWithFrameCache) }; } // namespace internal diff --git a/chromium/v8/src/objects/compressed-slots-inl.h b/chromium/v8/src/objects/compressed-slots-inl.h index b08bc938e5d..a93814fee24 100644 --- a/chromium/v8/src/objects/compressed-slots-inl.h +++ b/chromium/v8/src/objects/compressed-slots-inl.h @@ -22,6 +22,12 @@ namespace internal { CompressedObjectSlot::CompressedObjectSlot(Object* object) : SlotBase(reinterpret_cast<Address>(&object->ptr_)) {} +bool CompressedObjectSlot::contains_value(Address raw_value) const { + AtomicTagged_t value = AsAtomicTagged::Relaxed_Load(location()); + return static_cast<uint32_t>(value) == + static_cast<uint32_t>(static_cast<Tagged_t>(raw_value)); +} + Object CompressedObjectSlot::operator*() const { Tagged_t value = *location(); return Object(DecompressTaggedAny(address(), value)); @@ -61,54 +67,6 @@ Object CompressedObjectSlot::Release_CompareAndSwap(Object old, } // -// CompressedMapWordSlot implementation. -// - -bool CompressedMapWordSlot::contains_value(Address raw_value) const { - AtomicTagged_t value = AsAtomicTagged::Relaxed_Load(location()); - return static_cast<uint32_t>(value) == - static_cast<uint32_t>(static_cast<Tagged_t>(raw_value)); -} - -Object CompressedMapWordSlot::operator*() const { - Tagged_t value = *location(); - return Object(DecompressTaggedPointer(address(), value)); -} - -void CompressedMapWordSlot::store(Object value) const { - *location() = CompressTagged(value.ptr()); -} - -Object CompressedMapWordSlot::Relaxed_Load() const { - AtomicTagged_t value = AsAtomicTagged::Relaxed_Load(location()); - return Object(DecompressTaggedPointer(address(), value)); -} - -void CompressedMapWordSlot::Relaxed_Store(Object value) const { - Tagged_t ptr = CompressTagged(value.ptr()); - AsAtomicTagged::Relaxed_Store(location(), ptr); -} - -Object CompressedMapWordSlot::Acquire_Load() const { - AtomicTagged_t value = AsAtomicTagged::Acquire_Load(location()); - return Object(DecompressTaggedPointer(address(), value)); -} - -void CompressedMapWordSlot::Release_Store(Object value) const { - Tagged_t ptr = CompressTagged(value.ptr()); - AsAtomicTagged::Release_Store(location(), ptr); -} - -Object CompressedMapWordSlot::Release_CompareAndSwap(Object old, - Object target) const { - Tagged_t old_ptr = CompressTagged(old.ptr()); - Tagged_t target_ptr = CompressTagged(target.ptr()); - Tagged_t result = - AsAtomicTagged::Release_CompareAndSwap(location(), old_ptr, target_ptr); - return Object(DecompressTaggedPointer(address(), result)); -} - -// // CompressedMaybeObjectSlot implementation. // diff --git a/chromium/v8/src/objects/compressed-slots.h b/chromium/v8/src/objects/compressed-slots.h index 45df733caf7..07660b19612 100644 --- a/chromium/v8/src/objects/compressed-slots.h +++ b/chromium/v8/src/objects/compressed-slots.h @@ -34,32 +34,6 @@ class CompressedObjectSlot : public SlotBase<CompressedObjectSlot, Tagged_t> { explicit CompressedObjectSlot(SlotBase<T, TData, kSlotDataAlignment> slot) : SlotBase(slot.address()) {} - inline Object operator*() const; - inline void store(Object value) const; - - inline Object Acquire_Load() const; - inline Object Relaxed_Load() const; - inline void Relaxed_Store(Object value) const; - inline void Release_Store(Object value) const; - inline Object Release_CompareAndSwap(Object old, Object target) const; -}; - -// A CompressedMapWordSlot instance describes a kTaggedSize-sized map-word field -// ("slot") of heap objects holding a compressed tagged pointer or a Smi -// representing forwaring pointer value. -// This slot kind is similar to CompressedObjectSlot but decompression of -// forwarding pointer is different. -// Its address() is the address of the slot. -// The slot's contents can be read and written using operator* and store(). -class CompressedMapWordSlot : public SlotBase<CompressedMapWordSlot, Tagged_t> { - public: - using TObject = Object; - - static constexpr bool kCanBeWeak = false; - - CompressedMapWordSlot() : SlotBase(kNullAddress) {} - explicit CompressedMapWordSlot(Address ptr) : SlotBase(ptr) {} - // Compares memory representation of a value stored in the slot with given // raw value without decompression. inline bool contains_value(Address raw_value) const; @@ -67,10 +41,9 @@ class CompressedMapWordSlot : public SlotBase<CompressedMapWordSlot, Tagged_t> { inline Object operator*() const; inline void store(Object value) const; + inline Object Acquire_Load() const; inline Object Relaxed_Load() const; inline void Relaxed_Store(Object value) const; - - inline Object Acquire_Load() const; inline void Release_Store(Object value) const; inline Object Release_CompareAndSwap(Object old, Object target) const; }; diff --git a/chromium/v8/src/objects/contexts-inl.h b/chromium/v8/src/objects/contexts-inl.h index bb861a1d1e2..0c566dd081a 100644 --- a/chromium/v8/src/objects/contexts-inl.h +++ b/chromium/v8/src/objects/contexts-inl.h @@ -52,9 +52,15 @@ SMI_ACCESSORS(Context, length, kLengthOffset) CAST_ACCESSOR(NativeContext) Object Context::get(int index) const { + Isolate* isolate = GetIsolateForPtrCompr(*this); + return get(isolate, index); +} + +Object Context::get(Isolate* isolate, int index) const { DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(this->length())); - return RELAXED_READ_FIELD(*this, OffsetOfElementAt(index)); + return TaggedField<Object>::Relaxed_Load(isolate, *this, + OffsetOfElementAt(index)); } void Context::set(int index, Object value) { diff --git a/chromium/v8/src/objects/contexts.cc b/chromium/v8/src/objects/contexts.cc index cddbcb98c09..861e06d87f1 100644 --- a/chromium/v8/src/objects/contexts.cc +++ b/chromium/v8/src/objects/contexts.cc @@ -44,7 +44,7 @@ bool ScriptContextTable::Lookup(Isolate* isolate, ScriptContextTable table, DCHECK(context.IsScriptContext()); int slot_index = ScopeInfo::ContextSlotIndex( context.scope_info(), name, &result->mode, &result->init_flag, - &result->maybe_assigned_flag); + &result->maybe_assigned_flag, &result->requires_brand_check); if (slot_index >= 0) { result->context_index = i; @@ -105,12 +105,12 @@ ScopeInfo Context::scope_info() { return ScopeInfo::cast(get(SCOPE_INFO_INDEX)); } -Module Context::module() { +SourceTextModule Context::module() { Context current = *this; while (!current.IsModuleContext()) { current = current.previous(); } - return Module::cast(current.extension()); + return SourceTextModule::cast(current.extension()); } JSGlobalObject Context::global_object() { @@ -287,8 +287,10 @@ Handle<Object> Context::Lookup(Handle<Context> context, Handle<String> name, VariableMode mode; InitializationFlag flag; MaybeAssignedFlag maybe_assigned_flag; + RequiresBrandCheckFlag requires_brand_check; int slot_index = ScopeInfo::ContextSlotIndex(scope_info, *name, &mode, - &flag, &maybe_assigned_flag); + &flag, &maybe_assigned_flag, + &requires_brand_check); DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS); if (slot_index >= 0) { if (FLAG_trace_contexts) { @@ -338,8 +340,8 @@ Handle<Object> Context::Lookup(Handle<Context> context, Handle<String> name, *index = cell_index; *variable_mode = mode; *init_flag = flag; - *attributes = ModuleDescriptor::GetCellIndexKind(cell_index) == - ModuleDescriptor::kExport + *attributes = SourceTextModuleDescriptor::GetCellIndexKind( + cell_index) == SourceTextModuleDescriptor::kExport ? GetAttributesForMode(mode) : READ_ONLY; return handle(context->module(), isolate); @@ -394,31 +396,26 @@ Handle<Object> Context::Lookup(Handle<Context> context, Handle<String> name, return Handle<Object>::null(); } -void Context::AddOptimizedCode(Code code) { - DCHECK(IsNativeContext()); +void NativeContext::AddOptimizedCode(Code code) { DCHECK(code.kind() == Code::OPTIMIZED_FUNCTION); DCHECK(code.next_code_link().IsUndefined()); code.set_next_code_link(get(OPTIMIZED_CODE_LIST)); set(OPTIMIZED_CODE_LIST, code, UPDATE_WEAK_WRITE_BARRIER); } -void Context::SetOptimizedCodeListHead(Object head) { - DCHECK(IsNativeContext()); +void NativeContext::SetOptimizedCodeListHead(Object head) { set(OPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER); } -Object Context::OptimizedCodeListHead() { - DCHECK(IsNativeContext()); +Object NativeContext::OptimizedCodeListHead() { return get(OPTIMIZED_CODE_LIST); } -void Context::SetDeoptimizedCodeListHead(Object head) { - DCHECK(IsNativeContext()); +void NativeContext::SetDeoptimizedCodeListHead(Object head) { set(DEOPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER); } -Object Context::DeoptimizedCodeListHead() { - DCHECK(IsNativeContext()); +Object NativeContext::DeoptimizedCodeListHead() { return get(DEOPTIMIZED_CODE_LIST); } @@ -474,19 +471,14 @@ bool Context::IsBootstrappingOrValidParentContext(Object object, #endif -void Context::ResetErrorsThrown() { - DCHECK(IsNativeContext()); - set_errors_thrown(Smi::FromInt(0)); -} - -void Context::IncrementErrorsThrown() { - DCHECK(IsNativeContext()); +void NativeContext::ResetErrorsThrown() { set_errors_thrown(Smi::FromInt(0)); } +void NativeContext::IncrementErrorsThrown() { int previous_value = errors_thrown().value(); set_errors_thrown(Smi::FromInt(previous_value + 1)); } -int Context::GetErrorsThrown() { return errors_thrown().value(); } +int NativeContext::GetErrorsThrown() { return errors_thrown().value(); } STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); STATIC_ASSERT(NativeContext::kScopeInfoOffset == diff --git a/chromium/v8/src/objects/contexts.h b/chromium/v8/src/objects/contexts.h index d83e3515508..0c00aba08e4 100644 --- a/chromium/v8/src/objects/contexts.h +++ b/chromium/v8/src/objects/contexts.h @@ -38,9 +38,6 @@ enum ContextLookupFlags { // Factory::NewContext. #define NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(V) \ - V(ASYNC_FUNCTION_PROMISE_CREATE_INDEX, JSFunction, \ - async_function_promise_create) \ - V(IS_ARRAYLIKE, JSFunction, is_arraylike) \ V(GENERATOR_NEXT_INTERNAL, JSFunction, generator_next_internal) \ V(MAKE_ERROR_INDEX, JSFunction, make_error) \ V(MAKE_RANGE_ERROR_INDEX, JSFunction, make_range_error) \ @@ -48,20 +45,10 @@ enum ContextLookupFlags { V(MAKE_TYPE_ERROR_INDEX, JSFunction, make_type_error) \ V(MAKE_URI_ERROR_INDEX, JSFunction, make_uri_error) \ V(OBJECT_CREATE, JSFunction, object_create) \ - V(OBJECT_DEFINE_PROPERTIES, JSFunction, object_define_properties) \ - V(OBJECT_DEFINE_PROPERTY, JSFunction, object_define_property) \ - V(OBJECT_GET_PROTOTYPE_OF, JSFunction, object_get_prototype_of) \ - V(OBJECT_IS_EXTENSIBLE, JSFunction, object_is_extensible) \ - V(OBJECT_IS_FROZEN, JSFunction, object_is_frozen) \ - V(OBJECT_IS_SEALED, JSFunction, object_is_sealed) \ - V(OBJECT_KEYS, JSFunction, object_keys) \ V(REFLECT_APPLY_INDEX, JSFunction, reflect_apply) \ V(REFLECT_CONSTRUCT_INDEX, JSFunction, reflect_construct) \ - V(REFLECT_DEFINE_PROPERTY_INDEX, JSFunction, reflect_define_property) \ - V(REFLECT_DELETE_PROPERTY_INDEX, JSFunction, reflect_delete_property) \ V(MATH_FLOOR_INDEX, JSFunction, math_floor) \ V(MATH_POW_INDEX, JSFunction, math_pow) \ - V(NEW_PROMISE_CAPABILITY_INDEX, JSFunction, new_promise_capability) \ V(PROMISE_INTERNAL_CONSTRUCTOR_INDEX, JSFunction, \ promise_internal_constructor) \ V(IS_PROMISE_INDEX, JSFunction, is_promise) \ @@ -193,8 +180,10 @@ enum ContextLookupFlags { V(JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_MAP_INDEX, Map, \ js_finalization_group_cleanup_iterator_map) \ V(JS_WEAK_MAP_FUN_INDEX, JSFunction, js_weak_map_fun) \ - V(JS_WEAK_REF_MAP_INDEX, Map, js_weak_ref_map) \ V(JS_WEAK_SET_FUN_INDEX, JSFunction, js_weak_set_fun) \ + V(JS_WEAK_REF_FUNCTION_INDEX, JSFunction, js_weak_ref_fun) \ + V(JS_FINALIZATION_GROUP_FUNCTION_INDEX, JSFunction, \ + js_finalization_group_fun) \ V(MAP_CACHE_INDEX, Object, map_cache) \ V(MAP_KEY_ITERATOR_MAP_INDEX, Map, map_key_iterator_map) \ V(MAP_KEY_VALUE_ITERATOR_MAP_INDEX, Map, map_key_value_iterator_map) \ @@ -238,12 +227,14 @@ enum ContextLookupFlags { V(REGEXP_EXEC_FUNCTION_INDEX, JSFunction, regexp_exec_function) \ V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \ V(REGEXP_LAST_MATCH_INFO_INDEX, RegExpMatchInfo, regexp_last_match_info) \ + V(REGEXP_PROTOTYPE_INDEX, JSObject, regexp_prototype) \ V(REGEXP_PROTOTYPE_MAP_INDEX, Map, regexp_prototype_map) \ + V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map) \ + V(REGEXP_SPECIES_PROTECTOR_INDEX, PropertyCell, regexp_species_protector) \ V(INITIAL_REGEXP_STRING_ITERATOR_PROTOTYPE_MAP_INDEX, Map, \ initial_regexp_string_iterator_prototype_map) \ - V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map) \ - V(REGEXP_PROTOTYPE_INDEX, JSObject, regexp_prototype) \ V(SCRIPT_CONTEXT_TABLE_INDEX, ScriptContextTable, script_context_table) \ + V(SCRIPT_EXECUTION_CALLBACK_INDEX, Object, script_execution_callback) \ V(SECURITY_TOKEN_INDEX, Object, security_token) \ V(SERIALIZED_OBJECTS, FixedArray, serialized_objects) \ V(SET_VALUE_ITERATOR_MAP_INDEX, Map, set_value_iterator_map) \ @@ -302,7 +293,6 @@ enum ContextLookupFlags { V(SYMBOL_FUNCTION_INDEX, JSFunction, symbol_function) \ V(WASM_EXPORTED_FUNCTION_MAP_INDEX, Map, wasm_exported_function_map) \ V(WASM_EXCEPTION_CONSTRUCTOR_INDEX, JSFunction, wasm_exception_constructor) \ - V(WASM_FUNCTION_CONSTRUCTOR_INDEX, JSFunction, wasm_function_constructor) \ V(WASM_GLOBAL_CONSTRUCTOR_INDEX, JSFunction, wasm_global_constructor) \ V(WASM_INSTANCE_CONSTRUCTOR_INDEX, JSFunction, wasm_instance_constructor) \ V(WASM_MEMORY_CONSTRUCTOR_INDEX, JSFunction, wasm_memory_constructor) \ @@ -366,6 +356,7 @@ class ScriptContextTable : public FixedArray { VariableMode mode; InitializationFlag init_flag; MaybeAssignedFlag maybe_assigned_flag; + RequiresBrandCheckFlag requires_brand_check; }; inline int used() const; @@ -453,6 +444,7 @@ class Context : public HeapObject { // Setter and getter for elements. V8_INLINE Object get(int index) const; + V8_INLINE Object get(Isolate* isolate, int index) const; V8_INLINE void set(int index, Object value); // Setter with explicit barrier mode. V8_INLINE void set(int index, Object value, WriteBarrierMode mode); @@ -531,10 +523,6 @@ class Context : public HeapObject { static const int kNoContext = 0; static const int kInvalidContext = 1; - void ResetErrorsThrown(); - void IncrementErrorsThrown(); - int GetErrorsThrown(); - // Direct slot access. inline void set_scope_info(ScopeInfo scope_info); @@ -553,7 +541,7 @@ class Context : public HeapObject { // Find the module context (assuming there is one) and return the associated // module object. - Module module(); + SourceTextModule module(); // Get the context where var declarations will be hoisted to, which // may be the context itself. @@ -591,14 +579,6 @@ class Context : public HeapObject { inline bool HasSameSecurityTokenAs(Context that) const; - // The native context also stores a list of all optimized code and a - // list of all deoptimized code, which are needed by the deoptimizer. - V8_EXPORT_PRIVATE void AddOptimizedCode(Code code); - void SetOptimizedCodeListHead(Object head); - Object OptimizedCodeListHead(); - void SetDeoptimizedCodeListHead(Object head); - Object DeoptimizedCodeListHead(); - Handle<Object> ErrorMessageForCodeGenerationFromStrings(); static int IntrinsicIndexForName(Handle<String> name); @@ -703,6 +683,18 @@ class NativeContext : public Context { class BodyDescriptor; + // The native context stores a list of all optimized code and a list of all + // deoptimized code, which are needed by the deoptimizer. + V8_EXPORT_PRIVATE void AddOptimizedCode(Code code); + void SetOptimizedCodeListHead(Object head); + Object OptimizedCodeListHead(); + void SetDeoptimizedCodeListHead(Object head); + Object DeoptimizedCodeListHead(); + + void ResetErrorsThrown(); + void IncrementErrorsThrown(); + int GetErrorsThrown(); + private: STATIC_ASSERT(OffsetOfElementAt(EMBEDDER_DATA_INDEX) == Internals::kNativeContextEmbedderDataOffset); diff --git a/chromium/v8/src/objects/descriptor-array-inl.h b/chromium/v8/src/objects/descriptor-array-inl.h index 1cd64c1bf1d..e2805d795a0 100644 --- a/chromium/v8/src/objects/descriptor-array-inl.h +++ b/chromium/v8/src/objects/descriptor-array-inl.h @@ -25,13 +25,9 @@ namespace v8 { namespace internal { OBJECT_CONSTRUCTORS_IMPL(DescriptorArray, HeapObject) -OBJECT_CONSTRUCTORS_IMPL(EnumCache, Struct) +TQ_OBJECT_CONSTRUCTORS_IMPL(EnumCache) CAST_ACCESSOR(DescriptorArray) -CAST_ACCESSOR(EnumCache) - -ACCESSORS(EnumCache, keys, FixedArray, kKeysOffset) -ACCESSORS(EnumCache, indices, FixedArray, kIndicesOffset) ACCESSORS(DescriptorArray, enum_cache, EnumCache, kEnumCacheOffset) RELAXED_INT16_ACCESSORS(DescriptorArray, number_of_all_descriptors, @@ -106,17 +102,22 @@ ObjectSlot DescriptorArray::GetDescriptorSlot(int descriptor) { return RawField(OffsetOfDescriptorAt(descriptor)); } -ObjectSlot DescriptorArray::GetKeySlot(int descriptor) { - DCHECK_LE(descriptor, number_of_all_descriptors()); - ObjectSlot slot = GetDescriptorSlot(descriptor) + kEntryKeyIndex; - DCHECK((*slot).IsObject()); - return slot; +Name DescriptorArray::GetKey(int descriptor_number) const { + Isolate* isolate = GetIsolateForPtrCompr(*this); + return GetKey(isolate, descriptor_number); } -Name DescriptorArray::GetKey(int descriptor_number) const { - DCHECK(descriptor_number < number_of_descriptors()); - return Name::cast( - get(ToKeyIndex(descriptor_number))->GetHeapObjectAssumeStrong()); +Name DescriptorArray::GetKey(Isolate* isolate, int descriptor_number) const { + DCHECK_LT(descriptor_number, number_of_descriptors()); + int entry_offset = OffsetOfDescriptorAt(descriptor_number); + return Name::cast(EntryKeyField::Relaxed_Load(isolate, *this, entry_offset)); +} + +void DescriptorArray::SetKey(int descriptor_number, Name key) { + DCHECK_LT(descriptor_number, number_of_descriptors()); + int entry_offset = OffsetOfDescriptorAt(descriptor_number); + EntryKeyField::Relaxed_Store(*this, entry_offset, key); + WRITE_BARRIER(*this, entry_offset + kEntryKeyOffset, key); } int DescriptorArray::GetSortedKeyIndex(int descriptor_number) { @@ -124,38 +125,59 @@ int DescriptorArray::GetSortedKeyIndex(int descriptor_number) { } Name DescriptorArray::GetSortedKey(int descriptor_number) { - return GetKey(GetSortedKeyIndex(descriptor_number)); + Isolate* isolate = GetIsolateForPtrCompr(*this); + return GetSortedKey(isolate, descriptor_number); } -void DescriptorArray::SetSortedKey(int descriptor_index, int pointer) { - PropertyDetails details = GetDetails(descriptor_index); - set(ToDetailsIndex(descriptor_index), - MaybeObject::FromObject(details.set_pointer(pointer).AsSmi())); +Name DescriptorArray::GetSortedKey(Isolate* isolate, int descriptor_number) { + return GetKey(isolate, GetSortedKeyIndex(descriptor_number)); } -MaybeObjectSlot DescriptorArray::GetValueSlot(int descriptor) { - DCHECK_LT(descriptor, number_of_descriptors()); - return MaybeObjectSlot(GetDescriptorSlot(descriptor) + kEntryValueIndex); +void DescriptorArray::SetSortedKey(int descriptor_number, int pointer) { + PropertyDetails details = GetDetails(descriptor_number); + SetDetails(descriptor_number, details.set_pointer(pointer)); } Object DescriptorArray::GetStrongValue(int descriptor_number) { - DCHECK(descriptor_number < number_of_descriptors()); - return get(ToValueIndex(descriptor_number))->cast<Object>(); + Isolate* isolate = GetIsolateForPtrCompr(*this); + return GetStrongValue(isolate, descriptor_number); +} + +Object DescriptorArray::GetStrongValue(Isolate* isolate, + int descriptor_number) { + return GetValue(isolate, descriptor_number).cast<Object>(); } -void DescriptorArray::SetValue(int descriptor_index, Object value) { - set(ToValueIndex(descriptor_index), MaybeObject::FromObject(value)); +void DescriptorArray::SetValue(int descriptor_number, MaybeObject value) { + DCHECK_LT(descriptor_number, number_of_descriptors()); + int entry_offset = OffsetOfDescriptorAt(descriptor_number); + EntryValueField::Relaxed_Store(*this, entry_offset, value); + WEAK_WRITE_BARRIER(*this, entry_offset + kEntryValueOffset, value); } MaybeObject DescriptorArray::GetValue(int descriptor_number) { + Isolate* isolate = GetIsolateForPtrCompr(*this); + return GetValue(isolate, descriptor_number); +} + +MaybeObject DescriptorArray::GetValue(Isolate* isolate, int descriptor_number) { DCHECK_LT(descriptor_number, number_of_descriptors()); - return get(ToValueIndex(descriptor_number)); + int entry_offset = OffsetOfDescriptorAt(descriptor_number); + return EntryValueField::Relaxed_Load(isolate, *this, entry_offset); } PropertyDetails DescriptorArray::GetDetails(int descriptor_number) { - DCHECK(descriptor_number < number_of_descriptors()); - MaybeObject details = get(ToDetailsIndex(descriptor_number)); - return PropertyDetails(details->ToSmi()); + DCHECK_LT(descriptor_number, number_of_descriptors()); + int entry_offset = OffsetOfDescriptorAt(descriptor_number); + Smi details = EntryDetailsField::Relaxed_Load(*this, entry_offset); + return PropertyDetails(details); +} + +void DescriptorArray::SetDetails(int descriptor_number, + PropertyDetails details) { + DCHECK_LT(descriptor_number, number_of_descriptors()); + int entry_offset = OffsetOfDescriptorAt(descriptor_number); + EntryDetailsField::Relaxed_Store(*this, entry_offset, details.AsSmi()); } int DescriptorArray::GetFieldIndex(int descriptor_number) { @@ -164,19 +186,22 @@ int DescriptorArray::GetFieldIndex(int descriptor_number) { } FieldType DescriptorArray::GetFieldType(int descriptor_number) { + Isolate* isolate = GetIsolateForPtrCompr(*this); + return GetFieldType(isolate, descriptor_number); +} + +FieldType DescriptorArray::GetFieldType(Isolate* isolate, + int descriptor_number) { DCHECK_EQ(GetDetails(descriptor_number).location(), kField); - MaybeObject wrapped_type = GetValue(descriptor_number); + MaybeObject wrapped_type = GetValue(isolate, descriptor_number); return Map::UnwrapFieldType(wrapped_type); } void DescriptorArray::Set(int descriptor_number, Name key, MaybeObject value, PropertyDetails details) { - // Range check. - DCHECK(descriptor_number < number_of_descriptors()); - set(ToKeyIndex(descriptor_number), MaybeObject::FromObject(key)); - set(ToValueIndex(descriptor_number), value); - set(ToDetailsIndex(descriptor_number), - MaybeObject::FromObject(details.AsSmi())); + SetKey(descriptor_number, key); + SetDetails(descriptor_number, details); + SetValue(descriptor_number, value); } void DescriptorArray::Set(int descriptor_number, Descriptor* desc) { @@ -211,21 +236,6 @@ void DescriptorArray::SwapSortedKeys(int first, int second) { SetSortedKey(second, first_key); } -int DescriptorArray::length() const { - return number_of_all_descriptors() * kEntrySize; -} - -MaybeObject DescriptorArray::get(int index) const { - DCHECK(index >= 0 && index < this->length()); - return RELAXED_READ_WEAK_FIELD(*this, offset(index)); -} - -void DescriptorArray::set(int index, MaybeObject value) { - DCHECK(index >= 0 && index < this->length()); - RELAXED_WRITE_WEAK_FIELD(*this, offset(index), value); - WEAK_WRITE_BARRIER(*this, offset(index), value); -} - } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/objects/descriptor-array.h b/chromium/v8/src/objects/descriptor-array.h index 3c1fa98a379..0f17cd22eac 100644 --- a/chromium/v8/src/objects/descriptor-array.h +++ b/chromium/v8/src/objects/descriptor-array.h @@ -22,21 +22,11 @@ class Handle; class Isolate; // An EnumCache is a pair used to hold keys and indices caches. -class EnumCache : public Struct { +class EnumCache : public TorqueGeneratedEnumCache<EnumCache, Struct> { public: - DECL_ACCESSORS(keys, FixedArray) - DECL_ACCESSORS(indices, FixedArray) - - DECL_CAST(EnumCache) - - DECL_PRINTER(EnumCache) DECL_VERIFIER(EnumCache) - // Layout description. - DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize, - TORQUE_GENERATED_ENUM_CACHE_FIELDS) - - OBJECT_CONSTRUCTORS(EnumCache, Struct); + TQ_OBJECT_CONSTRUCTORS(EnumCache) }; // A DescriptorArray is a custom array that holds instance descriptors. @@ -73,14 +63,18 @@ class DescriptorArray : public HeapObject { // Accessors for fetching instance descriptor at descriptor number. inline Name GetKey(int descriptor_number) const; + inline Name GetKey(Isolate* isolate, int descriptor_number) const; inline Object GetStrongValue(int descriptor_number); - inline void SetValue(int descriptor_number, Object value); + inline Object GetStrongValue(Isolate* isolate, int descriptor_number); inline MaybeObject GetValue(int descriptor_number); + inline MaybeObject GetValue(Isolate* isolate, int descriptor_number); inline PropertyDetails GetDetails(int descriptor_number); inline int GetFieldIndex(int descriptor_number); inline FieldType GetFieldType(int descriptor_number); + inline FieldType GetFieldType(Isolate* isolate, int descriptor_number); inline Name GetSortedKey(int descriptor_number); + inline Name GetSortedKey(Isolate* isolate, int descriptor_number); inline int GetSortedKeyIndex(int descriptor_number); inline void SetSortedKey(int pointer, int descriptor_number); @@ -153,15 +147,13 @@ class DescriptorArray : public HeapObject { int16_t number_of_marked_descriptors); static constexpr int SizeFor(int number_of_all_descriptors) { - return offset(number_of_all_descriptors * kEntrySize); + return OffsetOfDescriptorAt(number_of_all_descriptors); } static constexpr int OffsetOfDescriptorAt(int descriptor) { - return offset(descriptor * kEntrySize); + return kHeaderSize + descriptor * kEntrySize * kTaggedSize; } inline ObjectSlot GetFirstPointerSlot(); inline ObjectSlot GetDescriptorSlot(int descriptor); - inline ObjectSlot GetKeySlot(int descriptor); - inline MaybeObjectSlot GetValueSlot(int descriptor); static_assert(kEndOfStrongFieldsOffset == kStartOfWeakFieldsOffset, "Weak fields follow strong fields."); @@ -178,6 +170,10 @@ class DescriptorArray : public HeapObject { static const int kEntryValueIndex = 2; static const int kEntrySize = 3; + static const int kEntryKeyOffset = kEntryKeyIndex * kTaggedSize; + static const int kEntryDetailsOffset = kEntryDetailsIndex * kTaggedSize; + static const int kEntryValueOffset = kEntryValueIndex * kTaggedSize; + // Print all the descriptors. void PrintDescriptors(std::ostream& os); void PrintDescriptorDetails(std::ostream& os, int descriptor, @@ -207,15 +203,16 @@ class DescriptorArray : public HeapObject { return (descriptor_number * kEntrySize) + kEntryValueIndex; } + using EntryKeyField = TaggedField<HeapObject, kEntryKeyOffset>; + using EntryDetailsField = TaggedField<Smi, kEntryDetailsOffset>; + using EntryValueField = TaggedField<MaybeObject, kEntryValueOffset>; + private: DECL_INT16_ACCESSORS(filler16bits) - // Low-level per-element accessors. - static constexpr int offset(int index) { - return kHeaderSize + index * kTaggedSize; - } - inline int length() const; - inline MaybeObject get(int index) const; - inline void set(int index, MaybeObject value); + + inline void SetKey(int descriptor_number, Name key); + inline void SetValue(int descriptor_number, MaybeObject value); + inline void SetDetails(int descriptor_number, PropertyDetails details); // Transfer a complete descriptor from the src descriptor array to this // descriptor array. diff --git a/chromium/v8/src/objects/dictionary-inl.h b/chromium/v8/src/objects/dictionary-inl.h index a1692978f36..92c1d0940f5 100644 --- a/chromium/v8/src/objects/dictionary-inl.h +++ b/chromium/v8/src/objects/dictionary-inl.h @@ -98,15 +98,27 @@ RootIndex GlobalDictionaryShape::GetMapRootIndex() { return RootIndex::kGlobalDictionaryMap; } -Name NameDictionary::NameAt(int entry) { return Name::cast(KeyAt(entry)); } +Name NameDictionary::NameAt(int entry) { + Isolate* isolate = GetIsolateForPtrCompr(*this); + return NameAt(isolate, entry); +} + +Name NameDictionary::NameAt(Isolate* isolate, int entry) { + return Name::cast(KeyAt(isolate, entry)); +} RootIndex NameDictionaryShape::GetMapRootIndex() { return RootIndex::kNameDictionaryMap; } PropertyCell GlobalDictionary::CellAt(int entry) { - DCHECK(KeyAt(entry).IsPropertyCell()); - return PropertyCell::cast(KeyAt(entry)); + Isolate* isolate = GetIsolateForPtrCompr(*this); + return CellAt(isolate, entry); +} + +PropertyCell GlobalDictionary::CellAt(Isolate* isolate, int entry) { + DCHECK(KeyAt(isolate, entry).IsPropertyCell(isolate)); + return PropertyCell::cast(KeyAt(isolate, entry)); } bool GlobalDictionaryShape::IsLive(ReadOnlyRoots roots, Object k) { @@ -118,8 +130,23 @@ bool GlobalDictionaryShape::IsKey(ReadOnlyRoots roots, Object k) { return IsLive(roots, k) && !PropertyCell::cast(k).value().IsTheHole(roots); } -Name GlobalDictionary::NameAt(int entry) { return CellAt(entry).name(); } -Object GlobalDictionary::ValueAt(int entry) { return CellAt(entry).value(); } +Name GlobalDictionary::NameAt(int entry) { + Isolate* isolate = GetIsolateForPtrCompr(*this); + return NameAt(isolate, entry); +} + +Name GlobalDictionary::NameAt(Isolate* isolate, int entry) { + return CellAt(isolate, entry).name(isolate); +} + +Object GlobalDictionary::ValueAt(int entry) { + Isolate* isolate = GetIsolateForPtrCompr(*this); + return ValueAt(isolate, entry); +} + +Object GlobalDictionary::ValueAt(Isolate* isolate, int entry) { + return CellAt(isolate, entry).value(isolate); +} void GlobalDictionary::SetEntry(Isolate* isolate, int entry, Object key, Object value, PropertyDetails details) { diff --git a/chromium/v8/src/objects/dictionary.h b/chromium/v8/src/objects/dictionary.h index ca709f34d84..fe6001f58c9 100644 --- a/chromium/v8/src/objects/dictionary.h +++ b/chromium/v8/src/objects/dictionary.h @@ -32,7 +32,11 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) Dictionary using Key = typename Shape::Key; // Returns the value at entry. Object ValueAt(int entry) { - return this->get(DerivedHashTable::EntryToIndex(entry) + 1); + Isolate* isolate = GetIsolateForPtrCompr(*this); + return ValueAt(isolate, entry); + } + Object ValueAt(Isolate* isolate, int entry) { + return this->get(isolate, DerivedHashTable::EntryToIndex(entry) + 1); } // Set the value for entry. @@ -208,6 +212,8 @@ class V8_EXPORT_PRIVATE NameDictionary static const int kInitialCapacity = 2; inline Name NameAt(int entry); + inline Name NameAt(Isolate* isolate, int entry); + inline void set_hash(int hash); inline int hash() const; @@ -246,10 +252,13 @@ class V8_EXPORT_PRIVATE GlobalDictionary DECL_CAST(GlobalDictionary) inline Object ValueAt(int entry); + inline Object ValueAt(Isolate* isolate, int entry); inline PropertyCell CellAt(int entry); + inline PropertyCell CellAt(Isolate* isolate, int entry); inline void SetEntry(Isolate* isolate, int entry, Object key, Object value, PropertyDetails details); inline Name NameAt(int entry); + inline Name NameAt(Isolate* isolate, int entry); inline void ValueAtPut(int entry, Object value); OBJECT_CONSTRUCTORS( diff --git a/chromium/v8/src/objects/elements.cc b/chromium/v8/src/objects/elements.cc index e1232a0d5b0..4bdfba052df 100644 --- a/chromium/v8/src/objects/elements.cc +++ b/chromium/v8/src/objects/elements.cc @@ -4,10 +4,10 @@ #include "src/objects/elements.h" +#include "src/common/message-template.h" #include "src/execution/arguments.h" #include "src/execution/frames.h" #include "src/execution/isolate-inl.h" -#include "src/execution/message-template.h" #include "src/heap/factory.h" #include "src/heap/heap-inl.h" // For MaxNumberToStringCacheSize. #include "src/heap/heap-write-barrier-inl.h" @@ -141,6 +141,12 @@ WriteBarrierMode GetWriteBarrierMode(ElementsKind kind) { return UPDATE_WRITE_BARRIER; } +// If kCopyToEndAndInitializeToHole is specified as the copy_size to +// CopyElements, it copies all of elements from source after source_start to +// destination array, padding any remaining uninitialized elements in the +// destination array with the hole. +constexpr int kCopyToEndAndInitializeToHole = -1; + void CopyObjectToObjectElements(Isolate* isolate, FixedArrayBase from_base, ElementsKind from_kind, uint32_t from_start, FixedArrayBase to_base, ElementsKind to_kind, @@ -150,17 +156,14 @@ void CopyObjectToObjectElements(Isolate* isolate, FixedArrayBase from_base, DisallowHeapAllocation no_allocation; int copy_size = raw_copy_size; if (raw_copy_size < 0) { - DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd || - raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); + DCHECK_EQ(kCopyToEndAndInitializeToHole, raw_copy_size); copy_size = Min(from_base.length() - from_start, to_base.length() - to_start); - if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - int start = to_start + copy_size; - int length = to_base.length() - start; - if (length > 0) { - MemsetTagged(FixedArray::cast(to_base).RawFieldOfElementAt(start), - roots.the_hole_value(), length); - } + int start = to_start + copy_size; + int length = to_base.length() - start; + if (length > 0) { + MemsetTagged(FixedArray::cast(to_base).RawFieldOfElementAt(start), + roots.the_hole_value(), length); } } DCHECK((copy_size + static_cast<int>(to_start)) <= to_base.length() && @@ -179,24 +182,21 @@ void CopyObjectToObjectElements(Isolate* isolate, FixedArrayBase from_base, write_barrier_mode); } -static void CopyDictionaryToObjectElements( - Isolate* isolate, FixedArrayBase from_base, uint32_t from_start, - FixedArrayBase to_base, ElementsKind to_kind, uint32_t to_start, - int raw_copy_size) { +void CopyDictionaryToObjectElements(Isolate* isolate, FixedArrayBase from_base, + uint32_t from_start, FixedArrayBase to_base, + ElementsKind to_kind, uint32_t to_start, + int raw_copy_size) { DisallowHeapAllocation no_allocation; NumberDictionary from = NumberDictionary::cast(from_base); int copy_size = raw_copy_size; if (raw_copy_size < 0) { - DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd || - raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); + DCHECK_EQ(kCopyToEndAndInitializeToHole, raw_copy_size); copy_size = from.max_number_key() + 1 - from_start; - if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - int start = to_start + copy_size; - int length = to_base.length() - start; - if (length > 0) { - MemsetTagged(FixedArray::cast(to_base).RawFieldOfElementAt(start), - ReadOnlyRoots(isolate).the_hole_value(), length); - } + int start = to_start + copy_size; + int length = to_base.length() - start; + if (length > 0) { + MemsetTagged(FixedArray::cast(to_base).RawFieldOfElementAt(start), + ReadOnlyRoots(isolate).the_hole_value(), length); } } DCHECK(to_base != from_base); @@ -223,28 +223,23 @@ static void CopyDictionaryToObjectElements( // NOTE: this method violates the handlified function signature convention: // raw pointer parameters in the function that allocates. // See ElementsAccessorBase::CopyElements() for details. -static void CopyDoubleToObjectElements(Isolate* isolate, - FixedArrayBase from_base, - uint32_t from_start, - FixedArrayBase to_base, - uint32_t to_start, int raw_copy_size) { +void CopyDoubleToObjectElements(Isolate* isolate, FixedArrayBase from_base, + uint32_t from_start, FixedArrayBase to_base, + uint32_t to_start, int raw_copy_size) { int copy_size = raw_copy_size; if (raw_copy_size < 0) { DisallowHeapAllocation no_allocation; - DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd || - raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); + DCHECK_EQ(kCopyToEndAndInitializeToHole, raw_copy_size); copy_size = Min(from_base.length() - from_start, to_base.length() - to_start); - if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - // Also initialize the area that will be copied over since HeapNumber - // allocation below can cause an incremental marking step, requiring all - // existing heap objects to be propertly initialized. - int start = to_start; - int length = to_base.length() - start; - if (length > 0) { - MemsetTagged(FixedArray::cast(to_base).RawFieldOfElementAt(start), - ReadOnlyRoots(isolate).the_hole_value(), length); - } + // Also initialize the area that will be copied over since HeapNumber + // allocation below can cause an incremental marking step, requiring all + // existing heap objects to be propertly initialized. + int start = to_start; + int length = to_base.length() - start; + if (length > 0) { + MemsetTagged(FixedArray::cast(to_base).RawFieldOfElementAt(start), + ReadOnlyRoots(isolate).the_hole_value(), length); } } @@ -272,21 +267,17 @@ static void CopyDoubleToObjectElements(Isolate* isolate, } } -static void CopyDoubleToDoubleElements(FixedArrayBase from_base, - uint32_t from_start, - FixedArrayBase to_base, - uint32_t to_start, int raw_copy_size) { +void CopyDoubleToDoubleElements(FixedArrayBase from_base, uint32_t from_start, + FixedArrayBase to_base, uint32_t to_start, + int raw_copy_size) { DisallowHeapAllocation no_allocation; int copy_size = raw_copy_size; if (raw_copy_size < 0) { - DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd || - raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); + DCHECK_EQ(kCopyToEndAndInitializeToHole, raw_copy_size); copy_size = Min(from_base.length() - from_start, to_base.length() - to_start); - if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - for (int i = to_start + copy_size; i < to_base.length(); ++i) { - FixedDoubleArray::cast(to_base).set_the_hole(i); - } + for (int i = to_start + copy_size; i < to_base.length(); ++i) { + FixedDoubleArray::cast(to_base).set_the_hole(i); } } DCHECK((copy_size + static_cast<int>(to_start)) <= to_base.length() && @@ -312,19 +303,16 @@ static void CopyDoubleToDoubleElements(FixedArrayBase from_base, #endif } -static void CopySmiToDoubleElements(FixedArrayBase from_base, - uint32_t from_start, FixedArrayBase to_base, - uint32_t to_start, int raw_copy_size) { +void CopySmiToDoubleElements(FixedArrayBase from_base, uint32_t from_start, + FixedArrayBase to_base, uint32_t to_start, + int raw_copy_size) { DisallowHeapAllocation no_allocation; int copy_size = raw_copy_size; if (raw_copy_size < 0) { - DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd || - raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); + DCHECK_EQ(kCopyToEndAndInitializeToHole, raw_copy_size); copy_size = from_base.length() - from_start; - if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - for (int i = to_start + copy_size; i < to_base.length(); ++i) { - FixedDoubleArray::cast(to_base).set_the_hole(i); - } + for (int i = to_start + copy_size; i < to_base.length(); ++i) { + FixedDoubleArray::cast(to_base).set_the_hole(i); } } DCHECK((copy_size + static_cast<int>(to_start)) <= to_base.length() && @@ -344,25 +332,19 @@ static void CopySmiToDoubleElements(FixedArrayBase from_base, } } -static void CopyPackedSmiToDoubleElements(FixedArrayBase from_base, - uint32_t from_start, - FixedArrayBase to_base, - uint32_t to_start, int packed_size, - int raw_copy_size) { +void CopyPackedSmiToDoubleElements(FixedArrayBase from_base, + uint32_t from_start, FixedArrayBase to_base, + uint32_t to_start, int packed_size, + int raw_copy_size) { DisallowHeapAllocation no_allocation; int copy_size = raw_copy_size; uint32_t to_end; if (raw_copy_size < 0) { - DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd || - raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); + DCHECK_EQ(kCopyToEndAndInitializeToHole, raw_copy_size); copy_size = packed_size - from_start; - if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - to_end = to_base.length(); - for (uint32_t i = to_start + copy_size; i < to_end; ++i) { - FixedDoubleArray::cast(to_base).set_the_hole(i); - } - } else { - to_end = to_start + static_cast<uint32_t>(copy_size); + to_end = to_base.length(); + for (uint32_t i = to_start + copy_size; i < to_end; ++i) { + FixedDoubleArray::cast(to_base).set_the_hole(i); } } else { to_end = to_start + static_cast<uint32_t>(copy_size); @@ -382,20 +364,16 @@ static void CopyPackedSmiToDoubleElements(FixedArrayBase from_base, } } -static void CopyObjectToDoubleElements(FixedArrayBase from_base, - uint32_t from_start, - FixedArrayBase to_base, - uint32_t to_start, int raw_copy_size) { +void CopyObjectToDoubleElements(FixedArrayBase from_base, uint32_t from_start, + FixedArrayBase to_base, uint32_t to_start, + int raw_copy_size) { DisallowHeapAllocation no_allocation; int copy_size = raw_copy_size; if (raw_copy_size < 0) { - DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd || - raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); + DCHECK_EQ(kCopyToEndAndInitializeToHole, raw_copy_size); copy_size = from_base.length() - from_start; - if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - for (int i = to_start + copy_size; i < to_base.length(); ++i) { - FixedDoubleArray::cast(to_base).set_the_hole(i); - } + for (int i = to_start + copy_size; i < to_base.length(); ++i) { + FixedDoubleArray::cast(to_base).set_the_hole(i); } } DCHECK((copy_size + static_cast<int>(to_start)) <= to_base.length() && @@ -415,20 +393,17 @@ static void CopyObjectToDoubleElements(FixedArrayBase from_base, } } -static void CopyDictionaryToDoubleElements( - Isolate* isolate, FixedArrayBase from_base, uint32_t from_start, - FixedArrayBase to_base, uint32_t to_start, int raw_copy_size) { +void CopyDictionaryToDoubleElements(Isolate* isolate, FixedArrayBase from_base, + uint32_t from_start, FixedArrayBase to_base, + uint32_t to_start, int raw_copy_size) { DisallowHeapAllocation no_allocation; NumberDictionary from = NumberDictionary::cast(from_base); int copy_size = raw_copy_size; if (copy_size < 0) { - DCHECK(copy_size == ElementsAccessor::kCopyToEnd || - copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); + DCHECK_EQ(kCopyToEndAndInitializeToHole, copy_size); copy_size = from.max_number_key() + 1 - from_start; - if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { - for (int i = to_start + copy_size; i < to_base.length(); ++i) { - FixedDoubleArray::cast(to_base).set_the_hole(i); - } + for (int i = to_start + copy_size; i < to_base.length(); ++i) { + FixedDoubleArray::cast(to_base).set_the_hole(i); } } if (copy_size == 0) return; @@ -447,17 +422,16 @@ static void CopyDictionaryToDoubleElements( } } -static void SortIndices(Isolate* isolate, Handle<FixedArray> indices, - uint32_t sort_size) { +void SortIndices(Isolate* isolate, Handle<FixedArray> indices, + uint32_t sort_size) { // Use AtomicSlot wrapper to ensure that std::sort uses atomic load and // store operations that are safe for concurrent marking. AtomicSlot start(indices->GetFirstElementAddress()); AtomicSlot end(start + sort_size); std::sort(start, end, [isolate](Tagged_t elementA, Tagged_t elementB) { #ifdef V8_COMPRESS_POINTERS - DEFINE_ROOT_VALUE(isolate); - Object a(DecompressTaggedAny(ROOT_VALUE, elementA)); - Object b(DecompressTaggedAny(ROOT_VALUE, elementB)); + Object a(DecompressTaggedAny(isolate, elementA)); + Object b(DecompressTaggedAny(isolate, elementB)); #else Object a(elementA); Object b(elementB); @@ -474,10 +448,9 @@ static void SortIndices(Isolate* isolate, Handle<FixedArray> indices, ObjectSlot(end)); } -static Maybe<bool> IncludesValueSlowPath(Isolate* isolate, - Handle<JSObject> receiver, - Handle<Object> value, - uint32_t start_from, uint32_t length) { +Maybe<bool> IncludesValueSlowPath(Isolate* isolate, Handle<JSObject> receiver, + Handle<Object> value, uint32_t start_from, + uint32_t length) { bool search_for_hole = value->IsUndefined(isolate); for (uint32_t k = start_from; k < length; ++k) { LookupIterator it(isolate, receiver, k); @@ -495,11 +468,9 @@ static Maybe<bool> IncludesValueSlowPath(Isolate* isolate, return Just(false); } -static Maybe<int64_t> IndexOfValueSlowPath(Isolate* isolate, - Handle<JSObject> receiver, - Handle<Object> value, - uint32_t start_from, - uint32_t length) { +Maybe<int64_t> IndexOfValueSlowPath(Isolate* isolate, Handle<JSObject> receiver, + Handle<Object> value, uint32_t start_from, + uint32_t length) { for (uint32_t k = start_from; k < length; ++k) { LookupIterator it(isolate, receiver, k); if (!it.IsFound()) { @@ -595,23 +566,6 @@ class ElementsAccessorBase : public InternalElementsAccessor { return true; } - static void TryTransitionResultArrayToPacked(Handle<JSArray> array) { - if (!IsHoleyElementsKind(kind())) return; - Handle<FixedArrayBase> backing_store(array->elements(), - array->GetIsolate()); - int length = Smi::ToInt(array->length()); - if (!Subclass::IsPackedImpl(*array, *backing_store, 0, length)) return; - - ElementsKind packed_kind = GetPackedElementsKind(kind()); - Handle<Map> new_map = - JSObject::GetElementsTransitionMap(array, packed_kind); - JSObject::MigrateToMap(array, new_map); - if (FLAG_trace_elements_transitions) { - JSObject::PrintElementsTransition(stdout, array, kind(), backing_store, - packed_kind, backing_store); - } - } - bool HasElement(JSObject holder, uint32_t index, FixedArrayBase backing_store, PropertyFilter filter) final { return Subclass::HasElementImpl(holder.GetIsolate(), holder, index, @@ -804,22 +758,14 @@ class ElementsAccessorBase : public InternalElementsAccessor { static Handle<FixedArrayBase> ConvertElementsWithCapacity( Handle<JSObject> object, Handle<FixedArrayBase> old_elements, ElementsKind from_kind, uint32_t capacity) { - return ConvertElementsWithCapacity( - object, old_elements, from_kind, capacity, 0, 0, - ElementsAccessor::kCopyToEndAndInitializeToHole); - } - - static Handle<FixedArrayBase> ConvertElementsWithCapacity( - Handle<JSObject> object, Handle<FixedArrayBase> old_elements, - ElementsKind from_kind, uint32_t capacity, int copy_size) { return ConvertElementsWithCapacity(object, old_elements, from_kind, - capacity, 0, 0, copy_size); + capacity, 0, 0); } static Handle<FixedArrayBase> ConvertElementsWithCapacity( Handle<JSObject> object, Handle<FixedArrayBase> old_elements, ElementsKind from_kind, uint32_t capacity, uint32_t src_index, - uint32_t dst_index, int copy_size) { + uint32_t dst_index) { Isolate* isolate = object->GetIsolate(); Handle<FixedArrayBase> new_elements; if (IsDoubleElementsKind(kind())) { @@ -834,14 +780,16 @@ class ElementsAccessorBase : public InternalElementsAccessor { } Subclass::CopyElementsImpl(isolate, *old_elements, src_index, *new_elements, - from_kind, dst_index, packed_size, copy_size); + from_kind, dst_index, packed_size, + kCopyToEndAndInitializeToHole); return new_elements; } static void TransitionElementsKindImpl(Handle<JSObject> object, Handle<Map> to_map) { - Handle<Map> from_map = handle(object->map(), object->GetIsolate()); + Isolate* isolate = object->GetIsolate(); + Handle<Map> from_map = handle(object->map(), isolate); ElementsKind from_kind = from_map->elements_kind(); ElementsKind to_kind = to_map->elements_kind(); if (IsHoleyElementsKind(from_kind)) { @@ -853,14 +801,12 @@ class ElementsAccessorBase : public InternalElementsAccessor { DCHECK(IsFastElementsKind(to_kind)); DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind); - Handle<FixedArrayBase> from_elements(object->elements(), - object->GetIsolate()); - if (object->elements() == - object->GetReadOnlyRoots().empty_fixed_array() || + Handle<FixedArrayBase> from_elements(object->elements(), isolate); + if (object->elements() == ReadOnlyRoots(isolate).empty_fixed_array() || IsDoubleElementsKind(from_kind) == IsDoubleElementsKind(to_kind)) { // No change is needed to the elements() buffer, the transition // only requires a map change. - JSObject::MigrateToMap(object, to_map); + JSObject::MigrateToMap(isolate, object, to_map); } else { DCHECK( (IsSmiElementsKind(from_kind) && IsDoubleElementsKind(to_kind)) || @@ -871,9 +817,9 @@ class ElementsAccessorBase : public InternalElementsAccessor { JSObject::SetMapAndElements(object, to_map, elements); } if (FLAG_trace_elements_transitions) { - JSObject::PrintElementsTransition( - stdout, object, from_kind, from_elements, to_kind, - handle(object->elements(), object->GetIsolate())); + JSObject::PrintElementsTransition(stdout, object, from_kind, + from_elements, to_kind, + handle(object->elements(), isolate)); } } } @@ -2394,7 +2340,7 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> { // Copy over all objects to a new backing_store. backing_store = Subclass::ConvertElementsWithCapacity( receiver, backing_store, KindTraits::Kind, capacity, 0, - copy_dst_index, ElementsAccessor::kCopyToEndAndInitializeToHole); + copy_dst_index); receiver->set_elements(*backing_store); } else if (add_position == AT_START) { // If the backing store has enough capacity and we add elements to the @@ -2639,7 +2585,7 @@ class FastSealedObjectElementsAccessor "SlowCopyForSetLengthImpl"); new_map->set_is_extensible(false); new_map->set_elements_kind(DICTIONARY_ELEMENTS); - JSObject::MigrateToMap(array, new_map); + JSObject::MigrateToMap(isolate, array, new_map); if (!new_element_dictionary.is_null()) { array->set_elements(*new_element_dictionary); @@ -2955,7 +2901,7 @@ class TypedElementsAccessor // fields (external pointers, doubles and BigInt data) are only // kTaggedSize aligned so we have to use unaligned pointer friendly way of // accessing them in order to avoid undefined behavior in C++ code. - WriteUnalignedValue<ElementType>( + base::WriteUnalignedValue<ElementType>( reinterpret_cast<Address>(data_ptr + entry), value); } else { data_ptr[entry] = value; @@ -2995,7 +2941,7 @@ class TypedElementsAccessor // fields (external pointers, doubles and BigInt data) are only // kTaggedSize aligned so we have to use unaligned pointer friendly way of // accessing them in order to avoid undefined behavior in C++ code. - result = ReadUnalignedValue<ElementType>( + result = base::ReadUnalignedValue<ElementType>( reinterpret_cast<Address>(data_ptr + entry)); } else { result = data_ptr[entry]; @@ -3664,10 +3610,7 @@ Handle<Object> TypedElementsAccessor<UINT32_ELEMENTS, uint32_t>::ToHandle( // static template <> float TypedElementsAccessor<FLOAT32_ELEMENTS, float>::FromScalar(double value) { - using limits = std::numeric_limits<float>; - if (value > limits::max()) return limits::infinity(); - if (value < limits::lowest()) return -limits::infinity(); - return static_cast<float>(value); + return DoubleToFloat32(value); } // static @@ -4377,7 +4320,7 @@ class FastSloppyArgumentsElementsAccessor ConvertElementsWithCapacity(object, old_arguments, from_kind, capacity); Handle<Map> new_map = JSObject::GetElementsTransitionMap( object, FAST_SLOPPY_ARGUMENTS_ELEMENTS); - JSObject::MigrateToMap(object, new_map); + JSObject::MigrateToMap(isolate, object, new_map); elements->set_arguments(FixedArray::cast(*arguments)); JSObject::ValidateElements(*object); } @@ -4549,8 +4492,8 @@ class StringWrapperElementsAccessor private: static String GetString(JSObject holder) { - DCHECK(holder.IsJSValue()); - JSValue js_value = JSValue::cast(holder); + DCHECK(holder.IsJSPrimitiveWrapper()); + JSPrimitiveWrapper js_value = JSPrimitiveWrapper::cast(holder); DCHECK(js_value.value().IsString()); return String::cast(js_value.value()); } diff --git a/chromium/v8/src/objects/elements.h b/chromium/v8/src/objects/elements.h index 844cd2ed943..a72a6b068e4 100644 --- a/chromium/v8/src/objects/elements.h +++ b/chromium/v8/src/objects/elements.h @@ -66,15 +66,6 @@ class ElementsAccessor { // element that is non-deletable. virtual void SetLength(Handle<JSArray> holder, uint32_t new_length) = 0; - // If kCopyToEnd is specified as the copy_size to CopyElements, it copies all - // of elements from source after source_start to the destination array. - static const int kCopyToEnd = -1; - // If kCopyToEndAndInitializeToHole is specified as the copy_size to - // CopyElements, it copies all of elements from source after source_start to - // destination array, padding any remaining uninitialized elements in the - // destination array with the hole. - static const int kCopyToEndAndInitializeToHole = -2; - // Copy all indices that have elements from |object| into the given // KeyAccumulator. For Dictionary-based element-kinds we filter out elements // whose PropertyAttribute match |filter|. @@ -210,7 +201,7 @@ class ElementsAccessor { uint32_t destination_start, int copy_size) = 0; private: - static ElementsAccessor** elements_accessors_; + V8_EXPORT_PRIVATE static ElementsAccessor** elements_accessors_; DISALLOW_COPY_AND_ASSIGN(ElementsAccessor); }; diff --git a/chromium/v8/src/objects/embedder-data-slot-inl.h b/chromium/v8/src/objects/embedder-data-slot-inl.h index 6830a4d22ef..78189ba3812 100644 --- a/chromium/v8/src/objects/embedder-data-slot-inl.h +++ b/chromium/v8/src/objects/embedder-data-slot-inl.h @@ -7,7 +7,7 @@ #include "src/objects/embedder-data-slot.h" -#include "src/common/v8memory.h" +#include "src/base/memory.h" #include "src/heap/heap-write-barrier-inl.h" #include "src/objects/embedder-data-array.h" #include "src/objects/js-objects-inl.h" @@ -77,7 +77,7 @@ bool EmbedderDataSlot::ToAlignedPointer(void** out_pointer) const { // fields (external pointers, doubles and BigInt data) are only kTaggedSize // aligned so we have to use unaligned pointer friendly way of accessing them // in order to avoid undefined behavior in C++ code. - Address raw_value = ReadUnalignedValue<Address>(address()); + Address raw_value = base::ReadUnalignedValue<Address>(address()); #else Address raw_value = *location(); #endif @@ -103,7 +103,7 @@ EmbedderDataSlot::RawData EmbedderDataSlot::load_raw( // fields (external pointers, doubles and BigInt data) are only kTaggedSize // aligned so we have to use unaligned pointer friendly way of accessing them // in order to avoid undefined behavior in C++ code. - return ReadUnalignedValue<Address>(address()); + return base::ReadUnalignedValue<Address>(address()); #else return *location(); #endif diff --git a/chromium/v8/src/objects/feedback-vector-inl.h b/chromium/v8/src/objects/feedback-vector-inl.h index 6b1fdcc1e50..9cdc03b5c24 100644 --- a/chromium/v8/src/objects/feedback-vector-inl.h +++ b/chromium/v8/src/objects/feedback-vector-inl.h @@ -155,13 +155,22 @@ FeedbackSlot FeedbackVector::ToSlot(int index) { } MaybeObject FeedbackVector::Get(FeedbackSlot slot) const { - return get(GetIndex(slot)); + Isolate* isolate = GetIsolateForPtrCompr(*this); + return Get(isolate, slot); +} + +MaybeObject FeedbackVector::Get(Isolate* isolate, FeedbackSlot slot) const { + return get(isolate, GetIndex(slot)); } MaybeObject FeedbackVector::get(int index) const { - DCHECK_GE(index, 0); - DCHECK_LT(index, this->length()); - int offset = kFeedbackSlotsOffset + index * kTaggedSize; + Isolate* isolate = GetIsolateForPtrCompr(*this); + return get(isolate, index); +} + +MaybeObject FeedbackVector::get(Isolate* isolate, int index) const { + DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); + int offset = OffsetOfElementAt(index); return RELAXED_READ_WEAK_FIELD(*this, offset); } @@ -180,7 +189,7 @@ void FeedbackVector::Set(FeedbackSlot slot, MaybeObject value, void FeedbackVector::set(int index, MaybeObject value, WriteBarrierMode mode) { DCHECK_GE(index, 0); DCHECK_LT(index, this->length()); - int offset = kFeedbackSlotsOffset + index * kTaggedSize; + int offset = OffsetOfElementAt(index); RELAXED_WRITE_WEAK_FIELD(*this, offset, value); CONDITIONAL_WEAK_WRITE_BARRIER(*this, offset, value, mode); } diff --git a/chromium/v8/src/objects/feedback-vector.cc b/chromium/v8/src/objects/feedback-vector.cc index 0393a55f692..4f4826eab36 100644 --- a/chromium/v8/src/objects/feedback-vector.cc +++ b/chromium/v8/src/objects/feedback-vector.cc @@ -374,6 +374,7 @@ void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization( } bool FeedbackVector::ClearSlots(Isolate* isolate) { + if (!shared_function_info().HasFeedbackMetadata()) return false; MaybeObject uninitialized_sentinel = MaybeObject::FromObject( FeedbackVector::RawUninitializedSentinel(isolate)); @@ -943,6 +944,7 @@ int FeedbackNexus::ExtractMaps(MapHandles* maps) const { IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) || IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind())); + DisallowHeapAllocation no_gc; Isolate* isolate = GetIsolate(); MaybeObject feedback = GetFeedback(); bool is_named_feedback = IsPropertyNameFeedback(feedback); @@ -986,19 +988,22 @@ int FeedbackNexus::ExtractMaps(MapHandles* maps) const { return 0; } -MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const { +int FeedbackNexus::ExtractMapsAndHandlers(MapHandles* maps, + MaybeObjectHandles* handlers) const { DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) || IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) || IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) || - IsKeyedHasICKind(kind())); + IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind())); - MaybeObject feedback = GetFeedback(); + DisallowHeapAllocation no_gc; Isolate* isolate = GetIsolate(); + MaybeObject feedback = GetFeedback(); bool is_named_feedback = IsPropertyNameFeedback(feedback); HeapObject heap_object; if ((feedback->GetHeapObjectIfStrong(&heap_object) && heap_object.IsWeakFixedArray()) || is_named_feedback) { + int found = 0; WeakFixedArray array; if (is_named_feedback) { array = @@ -1011,36 +1016,39 @@ MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const { for (int i = 0; i < array.length(); i += increment) { DCHECK(array.Get(i)->IsWeakOrCleared()); if (array.Get(i)->GetHeapObjectIfWeak(&heap_object)) { - Map array_map = Map::cast(heap_object); - if (array_map == *map && !array.Get(i + increment - 1)->IsCleared()) { - MaybeObject handler = array.Get(i + increment - 1); + MaybeObject handler = array.Get(i + 1); + if (!handler->IsCleared()) { DCHECK(IC::IsHandler(handler)); - return handle(handler, isolate); + Map map = Map::cast(heap_object); + maps->push_back(handle(map, isolate)); + handlers->push_back(handle(handler, isolate)); + found++; } } } + return found; } else if (feedback->GetHeapObjectIfWeak(&heap_object)) { - Map cell_map = Map::cast(heap_object); - if (cell_map == *map && !GetFeedbackExtra()->IsCleared()) { - MaybeObject handler = GetFeedbackExtra(); + MaybeObject handler = GetFeedbackExtra(); + if (!handler->IsCleared()) { DCHECK(IC::IsHandler(handler)); - return handle(handler, isolate); + Map map = Map::cast(heap_object); + maps->push_back(handle(map, isolate)); + handlers->push_back(handle(handler, isolate)); + return 1; } } - return MaybeObjectHandle(); + return 0; } -bool FeedbackNexus::FindHandlers(MaybeObjectHandles* code_list, - int length) const { +MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const { DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) || IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) || IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) || - IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind())); + IsKeyedHasICKind(kind())); MaybeObject feedback = GetFeedback(); Isolate* isolate = GetIsolate(); - int count = 0; bool is_named_feedback = IsPropertyNameFeedback(feedback); HeapObject heap_object; if ((feedback->GetHeapObjectIfStrong(&heap_object) && @@ -1056,25 +1064,26 @@ bool FeedbackNexus::FindHandlers(MaybeObjectHandles* code_list, const int increment = 2; HeapObject heap_object; for (int i = 0; i < array.length(); i += increment) { - // Be sure to skip handlers whose maps have been cleared. DCHECK(array.Get(i)->IsWeakOrCleared()); - if (array.Get(i)->GetHeapObjectIfWeak(&heap_object) && - !array.Get(i + increment - 1)->IsCleared()) { - MaybeObject handler = array.Get(i + increment - 1); - DCHECK(IC::IsHandler(handler)); - code_list->push_back(handle(handler, isolate)); - count++; + if (array.Get(i)->GetHeapObjectIfWeak(&heap_object)) { + Map array_map = Map::cast(heap_object); + if (array_map == *map && !array.Get(i + increment - 1)->IsCleared()) { + MaybeObject handler = array.Get(i + increment - 1); + DCHECK(IC::IsHandler(handler)); + return handle(handler, isolate); + } } } } else if (feedback->GetHeapObjectIfWeak(&heap_object)) { - MaybeObject extra = GetFeedbackExtra(); - if (!extra->IsCleared()) { - DCHECK(IC::IsHandler(extra)); - code_list->push_back(handle(extra, isolate)); - count++; + Map cell_map = Map::cast(heap_object); + if (cell_map == *map && !GetFeedbackExtra()->IsCleared()) { + MaybeObject handler = GetFeedbackExtra(); + DCHECK(IC::IsHandler(handler)); + return handle(handler, isolate); } } - return count == length; + + return MaybeObjectHandle(); } Name FeedbackNexus::GetName() const { @@ -1095,8 +1104,7 @@ KeyedAccessLoadMode FeedbackNexus::GetKeyedAccessLoadMode() const { if (GetKeyType() == PROPERTY) return STANDARD_LOAD; - ExtractMaps(&maps); - FindHandlers(&handlers, static_cast<int>(maps.size())); + ExtractMapsAndHandlers(&maps, &handlers); for (MaybeObjectHandle const& handler : handlers) { KeyedAccessLoadMode mode = LoadHandler::GetKeyedAccessLoadMode(*handler); if (mode != STANDARD_LOAD) return mode; @@ -1179,8 +1187,7 @@ KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const { if (GetKeyType() == PROPERTY) return mode; - ExtractMaps(&maps); - FindHandlers(&handlers, static_cast<int>(maps.size())); + ExtractMapsAndHandlers(&maps, &handlers); for (const MaybeObjectHandle& maybe_code_handler : handlers) { // The first handler that isn't the slow handler will have the bits we need. Handle<Code> handler; diff --git a/chromium/v8/src/objects/feedback-vector.h b/chromium/v8/src/objects/feedback-vector.h index 89e0b9e6aae..af03bb4130c 100644 --- a/chromium/v8/src/objects/feedback-vector.h +++ b/chromium/v8/src/objects/feedback-vector.h @@ -233,7 +233,9 @@ class FeedbackVector : public HeapObject { // Conversion from an integer index to the underlying array to a slot. static inline FeedbackSlot ToSlot(int index); inline MaybeObject Get(FeedbackSlot slot) const; + inline MaybeObject Get(Isolate* isolate, FeedbackSlot slot) const; inline MaybeObject get(int index) const; + inline MaybeObject get(Isolate* isolate, int index) const; inline void Set(FeedbackSlot slot, MaybeObject value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); inline void set(int index, MaybeObject value, @@ -322,11 +324,13 @@ class FeedbackVector : public HeapObject { class BodyDescriptor; - // Garbage collection support. - static constexpr int SizeFor(int length) { - return kFeedbackSlotsOffset + length * kTaggedSize; + static constexpr int OffsetOfElementAt(int index) { + return kFeedbackSlotsOffset + index * kTaggedSize; } + // Garbage collection support. + static constexpr int SizeFor(int length) { return OffsetOfElementAt(length); } + private: static void AddToVectorsForProfilingTools(Isolate* isolate, Handle<FeedbackVector> vector); @@ -561,6 +565,7 @@ class FeedbackMetadata : public HeapObject { // Verify that an empty hash field looks like a tagged object, but can't // possibly be confused with a pointer. +// NOLINTNEXTLINE(runtime/references) (false positive) STATIC_ASSERT((Name::kEmptyHashField & kHeapObjectTag) == kHeapObjectTag); STATIC_ASSERT(Name::kEmptyHashField == 0x3); // Verify that a set hash field will not look like a tagged object. @@ -646,8 +651,9 @@ class V8_EXPORT_PRIVATE FeedbackNexus final { Map GetFirstMap() const; int ExtractMaps(MapHandles* maps) const; + int ExtractMapsAndHandlers(MapHandles* maps, + MaybeObjectHandles* handlers) const; MaybeObjectHandle FindHandlerForMap(Handle<Map> map) const; - bool FindHandlers(MaybeObjectHandles* code_list, int length = -1) const; bool IsCleared() const { InlineCacheState state = ic_state(); diff --git a/chromium/v8/src/objects/field-index-inl.h b/chromium/v8/src/objects/field-index-inl.h index be60fb54a2a..997cd68c32b 100644 --- a/chromium/v8/src/objects/field-index-inl.h +++ b/chromium/v8/src/objects/field-index-inl.h @@ -19,7 +19,7 @@ FieldIndex FieldIndex::ForInObjectOffset(int offset, Encoding encoding) { return FieldIndex(true, offset, encoding, 0, 0); } -FieldIndex FieldIndex::ForPropertyIndex(const Map map, int property_index, +FieldIndex FieldIndex::ForPropertyIndex(Map map, int property_index, Representation representation) { DCHECK(map.instance_type() >= FIRST_NONSTRING_TYPE); int inobject_properties = map.GetInObjectProperties(); @@ -60,9 +60,15 @@ int FieldIndex::GetLoadByFieldIndex() const { return is_double() ? (result | 1) : result; } -FieldIndex FieldIndex::ForDescriptor(const Map map, int descriptor_index) { +FieldIndex FieldIndex::ForDescriptor(Map map, int descriptor_index) { + Isolate* isolate = GetIsolateForPtrCompr(map); + return ForDescriptor(isolate, map, descriptor_index); +} + +FieldIndex FieldIndex::ForDescriptor(Isolate* isolate, Map map, + int descriptor_index) { PropertyDetails details = - map.instance_descriptors().GetDetails(descriptor_index); + map.instance_descriptors(isolate).GetDetails(descriptor_index); int field_index = details.field_index(); return ForPropertyIndex(map, field_index, details.representation()); } diff --git a/chromium/v8/src/objects/field-index.h b/chromium/v8/src/objects/field-index.h index f352ef68007..a6657634c82 100644 --- a/chromium/v8/src/objects/field-index.h +++ b/chromium/v8/src/objects/field-index.h @@ -24,10 +24,12 @@ class FieldIndex final { FieldIndex() : bit_field_(0) {} static inline FieldIndex ForPropertyIndex( - const Map map, int index, + Map map, int index, Representation representation = Representation::Tagged()); static inline FieldIndex ForInObjectOffset(int offset, Encoding encoding); - static inline FieldIndex ForDescriptor(const Map map, int descriptor_index); + static inline FieldIndex ForDescriptor(Map map, int descriptor_index); + static inline FieldIndex ForDescriptor(Isolate* isolate, Map map, + int descriptor_index); inline int GetLoadByFieldIndex() const; diff --git a/chromium/v8/src/objects/fixed-array-inl.h b/chromium/v8/src/objects/fixed-array-inl.h index 6d2b42edbf1..79c29a6eeba 100644 --- a/chromium/v8/src/objects/fixed-array-inl.h +++ b/chromium/v8/src/objects/fixed-array-inl.h @@ -90,51 +90,57 @@ bool FixedArray::ContainsOnlySmisOrHoles() { } Object FixedArray::get(int index) const { - DCHECK(index >= 0 && index < this->length()); - return RELAXED_READ_FIELD(*this, kHeaderSize + index * kTaggedSize); + Isolate* isolate = GetIsolateForPtrCompr(*this); + return get(isolate, index); +} + +Object FixedArray::get(Isolate* isolate, int index) const { + DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); + return TaggedField<Object>::Relaxed_Load(isolate, *this, + OffsetOfElementAt(index)); } Handle<Object> FixedArray::get(FixedArray array, int index, Isolate* isolate) { - return handle(array.get(index), isolate); + return handle(array.get(isolate, index), isolate); } bool FixedArray::is_the_hole(Isolate* isolate, int index) { - return get(index).IsTheHole(isolate); + return get(isolate, index).IsTheHole(isolate); } void FixedArray::set(int index, Smi value) { DCHECK_NE(map(), GetReadOnlyRoots().fixed_cow_array_map()); - DCHECK_LT(index, this->length()); + DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); DCHECK(Object(value).IsSmi()); - int offset = kHeaderSize + index * kTaggedSize; + int offset = OffsetOfElementAt(index); RELAXED_WRITE_FIELD(*this, offset, value); } void FixedArray::set(int index, Object value) { DCHECK_NE(GetReadOnlyRoots().fixed_cow_array_map(), map()); DCHECK(IsFixedArray()); - DCHECK_GE(index, 0); - DCHECK_LT(index, this->length()); - int offset = kHeaderSize + index * kTaggedSize; + DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); + int offset = OffsetOfElementAt(index); RELAXED_WRITE_FIELD(*this, offset, value); WRITE_BARRIER(*this, offset, value); } void FixedArray::set(int index, Object value, WriteBarrierMode mode) { DCHECK_NE(map(), GetReadOnlyRoots().fixed_cow_array_map()); - DCHECK_GE(index, 0); - DCHECK_LT(index, this->length()); - int offset = kHeaderSize + index * kTaggedSize; + DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); + int offset = OffsetOfElementAt(index); RELAXED_WRITE_FIELD(*this, offset, value); CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode); } +// static void FixedArray::NoWriteBarrierSet(FixedArray array, int index, Object value) { DCHECK_NE(array.map(), array.GetReadOnlyRoots().fixed_cow_array_map()); - DCHECK_GE(index, 0); - DCHECK_LT(index, array.length()); + DCHECK_LT(static_cast<unsigned>(index), + static_cast<unsigned>(array.length())); DCHECK(!ObjectInYoungGeneration(value)); - RELAXED_WRITE_FIELD(array, kHeaderSize + index * kTaggedSize, value); + int offset = OffsetOfElementAt(index); + RELAXED_WRITE_FIELD(array, offset, value); } void FixedArray::set_undefined(int index) { @@ -323,7 +329,7 @@ uint64_t FixedDoubleArray::get_representation(int index) { DCHECK(index >= 0 && index < this->length()); int offset = kHeaderSize + index * kDoubleSize; // Bug(v8:8875): Doubles may be unaligned. - return ReadUnalignedValue<uint64_t>(field_address(offset)); + return base::ReadUnalignedValue<uint64_t>(field_address(offset)); } Handle<Object> FixedDoubleArray::get(FixedDoubleArray array, int index, @@ -355,7 +361,7 @@ void FixedDoubleArray::set_the_hole(int index) { DCHECK(map() != GetReadOnlyRoots().fixed_cow_array_map() && map() != GetReadOnlyRoots().fixed_array_map()); int offset = kHeaderSize + index * kDoubleSize; - WriteUnalignedValue<uint64_t>(field_address(offset), kHoleNanInt64); + base::WriteUnalignedValue<uint64_t>(field_address(offset), kHoleNanInt64); } bool FixedDoubleArray::is_the_hole(Isolate* isolate, int index) { @@ -382,8 +388,14 @@ void FixedDoubleArray::FillWithHoles(int from, int to) { } MaybeObject WeakFixedArray::Get(int index) const { - DCHECK(index >= 0 && index < this->length()); - return RELAXED_READ_WEAK_FIELD(*this, OffsetOfElementAt(index)); + Isolate* isolate = GetIsolateForPtrCompr(*this); + return Get(isolate, index); +} + +MaybeObject WeakFixedArray::Get(Isolate* isolate, int index) const { + DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(length())); + return TaggedField<MaybeObject>::Relaxed_Load(isolate, *this, + OffsetOfElementAt(index)); } void WeakFixedArray::Set(int index, MaybeObject value) { @@ -424,8 +436,14 @@ void WeakFixedArray::CopyElements(Isolate* isolate, int dst_index, } MaybeObject WeakArrayList::Get(int index) const { - DCHECK(index >= 0 && index < this->capacity()); - return RELAXED_READ_WEAK_FIELD(*this, OffsetOfElementAt(index)); + Isolate* isolate = GetIsolateForPtrCompr(*this); + return Get(isolate, index); +} + +MaybeObject WeakArrayList::Get(Isolate* isolate, int index) const { + DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(capacity())); + return TaggedField<MaybeObject>::Relaxed_Load(isolate, *this, + OffsetOfElementAt(index)); } void WeakArrayList::Set(int index, MaybeObject value, WriteBarrierMode mode) { @@ -478,6 +496,10 @@ Object ArrayList::Get(int index) const { return FixedArray::cast(*this).get(kFirstIndex + index); } +Object ArrayList::Get(Isolate* isolate, int index) const { + return FixedArray::cast(*this).get(isolate, kFirstIndex + index); +} + ObjectSlot ArrayList::Slot(int index) { return RawField(OffsetOfElementAt(kFirstIndex + index)); } @@ -538,6 +560,16 @@ void ByteArray::set_uint32(int index, uint32_t value) { WriteField<uint32_t>(kHeaderSize + index * kUInt32Size, value); } +uint32_t ByteArray::get_uint32_relaxed(int index) const { + DCHECK(index >= 0 && index < this->length() / kUInt32Size); + return RELAXED_READ_UINT32_FIELD(*this, kHeaderSize + index * kUInt32Size); +} + +void ByteArray::set_uint32_relaxed(int index, uint32_t value) { + DCHECK(index >= 0 && index < this->length() / kUInt32Size); + RELAXED_WRITE_UINT32_FIELD(*this, kHeaderSize + index * kUInt32Size, value); +} + void ByteArray::clear_padding() { int data_size = length() + kHeaderSize; memset(reinterpret_cast<void*>(address() + data_size), 0, Size() - data_size); @@ -589,6 +621,10 @@ Object TemplateList::get(int index) const { return FixedArray::cast(*this).get(kFirstElementIndex + index); } +Object TemplateList::get(Isolate* isolate, int index) const { + return FixedArray::cast(*this).get(isolate, kFirstElementIndex + index); +} + void TemplateList::set(int index, Object value) { FixedArray::cast(*this).set(kFirstElementIndex + index, value); } diff --git a/chromium/v8/src/objects/fixed-array.h b/chromium/v8/src/objects/fixed-array.h index 02f26502b25..ca6f06e83cd 100644 --- a/chromium/v8/src/objects/fixed-array.h +++ b/chromium/v8/src/objects/fixed-array.h @@ -72,16 +72,15 @@ enum FixedArraySubInstanceType { class FixedArrayBase : public HeapObject { public: // [length]: length of the array. - inline int length() const; - inline void set_length(int value); + DECL_INT_ACCESSORS(length) // Get and set the length using acquire loads and release stores. - inline int synchronized_length() const; - inline void synchronized_set_length(int value); + DECL_SYNCHRONIZED_INT_ACCESSORS(length) inline Object unchecked_synchronized_length() const; DECL_CAST(FixedArrayBase) + DECL_VERIFIER(FixedArrayBase) static int GetMaxLengthForNewSpaceAllocation(ElementsKind kind); @@ -113,6 +112,8 @@ class FixedArray : public FixedArrayBase { public: // Setter and getter for elements. inline Object get(int index) const; + inline Object get(Isolate* isolate, int index) const; + static inline Handle<Object> get(FixedArray array, int index, Isolate* isolate); @@ -267,6 +268,7 @@ class WeakFixedArray : public HeapObject { DECL_CAST(WeakFixedArray) inline MaybeObject Get(int index) const; + inline MaybeObject Get(Isolate* isolate, int index) const; // Setter that uses write barrier. inline void Set(int index, MaybeObject value); @@ -281,8 +283,7 @@ class WeakFixedArray : public HeapObject { DECL_INT_ACCESSORS(length) // Get and set the length using acquire loads and release stores. - inline int synchronized_length() const; - inline void synchronized_set_length(int value); + DECL_SYNCHRONIZED_INT_ACCESSORS(length) // Gives access to raw memory which stores the array's data. inline MaybeObjectSlot data_start(); @@ -336,6 +337,7 @@ class WeakArrayList : public HeapObject { const MaybeObjectHandle& value); inline MaybeObject Get(int index) const; + inline MaybeObject Get(Isolate* isolate, int index) const; // Set the element at index to obj. The underlying array must be large enough. // If you need to grow the WeakArrayList, use the static AddToEnd() method @@ -359,19 +361,12 @@ class WeakArrayList : public HeapObject { DECL_INT_ACCESSORS(length) // Get and set the capacity using acquire loads and release stores. - inline int synchronized_capacity() const; - inline void synchronized_set_capacity(int value); - + DECL_SYNCHRONIZED_INT_ACCESSORS(capacity) // Layout description. -#define WEAK_ARRAY_LIST_FIELDS(V) \ - V(kCapacityOffset, kTaggedSize) \ - V(kLengthOffset, kTaggedSize) \ - /* Header size. */ \ - V(kHeaderSize, 0) - - DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, WEAK_ARRAY_LIST_FIELDS) -#undef WEAK_ARRAY_LIST_FIELDS + DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, + TORQUE_GENERATED_WEAK_ARRAY_LIST_FIELDS) + static constexpr int kHeaderSize = kSize; using BodyDescriptor = WeakArrayBodyDescriptor; @@ -442,6 +437,7 @@ class ArrayList : public FixedArray { // storage capacity, i.e., length(). inline void SetLength(int length); inline Object Get(int index) const; + inline Object Get(Isolate* isolate, int index) const; inline ObjectSlot Slot(int index); // Set the element at index to obj. The underlying array must be large enough. @@ -492,6 +488,9 @@ class ByteArray : public FixedArrayBase { inline uint32_t get_uint32(int index) const; inline void set_uint32(int index, uint32_t value); + inline uint32_t get_uint32_relaxed(int index) const; + inline void set_uint32_relaxed(int index, uint32_t value); + // Clear uninitialized padding space. This ensures that the snapshot content // is deterministic. inline void clear_padding(); @@ -552,9 +551,9 @@ class PodArray : public ByteArray { static Handle<PodArray<T>> New( Isolate* isolate, int length, AllocationType allocation = AllocationType::kYoung); - void copy_out(int index, T* result) { + void copy_out(int index, T* result, int length) { ByteArray::copy_out(index * sizeof(T), reinterpret_cast<byte*>(result), - sizeof(T)); + length * sizeof(T)); } void copy_in(int index, const T* buffer, int length) { @@ -562,9 +561,14 @@ class PodArray : public ByteArray { length * sizeof(T)); } + bool matches(const T* buffer, int length) { + DCHECK_LE(length, this->length()); + return memcmp(GetDataStartAddress(), buffer, length * sizeof(T)) == 0; + } + T get(int index) { T result; - copy_out(index, &result); + copy_out(index, &result, 1); return result; } @@ -581,6 +585,7 @@ class TemplateList : public FixedArray { static Handle<TemplateList> New(Isolate* isolate, int size); inline int length() const; inline Object get(int index) const; + inline Object get(Isolate* isolate, int index) const; inline void set(int index, Object value); static Handle<TemplateList> Add(Isolate* isolate, Handle<TemplateList> list, Handle<Object> value); diff --git a/chromium/v8/src/objects/free-space-inl.h b/chromium/v8/src/objects/free-space-inl.h index bea8257515e..848b8202aec 100644 --- a/chromium/v8/src/objects/free-space-inl.h +++ b/chromium/v8/src/objects/free-space-inl.h @@ -26,29 +26,14 @@ RELAXED_SMI_ACCESSORS(FreeSpace, size, kSizeOffset) int FreeSpace::Size() { return size(); } FreeSpace FreeSpace::next() { -#ifdef DEBUG - Heap* heap = GetHeapFromWritableObject(*this); - Object free_space_map = - Isolate::FromHeap(heap)->root(RootIndex::kFreeSpaceMap); - DCHECK_IMPLIES(!map_slot().contains_value(free_space_map.ptr()), - !heap->deserialization_complete() && - map_slot().contains_value(kNullAddress)); -#endif - DCHECK_LE(kNextOffset + kTaggedSize, relaxed_read_size()); - return FreeSpace::unchecked_cast(*ObjectSlot(address() + kNextOffset)); + DCHECK(IsValid()); + return FreeSpace::unchecked_cast( + TaggedField<Object, kNextOffset>::load(*this)); } void FreeSpace::set_next(FreeSpace next) { -#ifdef DEBUG - Heap* heap = GetHeapFromWritableObject(*this); - Object free_space_map = - Isolate::FromHeap(heap)->root(RootIndex::kFreeSpaceMap); - DCHECK_IMPLIES(!map_slot().contains_value(free_space_map.ptr()), - !heap->deserialization_complete() && - map_slot().contains_value(kNullAddress)); -#endif - DCHECK_LE(kNextOffset + kTaggedSize, relaxed_read_size()); - ObjectSlot(address() + kNextOffset).Relaxed_Store(next); + DCHECK(IsValid()); + RELAXED_WRITE_FIELD(*this, kNextOffset, next); } FreeSpace FreeSpace::cast(HeapObject o) { @@ -61,6 +46,17 @@ FreeSpace FreeSpace::unchecked_cast(const Object o) { return bit_cast<FreeSpace>(o); } +bool FreeSpace::IsValid() { + Heap* heap = GetHeapFromWritableObject(*this); + Object free_space_map = + Isolate::FromHeap(heap)->root(RootIndex::kFreeSpaceMap); + CHECK_IMPLIES(!map_slot().contains_value(free_space_map.ptr()), + !heap->deserialization_complete() && + map_slot().contains_value(kNullAddress)); + CHECK_LE(kNextOffset + kTaggedSize, relaxed_read_size()); + return true; +} + } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/objects/free-space.h b/chromium/v8/src/objects/free-space.h index 38f57946463..57147270369 100644 --- a/chromium/v8/src/objects/free-space.h +++ b/chromium/v8/src/objects/free-space.h @@ -44,6 +44,9 @@ class FreeSpace : public HeapObject { DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, TORQUE_GENERATED_FREE_SPACE_FIELDS) + private: + inline bool IsValid(); + OBJECT_CONSTRUCTORS(FreeSpace, HeapObject); }; diff --git a/chromium/v8/src/objects/hash-table-inl.h b/chromium/v8/src/objects/hash-table-inl.h index 77453721ae2..b807851d85f 100644 --- a/chromium/v8/src/objects/hash-table-inl.h +++ b/chromium/v8/src/objects/hash-table-inl.h @@ -71,14 +71,19 @@ void EphemeronHashTable::set_key(int index, Object value, } int HashTableBase::NumberOfElements() const { - return Smi::ToInt(get(kNumberOfElementsIndex)); + int offset = OffsetOfElementAt(kNumberOfElementsIndex); + return TaggedField<Smi>::load(*this, offset).value(); } int HashTableBase::NumberOfDeletedElements() const { - return Smi::ToInt(get(kNumberOfDeletedElementsIndex)); + int offset = OffsetOfElementAt(kNumberOfDeletedElementsIndex); + return TaggedField<Smi>::load(*this, offset).value(); } -int HashTableBase::Capacity() const { return Smi::ToInt(get(kCapacityIndex)); } +int HashTableBase::Capacity() const { + int offset = OffsetOfElementAt(kCapacityIndex); + return TaggedField<Smi>::load(*this, offset).value(); +} void HashTableBase::ElementAdded() { SetNumberOfElements(NumberOfElements() + 1); @@ -165,6 +170,15 @@ bool HashTable<Derived, Shape>::ToKey(ReadOnlyRoots roots, int entry, } template <typename Derived, typename Shape> +bool HashTable<Derived, Shape>::ToKey(Isolate* isolate, int entry, + Object* out_k) { + Object k = KeyAt(isolate, entry); + if (!IsKey(GetReadOnlyRoots(isolate), k)) return false; + *out_k = Shape::Unwrap(k); + return true; +} + +template <typename Derived, typename Shape> void HashTable<Derived, Shape>::set_key(int index, Object value) { DCHECK(!IsEphemeronHashTable()); FixedArray::set(index, value); diff --git a/chromium/v8/src/objects/hash-table.h b/chromium/v8/src/objects/hash-table.h index 610dc9d28ed..54d8ce0d2ae 100644 --- a/chromium/v8/src/objects/hash-table.h +++ b/chromium/v8/src/objects/hash-table.h @@ -160,9 +160,16 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) HashTable static bool IsKey(ReadOnlyRoots roots, Object k); inline bool ToKey(ReadOnlyRoots roots, int entry, Object* out_k); + inline bool ToKey(Isolate* isolate, int entry, Object* out_k); // Returns the key at entry. - Object KeyAt(int entry) { return get(EntryToIndex(entry) + kEntryKeyIndex); } + Object KeyAt(int entry) { + Isolate* isolate = GetIsolateForPtrCompr(*this); + return KeyAt(isolate, entry); + } + Object KeyAt(Isolate* isolate, int entry) { + return get(isolate, EntryToIndex(entry) + kEntryKeyIndex); + } static const int kElementsStartIndex = kPrefixStartIndex + Shape::kPrefixSize; static const int kEntrySize = Shape::kEntrySize; diff --git a/chromium/v8/src/objects/heap-number-inl.h b/chromium/v8/src/objects/heap-number-inl.h index 3986e9146c7..3d70d71c898 100644 --- a/chromium/v8/src/objects/heap-number-inl.h +++ b/chromium/v8/src/objects/heap-number-inl.h @@ -31,11 +31,11 @@ void HeapNumberBase::set_value(double value) { uint64_t HeapNumberBase::value_as_bits() const { // Bug(v8:8875): HeapNumber's double may be unaligned. - return ReadUnalignedValue<uint64_t>(field_address(kValueOffset)); + return base::ReadUnalignedValue<uint64_t>(field_address(kValueOffset)); } void HeapNumberBase::set_value_as_bits(uint64_t bits) { - WriteUnalignedValue<uint64_t>(field_address(kValueOffset), bits); + base::WriteUnalignedValue<uint64_t>(field_address(kValueOffset), bits); } int HeapNumberBase::get_exponent() { diff --git a/chromium/v8/src/objects/heap-object-inl.h b/chromium/v8/src/objects/heap-object-inl.h index 3d5deeff632..88c0011bdf6 100644 --- a/chromium/v8/src/objects/heap-object-inl.h +++ b/chromium/v8/src/objects/heap-object-inl.h @@ -7,10 +7,6 @@ #include "src/objects/heap-object.h" -#include "src/heap/heap-write-barrier-inl.h" -// TODO(jkummerow): Get rid of this by moving NROSO::GetIsolate elsewhere. -#include "src/execution/isolate.h" - // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -24,16 +20,6 @@ HeapObject::HeapObject(Address ptr, AllowInlineSmiStorage allow_smi) IsHeapObject()); } -// static -Heap* NeverReadOnlySpaceObject::GetHeap(const HeapObject object) { - return GetHeapFromWritableObject(object); -} - -// static -Isolate* NeverReadOnlySpaceObject::GetIsolate(const HeapObject object) { - return Isolate::FromHeap(GetHeap(object)); -} - } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/objects/heap-object.h b/chromium/v8/src/objects/heap-object.h index 9ca51bdda1e..ad5475c9e80 100644 --- a/chromium/v8/src/objects/heap-object.h +++ b/chromium/v8/src/objects/heap-object.h @@ -9,6 +9,7 @@ #include "src/roots/roots.h" #include "src/objects/objects.h" +#include "src/objects/tagged-field.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -22,27 +23,30 @@ class Heap; // objects. class HeapObject : public Object { public: - bool is_null() const { return ptr() == kNullAddress; } + bool is_null() const { + return static_cast<Tagged_t>(ptr()) == static_cast<Tagged_t>(kNullAddress); + } // [map]: Contains a map which contains the object's reflective // information. - inline Map map() const; + DECL_GETTER(map, Map) inline void set_map(Map value); - inline MapWordSlot map_slot() const; + inline ObjectSlot map_slot() const; // The no-write-barrier version. This is OK if the object is white and in // new space, or if the value is an immortal immutable object, like the maps // of primitive (non-JS) objects like strings, heap numbers etc. inline void set_map_no_write_barrier(Map value); - // Get the map using acquire load. - inline Map synchronized_map() const; - inline MapWord synchronized_map_word() const; - - // Set the map using release store + // Access the map using acquire load and release store. + DECL_GETTER(synchronized_map, Map) inline void synchronized_set_map(Map value); - inline void synchronized_set_map_word(MapWord map_word); + + // Compare-and-swaps map word using release store, returns true if the map + // word was actually swapped. + inline bool synchronized_compare_and_swap_map_word(MapWord old_map_word, + MapWord new_map_word); // Initialize the map immediately after the object is allocated. // Do not use this outside Heap. @@ -51,18 +55,29 @@ class HeapObject : public Object { // During garbage collection, the map word of a heap object does not // necessarily contain a map pointer. - inline MapWord map_word() const; + DECL_GETTER(map_word, MapWord) inline void set_map_word(MapWord map_word); + // Access the map word using acquire load and release store. + DECL_GETTER(synchronized_map_word, MapWord) + inline void synchronized_set_map_word(MapWord map_word); + // TODO(v8:7464): Once RO_SPACE is shared between isolates, this method can be // removed as ReadOnlyRoots will be accessible from a global variable. For now // this method exists to help remove GetIsolate/GetHeap from HeapObject, in a // way that doesn't require passing Isolate/Heap down huge call chains or to // places where it might not be safe to access it. inline ReadOnlyRoots GetReadOnlyRoots() const; + // This version is intended to be used for the isolate values produced by + // i::GetIsolateForPtrCompr(HeapObject) function which may return nullptr. + inline ReadOnlyRoots GetReadOnlyRoots(Isolate* isolate) const; -#define IS_TYPE_FUNCTION_DECL(Type) V8_INLINE bool Is##Type() const; +#define IS_TYPE_FUNCTION_DECL(Type) \ + V8_INLINE bool Is##Type() const; \ + V8_INLINE bool Is##Type(Isolate* isolate) const; HEAP_OBJECT_TYPE_LIST(IS_TYPE_FUNCTION_DECL) + IS_TYPE_FUNCTION_DECL(HashTableBase) + IS_TYPE_FUNCTION_DECL(SmallOrderedHashTable) #undef IS_TYPE_FUNCTION_DECL bool IsExternal(Isolate* isolate) const; @@ -74,13 +89,12 @@ class HeapObject : public Object { V8_INLINE bool Is##Type(ReadOnlyRoots roots) const; \ V8_INLINE bool Is##Type() const; ODDBALL_LIST(IS_TYPE_FUNCTION_DECL) + IS_TYPE_FUNCTION_DECL(NullOrUndefined, /* unused */) #undef IS_TYPE_FUNCTION_DECL - V8_INLINE bool IsNullOrUndefined(Isolate* isolate) const; - V8_INLINE bool IsNullOrUndefined(ReadOnlyRoots roots) const; - V8_INLINE bool IsNullOrUndefined() const; - -#define DECL_STRUCT_PREDICATE(NAME, Name, name) V8_INLINE bool Is##Name() const; +#define DECL_STRUCT_PREDICATE(NAME, Name, name) \ + V8_INLINE bool Is##Name() const; \ + V8_INLINE bool Is##Name(Isolate* isolate) const; STRUCT_LIST(DECL_STRUCT_PREDICATE) #undef DECL_STRUCT_PREDICATE @@ -189,6 +203,8 @@ class HeapObject : public Object { STATIC_ASSERT(kMapOffset == Internals::kHeapObjectMapOffset); + using MapField = TaggedField<MapWord, HeapObject::kMapOffset>; + inline Address GetFieldAddress(int field_offset) const; protected: @@ -203,16 +219,6 @@ class HeapObject : public Object { OBJECT_CONSTRUCTORS_IMPL(HeapObject, Object) CAST_ACCESSOR(HeapObject) -// Helper class for objects that can never be in RO space. -class NeverReadOnlySpaceObject { - public: - // The Heap the object was allocated in. Used also to access Isolate. - static inline Heap* GetHeap(const HeapObject object); - - // Convenience method to get current isolate. - static inline Isolate* GetIsolate(const HeapObject object); -}; - } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/objects/instance-type.h b/chromium/v8/src/objects/instance-type.h index 559ed347841..79c953aa872 100644 --- a/chromium/v8/src/objects/instance-type.h +++ b/chromium/v8/src/objects/instance-type.h @@ -11,6 +11,8 @@ // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" +#include "torque-generated/instance-types-tq.h" + namespace v8 { namespace internal { @@ -32,11 +34,16 @@ enum StringRepresentationTag { }; const uint32_t kIsIndirectStringMask = 1 << 0; const uint32_t kIsIndirectStringTag = 1 << 0; +// NOLINTNEXTLINE(runtime/references) (false positive) STATIC_ASSERT((kSeqStringTag & kIsIndirectStringMask) == 0); +// NOLINTNEXTLINE(runtime/references) (false positive) STATIC_ASSERT((kExternalStringTag & kIsIndirectStringMask) == 0); +// NOLINTNEXTLINE(runtime/references) (false positive) STATIC_ASSERT((kConsStringTag & kIsIndirectStringMask) == kIsIndirectStringTag); +// NOLINTNEXTLINE(runtime/references) (false positive) STATIC_ASSERT((kSlicedStringTag & kIsIndirectStringMask) == kIsIndirectStringTag); +// NOLINTNEXTLINE(runtime/references) (false positive) STATIC_ASSERT((kThinStringTag & kIsIndirectStringMask) == kIsIndirectStringTag); // For strings, bit 3 indicates whether the string consists of two-byte @@ -141,6 +148,7 @@ enum InstanceType : uint16_t { ACCESSOR_PAIR_TYPE, ALIASED_ARGUMENTS_ENTRY_TYPE, ALLOCATION_MEMENTO_TYPE, + ARRAY_BOILERPLATE_DESCRIPTION_TYPE, ASM_WASM_DATA_TYPE, ASYNC_GENERATOR_REQUEST_TYPE, CLASS_POSITIONS_TYPE, @@ -150,24 +158,23 @@ enum InstanceType : uint16_t { FUNCTION_TEMPLATE_RARE_DATA_TYPE, INTERCEPTOR_INFO_TYPE, INTERPRETER_DATA_TYPE, - MODULE_INFO_ENTRY_TYPE, - MODULE_TYPE, OBJECT_TEMPLATE_INFO_TYPE, PROMISE_CAPABILITY_TYPE, PROMISE_REACTION_TYPE, PROTOTYPE_INFO_TYPE, SCRIPT_TYPE, SOURCE_POSITION_TABLE_WITH_FRAME_CACHE_TYPE, + SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE, STACK_FRAME_INFO_TYPE, STACK_TRACE_FRAME_TYPE, TEMPLATE_OBJECT_DESCRIPTION_TYPE, TUPLE2_TYPE, TUPLE3_TYPE, - ARRAY_BOILERPLATE_DESCRIPTION_TYPE, WASM_CAPI_FUNCTION_DATA_TYPE, WASM_DEBUG_INFO_TYPE, WASM_EXCEPTION_TAG_TYPE, WASM_EXPORTED_FUNCTION_DATA_TYPE, + WASM_INDIRECT_FUNCTION_TABLE_TYPE, WASM_JS_FUNCTION_DATA_TYPE, CALLABLE_TASK_TYPE, // FIRST_MICROTASK_TYPE @@ -177,6 +184,14 @@ enum InstanceType : uint16_t { PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE, FINALIZATION_GROUP_CLEANUP_JOB_TASK_TYPE, // LAST_MICROTASK_TYPE +#define MAKE_TORQUE_INSTANCE_TYPE(V) V, + TORQUE_DEFINED_INSTANCE_TYPES(MAKE_TORQUE_INSTANCE_TYPE) +#undef MAKE_TORQUE_INSTANCE_TYPE + + // Modules + SOURCE_TEXT_MODULE_TYPE, // FIRST_MODULE_TYPE + SYNTHETIC_MODULE_TYPE, // LAST_MODULE_TYPE + ALLOCATION_SITE_TYPE, EMBEDDER_DATA_ARRAY_TYPE, // FixedArrays. @@ -246,7 +261,7 @@ enum InstanceType : uint16_t { // Like JS_API_OBJECT_TYPE, but requires access checks and/or has // interceptors. JS_SPECIAL_API_OBJECT_TYPE = 0x0410, // LAST_SPECIAL_RECEIVER_TYPE - JS_VALUE_TYPE, // LAST_CUSTOM_ELEMENTS_RECEIVER + JS_PRIMITIVE_WRAPPER_TYPE, // LAST_CUSTOM_ELEMENTS_RECEIVER // Like JS_OBJECT_TYPE, but created from API function. JS_API_OBJECT_TYPE = 0x0420, JS_OBJECT_TYPE, @@ -332,6 +347,9 @@ enum InstanceType : uint16_t { // Boundaries for testing if given HeapObject is a subclass of Microtask. FIRST_MICROTASK_TYPE = CALLABLE_TASK_TYPE, LAST_MICROTASK_TYPE = FINALIZATION_GROUP_CLEANUP_JOB_TASK_TYPE, + // Boundaries of module record types + FIRST_MODULE_TYPE = SOURCE_TEXT_MODULE_TYPE, + LAST_MODULE_TYPE = SYNTHETIC_MODULE_TYPE, // Boundary for promotion to old space. LAST_DATA_TYPE = FILLER_TYPE, // Boundary for objects represented as JSReceiver (i.e. JSObject or JSProxy). @@ -349,7 +367,7 @@ enum InstanceType : uint16_t { // Boundary case for testing JSReceivers that may have elements while having // an empty fixed array as elements backing store. This is true for string // wrappers. - LAST_CUSTOM_ELEMENTS_RECEIVER = JS_VALUE_TYPE, + LAST_CUSTOM_ELEMENTS_RECEIVER = JS_PRIMITIVE_WRAPPER_TYPE, FIRST_SET_ITERATOR_TYPE = JS_SET_KEY_VALUE_ITERATOR_TYPE, LAST_SET_ITERATOR_TYPE = JS_SET_VALUE_ITERATOR_TYPE, @@ -364,6 +382,7 @@ enum InstanceType : uint16_t { constexpr InstanceType LAST_STRING_TYPE = static_cast<InstanceType>(FIRST_NONSTRING_TYPE - 1); +// NOLINTNEXTLINE(runtime/references) (false positive) STATIC_ASSERT((FIRST_NONSTRING_TYPE & kIsNotStringMask) != kStringTag); STATIC_ASSERT(JS_OBJECT_TYPE == Internals::kJSObjectType); STATIC_ASSERT(JS_API_OBJECT_TYPE == Internals::kJSApiObjectType); @@ -420,12 +439,16 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, V(JSDataView, JS_DATA_VIEW_TYPE) \ V(JSDate, JS_DATE_TYPE) \ V(JSError, JS_ERROR_TYPE) \ + V(JSFinalizationGroup, JS_FINALIZATION_GROUP_TYPE) \ + V(JSFinalizationGroupCleanupIterator, \ + JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE) \ V(JSFunction, JS_FUNCTION_TYPE) \ V(JSGlobalObject, JS_GLOBAL_OBJECT_TYPE) \ V(JSGlobalProxy, JS_GLOBAL_PROXY_TYPE) \ V(JSMap, JS_MAP_TYPE) \ V(JSMessageObject, JS_MESSAGE_OBJECT_TYPE) \ V(JSModuleNamespace, JS_MODULE_NAMESPACE_TYPE) \ + V(JSPrimitiveWrapper, JS_PRIMITIVE_WRAPPER_TYPE) \ V(JSPromise, JS_PROMISE_TYPE) \ V(JSProxy, JS_PROXY_TYPE) \ V(JSRegExp, JS_REGEXP_TYPE) \ @@ -434,10 +457,6 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, V(JSSet, JS_SET_TYPE) \ V(JSStringIterator, JS_STRING_ITERATOR_TYPE) \ V(JSTypedArray, JS_TYPED_ARRAY_TYPE) \ - V(JSValue, JS_VALUE_TYPE) \ - V(JSFinalizationGroup, JS_FINALIZATION_GROUP_TYPE) \ - V(JSFinalizationGroupCleanupIterator, \ - JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE) \ V(JSWeakMap, JS_WEAK_MAP_TYPE) \ V(JSWeakRef, JS_WEAK_REF_TYPE) \ V(JSWeakSet, JS_WEAK_SET_TYPE) \ @@ -462,9 +481,11 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, V(SmallOrderedHashMap, SMALL_ORDERED_HASH_MAP_TYPE) \ V(SmallOrderedHashSet, SMALL_ORDERED_HASH_SET_TYPE) \ V(SmallOrderedNameDictionary, SMALL_ORDERED_NAME_DICTIONARY_TYPE) \ + V(SourceTextModule, SOURCE_TEXT_MODULE_TYPE) \ V(StoreHandler, STORE_HANDLER_TYPE) \ V(StringTable, STRING_TABLE_TYPE) \ V(Symbol, SYMBOL_TYPE) \ + V(SyntheticModule, SYNTHETIC_MODULE_TYPE) \ V(TransitionArray, TRANSITION_ARRAY_TYPE) \ V(UncompiledDataWithoutPreparseData, \ UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE) \ @@ -505,6 +526,7 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, V(JSMapIterator, FIRST_MAP_ITERATOR_TYPE, LAST_MAP_ITERATOR_TYPE) \ V(JSSetIterator, FIRST_SET_ITERATOR_TYPE, LAST_SET_ITERATOR_TYPE) \ V(Microtask, FIRST_MICROTASK_TYPE, LAST_MICROTASK_TYPE) \ + V(Module, FIRST_MODULE_TYPE, LAST_MODULE_TYPE) \ V(Name, FIRST_NAME_TYPE, LAST_NAME_TYPE) \ V(String, FIRST_STRING_TYPE, LAST_STRING_TYPE) \ V(WeakFixedArray, FIRST_WEAK_FIXED_ARRAY_TYPE, LAST_WEAK_FIXED_ARRAY_TYPE) diff --git a/chromium/v8/src/objects/intl-objects.cc b/chromium/v8/src/objects/intl-objects.cc index f2bc87ebacc..dbf212aaf82 100644 --- a/chromium/v8/src/objects/intl-objects.cc +++ b/chromium/v8/src/objects/intl-objects.cc @@ -34,9 +34,11 @@ #include "unicode/formattedvalue.h" #include "unicode/locid.h" #include "unicode/normalizer2.h" +#include "unicode/numberformatter.h" #include "unicode/numfmt.h" #include "unicode/numsys.h" #include "unicode/timezone.h" +#include "unicode/ures.h" #include "unicode/ustring.h" #include "unicode/uvernum.h" // U_ICU_VERSION_MAJOR_NUM @@ -52,9 +54,8 @@ namespace v8 { namespace internal { namespace { -inline bool IsASCIIUpper(uint16_t ch) { return ch >= 'A' && ch <= 'Z'; } -const uint8_t kToLower[256] = { +constexpr uint8_t kToLower[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, @@ -79,20 +80,17 @@ const uint8_t kToLower[256] = { 0xFC, 0xFD, 0xFE, 0xFF, }; -inline uint16_t ToLatin1Lower(uint16_t ch) { +inline constexpr uint16_t ToLatin1Lower(uint16_t ch) { return static_cast<uint16_t>(kToLower[ch]); } -inline uint16_t ToASCIIUpper(uint16_t ch) { - return ch & ~((ch >= 'a' && ch <= 'z') << 5); -} - // Does not work for U+00DF (sharp-s), U+00B5 (micron), U+00FF. -inline uint16_t ToLatin1Upper(uint16_t ch) { +inline constexpr uint16_t ToLatin1Upper(uint16_t ch) { +#if V8_CAN_HAVE_DCHECK_IN_CONSTEXPR DCHECK(ch != 0xDF && ch != 0xB5 && ch != 0xFF); +#endif return ch & - ~(((ch >= 'a' && ch <= 'z') || (((ch & 0xE0) == 0xE0) && ch != 0xF7)) - << 5); + ~((IsAsciiLower(ch) || (((ch & 0xE0) == 0xE0) && ch != 0xF7)) << 5); } template <typename Char> @@ -104,7 +102,7 @@ bool ToUpperFastASCII(const Vector<const Char>& src, for (auto it = src.begin(); it != src.end(); ++it) { uint16_t ch = static_cast<uint16_t>(*it); ored |= ch; - result->SeqOneByteStringSet(index++, ToASCIIUpper(ch)); + result->SeqOneByteStringSet(index++, ToAsciiUpper(ch)); } return !(ored & ~0x7F); } @@ -155,7 +153,7 @@ void ToUpperWithSharpS(const Vector<const Char>& src, inline int FindFirstUpperOrNonAscii(String s, int length) { for (int index = 0; index < length; ++index) { uint16_t ch = s.Get(index); - if (V8_UNLIKELY(IsASCIIUpper(ch) || ch & ~0x7F)) { + if (V8_UNLIKELY(IsAsciiUpper(ch) || ch & ~0x7F)) { return index; } } @@ -180,12 +178,11 @@ const UChar* GetUCharBufferFromFlat(const String::FlatContent& flat, template <typename T> MaybeHandle<T> New(Isolate* isolate, Handle<JSFunction> constructor, Handle<Object> locales, Handle<Object> options) { - Handle<JSObject> result; + Handle<Map> map; ASSIGN_RETURN_ON_EXCEPTION( - isolate, result, - JSObject::New(constructor, constructor, Handle<AllocationSite>::null()), - T); - return T::Initialize(isolate, Handle<T>::cast(result), locales, options); + isolate, map, + JSFunction::GetDerivedMap(isolate, constructor, constructor), T); + return T::New(isolate, map, locales, options); } } // namespace @@ -212,6 +209,24 @@ icu::UnicodeString Intl::ToICUUnicodeString(Isolate* isolate, return icu::UnicodeString(uchar_buffer, length); } +icu::StringPiece Intl::ToICUStringPiece(Isolate* isolate, + Handle<String> string) { + DCHECK(string->IsFlat()); + DisallowHeapAllocation no_gc; + + const String::FlatContent& flat = string->GetFlatContent(no_gc); + if (!flat.IsOneByte()) return icu::StringPiece(nullptr, 0); + + int32_t length = string->length(); + const char* char_buffer = + reinterpret_cast<const char*>(flat.ToOneByteVector().begin()); + if (!String::IsAscii(char_buffer, length)) { + return icu::StringPiece(nullptr, 0); + } + + return icu::StringPiece(char_buffer, length); +} + namespace { MaybeHandle<String> LocaleConvertCase(Isolate* isolate, Handle<String> s, bool is_to_upper, const char* lang) { @@ -506,23 +521,59 @@ bool RemoveLocaleScriptTag(const std::string& icu_locale, return true; } +bool ValidateResource(const icu::Locale locale, const char* path, + const char* key) { + bool result = false; + UErrorCode status = U_ZERO_ERROR; + UResourceBundle* bundle = ures_open(path, locale.getName(), &status); + if (bundle != nullptr && status == U_ZERO_ERROR) { + if (key == nullptr) { + result = true; + } else { + UResourceBundle* key_bundle = + ures_getByKey(bundle, key, nullptr, &status); + result = key_bundle != nullptr && (status == U_ZERO_ERROR); + ures_close(key_bundle); + } + } + ures_close(bundle); + if (!result) { + if ((locale.getCountry()[0] != '\0') && (locale.getScript()[0] != '\0')) { + // Fallback to try without country. + std::string without_country(locale.getLanguage()); + without_country = without_country.append("-").append(locale.getScript()); + return ValidateResource(without_country.c_str(), path, key); + } else if ((locale.getCountry()[0] != '\0') || + (locale.getScript()[0] != '\0')) { + // Fallback to try with only language. + std::string language(locale.getLanguage()); + return ValidateResource(language.c_str(), path, key); + } + } + return result; +} + } // namespace std::set<std::string> Intl::BuildLocaleSet( - const icu::Locale* icu_available_locales, int32_t count) { + const icu::Locale* icu_available_locales, int32_t count, const char* path, + const char* validate_key) { std::set<std::string> locales; for (int32_t i = 0; i < count; ++i) { std::string locale = Intl::ToLanguageTag(icu_available_locales[i]).FromJust(); + if (path != nullptr || validate_key != nullptr) { + if (!ValidateResource(icu_available_locales[i], path, validate_key)) { + continue; + } + } locales.insert(locale); - std::string shortened_locale; if (RemoveLocaleScriptTag(locale, &shortened_locale)) { std::replace(shortened_locale.begin(), shortened_locale.end(), '_', '-'); locales.insert(shortened_locale); } } - return locales; } @@ -683,19 +734,10 @@ V8_WARN_UNUSED_RESULT Maybe<bool> Intl::GetBoolOption( namespace { -char AsciiToLower(char c) { - if (c < 'A' || c > 'Z') { - return c; - } - return c | (1 << 5); -} - -bool IsLowerAscii(char c) { return c >= 'a' && c < 'z'; } - bool IsTwoLetterLanguage(const std::string& locale) { // Two letters, both in range 'a'-'z'... - return locale.length() == 2 && IsLowerAscii(locale[0]) && - IsLowerAscii(locale[1]); + return locale.length() == 2 && IsAsciiLower(locale[0]) && + IsAsciiLower(locale[1]); } bool IsDeprecatedLanguage(const std::string& locale) { @@ -770,7 +812,7 @@ Maybe<std::string> Intl::CanonicalizeLanguageTag(Isolate* isolate, // Because per BCP 47 2.1.1 language tags are case-insensitive, lowercase // the input before any more check. - std::transform(locale.begin(), locale.end(), locale.begin(), AsciiToLower); + std::transform(locale.begin(), locale.end(), locale.begin(), ToAsciiLower); // ICU maps a few grandfathered tags to what looks like a regular language // tag even though IANA language tag registry does not have a preferred @@ -1020,6 +1062,16 @@ Handle<Object> Intl::CompareStrings(Isolate* isolate, UCollationResult result; UErrorCode status = U_ZERO_ERROR; + icu::StringPiece string_piece1 = Intl::ToICUStringPiece(isolate, string1); + if (!string_piece1.empty()) { + icu::StringPiece string_piece2 = Intl::ToICUStringPiece(isolate, string2); + if (!string_piece2.empty()) { + result = icu_collator.compareUTF8(string_piece1, string_piece2, status); + DCHECK(U_SUCCESS(status)); + return factory->NewNumberFromInt(result); + } + } + icu::UnicodeString string_val1 = Intl::ToICUUnicodeString(isolate, string1); icu::UnicodeString string_val2 = Intl::ToICUUnicodeString(isolate, string2); result = icu_collator.compare(string_val1, string_val2, status); @@ -1116,10 +1168,12 @@ Maybe<int> DefaultNumberOption(Isolate* isolate, Handle<Object> value, int min, return Just(FastD2I(floor(value_num->Number()))); } +} // namespace + // ecma402/#sec-getnumberoption -Maybe<int> GetNumberOption(Isolate* isolate, Handle<JSReceiver> options, - Handle<String> property, int min, int max, - int fallback) { +Maybe<int> Intl::GetNumberOption(Isolate* isolate, Handle<JSReceiver> options, + Handle<String> property, int min, int max, + int fallback) { // 1. Let value be ? Get(options, property). Handle<Object> value; ASSIGN_RETURN_ON_EXCEPTION_VALUE( @@ -1130,62 +1184,70 @@ Maybe<int> GetNumberOption(Isolate* isolate, Handle<JSReceiver> options, return DefaultNumberOption(isolate, value, min, max, fallback, property); } -Maybe<int> GetNumberOption(Isolate* isolate, Handle<JSReceiver> options, - const char* property, int min, int max, - int fallback) { - Handle<String> property_str = - isolate->factory()->NewStringFromAsciiChecked(property); - return GetNumberOption(isolate, options, property_str, min, max, fallback); -} - -} // namespace - Maybe<Intl::NumberFormatDigitOptions> Intl::SetNumberFormatDigitOptions( Isolate* isolate, Handle<JSReceiver> options, int mnfd_default, - int mxfd_default) { + int mxfd_default, bool notation_is_compact) { + Factory* factory = isolate->factory(); Intl::NumberFormatDigitOptions digit_options; // 5. Let mnid be ? GetNumberOption(options, "minimumIntegerDigits,", 1, 21, // 1). - int mnid; - if (!GetNumberOption(isolate, options, "minimumIntegerDigits", 1, 21, 1) + int mnid = 1; + if (!Intl::GetNumberOption(isolate, options, + factory->minimumIntegerDigits_string(), 1, 21, 1) .To(&mnid)) { return Nothing<NumberFormatDigitOptions>(); } - // 6. Let mnfd be ? GetNumberOption(options, "minimumFractionDigits", 0, 20, - // mnfdDefault). - int mnfd; - if (!GetNumberOption(isolate, options, "minimumFractionDigits", 0, 20, - mnfd_default) - .To(&mnfd)) { - return Nothing<NumberFormatDigitOptions>(); - } + int mnfd = 0; + int mxfd = 0; + Handle<Object> mnfd_obj; + Handle<Object> mxfd_obj; + if (FLAG_harmony_intl_numberformat_unified) { + // 6. Let mnfd be ? Get(options, "minimumFractionDigits"). + Handle<String> mnfd_str = factory->minimumFractionDigits_string(); + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + isolate, mnfd_obj, JSReceiver::GetProperty(isolate, options, mnfd_str), + Nothing<NumberFormatDigitOptions>()); + + // 8. Let mnfd be ? Get(options, "maximumFractionDigits"). + Handle<String> mxfd_str = factory->maximumFractionDigits_string(); + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + isolate, mxfd_obj, JSReceiver::GetProperty(isolate, options, mxfd_str), + Nothing<NumberFormatDigitOptions>()); + } else { + // 6. Let mnfd be ? GetNumberOption(options, "minimumFractionDigits", 0, 20, + // mnfdDefault). + if (!Intl::GetNumberOption(isolate, options, + factory->minimumFractionDigits_string(), 0, 20, + mnfd_default) + .To(&mnfd)) { + return Nothing<NumberFormatDigitOptions>(); + } - // 7. Let mxfdActualDefault be max( mnfd, mxfdDefault ). - int mxfd_actual_default = std::max(mnfd, mxfd_default); + // 7. Let mxfdActualDefault be max( mnfd, mxfdDefault ). + int mxfd_actual_default = std::max(mnfd, mxfd_default); - // 8. Let mxfd be ? GetNumberOption(options, - // "maximumFractionDigits", mnfd, 20, mxfdActualDefault). - int mxfd; - if (!GetNumberOption(isolate, options, "maximumFractionDigits", mnfd, 20, - mxfd_actual_default) - .To(&mxfd)) { - return Nothing<NumberFormatDigitOptions>(); + // 8. Let mxfd be ? GetNumberOption(options, + // "maximumFractionDigits", mnfd, 20, mxfdActualDefault). + if (!Intl::GetNumberOption(isolate, options, + factory->maximumFractionDigits_string(), mnfd, + 20, mxfd_actual_default) + .To(&mxfd)) { + return Nothing<NumberFormatDigitOptions>(); + } } // 9. Let mnsd be ? Get(options, "minimumSignificantDigits"). Handle<Object> mnsd_obj; - Handle<String> mnsd_str = - isolate->factory()->minimumSignificantDigits_string(); + Handle<String> mnsd_str = factory->minimumSignificantDigits_string(); ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, mnsd_obj, JSReceiver::GetProperty(isolate, options, mnsd_str), Nothing<NumberFormatDigitOptions>()); // 10. Let mxsd be ? Get(options, "maximumSignificantDigits"). Handle<Object> mxsd_obj; - Handle<String> mxsd_str = - isolate->factory()->maximumSignificantDigits_string(); + Handle<String> mxsd_str = factory->maximumSignificantDigits_string(); ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, mxsd_obj, JSReceiver::GetProperty(isolate, options, mxsd_str), Nothing<NumberFormatDigitOptions>()); @@ -1222,8 +1284,50 @@ Maybe<Intl::NumberFormatDigitOptions> Intl::SetNumberFormatDigitOptions( } else { digit_options.minimum_significant_digits = 0; digit_options.maximum_significant_digits = 0; - } + if (FLAG_harmony_intl_numberformat_unified) { + // 15. Else If mnfd is not undefined or mxfd is not undefined, then + if (!mnfd_obj->IsUndefined(isolate) || !mxfd_obj->IsUndefined(isolate)) { + // 15. b. Let mnfd be ? DefaultNumberOption(mnfd, 0, 20, mnfdDefault). + Handle<String> mnfd_str = factory->minimumFractionDigits_string(); + if (!DefaultNumberOption(isolate, mnfd_obj, 0, 20, mnfd_default, + mnfd_str) + .To(&mnfd)) { + return Nothing<NumberFormatDigitOptions>(); + } + + // 15. c. Let mxfdActualDefault be max( mnfd, mxfdDefault ). + int mxfd_actual_default = std::max(mnfd, mxfd_default); + + // 15. d. Let mxfd be ? DefaultNumberOption(mxfd, mnfd, 20, + // mxfdActualDefault). + Handle<String> mxfd_str = factory->maximumFractionDigits_string(); + if (!DefaultNumberOption(isolate, mxfd_obj, mnfd, 20, + mxfd_actual_default, mxfd_str) + .To(&mxfd)) { + return Nothing<NumberFormatDigitOptions>(); + } + // 15. e. Set intlObj.[[MinimumFractionDigits]] to mnfd. + digit_options.minimum_fraction_digits = mnfd; + + // 15. f. Set intlObj.[[MaximumFractionDigits]] to mxfd. + digit_options.maximum_fraction_digits = mxfd; + // Else If intlObj.[[Notation]] is "compact", then + } else if (notation_is_compact) { + // a. Set intlObj.[[RoundingType]] to "compact-rounding". + // Set minimum_significant_digits to -1 to represent roundingtype is + // "compact-rounding". + digit_options.minimum_significant_digits = -1; + // 17. Else, + } else { + // 17. b. Set intlObj.[[MinimumFractionDigits]] to mnfdDefault. + digit_options.minimum_fraction_digits = mnfd_default; + + // 17. c. Set intlObj.[[MaximumFractionDigits]] to mxfdDefault. + digit_options.maximum_fraction_digits = mxfd_default; + } + } + } return Just(digit_options); } @@ -1678,7 +1782,7 @@ Intl::ResolvedLocale Intl::ResolveLocale( return Intl::ResolvedLocale{canonicalized_locale, icu_locale, extensions}; } -Managed<icu::UnicodeString> Intl::SetTextToBreakIterator( +Handle<Managed<icu::UnicodeString>> Intl::SetTextToBreakIterator( Isolate* isolate, Handle<String> text, icu::BreakIterator* break_iterator) { text = String::Flatten(isolate, text); icu::UnicodeString* u_text = @@ -1688,7 +1792,7 @@ Managed<icu::UnicodeString> Intl::SetTextToBreakIterator( Managed<icu::UnicodeString>::FromRawPtr(isolate, 0, u_text); break_iterator->setText(*u_text); - return *new_u_text; + return new_u_text; } // ecma262 #sec-string.prototype.normalize @@ -1927,8 +2031,18 @@ const std::set<std::string>& Intl::GetAvailableLocalesForLocale() { return available_locales.Pointer()->Get(); } +namespace { + +struct CheckCalendar { + static const char* key() { return "calendar"; } + static const char* path() { return nullptr; } +}; + +} // namespace + const std::set<std::string>& Intl::GetAvailableLocalesForDateFormat() { - static base::LazyInstance<Intl::AvailableLocales<icu::DateFormat>>::type + static base::LazyInstance< + Intl::AvailableLocales<icu::DateFormat, CheckCalendar>>::type available_locales = LAZY_INSTANCE_INITIALIZER; return available_locales.Pointer()->Get(); } @@ -1966,16 +2080,17 @@ Handle<String> Intl::NumberFieldToType(Isolate* isolate, : isolate->factory()->plusSign_string(); } else { double number = numeric_obj->Number(); - return number < 0 ? isolate->factory()->minusSign_string() - : isolate->factory()->plusSign_string(); + return std::signbit(number) ? isolate->factory()->minusSign_string() + : isolate->factory()->plusSign_string(); } case UNUM_EXPONENT_SYMBOL_FIELD: + return isolate->factory()->exponentSeparator_string(); + case UNUM_EXPONENT_SIGN_FIELD: + return isolate->factory()->exponentMinusSign_string(); + case UNUM_EXPONENT_FIELD: - // We should never get these because we're not using any scientific - // formatter. - UNREACHABLE(); - return Handle<String>(); + return isolate->factory()->exponentInteger_string(); case UNUM_PERMILL_FIELD: // We're not creating any permill formatter, and it's not even clear how diff --git a/chromium/v8/src/objects/intl-objects.h b/chromium/v8/src/objects/intl-objects.h index 1274fa05495..4d4d3245fd3 100644 --- a/chromium/v8/src/objects/intl-objects.h +++ b/chromium/v8/src/objects/intl-objects.h @@ -49,7 +49,8 @@ class Intl { // script; eg, pa_Guru_IN (language=Panjabi, script=Gurmukhi, country-India) // would include pa_IN. static std::set<std::string> BuildLocaleSet( - const icu::Locale* icu_available_locales, int32_t count); + const icu::Locale* icu_available_locales, int32_t count, const char* path, + const char* validate_key); static Maybe<std::string> ToLanguageTag(const icu::Locale& locale); @@ -126,6 +127,10 @@ class Intl { Isolate* isolate, Handle<JSReceiver> options, const char* property, const char* service, bool* result); + V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static Maybe<int> GetNumberOption( + Isolate* isolate, Handle<JSReceiver> options, Handle<String> property, + int min, int max, int fallback); + // Canonicalize the locale. // https://tc39.github.io/ecma402/#sec-canonicalizelanguagetag, // including type check and structural validity check. @@ -180,7 +185,8 @@ class Intl { }; V8_WARN_UNUSED_RESULT static Maybe<NumberFormatDigitOptions> SetNumberFormatDigitOptions(Isolate* isolate, Handle<JSReceiver> options, - int mnfd_default, int mxfd_default); + int mnfd_default, int mxfd_default, + bool notation_is_compact); static icu::Locale CreateICULocale(const std::string& bcp47_locale); @@ -277,20 +283,26 @@ class Intl { // A helper template to implement the GetAvailableLocales // Usage in src/objects/js-XXX.cc - // // const std::set<std::string>& JSXxx::GetAvailableLocales() { // static base::LazyInstance<Intl::AvailableLocales<icu::YYY>>::type // available_locales = LAZY_INSTANCE_INITIALIZER; // return available_locales.Pointer()->Get(); // } - template <typename T> + + struct SkipResourceCheck { + static const char* key() { return nullptr; } + static const char* path() { return nullptr; } + }; + + template <typename T, typename C = SkipResourceCheck> class AvailableLocales { public: AvailableLocales() { int32_t num_locales = 0; const icu::Locale* icu_available_locales = T::getAvailableLocales(num_locales); - set = Intl::BuildLocaleSet(icu_available_locales, num_locales); + set = Intl::BuildLocaleSet(icu_available_locales, num_locales, C::path(), + C::key()); } virtual ~AvailableLocales() {} const std::set<std::string>& Get() const { return set; } @@ -300,7 +312,7 @@ class Intl { }; // Utility function to set text to BreakIterator. - static Managed<icu::UnicodeString> SetTextToBreakIterator( + static Handle<Managed<icu::UnicodeString>> SetTextToBreakIterator( Isolate* isolate, Handle<String> text, icu::BreakIterator* break_iterator); @@ -313,6 +325,10 @@ class Intl { static icu::UnicodeString ToICUUnicodeString(Isolate* isolate, Handle<String> string); + // Convert a Handle<String> to icu::StringPiece + static icu::StringPiece ToICUStringPiece(Isolate* isolate, + Handle<String> string); + static const uint8_t* ToLatin1LowerTable(); static String ConvertOneByteToLower(String src, String dst); diff --git a/chromium/v8/src/objects/intl-objects.tq b/chromium/v8/src/objects/intl-objects.tq index 67d8537feb0..d91df566c35 100644 --- a/chromium/v8/src/objects/intl-objects.tq +++ b/chromium/v8/src/objects/intl-objects.tq @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include 'src/objects/js-break-iterator.h' +#include 'src/objects/js-collator.h' #include 'src/objects/js-number-format.h' #include 'src/objects/js-objects.h' #include 'src/objects/js-plural-rules.h' @@ -37,8 +39,9 @@ extern class JSNumberFormat extends JSObject { extern class JSPluralRules extends JSObject { locale: String; flags: Smi; - icu_plural_rules: Foreign; // Managed<icu::PluralRules> - icu_decimal_format: Foreign; // Managed<icu::DecimalFormat> + icu_plural_rules: Foreign; // Managed<icu::PluralRules> + icu_number_formatter: + Foreign; // Managed<icu::number::LocalizedNumberFormatter> } extern class JSRelativeTimeFormat extends JSObject { @@ -62,3 +65,20 @@ extern class JSSegmentIterator extends JSObject { unicode_string: Foreign; // Managed<icu::UnicodeString> flags: Smi; } + +extern class JSV8BreakIterator extends JSObject { + locale: String; + break_iterator: Foreign; // Managed<icu::BreakIterator>; + unicode_string: Foreign; // Managed<icu::UnicodeString>; + bound_adopt_text: Undefined | JSFunction; + bound_first: Undefined | JSFunction; + bound_next: Undefined | JSFunction; + bound_current: Undefined | JSFunction; + bound_break_type: Undefined | JSFunction; + break_iterator_type: Smi; +} + +extern class JSCollator extends JSObject { + icu_collator: Foreign; // Managed<icu::Collator> + bound_compare: Undefined | JSFunction; +} diff --git a/chromium/v8/src/objects/js-array-buffer-inl.h b/chromium/v8/src/objects/js-array-buffer-inl.h index 061fec10f74..9151be6da49 100644 --- a/chromium/v8/src/objects/js-array-buffer-inl.h +++ b/chromium/v8/src/objects/js-array-buffer-inl.h @@ -91,11 +91,11 @@ void JSArrayBuffer::clear_padding() { } void JSArrayBuffer::set_bit_field(uint32_t bits) { - WriteField<uint32_t>(kBitFieldOffset, bits); + RELAXED_WRITE_UINT32_FIELD(*this, kBitFieldOffset, bits); } uint32_t JSArrayBuffer::bit_field() const { - return ReadField<uint32_t>(kBitFieldOffset); + return RELAXED_READ_UINT32_FIELD(*this, kBitFieldOffset); } // |bit_field| fields. diff --git a/chromium/v8/src/objects/js-array-buffer.h b/chromium/v8/src/objects/js-array-buffer.h index b22001f04a1..7bf2e1ae94b 100644 --- a/chromium/v8/src/objects/js-array-buffer.h +++ b/chromium/v8/src/objects/js-array-buffer.h @@ -243,6 +243,12 @@ class JSTypedArray : public JSArrayBufferView { class BodyDescriptor; +#ifdef V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP + static constexpr size_t kMaxSizeInHeap = V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP; +#else + static constexpr size_t kMaxSizeInHeap = 64; +#endif + private: static Handle<JSArrayBuffer> MaterializeArrayBuffer( Handle<JSTypedArray> typed_array); diff --git a/chromium/v8/src/objects/js-array-inl.h b/chromium/v8/src/objects/js-array-inl.h index 335fabba865..1ff7dcb123c 100644 --- a/chromium/v8/src/objects/js-array-inl.h +++ b/chromium/v8/src/objects/js-array-inl.h @@ -61,13 +61,14 @@ bool JSArray::HasArrayPrototype(Isolate* isolate) { ACCESSORS(JSArrayIterator, iterated_object, Object, kIteratedObjectOffset) ACCESSORS(JSArrayIterator, next_index, Object, kNextIndexOffset) +SMI_ACCESSORS(JSArrayIterator, raw_kind, kKindOffset) + IterationKind JSArrayIterator::kind() const { - return static_cast<IterationKind>( - Smi::cast(READ_FIELD(*this, kKindOffset)).value()); + return static_cast<IterationKind>(raw_kind()); } void JSArrayIterator::set_kind(IterationKind kind) { - WRITE_FIELD(*this, kKindOffset, Smi::FromInt(static_cast<int>(kind))); + set_raw_kind(static_cast<int>(kind)); } } // namespace internal diff --git a/chromium/v8/src/objects/js-array.h b/chromium/v8/src/objects/js-array.h index 4bc296e31e1..eb581c104e0 100644 --- a/chromium/v8/src/objects/js-array.h +++ b/chromium/v8/src/objects/js-array.h @@ -132,7 +132,8 @@ class JSArray : public JSObject { OBJECT_CONSTRUCTORS(JSArray, JSObject); }; -Handle<Object> CacheInitialJSArrayMaps(Handle<Context> native_context, +Handle<Object> CacheInitialJSArrayMaps(Isolate* isolate, + Handle<Context> native_context, Handle<Map> initial_map); // The JSArrayIterator describes JavaScript Array Iterators Objects, as @@ -179,6 +180,9 @@ class JSArrayIterator : public JSObject { DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, TORQUE_GENERATED_JSARRAY_ITERATOR_FIELDS) + private: + DECL_INT_ACCESSORS(raw_kind) + OBJECT_CONSTRUCTORS(JSArrayIterator, JSObject); }; diff --git a/chromium/v8/src/objects/js-break-iterator-inl.h b/chromium/v8/src/objects/js-break-iterator-inl.h index 177d9d352b9..86e87ddb0dc 100644 --- a/chromium/v8/src/objects/js-break-iterator-inl.h +++ b/chromium/v8/src/objects/js-break-iterator-inl.h @@ -20,14 +20,12 @@ namespace internal { OBJECT_CONSTRUCTORS_IMPL(JSV8BreakIterator, JSObject) -inline void JSV8BreakIterator::set_type(Type type) { - DCHECK_GT(JSV8BreakIterator::Type::COUNT, type); - WRITE_FIELD(*this, kTypeOffset, Smi::FromInt(static_cast<int>(type))); +inline JSV8BreakIterator::Type JSV8BreakIterator::type() const { + return static_cast<JSV8BreakIterator::Type>(raw_type()); } -inline JSV8BreakIterator::Type JSV8BreakIterator::type() const { - Object value = READ_FIELD(*this, kTypeOffset); - return static_cast<JSV8BreakIterator::Type>(Smi::ToInt(value)); +inline void JSV8BreakIterator::set_type(Type type) { + set_raw_type(static_cast<int>(type)); } ACCESSORS(JSV8BreakIterator, locale, String, kLocaleOffset) @@ -41,6 +39,8 @@ ACCESSORS(JSV8BreakIterator, bound_next, Object, kBoundNextOffset) ACCESSORS(JSV8BreakIterator, bound_current, Object, kBoundCurrentOffset) ACCESSORS(JSV8BreakIterator, bound_break_type, Object, kBoundBreakTypeOffset) +SMI_ACCESSORS(JSV8BreakIterator, raw_type, kBreakIteratorTypeOffset) + CAST_ACCESSOR(JSV8BreakIterator) } // namespace internal diff --git a/chromium/v8/src/objects/js-break-iterator.cc b/chromium/v8/src/objects/js-break-iterator.cc index 4879fb41a4c..31ed3f86117 100644 --- a/chromium/v8/src/objects/js-break-iterator.cc +++ b/chromium/v8/src/objects/js-break-iterator.cc @@ -15,9 +15,9 @@ namespace v8 { namespace internal { -MaybeHandle<JSV8BreakIterator> JSV8BreakIterator::Initialize( - Isolate* isolate, Handle<JSV8BreakIterator> break_iterator_holder, - Handle<Object> locales, Handle<Object> options_obj) { +MaybeHandle<JSV8BreakIterator> JSV8BreakIterator::New( + Isolate* isolate, Handle<Map> map, Handle<Object> locales, + Handle<Object> options_obj) { Factory* factory = isolate->factory(); // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales). @@ -96,8 +96,13 @@ MaybeHandle<JSV8BreakIterator> JSV8BreakIterator::Initialize( Handle<String> locale_str = isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str()); - break_iterator_holder->set_locale(*locale_str); + // Now all properties are ready, so we can allocate the result object. + Handle<JSV8BreakIterator> break_iterator_holder = + Handle<JSV8BreakIterator>::cast( + isolate->factory()->NewFastOrSlowJSObjectFromMap(map)); + DisallowHeapAllocation no_gc; + break_iterator_holder->set_locale(*locale_str); break_iterator_holder->set_type(type_enum); break_iterator_holder->set_break_iterator(*managed_break_iterator); break_iterator_holder->set_unicode_string(*managed_unicode_string); @@ -126,9 +131,9 @@ void JSV8BreakIterator::AdoptText( icu::BreakIterator* break_iterator = break_iterator_holder->break_iterator().raw(); CHECK_NOT_NULL(break_iterator); - Managed<icu::UnicodeString> unicode_string = + Handle<Managed<icu::UnicodeString>> unicode_string = Intl::SetTextToBreakIterator(isolate, text, break_iterator); - break_iterator_holder->set_unicode_string(unicode_string); + break_iterator_holder->set_unicode_string(*unicode_string); } Handle<String> JSV8BreakIterator::TypeAsString() const { @@ -141,9 +146,8 @@ Handle<String> JSV8BreakIterator::TypeAsString() const { return GetReadOnlyRoots().sentence_string_handle(); case Type::LINE: return GetReadOnlyRoots().line_string_handle(); - case Type::COUNT: - UNREACHABLE(); } + UNREACHABLE(); } Handle<Object> JSV8BreakIterator::Current( diff --git a/chromium/v8/src/objects/js-break-iterator.h b/chromium/v8/src/objects/js-break-iterator.h index fe94c177c4a..4b40192c813 100644 --- a/chromium/v8/src/objects/js-break-iterator.h +++ b/chromium/v8/src/objects/js-break-iterator.h @@ -15,6 +15,7 @@ #include "src/objects/intl-objects.h" #include "src/objects/managed.h" #include "src/objects/objects.h" +#include "torque-generated/field-offsets-tq.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -28,9 +29,9 @@ namespace internal { class JSV8BreakIterator : public JSObject { public: - V8_WARN_UNUSED_RESULT static MaybeHandle<JSV8BreakIterator> Initialize( - Isolate* isolate, Handle<JSV8BreakIterator> break_iterator, - Handle<Object> input_locales, Handle<Object> input_options); + V8_WARN_UNUSED_RESULT static MaybeHandle<JSV8BreakIterator> New( + Isolate* isolate, Handle<Map> map, Handle<Object> input_locales, + Handle<Object> input_options); static Handle<JSObject> ResolvedOptions( Isolate* isolate, Handle<JSV8BreakIterator> break_iterator); @@ -50,7 +51,7 @@ class JSV8BreakIterator : public JSObject { static String BreakType(Isolate* isolate, Handle<JSV8BreakIterator> break_iterator); - enum class Type { CHARACTER, WORD, SENTENCE, LINE, COUNT }; + enum class Type { CHARACTER, WORD, SENTENCE, LINE }; inline void set_type(Type type); inline Type type() const; @@ -69,23 +70,12 @@ class JSV8BreakIterator : public JSObject { DECL_ACCESSORS(bound_current, Object) DECL_ACCESSORS(bound_break_type, Object) -// Layout description. -#define BREAK_ITERATOR_FIELDS(V) \ - /* Pointer fields. */ \ - V(kLocaleOffset, kTaggedSize) \ - V(kTypeOffset, kTaggedSize) \ - V(kBreakIteratorOffset, kTaggedSize) \ - V(kUnicodeStringOffset, kTaggedSize) \ - V(kBoundAdoptTextOffset, kTaggedSize) \ - V(kBoundFirstOffset, kTaggedSize) \ - V(kBoundNextOffset, kTaggedSize) \ - V(kBoundCurrentOffset, kTaggedSize) \ - V(kBoundBreakTypeOffset, kTaggedSize) \ - /* Total Size */ \ - V(kSize, 0) - - DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, BREAK_ITERATOR_FIELDS) -#undef BREAK_ITERATOR_FIELDS + // Layout description. + DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, + TORQUE_GENERATED_JSV8BREAK_ITERATOR_FIELDS) + + private: + DECL_INT_ACCESSORS(raw_type) OBJECT_CONSTRUCTORS(JSV8BreakIterator, JSObject); }; diff --git a/chromium/v8/src/objects/js-collator-inl.h b/chromium/v8/src/objects/js-collator-inl.h index e82351993db..a8d38933160 100644 --- a/chromium/v8/src/objects/js-collator-inl.h +++ b/chromium/v8/src/objects/js-collator-inl.h @@ -20,7 +20,7 @@ namespace internal { OBJECT_CONSTRUCTORS_IMPL(JSCollator, JSObject) -ACCESSORS(JSCollator, icu_collator, Managed<icu::Collator>, kICUCollatorOffset) +ACCESSORS(JSCollator, icu_collator, Managed<icu::Collator>, kIcuCollatorOffset) ACCESSORS(JSCollator, bound_compare, Object, kBoundCompareOffset) CAST_ACCESSOR(JSCollator) diff --git a/chromium/v8/src/objects/js-collator.cc b/chromium/v8/src/objects/js-collator.cc index 4a1e8574039..0413e2acd1e 100644 --- a/chromium/v8/src/objects/js-collator.cc +++ b/chromium/v8/src/objects/js-collator.cc @@ -15,7 +15,9 @@ #include "unicode/locid.h" #include "unicode/strenum.h" #include "unicode/ucol.h" +#include "unicode/udata.h" #include "unicode/uloc.h" +#include "unicode/utypes.h" namespace v8 { namespace internal { @@ -239,10 +241,9 @@ void SetCaseFirstOption(icu::Collator* icu_collator, } // anonymous namespace // static -MaybeHandle<JSCollator> JSCollator::Initialize(Isolate* isolate, - Handle<JSCollator> collator, - Handle<Object> locales, - Handle<Object> options_obj) { +MaybeHandle<JSCollator> JSCollator::New(Isolate* isolate, Handle<Map> map, + Handle<Object> locales, + Handle<Object> options_obj) { // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales). Maybe<std::vector<std::string>> maybe_requested_locales = Intl::CanonicalizeLocaleList(isolate, locales); @@ -465,15 +466,31 @@ MaybeHandle<JSCollator> JSCollator::Initialize(Isolate* isolate, Handle<Managed<icu::Collator>> managed_collator = Managed<icu::Collator>::FromUniquePtr(isolate, 0, std::move(icu_collator)); + + // Now all properties are ready, so we can allocate the result object. + Handle<JSCollator> collator = Handle<JSCollator>::cast( + isolate->factory()->NewFastOrSlowJSObjectFromMap(map)); + DisallowHeapAllocation no_gc; collator->set_icu_collator(*managed_collator); // 29. Return collator. return collator; } +namespace { + +struct CheckColl { + static const char* key() { return nullptr; } +#define U_ICUDATA_COLL U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "coll" + static const char* path() { return U_ICUDATA_COLL; } +#undef U_ICUDATA_COLL +}; + +} // namespace + const std::set<std::string>& JSCollator::GetAvailableLocales() { - static base::LazyInstance<Intl::AvailableLocales<icu::Collator>>::type - available_locales = LAZY_INSTANCE_INITIALIZER; + static base::LazyInstance<Intl::AvailableLocales<icu::Collator, CheckColl>>:: + type available_locales = LAZY_INSTANCE_INITIALIZER; return available_locales.Pointer()->Get(); } diff --git a/chromium/v8/src/objects/js-collator.h b/chromium/v8/src/objects/js-collator.h index 2bedbf811a9..e9114afeb1e 100644 --- a/chromium/v8/src/objects/js-collator.h +++ b/chromium/v8/src/objects/js-collator.h @@ -32,8 +32,8 @@ namespace internal { class JSCollator : public JSObject { public: // ecma402/#sec-initializecollator - V8_WARN_UNUSED_RESULT static MaybeHandle<JSCollator> Initialize( - Isolate* isolate, Handle<JSCollator> collator, Handle<Object> locales, + V8_WARN_UNUSED_RESULT static MaybeHandle<JSCollator> New( + Isolate* isolate, Handle<Map> map, Handle<Object> locales, Handle<Object> options); // ecma402/#sec-intl.collator.prototype.resolvedoptions @@ -47,14 +47,8 @@ class JSCollator : public JSObject { DECL_VERIFIER(JSCollator) // Layout description. -#define JS_COLLATOR_FIELDS(V) \ - V(kICUCollatorOffset, kTaggedSize) \ - V(kBoundCompareOffset, kTaggedSize) \ - /* Total size. */ \ - V(kSize, 0) - - DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, JS_COLLATOR_FIELDS) -#undef JS_COLLATOR_FIELDS + DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, + TORQUE_GENERATED_JSCOLLATOR_FIELDS) DECL_ACCESSORS(icu_collator, Managed<icu::Collator>) DECL_ACCESSORS(bound_compare, Object) diff --git a/chromium/v8/src/objects/js-collection-iterator.h b/chromium/v8/src/objects/js-collection-iterator.h index 4952f04a728..c002294b017 100644 --- a/chromium/v8/src/objects/js-collection-iterator.h +++ b/chromium/v8/src/objects/js-collection-iterator.h @@ -25,6 +25,7 @@ class JSCollectionIterator : public JSObject { DECL_ACCESSORS(index, Object) void JSCollectionIteratorPrint(std::ostream& os, const char* name); + DECL_VERIFIER(JSCollectionIterator) DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, TORQUE_GENERATED_JSCOLLECTION_ITERATOR_FIELDS) diff --git a/chromium/v8/src/objects/js-collection.h b/chromium/v8/src/objects/js-collection.h index 6dfde352caf..0a856ca0628 100644 --- a/chromium/v8/src/objects/js-collection.h +++ b/chromium/v8/src/objects/js-collection.h @@ -30,6 +30,8 @@ class JSCollection : public JSObject { static const int kAddFunctionDescriptorIndex = 3; + DECL_VERIFIER(JSCollection) + OBJECT_CONSTRUCTORS(JSCollection, JSObject); }; @@ -114,6 +116,8 @@ class JSWeakCollection : public JSObject { static Handle<JSArray> GetEntries(Handle<JSWeakCollection> holder, int max_entries); + DECL_VERIFIER(JSWeakCollection) + DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, TORQUE_GENERATED_JSWEAK_COLLECTION_FIELDS) diff --git a/chromium/v8/src/objects/js-date-time-format.cc b/chromium/v8/src/objects/js-date-time-format.cc index 8730e0a39b8..db7ba273124 100644 --- a/chromium/v8/src/objects/js-date-time-format.cc +++ b/chromium/v8/src/objects/js-date-time-format.cc @@ -56,13 +56,13 @@ class PatternItem { std::vector<const char*> allowed_values; }; -static const std::vector<PatternItem> BuildPatternItems() { +static std::vector<PatternItem> BuildPatternItems() { const std::vector<const char*> kLongShort = {"long", "short"}; const std::vector<const char*> kNarrowLongShort = {"narrow", "long", "short"}; const std::vector<const char*> k2DigitNumeric = {"2-digit", "numeric"}; const std::vector<const char*> kNarrowLongShort2DigitNumeric = { "narrow", "long", "short", "2-digit", "numeric"}; - const std::vector<PatternItem> kPatternItems = { + std::vector<PatternItem> items = { PatternItem("weekday", {{"EEEEE", "narrow"}, {"EEEE", "long"}, @@ -75,38 +75,59 @@ static const std::vector<PatternItem> BuildPatternItems() { {{"GGGGG", "narrow"}, {"GGGG", "long"}, {"GGG", "short"}}, kNarrowLongShort), PatternItem("year", {{"yy", "2-digit"}, {"y", "numeric"}}, - k2DigitNumeric), - // Sometimes we get L instead of M for month - standalone name. - PatternItem("month", - {{"MMMMM", "narrow"}, - {"MMMM", "long"}, - {"MMM", "short"}, - {"MM", "2-digit"}, - {"M", "numeric"}, - {"LLLLL", "narrow"}, - {"LLLL", "long"}, - {"LLL", "short"}, - {"LL", "2-digit"}, - {"L", "numeric"}}, - kNarrowLongShort2DigitNumeric), - PatternItem("day", {{"dd", "2-digit"}, {"d", "numeric"}}, k2DigitNumeric), - PatternItem("hour", - {{"HH", "2-digit"}, - {"H", "numeric"}, - {"hh", "2-digit"}, - {"h", "numeric"}, - {"kk", "2-digit"}, - {"k", "numeric"}, - {"KK", "2-digit"}, - {"K", "numeric"}}, - k2DigitNumeric), - PatternItem("minute", {{"mm", "2-digit"}, {"m", "numeric"}}, - k2DigitNumeric), - PatternItem("second", {{"ss", "2-digit"}, {"s", "numeric"}}, - k2DigitNumeric), - PatternItem("timeZoneName", {{"zzzz", "long"}, {"z", "short"}}, - kLongShort)}; - return kPatternItems; + k2DigitNumeric)}; + if (FLAG_harmony_intl_dateformat_quarter) { + items.push_back(PatternItem("quarter", + {{"QQQQQ", "narrow"}, + {"QQQQ", "long"}, + {"QQQ", "short"}, + {"qqqqq", "narrow"}, + {"qqqq", "long"}, + {"qqq", "short"}}, + kNarrowLongShort)); + } + // Sometimes we get L instead of M for month - standalone name. + items.push_back(PatternItem("month", + {{"MMMMM", "narrow"}, + {"MMMM", "long"}, + {"MMM", "short"}, + {"MM", "2-digit"}, + {"M", "numeric"}, + {"LLLLL", "narrow"}, + {"LLLL", "long"}, + {"LLL", "short"}, + {"LL", "2-digit"}, + {"L", "numeric"}}, + kNarrowLongShort2DigitNumeric)); + items.push_back(PatternItem("day", {{"dd", "2-digit"}, {"d", "numeric"}}, + k2DigitNumeric)); + if (FLAG_harmony_intl_dateformat_day_period) { + items.push_back(PatternItem("dayPeriod", + {{"BBBBB", "narrow"}, + {"bbbbb", "narrow"}, + {"BBBB", "long"}, + {"bbbb", "long"}, + {"B", "short"}, + {"b", "short"}}, + kNarrowLongShort)); + } + items.push_back(PatternItem("hour", + {{"HH", "2-digit"}, + {"H", "numeric"}, + {"hh", "2-digit"}, + {"h", "numeric"}, + {"kk", "2-digit"}, + {"k", "numeric"}, + {"KK", "2-digit"}, + {"K", "numeric"}}, + k2DigitNumeric)); + items.push_back(PatternItem("minute", {{"mm", "2-digit"}, {"m", "numeric"}}, + k2DigitNumeric)); + items.push_back(PatternItem("second", {{"ss", "2-digit"}, {"s", "numeric"}}, + k2DigitNumeric)); + items.push_back(PatternItem("timeZoneName", + {{"zzzz", "long"}, {"z", "short"}}, kLongShort)); + return items; } class PatternItems { @@ -348,6 +369,16 @@ Handle<String> DateTimeStyleAsString(Isolate* isolate, } } +int FractionalSecondDigitsFromPattern(const std::string& pattern) { + int result = 0; + for (size_t i = 0; i < pattern.length() && result < 3; i++) { + if (pattern[i] == 'S') { + result++; + } + } + return result; +} + } // namespace // ecma402 #sec-intl.datetimeformat.prototype.resolvedoptions @@ -532,6 +563,13 @@ MaybeHandle<JSObject> JSDateTimeFormat::ResolvedOptions( Just(kDontThrow)) .FromJust()); } + if (FLAG_harmony_intl_dateformat_fractional_second_digits) { + int fsd = FractionalSecondDigitsFromPattern(pattern); + CHECK(JSReceiver::CreateDataProperty( + isolate, options, factory->fractionalSecondDigits_string(), + factory->NewNumberFromInt(fsd), Just(kDontThrow)) + .FromJust()); + } return options; } @@ -643,17 +681,14 @@ MaybeHandle<String> JSDateTimeFormat::ToLocaleDateTime( JSFunction::cast( isolate->context().native_context().intl_date_time_format_function()), isolate); - Handle<JSObject> obj; + Handle<Map> map; ASSIGN_RETURN_ON_EXCEPTION( - isolate, obj, - JSObject::New(constructor, constructor, Handle<AllocationSite>::null()), - String); + isolate, map, + JSFunction::GetDerivedMap(isolate, constructor, constructor), String); Handle<JSDateTimeFormat> date_time_format; ASSIGN_RETURN_ON_EXCEPTION( isolate, date_time_format, - JSDateTimeFormat::Initialize(isolate, Handle<JSDateTimeFormat>::cast(obj), - locales, internal_options), - String); + JSDateTimeFormat::New(isolate, map, locales, internal_options), String); if (can_cache) { isolate->set_icu_object_in_cache( @@ -669,27 +704,23 @@ MaybeHandle<String> JSDateTimeFormat::ToLocaleDateTime( namespace { Maybe<bool> IsPropertyUndefined(Isolate* isolate, Handle<JSObject> options, - const char* property) { - Factory* factory = isolate->factory(); + Handle<String> property) { // i. Let prop be the property name. // ii. Let value be ? Get(options, prop). Handle<Object> value; ASSIGN_RETURN_ON_EXCEPTION_VALUE( - isolate, value, - Object::GetPropertyOrElement( - isolate, options, factory->NewStringFromAsciiChecked(property)), + isolate, value, Object::GetPropertyOrElement(isolate, options, property), Nothing<bool>()); return Just(value->IsUndefined(isolate)); } Maybe<bool> NeedsDefault(Isolate* isolate, Handle<JSObject> options, - const std::vector<std::string>& props) { + const std::vector<Handle<String>>& props) { bool needs_default = true; for (const auto& prop : props) { // i. Let prop be the property name. // ii. Let value be ? Get(options, prop) - Maybe<bool> maybe_undefined = - IsPropertyUndefined(isolate, options, prop.c_str()); + Maybe<bool> maybe_undefined = IsPropertyUndefined(isolate, options, prop); MAYBE_RETURN(maybe_undefined, Nothing<bool>()); // iii. If value is not undefined, let needDefaults be false. if (!maybe_undefined.FromJust()) { @@ -741,8 +772,15 @@ MaybeHandle<JSObject> JSDateTimeFormat::ToDateTimeOptions( // 4. If required is "date" or "any", then if (required == RequiredOption::kAny || required == RequiredOption::kDate) { - // a. For each of the property names "weekday", "year", "month", "day", do - const std::vector<std::string> list({"weekday", "year", "month", "day"}); + // a. For each of the property names "weekday", "year", "quarter", "month", + // "day", do + std::vector<Handle<String>> list( + {factory->weekday_string(), factory->year_string()}); + if (FLAG_harmony_intl_dateformat_quarter) { + list.push_back(factory->quarter_string()); + } + list.push_back(factory->month_string()); + list.push_back(factory->day_string()); Maybe<bool> maybe_needs_default = NeedsDefault(isolate, options, list); MAYBE_RETURN(maybe_needs_default, Handle<JSObject>()); needs_default = maybe_needs_default.FromJust(); @@ -750,8 +788,18 @@ MaybeHandle<JSObject> JSDateTimeFormat::ToDateTimeOptions( // 5. If required is "time" or "any", then if (required == RequiredOption::kAny || required == RequiredOption::kTime) { - // a. For each of the property names "hour", "minute", "second", do - const std::vector<std::string> list({"hour", "minute", "second"}); + // a. For each of the property names "dayPeriod", "hour", "minute", + // "second", "fractionalSecondDigits", do + std::vector<Handle<String>> list; + if (FLAG_harmony_intl_dateformat_day_period) { + list.push_back(factory->dayPeriod_string()); + } + list.push_back(factory->hour_string()); + list.push_back(factory->minute_string()); + list.push_back(factory->second_string()); + if (FLAG_harmony_intl_dateformat_fractional_second_digits) { + list.push_back(factory->fractionalSecondDigits_string()); + } Maybe<bool> maybe_needs_default = NeedsDefault(isolate, options, list); MAYBE_RETURN(maybe_needs_default, Handle<JSObject>()); needs_default &= maybe_needs_default.FromJust(); @@ -890,7 +938,7 @@ icu::Calendar* CreateCalendar(Isolate* isolate, const icu::Locale& icu_locale, std::unique_ptr<icu::SimpleDateFormat> CreateICUDateFormat( const icu::Locale& icu_locale, const icu::UnicodeString& skeleton, - icu::DateTimePatternGenerator& generator) { + icu::DateTimePatternGenerator& generator) { // NOLINT(runtime/references) // See https://github.com/tc39/ecma402/issues/225 . The best pattern // generation needs to be done in the base locale according to the // current spec however odd it may be. See also crbug.com/826549 . @@ -920,9 +968,9 @@ std::unique_ptr<icu::SimpleDateFormat> CreateICUDateFormat( class DateFormatCache { public: - icu::SimpleDateFormat* Create(const icu::Locale& icu_locale, - const icu::UnicodeString& skeleton, - icu::DateTimePatternGenerator& generator) { + icu::SimpleDateFormat* Create( + const icu::Locale& icu_locale, const icu::UnicodeString& skeleton, + icu::DateTimePatternGenerator& generator) { // NOLINT(runtime/references) std::string key; skeleton.toUTF8String<std::string>(key); key += ":"; @@ -951,7 +999,7 @@ class DateFormatCache { std::unique_ptr<icu::SimpleDateFormat> CreateICUDateFormatFromCache( const icu::Locale& icu_locale, const icu::UnicodeString& skeleton, - icu::DateTimePatternGenerator& generator) { + icu::DateTimePatternGenerator& generator) { // NOLINT(runtime/references) static base::LazyInstance<DateFormatCache>::type cache = LAZY_INSTANCE_INITIALIZER; return std::unique_ptr<icu::SimpleDateFormat>( @@ -1087,7 +1135,8 @@ icu::UnicodeString ReplaceSkeleton(const icu::UnicodeString input, std::unique_ptr<icu::SimpleDateFormat> DateTimeStylePattern( JSDateTimeFormat::DateTimeStyle date_style, JSDateTimeFormat::DateTimeStyle time_style, const icu::Locale& icu_locale, - Intl::HourCycle hc, icu::DateTimePatternGenerator& generator) { + Intl::HourCycle hc, + icu::DateTimePatternGenerator& generator) { // NOLINT(runtime/references) std::unique_ptr<icu::SimpleDateFormat> result; if (date_style != JSDateTimeFormat::DateTimeStyle::kUndefined) { if (time_style != JSDateTimeFormat::DateTimeStyle::kUndefined) { @@ -1156,10 +1205,9 @@ class DateTimePatternGeneratorCache { enum FormatMatcherOption { kBestFit, kBasic }; // ecma402/#sec-initializedatetimeformat -MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize( - Isolate* isolate, Handle<JSDateTimeFormat> date_time_format, - Handle<Object> locales, Handle<Object> input_options) { - date_time_format->set_flags(0); +MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::New( + Isolate* isolate, Handle<Map> map, Handle<Object> locales, + Handle<Object> input_options) { Factory* factory = isolate->factory(); // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales). Maybe<std::vector<std::string>> maybe_requested_locales = @@ -1347,7 +1395,6 @@ MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize( } } } - date_time_format->set_hour_cycle(hc); DateTimeStyle date_style = DateTimeStyle::kUndefined; DateTimeStyle time_style = DateTimeStyle::kUndefined; @@ -1367,9 +1414,6 @@ MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize( // 29. If dateStyle is not undefined, set dateTimeFormat.[[DateStyle]] to // dateStyle. date_style = maybe_date_style.FromJust(); - if (date_style != DateTimeStyle::kUndefined) { - date_time_format->set_date_style(date_style); - } // 30. Let timeStyle be ? GetOption(options, "timeStyle", "string", « // "full", "long", "medium", "short" »). @@ -1385,9 +1429,6 @@ MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize( // 31. If timeStyle is not undefined, set dateTimeFormat.[[TimeStyle]] to // timeStyle. time_style = maybe_time_style.FromJust(); - if (time_style != DateTimeStyle::kUndefined) { - date_time_format->set_time_style(time_style); - } // 32. If dateStyle or timeStyle are not undefined, then if (date_style != DateTimeStyle::kUndefined || @@ -1419,6 +1460,16 @@ MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize( skeleton += item.map.find(input.get())->second; } } + if (FLAG_harmony_intl_dateformat_fractional_second_digits) { + Maybe<int> maybe_fsd = Intl::GetNumberOption( + isolate, options, factory->fractionalSecondDigits_string(), 0, 3, 0); + MAYBE_RETURN(maybe_fsd, MaybeHandle<JSDateTimeFormat>()); + // Convert fractionalSecondDigits to skeleton. + int fsd = maybe_fsd.FromJust(); + for (int i = 0; i < fsd; i++) { + skeleton += "S"; + } + } enum FormatMatcherOption { kBestFit, kBasic }; // We implement only best fit algorithm, but still need to check @@ -1451,7 +1502,7 @@ MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize( // g. If dateTimeFormat.[[Hour]] is not undefined, then if (!has_hour_option) { // h. Else, i. Set dateTimeFormat.[[HourCycle]] to undefined. - date_time_format->set_hour_cycle(Intl::HourCycle::kUndefined); + hc = Intl::HourCycle::kUndefined; } } @@ -1477,8 +1528,7 @@ MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize( maybe_hour_cycle.FromJust() != Intl::HourCycle::kUndefined) { auto hc_extension_it = r.extensions.find("hc"); if (hc_extension_it != r.extensions.end()) { - if (date_time_format->hour_cycle() != - Intl::ToHourCycle(hc_extension_it->second.c_str())) { + if (hc != Intl::ToHourCycle(hc_extension_it->second.c_str())) { // Remove -hc- if it does not agree with what we used. UErrorCode status = U_ZERO_ERROR; icu_locale.setUnicodeKeywordValue("hc", nullptr, status); @@ -1490,16 +1540,28 @@ MaybeHandle<JSDateTimeFormat> JSDateTimeFormat::Initialize( Handle<Managed<icu::Locale>> managed_locale = Managed<icu::Locale>::FromRawPtr(isolate, 0, icu_locale.clone()); - date_time_format->set_icu_locale(*managed_locale); Handle<Managed<icu::SimpleDateFormat>> managed_format = Managed<icu::SimpleDateFormat>::FromUniquePtr(isolate, 0, std::move(icu_date_format)); - date_time_format->set_icu_simple_date_format(*managed_format); Handle<Managed<icu::DateIntervalFormat>> managed_interval_format = Managed<icu::DateIntervalFormat>::FromRawPtr(isolate, 0, nullptr); - date_time_format->set_icu_date_interval_format(*managed_interval_format); + // Now all properties are ready, so we can allocate the result object. + Handle<JSDateTimeFormat> date_time_format = Handle<JSDateTimeFormat>::cast( + isolate->factory()->NewFastOrSlowJSObjectFromMap(map)); + DisallowHeapAllocation no_gc; + date_time_format->set_flags(0); + date_time_format->set_hour_cycle(hc); + if (date_style != DateTimeStyle::kUndefined) { + date_time_format->set_date_style(date_style); + } + if (time_style != DateTimeStyle::kUndefined) { + date_time_format->set_time_style(time_style); + } + date_time_format->set_icu_locale(*managed_locale); + date_time_format->set_icu_simple_date_format(*managed_format); + date_time_format->set_icu_date_interval_format(*managed_interval_format); return date_time_format; } @@ -1516,6 +1578,9 @@ Handle<String> IcuDateFieldIdToDateType(int32_t field_id, Isolate* isolate) { case UDAT_EXTENDED_YEAR_FIELD: case UDAT_YEAR_NAME_FIELD: return isolate->factory()->year_string(); + case UDAT_QUARTER_FIELD: + case UDAT_STANDALONE_QUARTER_FIELD: + return isolate->factory()->quarter_string(); case UDAT_MONTH_FIELD: case UDAT_STANDALONE_MONTH_FIELD: return isolate->factory()->month_string(); @@ -1535,6 +1600,8 @@ Handle<String> IcuDateFieldIdToDateType(int32_t field_id, Isolate* isolate) { case UDAT_STANDALONE_DAY_FIELD: return isolate->factory()->weekday_string(); case UDAT_AM_PM_FIELD: + case UDAT_AM_PM_MIDNIGHT_NOON_FIELD: + case UDAT_FLEXIBLE_DAY_PERIOD_FIELD: return isolate->factory()->dayPeriod_string(); case UDAT_TIMEZONE_FIELD: case UDAT_TIMEZONE_RFC_FIELD: @@ -1546,6 +1613,8 @@ Handle<String> IcuDateFieldIdToDateType(int32_t field_id, Isolate* isolate) { return isolate->factory()->timeZoneName_string(); case UDAT_ERA_FIELD: return isolate->factory()->era_string(); + case UDAT_FRACTIONAL_SECOND_FIELD: + return isolate->factory()->fractionalSecond_string(); default: // Other UDAT_*_FIELD's cannot show up because there is no way to specify // them via options of Intl.DateTimeFormat. diff --git a/chromium/v8/src/objects/js-date-time-format.h b/chromium/v8/src/objects/js-date-time-format.h index 664ccdcdf72..f4a8ccc8f5c 100644 --- a/chromium/v8/src/objects/js-date-time-format.h +++ b/chromium/v8/src/objects/js-date-time-format.h @@ -32,9 +32,9 @@ namespace internal { class JSDateTimeFormat : public JSObject { public: - V8_WARN_UNUSED_RESULT static MaybeHandle<JSDateTimeFormat> Initialize( - Isolate* isolate, Handle<JSDateTimeFormat> date_time_format, - Handle<Object> locales, Handle<Object> options); + V8_WARN_UNUSED_RESULT static MaybeHandle<JSDateTimeFormat> New( + Isolate* isolate, Handle<Map> map, Handle<Object> locales, + Handle<Object> options); V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> ResolvedOptions( Isolate* isolate, Handle<JSDateTimeFormat> date_time_format); diff --git a/chromium/v8/src/objects/js-list-format-inl.h b/chromium/v8/src/objects/js-list-format-inl.h index 96e61c22053..6a1529ad335 100644 --- a/chromium/v8/src/objects/js-list-format-inl.h +++ b/chromium/v8/src/objects/js-list-format-inl.h @@ -27,7 +27,7 @@ ACCESSORS(JSListFormat, icu_formatter, Managed<icu::ListFormatter>, SMI_ACCESSORS(JSListFormat, flags, kFlagsOffset) inline void JSListFormat::set_style(Style style) { - DCHECK_GT(Style::COUNT, style); + DCHECK_GE(StyleBits::kMax, style); int hints = flags(); hints = StyleBits::update(hints, style); set_flags(hints); @@ -38,7 +38,7 @@ inline JSListFormat::Style JSListFormat::style() const { } inline void JSListFormat::set_type(Type type) { - DCHECK_GT(Type::COUNT, type); + DCHECK_GE(TypeBits::kMax, type); int hints = flags(); hints = TypeBits::update(hints, type); set_flags(hints); diff --git a/chromium/v8/src/objects/js-list-format.cc b/chromium/v8/src/objects/js-list-format.cc index 84691194ec8..4f303b18745 100644 --- a/chromium/v8/src/objects/js-list-format.cc +++ b/chromium/v8/src/objects/js-list-format.cc @@ -50,8 +50,6 @@ const char* GetIcuStyleString(JSListFormat::Style style, return kStandardShort; case JSListFormat::Style::NARROW: return kStandardNarrow; - case JSListFormat::Style::COUNT: - UNREACHABLE(); } case JSListFormat::Type::DISJUNCTION: switch (style) { @@ -61,8 +59,6 @@ const char* GetIcuStyleString(JSListFormat::Style style, return kOrShort; case JSListFormat::Style::NARROW: return kOrNarrow; - case JSListFormat::Style::COUNT: - UNREACHABLE(); } case JSListFormat::Type::UNIT: switch (style) { @@ -72,12 +68,9 @@ const char* GetIcuStyleString(JSListFormat::Style style, return kUnitShort; case JSListFormat::Style::NARROW: return kUnitNarrow; - case JSListFormat::Style::COUNT: - UNREACHABLE(); } - case JSListFormat::Type::COUNT: - UNREACHABLE(); } + UNREACHABLE(); } } // namespace @@ -114,11 +107,9 @@ JSListFormat::Type get_type(const char* str) { UNREACHABLE(); } -MaybeHandle<JSListFormat> JSListFormat::Initialize( - Isolate* isolate, Handle<JSListFormat> list_format, Handle<Object> locales, - Handle<Object> input_options) { - list_format->set_flags(0); - +MaybeHandle<JSListFormat> JSListFormat::New(Isolate* isolate, Handle<Map> map, + Handle<Object> locales, + Handle<Object> input_options) { Handle<JSReceiver> options; // 3. Let requestedLocales be ? CanonicalizeLocaleList(locales). Maybe<std::vector<std::string>> maybe_requested_locales = @@ -156,11 +147,8 @@ MaybeHandle<JSListFormat> JSListFormat::Initialize( Intl::ResolvedLocale r = Intl::ResolveLocale(isolate, JSListFormat::GetAvailableLocales(), requested_locales, matcher, {}); - - // 11. Set listFormat.[[Locale]] to r.[[Locale]]. Handle<String> locale_str = isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str()); - list_format->set_locale(*locale_str); // 12. Let t be GetOption(options, "type", "string", «"conjunction", // "disjunction", "unit"», "conjunction"). @@ -171,9 +159,6 @@ MaybeHandle<JSListFormat> JSListFormat::Initialize( MAYBE_RETURN(maybe_type, MaybeHandle<JSListFormat>()); Type type_enum = maybe_type.FromJust(); - // 13. Set listFormat.[[Type]] to t. - list_format->set_type(type_enum); - // 14. Let s be ? GetOption(options, "style", "string", // «"long", "short", "narrow"», "long"). Maybe<Style> maybe_style = Intl::GetStringOption<Style>( @@ -182,9 +167,6 @@ MaybeHandle<JSListFormat> JSListFormat::Initialize( MAYBE_RETURN(maybe_style, MaybeHandle<JSListFormat>()); Style style_enum = maybe_style.FromJust(); - // 15. Set listFormat.[[Style]] to s. - list_format->set_style(style_enum); - icu::Locale icu_locale = r.icu_locale; UErrorCode status = U_ZERO_ERROR; icu::ListFormatter* formatter = icu::ListFormatter::createInstance( @@ -198,7 +180,22 @@ MaybeHandle<JSListFormat> JSListFormat::Initialize( Handle<Managed<icu::ListFormatter>> managed_formatter = Managed<icu::ListFormatter>::FromRawPtr(isolate, 0, formatter); + // Now all properties are ready, so we can allocate the result object. + Handle<JSListFormat> list_format = Handle<JSListFormat>::cast( + isolate->factory()->NewFastOrSlowJSObjectFromMap(map)); + DisallowHeapAllocation no_gc; + list_format->set_flags(0); list_format->set_icu_formatter(*managed_formatter); + + // 11. Set listFormat.[[Locale]] to r.[[Locale]]. + list_format->set_locale(*locale_str); + + // 13. Set listFormat.[[Type]] to t. + list_format->set_type(type_enum); + + // 15. Set listFormat.[[Style]] to s. + list_format->set_style(style_enum); + return list_format; } @@ -234,9 +231,8 @@ Handle<String> JSListFormat::StyleAsString() const { return GetReadOnlyRoots().short_string_handle(); case Style::NARROW: return GetReadOnlyRoots().narrow_string_handle(); - case Style::COUNT: - UNREACHABLE(); } + UNREACHABLE(); } Handle<String> JSListFormat::TypeAsString() const { @@ -247,9 +243,8 @@ Handle<String> JSListFormat::TypeAsString() const { return GetReadOnlyRoots().disjunction_string_handle(); case Type::UNIT: return GetReadOnlyRoots().unit_string_handle(); - case Type::COUNT: - UNREACHABLE(); } + UNREACHABLE(); } namespace { @@ -375,11 +370,20 @@ MaybeHandle<JSArray> JSListFormat::FormatListToParts( FormattedListToJSArray); } +namespace { + +struct CheckListPattern { + static const char* key() { return "listPattern"; } + static const char* path() { return nullptr; } +}; + +} // namespace + const std::set<std::string>& JSListFormat::GetAvailableLocales() { - // Since ListFormatter does not have a method to list all supported - // locales, use the one in icu::Locale per comments in - // ICU FR at https://unicode-org.atlassian.net/browse/ICU-20015 - return Intl::GetAvailableLocalesForLocale(); + static base::LazyInstance< + Intl::AvailableLocales<icu::Locale, CheckListPattern>>::type + available_locales = LAZY_INSTANCE_INITIALIZER; + return available_locales.Pointer()->Get(); } } // namespace internal diff --git a/chromium/v8/src/objects/js-list-format.h b/chromium/v8/src/objects/js-list-format.h index 0284d05d427..df937722e65 100644 --- a/chromium/v8/src/objects/js-list-format.h +++ b/chromium/v8/src/objects/js-list-format.h @@ -30,11 +30,11 @@ namespace internal { class JSListFormat : public JSObject { public: - // Initializes relative time format object with properties derived from input + // Creates relative time format object with properties derived from input // locales and options. - static MaybeHandle<JSListFormat> Initialize( - Isolate* isolate, Handle<JSListFormat> list_format_holder, - Handle<Object> locales, Handle<Object> options); + static MaybeHandle<JSListFormat> New(Isolate* isolate, Handle<Map> map, + Handle<Object> locales, + Handle<Object> options); static Handle<JSObject> ResolvedOptions(Isolate* isolate, Handle<JSListFormat> format_holder); @@ -64,10 +64,9 @@ class JSListFormat : public JSObject { // // ecma402/#sec-properties-of-intl-listformat-instances enum class Style { - LONG, // Everything spelled out. - SHORT, // Abbreviations used when possible. - NARROW, // Use the shortest possible form. - COUNT + LONG, // Everything spelled out. + SHORT, // Abbreviations used when possible. + NARROW // Use the shortest possible form. }; inline void set_style(Style style); inline Style style() const; @@ -78,8 +77,7 @@ class JSListFormat : public JSObject { enum class Type { CONJUNCTION, // for "and"-based lists (e.g., "A, B and C") DISJUNCTION, // for "or"-based lists (e.g., "A, B or C"), - UNIT, // for lists of values with units (e.g., "5 pounds, 12 ounces"). - COUNT + UNIT // for lists of values with units (e.g., "5 pounds, 12 ounces"). }; inline void set_type(Type type); inline Type type() const; diff --git a/chromium/v8/src/objects/js-locale.cc b/chromium/v8/src/objects/js-locale.cc index 509f9a30695..4a66ea9eca7 100644 --- a/chromium/v8/src/objects/js-locale.cc +++ b/chromium/v8/src/objects/js-locale.cc @@ -313,10 +313,9 @@ Maybe<bool> ApplyOptionsToTag(Isolate* isolate, Handle<String> tag, } // namespace -MaybeHandle<JSLocale> JSLocale::Initialize(Isolate* isolate, - Handle<JSLocale> locale, - Handle<String> locale_str, - Handle<JSReceiver> options) { +MaybeHandle<JSLocale> JSLocale::New(Isolate* isolate, Handle<Map> map, + Handle<String> locale_str, + Handle<JSReceiver> options) { icu::LocaleBuilder builder; Maybe<bool> maybe_apply = ApplyOptionsToTag(isolate, locale_str, options, &builder); @@ -341,8 +340,12 @@ MaybeHandle<JSLocale> JSLocale::Initialize(Isolate* isolate, // 31. Set locale.[[Locale]] to r.[[locale]]. Handle<Managed<icu::Locale>> managed_locale = Managed<icu::Locale>::FromRawPtr(isolate, 0, icu_locale.clone()); - locale->set_icu_locale(*managed_locale); + // Now all properties are ready, so we can allocate the result object. + Handle<JSLocale> locale = Handle<JSLocale>::cast( + isolate->factory()->NewFastOrSlowJSObjectFromMap(map)); + DisallowHeapAllocation no_gc; + locale->set_icu_locale(*managed_locale); return locale; } diff --git a/chromium/v8/src/objects/js-locale.h b/chromium/v8/src/objects/js-locale.h index 1a833e0e189..e1806e6b7f8 100644 --- a/chromium/v8/src/objects/js-locale.h +++ b/chromium/v8/src/objects/js-locale.h @@ -27,12 +27,11 @@ namespace internal { class JSLocale : public JSObject { public: - // Initializes locale object with properties derived from input locale string + // Creates locale object with properties derived from input locale string // and options. - static MaybeHandle<JSLocale> Initialize(Isolate* isolate, - Handle<JSLocale> locale_holder, - Handle<String> locale, - Handle<JSReceiver> options); + static MaybeHandle<JSLocale> New(Isolate* isolate, Handle<Map> map, + Handle<String> locale, + Handle<JSReceiver> options); static Handle<String> Maximize(Isolate* isolate, String locale); static Handle<String> Minimize(Isolate* isolate, String locale); diff --git a/chromium/v8/src/objects/js-number-format-inl.h b/chromium/v8/src/objects/js-number-format-inl.h index bd76dfe5564..afdfef89f2c 100644 --- a/chromium/v8/src/objects/js-number-format-inl.h +++ b/chromium/v8/src/objects/js-number-format-inl.h @@ -66,6 +66,17 @@ inline void JSNumberFormat::set_maximum_fraction_digits(int digits) { set_flags(hints); } +inline void JSNumberFormat::set_style(Style style) { + DCHECK_GE(StyleBits::kMax, style); + int hints = flags(); + hints = StyleBits::update(hints, style); + set_flags(hints); +} + +inline JSNumberFormat::Style JSNumberFormat::style() const { + return StyleBits::decode(flags()); +} + CAST_ACCESSOR(JSNumberFormat) } // namespace internal diff --git a/chromium/v8/src/objects/js-number-format.cc b/chromium/v8/src/objects/js-number-format.cc index 67d545e0be1..d1e3ef4d0cb 100644 --- a/chromium/v8/src/objects/js-number-format.cc +++ b/chromium/v8/src/objects/js-number-format.cc @@ -31,19 +31,9 @@ namespace internal { namespace { -// [[Style]] is one of the values "decimal", "percent", "currency", -// or "unit" identifying the style of the number format. -// Note: "unit" is added in proposal-unified-intl-numberformat -enum class Style { - DECIMAL, - PERCENT, - CURRENCY, - UNIT, -}; - // [[CurrencyDisplay]] is one of the values "code", "symbol", "name", -// or "narrow-symbol" identifying the display of the currency number format. -// Note: "narrow-symbol" is added in proposal-unified-intl-numberformat +// or "narrowSymbol" identifying the display of the currency number format. +// Note: "narrowSymbol" is added in proposal-unified-intl-numberformat enum class CurrencyDisplay { CODE, SYMBOL, @@ -62,8 +52,8 @@ enum class CurrencySign { // [[UnitDisplay]] is one of the String values "short", "narrow", or "long", // specifying whether to display the unit as a symbol, narrow symbol, or -// localized long name if formatting with the "unit" or "percent" style. It is -// only used when [[Style]] has the value "unit" or "percent". +// localized long name if formatting with the "unit" style. It is +// only used when [[Style]] has the value "unit". enum class UnitDisplay { SHORT, NARROW, @@ -95,7 +85,7 @@ enum class CompactDisplay { }; // [[SignDisplay]] is one of the String values "auto", "always", "never", or -// "except-zero", specifying whether to show the sign on negative numbers +// "exceptZero", specifying whether to show the sign on negative numbers // only, positive and negative numbers including zero, neither positive nor // negative numbers, or positive and negative numbers but not zero. enum class SignDisplay { @@ -164,7 +154,9 @@ icu::number::Notation ToICUNotation(Notation notation, return icu::number::Notation::scientific(); case Notation::ENGINEERING: return icu::number::Notation::engineering(); + // 29. If notation is "compact", then case Notation::COMPACT: + // 29. a. Set numberFormat.[[CompactDisplay]] to compactDisplay. if (compact_display == CompactDisplay::SHORT) { return icu::number::Notation::compactShort(); } @@ -195,7 +187,9 @@ std::map<const std::string, icu::MeasureUnit> CreateUnitMap() { CHECK(U_SUCCESS(status)); std::map<const std::string, icu::MeasureUnit> map; for (auto it = units.begin(); it != units.end(); ++it) { - if (sanctioned.count(it->getSubtype()) > 0) { + // Need to skip none/percent + if (sanctioned.count(it->getSubtype()) > 0 && + strcmp("none", it->getType()) != 0) { map[it->getSubtype()] = *it; } } @@ -304,38 +298,16 @@ bool IsWellFormedCurrencyCode(const std::string& currency) { return (IsAToZ(currency[0]) && IsAToZ(currency[1]) && IsAToZ(currency[2])); } -// Parse the 'style' from the skeleton. -Style StyleFromSkeleton(const icu::UnicodeString& skeleton) { - // Ex: skeleton as - // "percent precision-integer rounding-mode-half-up scale/100" - if (skeleton.indexOf("percent") >= 0 && skeleton.indexOf("scale/100") >= 0) { - return Style::PERCENT; - } - // Ex: skeleton as "currency/TWD .00 rounding-mode-half-up" - if (skeleton.indexOf("currency") >= 0) { - return Style::CURRENCY; - } - // Ex: skeleton as - // "measure-unit/length-meter .### rounding-mode-half-up unit-width-narrow" - // or special case for "percent .### rounding-mode-half-up" - if (skeleton.indexOf("measure-unit") >= 0 || - skeleton.indexOf("percent") >= 0) { - return Style::UNIT; - } - // Ex: skeleton as ".### rounding-mode-half-up" - return Style::DECIMAL; -} - // Return the style as a String. -Handle<String> StyleAsString(Isolate* isolate, Style style) { +Handle<String> StyleAsString(Isolate* isolate, JSNumberFormat::Style style) { switch (style) { - case Style::PERCENT: + case JSNumberFormat::Style::PERCENT: return ReadOnlyRoots(isolate).percent_string_handle(); - case Style::CURRENCY: + case JSNumberFormat::Style::CURRENCY: return ReadOnlyRoots(isolate).currency_string_handle(); - case Style::UNIT: + case JSNumberFormat::Style::UNIT: return ReadOnlyRoots(isolate).unit_string_handle(); - case Style::DECIMAL: + case JSNumberFormat::Style::DECIMAL: return ReadOnlyRoots(isolate).decimal_string_handle(); } UNREACHABLE(); @@ -357,7 +329,7 @@ Handle<String> CurrencyDisplayString(Isolate* isolate, // Ex: skeleton as // "currency/TWD .00 rounding-mode-half-up unit-width-narrow; if (skeleton.indexOf("unit-width-narrow") >= 0) { - return ReadOnlyRoots(isolate).narrow_symbol_string_handle(); + return ReadOnlyRoots(isolate).narrowSymbol_string_handle(); } // Ex: skeleton as "currency/TWD .00 rounding-mode-half-up" return ReadOnlyRoots(isolate).symbol_string_handle(); @@ -480,11 +452,13 @@ Handle<String> SignDisplayString(Isolate* isolate, // "currency/TWD .00 rounding-mode-half-up sign-except-zero" if (skeleton.indexOf("sign-accounting-except-zero") >= 0 || skeleton.indexOf("sign-except-zero") >= 0) { - return ReadOnlyRoots(isolate).except_zero_string_handle(); + return ReadOnlyRoots(isolate).exceptZero_string_handle(); } return ReadOnlyRoots(isolate).auto_string_handle(); } +} // anonymous namespace + // Return the minimum integer digits by counting the number of '0' after // "integer-width/+" in the skeleton. // Ex: Return 15 for skeleton as @@ -492,7 +466,8 @@ Handle<String> SignDisplayString(Isolate* isolate, // 1 // 123456789012345 // Return default value as 1 if there are no "integer-width/+". -int32_t MinimumIntegerDigitsFromSkeleton(const icu::UnicodeString& skeleton) { +int32_t JSNumberFormat::MinimumIntegerDigitsFromSkeleton( + const icu::UnicodeString& skeleton) { // count the number of 0 after "integer-width/+" icu::UnicodeString search("integer-width/+"); int32_t index = skeleton.indexOf(search); @@ -515,8 +490,8 @@ int32_t MinimumIntegerDigitsFromSkeleton(const icu::UnicodeString& skeleton) { // 123 // 4567 // Set The minimum as 3 and maximum as 7. -bool FractionDigitsFromSkeleton(const icu::UnicodeString& skeleton, - int32_t* minimum, int32_t* maximum) { +bool JSNumberFormat::FractionDigitsFromSkeleton( + const icu::UnicodeString& skeleton, int32_t* minimum, int32_t* maximum) { icu::UnicodeString search("."); int32_t index = skeleton.indexOf(search); if (index < 0) return false; @@ -542,8 +517,8 @@ bool FractionDigitsFromSkeleton(const icu::UnicodeString& skeleton, // 12345 // 6789012 // Set The minimum as 5 and maximum as 12. -bool SignificantDigitsFromSkeleton(const icu::UnicodeString& skeleton, - int32_t* minimum, int32_t* maximum) { +bool JSNumberFormat::SignificantDigitsFromSkeleton( + const icu::UnicodeString& skeleton, int32_t* minimum, int32_t* maximum) { icu::UnicodeString search("@"); int32_t index = skeleton.indexOf(search); if (index < 0) return false; @@ -561,6 +536,8 @@ bool SignificantDigitsFromSkeleton(const icu::UnicodeString& skeleton, return true; } +namespace { + // Ex: percent .### rounding-mode-half-up // Special case for "percent" // Ex: "measure-unit/length-kilometer per-measure-unit/duration-hour .### @@ -630,6 +607,34 @@ std::string UnitFromSkeleton(const icu::UnicodeString& skeleton) { } // anonymous namespace +icu::number::LocalizedNumberFormatter +JSNumberFormat::SetDigitOptionsToFormatter( + const icu::number::LocalizedNumberFormatter& icu_number_formatter, + const Intl::NumberFormatDigitOptions& digit_options) { + icu::number::LocalizedNumberFormatter result = icu_number_formatter; + if (digit_options.minimum_integer_digits > 1) { + result = result.integerWidth(icu::number::IntegerWidth::zeroFillTo( + digit_options.minimum_integer_digits)); + } + if (FLAG_harmony_intl_numberformat_unified) { + // Value -1 of minimum_significant_digits represent the roundingtype is + // "compact-rounding". + if (digit_options.minimum_significant_digits < 0) { + return result; + } + } + icu::number::Precision precision = + (digit_options.minimum_significant_digits > 0) + ? icu::number::Precision::minMaxSignificantDigits( + digit_options.minimum_significant_digits, + digit_options.maximum_significant_digits) + : icu::number::Precision::minMaxFraction( + digit_options.minimum_fraction_digits, + digit_options.maximum_fraction_digits); + + return result.precision(precision); +} + // static // ecma402 #sec-intl.numberformat.prototype.resolvedoptions Handle<JSObject> JSNumberFormat::ResolvedOptions( @@ -642,9 +647,6 @@ Handle<JSObject> JSNumberFormat::ResolvedOptions( icu::UnicodeString skeleton = icu_number_formatter->toSkeleton(status); CHECK(U_SUCCESS(status)); - std::string s_str; - s_str = skeleton.toUTF8String<std::string>(s_str); - // 4. Let options be ! ObjectCreate(%ObjectPrototype%). Handle<JSObject> options = factory->NewJSObject(isolate->object_function()); @@ -680,7 +682,7 @@ Handle<JSObject> JSNumberFormat::ResolvedOptions( Just(kDontThrow)) .FromJust()); } - Style style = StyleFromSkeleton(skeleton); + JSNumberFormat::Style style = number_format->style(); CHECK(JSReceiver::CreateDataProperty( isolate, options, factory->style_string(), StyleAsString(isolate, style), Just(kDontThrow)) @@ -706,15 +708,15 @@ Handle<JSObject> JSNumberFormat::ResolvedOptions( } if (FLAG_harmony_intl_numberformat_unified) { - std::string unit = UnitFromSkeleton(skeleton); - if (!unit.empty()) { - CHECK(JSReceiver::CreateDataProperty( - isolate, options, factory->unit_string(), - isolate->factory()->NewStringFromAsciiChecked(unit.c_str()), - Just(kDontThrow)) - .FromJust()); - } - if (style == Style::UNIT || style == Style::PERCENT) { + if (style == JSNumberFormat::Style::UNIT) { + std::string unit = UnitFromSkeleton(skeleton); + if (!unit.empty()) { + CHECK(JSReceiver::CreateDataProperty( + isolate, options, factory->unit_string(), + isolate->factory()->NewStringFromAsciiChecked(unit.c_str()), + Just(kDontThrow)) + .FromJust()); + } CHECK(JSReceiver::CreateDataProperty( isolate, options, factory->unitDisplay_string(), UnitDisplayString(isolate, skeleton), Just(kDontThrow)) @@ -827,10 +829,10 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::UnwrapNumberFormat( } // static -MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize( - Isolate* isolate, Handle<JSNumberFormat> number_format, - Handle<Object> locales, Handle<Object> options_obj) { - number_format->set_flags(0); +MaybeHandle<JSNumberFormat> JSNumberFormat::New(Isolate* isolate, + Handle<Map> map, + Handle<Object> locales, + Handle<Object> options_obj) { Factory* factory = isolate->factory(); // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales). @@ -898,7 +900,6 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize( // 9. Set numberFormat.[[Locale]] to r.[[locale]]. Handle<String> locale_str = isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str()); - number_format->set_locale(*locale_str); // 11. Let dataLocale be r.[[dataLocale]]. @@ -911,17 +912,19 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize( const char* service = "Intl.NumberFormat"; std::vector<const char*> style_str_values({"decimal", "percent", "currency"}); - std::vector<Style> style_enum_values( - {Style::DECIMAL, Style::PERCENT, Style::CURRENCY}); + std::vector<JSNumberFormat::Style> style_enum_values( + {JSNumberFormat::Style::DECIMAL, JSNumberFormat::Style::PERCENT, + JSNumberFormat::Style::CURRENCY}); if (FLAG_harmony_intl_numberformat_unified) { style_str_values.push_back("unit"); - style_enum_values.push_back(Style::UNIT); + style_enum_values.push_back(JSNumberFormat::Style::UNIT); } - Maybe<Style> maybe_style = Intl::GetStringOption<Style>( - isolate, options, "style", service, style_str_values, style_enum_values, - Style::DECIMAL); + Maybe<JSNumberFormat::Style> maybe_style = + Intl::GetStringOption<JSNumberFormat::Style>( + isolate, options, "style", service, style_str_values, + style_enum_values, JSNumberFormat::Style::DECIMAL); MAYBE_RETURN(maybe_style, MaybeHandle<JSNumberFormat>()); - Style style = maybe_style.FromJust(); + JSNumberFormat::Style style = maybe_style.FromJust(); // 13. Set numberFormat.[[Style]] to style. @@ -952,14 +955,14 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize( // 16. If style is "currency" and currency is undefined, throw a TypeError // exception. - if (style == Style::CURRENCY && !found_currency.FromJust()) { + if (style == JSNumberFormat::Style::CURRENCY && !found_currency.FromJust()) { THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kCurrencyCode), JSNumberFormat); } // 17. If style is "currency", then int c_digits = 0; icu::UnicodeString currency_ustr; - if (style == Style::CURRENCY) { + if (style == JSNumberFormat::Style::CURRENCY) { // a. Let currency be the result of converting currency to upper case as // specified in 6.1 std::transform(currency.begin(), currency.end(), currency.begin(), toupper); @@ -975,7 +978,7 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize( std::vector<CurrencyDisplay> currency_display_enum_values( {CurrencyDisplay::CODE, CurrencyDisplay::SYMBOL, CurrencyDisplay::NAME}); if (FLAG_harmony_intl_numberformat_unified) { - currency_display_str_values.push_back("narrow-symbol"); + currency_display_str_values.push_back("narrowSymbol"); currency_display_enum_values.push_back(CurrencyDisplay::NARROW_SYMBOL); } Maybe<CurrencyDisplay> maybe_currency_display = @@ -1020,13 +1023,8 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize( MAYBE_RETURN(maybe_unit_display, MaybeHandle<JSNumberFormat>()); UnitDisplay unit_display = maybe_unit_display.FromJust(); - // If style is "percent", then - if (style == Style::PERCENT) { - // Let unit be "concentr-percent". - unit = "percent"; - } - // If style is "unit" or "percent", then - if (style == Style::PERCENT || style == Style::UNIT) { + // If style is "unit", then + if (style == JSNumberFormat::Style::UNIT) { // If unit is undefined, throw a TypeError exception. if (unit == "") { THROW_NEW_ERROR( @@ -1070,12 +1068,12 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize( } } - if (style == Style::PERCENT) { + if (style == JSNumberFormat::Style::PERCENT) { icu_number_formatter = icu_number_formatter.unit(icu::NoUnit::percent()) .scale(icu::number::Scale::powerOfTen(2)); } - if (style == Style::CURRENCY) { + if (style == JSNumberFormat::Style::CURRENCY) { // 19. If style is "currency", set numberFormat.[[CurrencyDisplay]] to // currencyDisplay. @@ -1099,19 +1097,19 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize( } } - // 20. If style is "currency", then + // 23. If style is "currency", then int mnfd_default, mxfd_default; - if (style == Style::CURRENCY) { + if (style == JSNumberFormat::Style::CURRENCY) { // a. Let mnfdDefault be cDigits. // b. Let mxfdDefault be cDigits. mnfd_default = c_digits; mxfd_default = c_digits; + // 24. Else, } else { - // 21. Else, // a. Let mnfdDefault be 0. mnfd_default = 0; // b. If style is "percent", then - if (style == Style::PERCENT) { + if (style == JSNumberFormat::Style::PERCENT) { // i. Let mxfdDefault be 0. mxfd_default = 0; } else { @@ -1120,51 +1118,11 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize( mxfd_default = 3; } } - // 22. Perform ? SetNumberFormatDigitOptions(numberFormat, options, - // mnfdDefault, mxfdDefault). - Maybe<Intl::NumberFormatDigitOptions> maybe_digit_options = - Intl::SetNumberFormatDigitOptions(isolate, options, mnfd_default, - mxfd_default); - MAYBE_RETURN(maybe_digit_options, Handle<JSNumberFormat>()); - Intl::NumberFormatDigitOptions digit_options = maybe_digit_options.FromJust(); - - icu::number::Precision precision = - (digit_options.minimum_significant_digits > 0) - ? icu::number::Precision::minMaxSignificantDigits( - digit_options.minimum_significant_digits, - digit_options.maximum_significant_digits) - : icu::number::Precision::minMaxFraction( - digit_options.minimum_fraction_digits, - digit_options.maximum_fraction_digits); - - if (digit_options.minimum_significant_digits > 0) { - // Currenct ECMA 402 spec mandate to record (Min|Max)imumFractionDigits - // uncondictionally while the unified number proposal eventually will only - // record either (Min|Max)imumFractionDigits or - // (Min|Max)imumSignaficantDigits Since LocalizedNumberFormatter can only - // remember one set, and during 2019-1-17 ECMA402 meeting that the committee - // decide not to take a PR to address that prior to the unified number - // proposal, we have to add these two 5 bits int into flags to remember the - // (Min|Max)imumFractionDigits while (Min|Max)imumSignaficantDigits is - // present. - // TODO(ftang) remove the following two lines once we ship - // int-number-format-unified - number_format->set_minimum_fraction_digits( - digit_options.minimum_fraction_digits); - number_format->set_maximum_fraction_digits( - digit_options.maximum_fraction_digits); - } - - icu_number_formatter = icu_number_formatter.precision(precision); - if (digit_options.minimum_integer_digits > 1) { - icu_number_formatter = - icu_number_formatter.integerWidth(icu::number::IntegerWidth::zeroFillTo( - digit_options.minimum_integer_digits)); - } + Notation notation = Notation::STANDARD; if (FLAG_harmony_intl_numberformat_unified) { - // Let notation be ? GetOption(options, "notation", "string", « "standard", - // "scientific", "engineering", "compact" », "standard"). + // 25. Let notation be ? GetOption(options, "notation", "string", « + // "standard", "scientific", "engineering", "compact" », "standard"). Maybe<Notation> maybe_notation = Intl::GetStringOption<Notation>( isolate, options, "notation", service, {"standard", "scientific", "engineering", "compact"}, @@ -1172,10 +1130,23 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize( Notation::COMPACT}, Notation::STANDARD); MAYBE_RETURN(maybe_notation, MaybeHandle<JSNumberFormat>()); - Notation notation = maybe_notation.FromJust(); + notation = maybe_notation.FromJust(); + } + + // 27. Perform ? SetNumberFormatDigitOptions(numberFormat, options, + // mnfdDefault, mxfdDefault). + Maybe<Intl::NumberFormatDigitOptions> maybe_digit_options = + Intl::SetNumberFormatDigitOptions(isolate, options, mnfd_default, + mxfd_default, + notation == Notation::COMPACT); + MAYBE_RETURN(maybe_digit_options, Handle<JSNumberFormat>()); + Intl::NumberFormatDigitOptions digit_options = maybe_digit_options.FromJust(); + icu_number_formatter = JSNumberFormat::SetDigitOptionsToFormatter( + icu_number_formatter, digit_options); - // Let compactDisplay be ? GetOption(options, "compactDisplay", "string", « - // "short", "long" », "short"). + if (FLAG_harmony_intl_numberformat_unified) { + // 28. Let compactDisplay be ? GetOption(options, "compactDisplay", + // "string", « "short", "long" », "short"). Maybe<CompactDisplay> maybe_compact_display = Intl::GetStringOption<CompactDisplay>( isolate, options, "compactDisplay", service, {"short", "long"}, @@ -1184,6 +1155,7 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize( MAYBE_RETURN(maybe_compact_display, MaybeHandle<JSNumberFormat>()); CompactDisplay compact_display = maybe_compact_display.FromJust(); + // 26. Set numberFormat.[[Notation]] to notation. // The default notation in ICU is Simple, which mapped from STANDARD // so we can skip setting it. if (notation != Notation::STANDARD) { @@ -1191,30 +1163,31 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize( ToICUNotation(notation, compact_display)); } } - // 23. Let useGrouping be ? GetOption(options, "useGrouping", "boolean", + // 30. Let useGrouping be ? GetOption(options, "useGrouping", "boolean", // undefined, true). bool use_grouping = true; Maybe<bool> found_use_grouping = Intl::GetBoolOption( isolate, options, "useGrouping", service, &use_grouping); MAYBE_RETURN(found_use_grouping, MaybeHandle<JSNumberFormat>()); - // 24. Set numberFormat.[[UseGrouping]] to useGrouping. + // 31. Set numberFormat.[[UseGrouping]] to useGrouping. if (!use_grouping) { icu_number_formatter = icu_number_formatter.grouping( UNumberGroupingStrategy::UNUM_GROUPING_OFF); } if (FLAG_harmony_intl_numberformat_unified) { - // Let signDisplay be ? GetOption(options, "signDisplay", "string", « - // "auto", "never", "always", "except-zero" », "auto"). + // 32. Let signDisplay be ? GetOption(options, "signDisplay", "string", « + // "auto", "never", "always", "exceptZero" », "auto"). Maybe<SignDisplay> maybe_sign_display = Intl::GetStringOption<SignDisplay>( isolate, options, "signDisplay", service, - {"auto", "never", "always", "except-zero"}, + {"auto", "never", "always", "exceptZero"}, {SignDisplay::AUTO, SignDisplay::NEVER, SignDisplay::ALWAYS, SignDisplay::EXCEPT_ZERO}, SignDisplay::AUTO); MAYBE_RETURN(maybe_sign_display, MaybeHandle<JSNumberFormat>()); SignDisplay sign_display = maybe_sign_display.FromJust(); + // 33. Set numberFormat.[[SignDisplay]] to signDisplay. // The default sign in ICU is UNUM_SIGN_AUTO which is mapped from // SignDisplay::AUTO and CurrencySign::STANDARD so we can skip setting // under that values for optimization. @@ -1244,6 +1217,33 @@ MaybeHandle<JSNumberFormat> JSNumberFormat::Initialize( Managed<icu::number::LocalizedNumberFormatter>::FromRawPtr( isolate, 0, new icu::number::LocalizedNumberFormatter(icu_number_formatter)); + + // Now all properties are ready, so we can allocate the result object. + Handle<JSNumberFormat> number_format = Handle<JSNumberFormat>::cast( + isolate->factory()->NewFastOrSlowJSObjectFromMap(map)); + DisallowHeapAllocation no_gc; + number_format->set_flags(0); + number_format->set_style(style); + number_format->set_locale(*locale_str); + + if (digit_options.minimum_significant_digits > 0) { + // The current ECMA 402 spec mandates recording (Min|Max)imumFractionDigits + // unconditionally, while the unified number proposal eventually will only + // record either (Min|Max)imumFractionDigits or + // (Min|Max)imumSignificantDigits. Since LocalizedNumberFormatter can only + // remember one set, and during 2019-1-17 ECMA402 meeting the committee + // decided not to take a PR to address that prior to the unified number + // proposal, we have to add these two 5-bit ints into flags to remember the + // (Min|Max)imumFractionDigits while (Min|Max)imumSignificantDigits is + // present. + // TODO(ftang) remove the following two lines once we ship + // int-number-format-unified + number_format->set_minimum_fraction_digits( + digit_options.minimum_fraction_digits); + number_format->set_maximum_fraction_digits( + digit_options.maximum_fraction_digits); + } + number_format->set_icu_number_formatter(*managed_number_formatter); number_format->set_bound_format(*factory->undefined_value()); @@ -1417,7 +1417,7 @@ namespace { Maybe<int> ConstructParts(Isolate* isolate, const icu::UnicodeString& formatted, icu::FieldPositionIterator* fp_iter, Handle<JSArray> result, int start_index, - Handle<Object> numeric_obj, Handle<String> unit) { + Handle<Object> numeric_obj, bool style_is_unit) { DCHECK(numeric_obj->IsNumeric()); int32_t length = formatted.length(); int index = start_index; @@ -1442,21 +1442,23 @@ Maybe<int> ConstructParts(Isolate* isolate, const icu::UnicodeString& formatted, for (auto it = parts.begin(); it < parts.end(); it++) { NumberFormatSpan part = *it; - Handle<String> field_type_string = - part.field_id == -1 - ? isolate->factory()->literal_string() - : Intl::NumberFieldToType(isolate, numeric_obj, part.field_id); + Handle<String> field_type_string = isolate->factory()->literal_string(); + if (part.field_id != -1) { + if (style_is_unit && static_cast<UNumberFormatFields>(part.field_id) == + UNUM_PERCENT_FIELD) { + // Special case when style is unit. + field_type_string = isolate->factory()->unit_string(); + } else { + field_type_string = + Intl::NumberFieldToType(isolate, numeric_obj, part.field_id); + } + } Handle<String> substring; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate, substring, Intl::ToString(isolate, formatted, part.begin_pos, part.end_pos), Nothing<int>()); - if (unit.is_null()) { - Intl::AddElement(isolate, result, index, field_type_string, substring); - } else { - Intl::AddElement(isolate, result, index, field_type_string, substring, - isolate->factory()->unit_string(), unit); - } + Intl::AddElement(isolate, result, index, field_type_string, substring); ++index; } JSObject::ValidateElements(*result); @@ -1480,16 +1482,26 @@ MaybeHandle<JSArray> JSNumberFormat::FormatToParts( MAYBE_RETURN(maybe_format, Handle<JSArray>()); Handle<JSArray> result = factory->NewJSArray(0); - Maybe<int> maybe_format_to_parts = - ConstructParts(isolate, maybe_format.FromJust(), &fp_iter, result, 0, - numeric_obj, Handle<String>()); + Maybe<int> maybe_format_to_parts = ConstructParts( + isolate, maybe_format.FromJust(), &fp_iter, result, 0, numeric_obj, + number_format->style() == JSNumberFormat::Style::UNIT); MAYBE_RETURN(maybe_format_to_parts, Handle<JSArray>()); return result; } +namespace { + +struct CheckNumberElements { + static const char* key() { return "NumberElements"; } + static const char* path() { return nullptr; } +}; + +} // namespace + const std::set<std::string>& JSNumberFormat::GetAvailableLocales() { - static base::LazyInstance<Intl::AvailableLocales<icu::NumberFormat>>::type + static base::LazyInstance< + Intl::AvailableLocales<icu::NumberFormat, CheckNumberElements>>::type available_locales = LAZY_INSTANCE_INITIALIZER; return available_locales.Pointer()->Get(); } diff --git a/chromium/v8/src/objects/js-number-format.h b/chromium/v8/src/objects/js-number-format.h index 6c59e76f7ab..2979ab10f43 100644 --- a/chromium/v8/src/objects/js-number-format.h +++ b/chromium/v8/src/objects/js-number-format.h @@ -17,14 +17,15 @@ #include "src/objects/intl-objects.h" #include "src/objects/managed.h" #include "src/objects/objects.h" -#include "unicode/numberformatter.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" namespace U_ICU_NAMESPACE { -class NumberFormat; class UnicodeString; +namespace number { +class LocalizedNumberFormatter; +} // namespace number } // namespace U_ICU_NAMESPACE namespace v8 { @@ -33,9 +34,9 @@ namespace internal { class JSNumberFormat : public JSObject { public: // ecma402/#sec-initializenumberformat - V8_WARN_UNUSED_RESULT static MaybeHandle<JSNumberFormat> Initialize( - Isolate* isolate, Handle<JSNumberFormat> number_format, - Handle<Object> locales, Handle<Object> options); + V8_WARN_UNUSED_RESULT static MaybeHandle<JSNumberFormat> New( + Isolate* isolate, Handle<Map> map, Handle<Object> locales, + Handle<Object> options); // ecma402/#sec-unwrapnumberformat V8_WARN_UNUSED_RESULT static MaybeHandle<JSNumberFormat> UnwrapNumberFormat( @@ -56,6 +57,17 @@ class JSNumberFormat : public JSObject { V8_EXPORT_PRIVATE static const std::set<std::string>& GetAvailableLocales(); + // Helper functions shared with JSPluralRules. + static int32_t MinimumIntegerDigitsFromSkeleton( + const icu::UnicodeString& skeleton); + static bool FractionDigitsFromSkeleton(const icu::UnicodeString& skeleton, + int32_t* minimum, int32_t* maximum); + static bool SignificantDigitsFromSkeleton(const icu::UnicodeString& skeleton, + int32_t* minimum, int32_t* maximum); + static icu::number::LocalizedNumberFormatter SetDigitOptionsToFormatter( + const icu::number::LocalizedNumberFormatter& icu_number_formatter, + const Intl::NumberFormatDigitOptions& digit_options); + DECL_CAST(JSNumberFormat) DECL_PRINTER(JSNumberFormat) DECL_VERIFIER(JSNumberFormat) @@ -80,6 +92,14 @@ class JSNumberFormat : public JSObject { inline int maximum_fraction_digits() const; inline void set_maximum_fraction_digits(int digits); + // [[Style]] is one of the values "decimal", "percent", "currency", + // or "unit" identifying the style of the number format. + // Note: "unit" is added in proposal-unified-intl-numberformat + enum class Style { DECIMAL, PERCENT, CURRENCY, UNIT }; + + inline void set_style(Style style); + inline Style style() const; + // Layout description. DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, TORQUE_GENERATED_JSNUMBER_FORMAT_FIELDS) @@ -87,13 +107,18 @@ class JSNumberFormat : public JSObject { // Bit positions in |flags|. #define FLAGS_BIT_FIELDS(V, _) \ V(MinimumFractionDigitsBits, int, 5, _) \ - V(MaximumFractionDigitsBits, int, 5, _) + V(MaximumFractionDigitsBits, int, 5, _) \ + V(StyleBits, Style, 2, _) DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS) #undef FLAGS_BIT_FIELDS STATIC_ASSERT(20 <= MinimumFractionDigitsBits::kMax); STATIC_ASSERT(20 <= MaximumFractionDigitsBits::kMax); + STATIC_ASSERT(Style::DECIMAL <= StyleBits::kMax); + STATIC_ASSERT(Style::PERCENT <= StyleBits::kMax); + STATIC_ASSERT(Style::CURRENCY <= StyleBits::kMax); + STATIC_ASSERT(Style::UNIT <= StyleBits::kMax); DECL_ACCESSORS(locale, String) DECL_ACCESSORS(icu_number_formatter, diff --git a/chromium/v8/src/objects/js-objects-inl.h b/chromium/v8/src/objects/js-objects-inl.h index 6b7a7d72f0c..10672d44438 100644 --- a/chromium/v8/src/objects/js-objects-inl.h +++ b/chromium/v8/src/objects/js-objects-inl.h @@ -8,6 +8,7 @@ #include "src/objects/js-objects.h" #include "src/heap/heap-write-barrier.h" +#include "src/objects/elements.h" #include "src/objects/embedder-data-slot-inl.h" #include "src/objects/feedback-cell-inl.h" #include "src/objects/feedback-vector.h" @@ -29,17 +30,17 @@ namespace v8 { namespace internal { OBJECT_CONSTRUCTORS_IMPL(JSReceiver, HeapObject) -OBJECT_CONSTRUCTORS_IMPL(JSObject, JSReceiver) +TQ_OBJECT_CONSTRUCTORS_IMPL(JSObject) OBJECT_CONSTRUCTORS_IMPL(JSAsyncFromSyncIterator, JSObject) OBJECT_CONSTRUCTORS_IMPL(JSBoundFunction, JSObject) OBJECT_CONSTRUCTORS_IMPL(JSDate, JSObject) OBJECT_CONSTRUCTORS_IMPL(JSFunction, JSObject) OBJECT_CONSTRUCTORS_IMPL(JSGlobalObject, JSObject) -OBJECT_CONSTRUCTORS_IMPL(JSGlobalProxy, JSObject) +TQ_OBJECT_CONSTRUCTORS_IMPL(JSGlobalProxy) JSIteratorResult::JSIteratorResult(Address ptr) : JSObject(ptr) {} OBJECT_CONSTRUCTORS_IMPL(JSMessageObject, JSObject) +TQ_OBJECT_CONSTRUCTORS_IMPL(JSPrimitiveWrapper) OBJECT_CONSTRUCTORS_IMPL(JSStringIterator, JSObject) -OBJECT_CONSTRUCTORS_IMPL(JSValue, JSObject) NEVER_READ_ONLY_SPACE_IMPL(JSReceiver) @@ -48,13 +49,10 @@ CAST_ACCESSOR(JSBoundFunction) CAST_ACCESSOR(JSDate) CAST_ACCESSOR(JSFunction) CAST_ACCESSOR(JSGlobalObject) -CAST_ACCESSOR(JSGlobalProxy) CAST_ACCESSOR(JSIteratorResult) CAST_ACCESSOR(JSMessageObject) -CAST_ACCESSOR(JSObject) CAST_ACCESSOR(JSReceiver) CAST_ACCESSOR(JSStringIterator) -CAST_ACCESSOR(JSValue) MaybeHandle<Object> JSReceiver::GetProperty(Isolate* isolate, Handle<JSReceiver> receiver, @@ -130,11 +128,6 @@ bool JSObject::PrototypeHasNoElements(Isolate* isolate, JSObject object) { ACCESSORS(JSReceiver, raw_properties_or_hash, Object, kPropertiesOrHashOffset) -FixedArrayBase JSObject::elements() const { - Object array = READ_FIELD(*this, kElementsOffset); - return FixedArrayBase::cast(array); -} - void JSObject::EnsureCanContainHeapObjectElements(Handle<JSObject> object) { JSObject::ValidateElements(*object); ElementsKind elements_kind = object->map().elements_kind(); @@ -225,39 +218,34 @@ void JSObject::EnsureCanContainElements(Handle<JSObject> object, void JSObject::SetMapAndElements(Handle<JSObject> object, Handle<Map> new_map, Handle<FixedArrayBase> value) { - JSObject::MigrateToMap(object, new_map); + Isolate* isolate = object->GetIsolate(); + JSObject::MigrateToMap(isolate, object, new_map); DCHECK((object->map().has_fast_smi_or_object_elements() || - (*value == object->GetReadOnlyRoots().empty_fixed_array()) || + (*value == ReadOnlyRoots(isolate).empty_fixed_array()) || object->map().has_fast_string_wrapper_elements()) == - (value->map() == object->GetReadOnlyRoots().fixed_array_map() || - value->map() == object->GetReadOnlyRoots().fixed_cow_array_map())); - DCHECK((*value == object->GetReadOnlyRoots().empty_fixed_array()) || + (value->map() == ReadOnlyRoots(isolate).fixed_array_map() || + value->map() == ReadOnlyRoots(isolate).fixed_cow_array_map())); + DCHECK((*value == ReadOnlyRoots(isolate).empty_fixed_array()) || (object->map().has_fast_double_elements() == value->IsFixedDoubleArray())); object->set_elements(*value); } -void JSObject::set_elements(FixedArrayBase value, WriteBarrierMode mode) { - WRITE_FIELD(*this, kElementsOffset, value); - CONDITIONAL_WRITE_BARRIER(*this, kElementsOffset, value, mode); -} - void JSObject::initialize_elements() { FixedArrayBase elements = map().GetInitialElements(); - WRITE_FIELD(*this, kElementsOffset, elements); + set_elements(elements, SKIP_WRITE_BARRIER); } -InterceptorInfo JSObject::GetIndexedInterceptor() { - return map().GetIndexedInterceptor(); +DEF_GETTER(JSObject, GetIndexedInterceptor, InterceptorInfo) { + return map(isolate).GetIndexedInterceptor(isolate); } -InterceptorInfo JSObject::GetNamedInterceptor() { - return map().GetNamedInterceptor(); +DEF_GETTER(JSObject, GetNamedInterceptor, InterceptorInfo) { + return map(isolate).GetNamedInterceptor(isolate); } -int JSObject::GetHeaderSize() const { return GetHeaderSize(map()); } - -int JSObject::GetHeaderSize(const Map map) { +// static +int JSObject::GetHeaderSize(Map map) { // Check for the most common kind of JavaScript object before // falling into the generic switch. This speeds up the internal // field operations considerably on average. @@ -268,7 +256,7 @@ int JSObject::GetHeaderSize(const Map map) { } // static -int JSObject::GetEmbedderFieldsStartOffset(const Map map) { +int JSObject::GetEmbedderFieldsStartOffset(Map map) { // Embedder fields are located after the object header. return GetHeaderSize(map); } @@ -278,7 +266,7 @@ int JSObject::GetEmbedderFieldsStartOffset() { } // static -int JSObject::GetEmbedderFieldCount(const Map map) { +int JSObject::GetEmbedderFieldCount(Map map) { int instance_size = map.instance_size(); if (instance_size == kVariableSizeSentinel) return 0; // Embedder fields are located after the object header, whereas in-object @@ -314,29 +302,39 @@ void JSObject::SetEmbedderField(int index, Smi value) { EmbedderDataSlot(*this, index).store_smi(value); } -bool JSObject::IsUnboxedDoubleField(FieldIndex index) { +bool JSObject::IsUnboxedDoubleField(FieldIndex index) const { + Isolate* isolate = GetIsolateForPtrCompr(*this); + return IsUnboxedDoubleField(isolate, index); +} + +bool JSObject::IsUnboxedDoubleField(Isolate* isolate, FieldIndex index) const { if (!FLAG_unbox_double_fields) return false; - return map().IsUnboxedDoubleField(index); + return map(isolate).IsUnboxedDoubleField(isolate, index); } // Access fast-case object properties at index. The use of these routines // is needed to correctly distinguish between properties stored in-object and // properties stored in the properties array. -Object JSObject::RawFastPropertyAt(FieldIndex index) { - DCHECK(!IsUnboxedDoubleField(index)); +Object JSObject::RawFastPropertyAt(FieldIndex index) const { + Isolate* isolate = GetIsolateForPtrCompr(*this); + return RawFastPropertyAt(isolate, index); +} + +Object JSObject::RawFastPropertyAt(Isolate* isolate, FieldIndex index) const { + DCHECK(!IsUnboxedDoubleField(isolate, index)); if (index.is_inobject()) { - return READ_FIELD(*this, index.offset()); + return TaggedField<Object>::load(isolate, *this, index.offset()); } else { - return property_array().get(index.outobject_array_index()); + return property_array(isolate).get(isolate, index.outobject_array_index()); } } -double JSObject::RawFastDoublePropertyAt(FieldIndex index) { +double JSObject::RawFastDoublePropertyAt(FieldIndex index) const { DCHECK(IsUnboxedDoubleField(index)); return ReadField<double>(index.offset()); } -uint64_t JSObject::RawFastDoublePropertyAsBitsAt(FieldIndex index) { +uint64_t JSObject::RawFastDoublePropertyAsBitsAt(FieldIndex index) const { DCHECK(IsUnboxedDoubleField(index)); return ReadField<uint64_t>(index.offset()); } @@ -417,7 +415,7 @@ int JSObject::GetInObjectPropertyOffset(int index) { Object JSObject::InObjectPropertyAt(int index) { int offset = GetInObjectPropertyOffset(index); - return READ_FIELD(*this, offset); + return TaggedField<Object>::load(*this, offset); } Object JSObject::InObjectPropertyAtPut(int index, Object value, @@ -452,10 +450,6 @@ void JSObject::InitializeBody(Map map, int start_offset, } } -Object JSBoundFunction::raw_bound_target_function() const { - return READ_FIELD(*this, kBoundTargetFunctionOffset); -} - ACCESSORS(JSBoundFunction, bound_target_function, JSReceiver, kBoundTargetFunctionOffset) ACCESSORS(JSBoundFunction, bound_this, Object, kBoundThisOffset) @@ -466,8 +460,6 @@ ACCESSORS(JSFunction, raw_feedback_cell, FeedbackCell, kFeedbackCellOffset) ACCESSORS(JSGlobalObject, native_context, NativeContext, kNativeContextOffset) ACCESSORS(JSGlobalObject, global_proxy, JSGlobalProxy, kGlobalProxyOffset) -ACCESSORS(JSGlobalProxy, native_context, Object, kNativeContextOffset) - FeedbackVector JSFunction::feedback_vector() const { DCHECK(has_feedback_vector()); return FeedbackVector::cast(raw_feedback_cell().value()); @@ -564,7 +556,8 @@ void JSFunction::set_code_no_write_barrier(Code value) { RELAXED_WRITE_FIELD(*this, kCodeOffset, value); } -SharedFunctionInfo JSFunction::shared() const { +// TODO(ishell): Why relaxed read but release store? +DEF_GETTER(JSFunction, shared, SharedFunctionInfo) { return SharedFunctionInfo::cast( RELAXED_READ_FIELD(*this, kSharedFunctionInfoOffset)); } @@ -606,11 +599,11 @@ bool JSFunction::has_closure_feedback_cell_array() const { } Context JSFunction::context() { - return Context::cast(READ_FIELD(*this, kContextOffset)); + return TaggedField<Context, kContextOffset>::load(*this); } bool JSFunction::has_context() const { - return READ_FIELD(*this, kContextOffset).IsContext(); + return TaggedField<HeapObject, kContextOffset>::load(*this).IsContext(); } JSGlobalProxy JSFunction::global_proxy() { return context().global_proxy(); } @@ -619,65 +612,73 @@ NativeContext JSFunction::native_context() { return context().native_context(); } -void JSFunction::set_context(Object value) { +void JSFunction::set_context(HeapObject value) { DCHECK(value.IsUndefined() || value.IsContext()); WRITE_FIELD(*this, kContextOffset, value); WRITE_BARRIER(*this, kContextOffset, value); } -ACCESSORS_CHECKED(JSFunction, prototype_or_initial_map, Object, +ACCESSORS_CHECKED(JSFunction, prototype_or_initial_map, HeapObject, kPrototypeOrInitialMapOffset, map().has_prototype_slot()) -bool JSFunction::has_prototype_slot() const { - return map().has_prototype_slot(); +DEF_GETTER(JSFunction, has_prototype_slot, bool) { + return map(isolate).has_prototype_slot(); } -Map JSFunction::initial_map() { return Map::cast(prototype_or_initial_map()); } +DEF_GETTER(JSFunction, initial_map, Map) { + return Map::cast(prototype_or_initial_map(isolate)); +} -bool JSFunction::has_initial_map() { - DCHECK(has_prototype_slot()); - return prototype_or_initial_map().IsMap(); +DEF_GETTER(JSFunction, has_initial_map, bool) { + DCHECK(has_prototype_slot(isolate)); + return prototype_or_initial_map(isolate).IsMap(isolate); } -bool JSFunction::has_instance_prototype() { - DCHECK(has_prototype_slot()); - return has_initial_map() || !prototype_or_initial_map().IsTheHole(); +DEF_GETTER(JSFunction, has_instance_prototype, bool) { + DCHECK(has_prototype_slot(isolate)); + // Can't use ReadOnlyRoots(isolate) as this isolate could be produced by + // i::GetIsolateForPtrCompr(HeapObject). + return has_initial_map(isolate) || + !prototype_or_initial_map(isolate).IsTheHole( + GetReadOnlyRoots(isolate)); } -bool JSFunction::has_prototype() { - DCHECK(has_prototype_slot()); - return map().has_non_instance_prototype() || has_instance_prototype(); +DEF_GETTER(JSFunction, has_prototype, bool) { + DCHECK(has_prototype_slot(isolate)); + return map(isolate).has_non_instance_prototype() || + has_instance_prototype(isolate); } -bool JSFunction::has_prototype_property() { - return (has_prototype_slot() && IsConstructor()) || - IsGeneratorFunction(shared().kind()); +DEF_GETTER(JSFunction, has_prototype_property, bool) { + return (has_prototype_slot(isolate) && IsConstructor(isolate)) || + IsGeneratorFunction(shared(isolate).kind()); } -bool JSFunction::PrototypeRequiresRuntimeLookup() { - return !has_prototype_property() || map().has_non_instance_prototype(); +DEF_GETTER(JSFunction, PrototypeRequiresRuntimeLookup, bool) { + return !has_prototype_property(isolate) || + map(isolate).has_non_instance_prototype(); } -HeapObject JSFunction::instance_prototype() { - DCHECK(has_instance_prototype()); - if (has_initial_map()) return initial_map().prototype(); +DEF_GETTER(JSFunction, instance_prototype, HeapObject) { + DCHECK(has_instance_prototype(isolate)); + if (has_initial_map(isolate)) return initial_map(isolate).prototype(isolate); // When there is no initial map and the prototype is a JSReceiver, the // initial map field is used for the prototype field. - return HeapObject::cast(prototype_or_initial_map()); + return HeapObject::cast(prototype_or_initial_map(isolate)); } -Object JSFunction::prototype() { - DCHECK(has_prototype()); +DEF_GETTER(JSFunction, prototype, Object) { + DCHECK(has_prototype(isolate)); // If the function's prototype property has been set to a non-JSReceiver // value, that value is stored in the constructor field of the map. - if (map().has_non_instance_prototype()) { - Object prototype = map().GetConstructor(); + if (map(isolate).has_non_instance_prototype()) { + Object prototype = map(isolate).GetConstructor(isolate); // The map must have a prototype in that field, not a back pointer. - DCHECK(!prototype.IsMap()); - DCHECK(!prototype.IsFunctionTemplateInfo()); + DCHECK(!prototype.IsMap(isolate)); + DCHECK(!prototype.IsFunctionTemplateInfo(isolate)); return prototype; } - return instance_prototype(); + return instance_prototype(isolate); } bool JSFunction::is_compiled() const { @@ -711,8 +712,6 @@ void JSFunction::ResetIfBytecodeFlushed() { } } -ACCESSORS(JSValue, value, Object, kValueOffset) - ACCESSORS(JSDate, value, Object, kValueOffset) ACCESSORS(JSDate, cache_stamp, Object, kCacheStampOffset) ACCESSORS(JSDate, year, Object, kYearOffset) @@ -738,12 +737,11 @@ int JSMessageObject::GetEndPosition() const { } MessageTemplate JSMessageObject::type() const { - Object value = READ_FIELD(*this, kMessageTypeOffset); - return MessageTemplateFromInt(Smi::ToInt(value)); + return MessageTemplateFromInt(raw_type()); } void JSMessageObject::set_type(MessageTemplate value) { - WRITE_FIELD(*this, kMessageTypeOffset, Smi::FromInt(static_cast<int>(value))); + set_raw_type(static_cast<int>(value)); } ACCESSORS(JSMessageObject, argument, Object, kArgumentsOffset) @@ -754,143 +752,154 @@ ACCESSORS(JSMessageObject, bytecode_offset, Smi, kBytecodeOffsetOffset) SMI_ACCESSORS(JSMessageObject, start_position, kStartPositionOffset) SMI_ACCESSORS(JSMessageObject, end_position, kEndPositionOffset) SMI_ACCESSORS(JSMessageObject, error_level, kErrorLevelOffset) +SMI_ACCESSORS(JSMessageObject, raw_type, kMessageTypeOffset) -ElementsKind JSObject::GetElementsKind() const { - ElementsKind kind = map().elements_kind(); +DEF_GETTER(JSObject, GetElementsKind, ElementsKind) { + ElementsKind kind = map(isolate).elements_kind(); #if VERIFY_HEAP && DEBUG - FixedArrayBase fixed_array = - FixedArrayBase::unchecked_cast(READ_FIELD(*this, kElementsOffset)); + FixedArrayBase fixed_array = FixedArrayBase::unchecked_cast( + TaggedField<HeapObject, kElementsOffset>::load(isolate, *this)); // If a GC was caused while constructing this object, the elements // pointer may point to a one pointer filler map. - if (ElementsAreSafeToExamine()) { - Map map = fixed_array.map(); + if (ElementsAreSafeToExamine(isolate)) { + Map map = fixed_array.map(isolate); if (IsSmiOrObjectElementsKind(kind)) { - DCHECK(map == GetReadOnlyRoots().fixed_array_map() || - map == GetReadOnlyRoots().fixed_cow_array_map()); + DCHECK(map == GetReadOnlyRoots(isolate).fixed_array_map() || + map == GetReadOnlyRoots(isolate).fixed_cow_array_map()); } else if (IsDoubleElementsKind(kind)) { - DCHECK(fixed_array.IsFixedDoubleArray() || - fixed_array == GetReadOnlyRoots().empty_fixed_array()); + DCHECK(fixed_array.IsFixedDoubleArray(isolate) || + fixed_array == GetReadOnlyRoots(isolate).empty_fixed_array()); } else if (kind == DICTIONARY_ELEMENTS) { - DCHECK(fixed_array.IsFixedArray()); - DCHECK(fixed_array.IsNumberDictionary()); + DCHECK(fixed_array.IsFixedArray(isolate)); + DCHECK(fixed_array.IsNumberDictionary(isolate)); } else { DCHECK(kind > DICTIONARY_ELEMENTS || IsFrozenOrSealedElementsKind(kind)); } - DCHECK(!IsSloppyArgumentsElementsKind(kind) || - (elements().IsFixedArray() && elements().length() >= 2)); + DCHECK( + !IsSloppyArgumentsElementsKind(kind) || + (elements(isolate).IsFixedArray() && elements(isolate).length() >= 2)); } #endif return kind; } -bool JSObject::HasObjectElements() { - return IsObjectElementsKind(GetElementsKind()); +DEF_GETTER(JSObject, GetElementsAccessor, ElementsAccessor*) { + return ElementsAccessor::ForKind(GetElementsKind(isolate)); +} + +DEF_GETTER(JSObject, HasObjectElements, bool) { + return IsObjectElementsKind(GetElementsKind(isolate)); } -bool JSObject::HasSmiElements() { return IsSmiElementsKind(GetElementsKind()); } +DEF_GETTER(JSObject, HasSmiElements, bool) { + return IsSmiElementsKind(GetElementsKind(isolate)); +} -bool JSObject::HasSmiOrObjectElements() { - return IsSmiOrObjectElementsKind(GetElementsKind()); +DEF_GETTER(JSObject, HasSmiOrObjectElements, bool) { + return IsSmiOrObjectElementsKind(GetElementsKind(isolate)); } -bool JSObject::HasDoubleElements() { - return IsDoubleElementsKind(GetElementsKind()); +DEF_GETTER(JSObject, HasDoubleElements, bool) { + return IsDoubleElementsKind(GetElementsKind(isolate)); } -bool JSObject::HasHoleyElements() { - return IsHoleyElementsKind(GetElementsKind()); +DEF_GETTER(JSObject, HasHoleyElements, bool) { + return IsHoleyElementsKind(GetElementsKind(isolate)); } -bool JSObject::HasFastElements() { - return IsFastElementsKind(GetElementsKind()); +DEF_GETTER(JSObject, HasFastElements, bool) { + return IsFastElementsKind(GetElementsKind(isolate)); } -bool JSObject::HasFastPackedElements() { - return IsFastPackedElementsKind(GetElementsKind()); +DEF_GETTER(JSObject, HasFastPackedElements, bool) { + return IsFastPackedElementsKind(GetElementsKind(isolate)); } -bool JSObject::HasDictionaryElements() { - return GetElementsKind() == DICTIONARY_ELEMENTS; +DEF_GETTER(JSObject, HasDictionaryElements, bool) { + return GetElementsKind(isolate) == DICTIONARY_ELEMENTS; } -bool JSObject::HasPackedElements() { - return GetElementsKind() == PACKED_ELEMENTS; +DEF_GETTER(JSObject, HasPackedElements, bool) { + return GetElementsKind(isolate) == PACKED_ELEMENTS; } -bool JSObject::HasFrozenOrSealedElements() { - return IsFrozenOrSealedElementsKind(GetElementsKind()); +DEF_GETTER(JSObject, HasFrozenOrSealedElements, bool) { + return IsFrozenOrSealedElementsKind(GetElementsKind(isolate)); } -bool JSObject::HasSealedElements() { - return IsSealedElementsKind(GetElementsKind()); +DEF_GETTER(JSObject, HasSealedElements, bool) { + return IsSealedElementsKind(GetElementsKind(isolate)); } -bool JSObject::HasFastArgumentsElements() { - return GetElementsKind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS; +DEF_GETTER(JSObject, HasFastArgumentsElements, bool) { + return GetElementsKind(isolate) == FAST_SLOPPY_ARGUMENTS_ELEMENTS; } -bool JSObject::HasSlowArgumentsElements() { - return GetElementsKind() == SLOW_SLOPPY_ARGUMENTS_ELEMENTS; +DEF_GETTER(JSObject, HasSlowArgumentsElements, bool) { + return GetElementsKind(isolate) == SLOW_SLOPPY_ARGUMENTS_ELEMENTS; } -bool JSObject::HasSloppyArgumentsElements() { - return IsSloppyArgumentsElementsKind(GetElementsKind()); +DEF_GETTER(JSObject, HasSloppyArgumentsElements, bool) { + return IsSloppyArgumentsElementsKind(GetElementsKind(isolate)); } -bool JSObject::HasStringWrapperElements() { - return IsStringWrapperElementsKind(GetElementsKind()); +DEF_GETTER(JSObject, HasStringWrapperElements, bool) { + return IsStringWrapperElementsKind(GetElementsKind(isolate)); } -bool JSObject::HasFastStringWrapperElements() { - return GetElementsKind() == FAST_STRING_WRAPPER_ELEMENTS; +DEF_GETTER(JSObject, HasFastStringWrapperElements, bool) { + return GetElementsKind(isolate) == FAST_STRING_WRAPPER_ELEMENTS; } -bool JSObject::HasSlowStringWrapperElements() { - return GetElementsKind() == SLOW_STRING_WRAPPER_ELEMENTS; +DEF_GETTER(JSObject, HasSlowStringWrapperElements, bool) { + return GetElementsKind(isolate) == SLOW_STRING_WRAPPER_ELEMENTS; } -bool JSObject::HasTypedArrayElements() { - DCHECK(!elements().is_null()); - return map().has_typed_array_elements(); +DEF_GETTER(JSObject, HasTypedArrayElements, bool) { + DCHECK(!elements(isolate).is_null()); + return map(isolate).has_typed_array_elements(); } #define FIXED_TYPED_ELEMENTS_CHECK(Type, type, TYPE, ctype) \ - bool JSObject::HasFixed##Type##Elements() { \ - return map().elements_kind() == TYPE##_ELEMENTS; \ + DEF_GETTER(JSObject, HasFixed##Type##Elements, bool) { \ + return map(isolate).elements_kind() == TYPE##_ELEMENTS; \ } TYPED_ARRAYS(FIXED_TYPED_ELEMENTS_CHECK) #undef FIXED_TYPED_ELEMENTS_CHECK -bool JSObject::HasNamedInterceptor() { return map().has_named_interceptor(); } +DEF_GETTER(JSObject, HasNamedInterceptor, bool) { + return map(isolate).has_named_interceptor(); +} -bool JSObject::HasIndexedInterceptor() { - return map().has_indexed_interceptor(); +DEF_GETTER(JSObject, HasIndexedInterceptor, bool) { + return map(isolate).has_indexed_interceptor(); } -void JSGlobalObject::set_global_dictionary(GlobalDictionary dictionary) { - DCHECK(IsJSGlobalObject()); - set_raw_properties_or_hash(dictionary); +DEF_GETTER(JSGlobalObject, global_dictionary, GlobalDictionary) { + DCHECK(!HasFastProperties(isolate)); + DCHECK(IsJSGlobalObject(isolate)); + return GlobalDictionary::cast(raw_properties_or_hash(isolate)); } -GlobalDictionary JSGlobalObject::global_dictionary() { - DCHECK(!HasFastProperties()); +void JSGlobalObject::set_global_dictionary(GlobalDictionary dictionary) { DCHECK(IsJSGlobalObject()); - return GlobalDictionary::cast(raw_properties_or_hash()); + set_raw_properties_or_hash(dictionary); } -NumberDictionary JSObject::element_dictionary() { - DCHECK(HasDictionaryElements() || HasSlowStringWrapperElements()); - return NumberDictionary::cast(elements()); +DEF_GETTER(JSObject, element_dictionary, NumberDictionary) { + DCHECK(HasDictionaryElements(isolate) || + HasSlowStringWrapperElements(isolate)); + return NumberDictionary::cast(elements(isolate)); } -void JSReceiver::initialize_properties() { - ReadOnlyRoots roots = GetReadOnlyRoots(); +void JSReceiver::initialize_properties(Isolate* isolate) { + ReadOnlyRoots roots(isolate); DCHECK(!ObjectInYoungGeneration(roots.empty_fixed_array())); DCHECK(!ObjectInYoungGeneration(roots.empty_property_dictionary())); - if (map().is_dictionary_map()) { + if (map(isolate).is_dictionary_map()) { WRITE_FIELD(*this, kPropertiesOrHashOffset, roots.empty_property_dictionary()); } else { @@ -898,36 +907,36 @@ void JSReceiver::initialize_properties() { } } -bool JSReceiver::HasFastProperties() const { - DCHECK(raw_properties_or_hash().IsSmi() || - ((raw_properties_or_hash().IsGlobalDictionary() || - raw_properties_or_hash().IsNameDictionary()) == - map().is_dictionary_map())); - return !map().is_dictionary_map(); +DEF_GETTER(JSReceiver, HasFastProperties, bool) { + DCHECK(raw_properties_or_hash(isolate).IsSmi() || + ((raw_properties_or_hash(isolate).IsGlobalDictionary(isolate) || + raw_properties_or_hash(isolate).IsNameDictionary(isolate)) == + map(isolate).is_dictionary_map())); + return !map(isolate).is_dictionary_map(); } -NameDictionary JSReceiver::property_dictionary() const { - DCHECK(!IsJSGlobalObject()); - DCHECK(!HasFastProperties()); - - Object prop = raw_properties_or_hash(); +DEF_GETTER(JSReceiver, property_dictionary, NameDictionary) { + DCHECK(!IsJSGlobalObject(isolate)); + DCHECK(!HasFastProperties(isolate)); + // Can't use ReadOnlyRoots(isolate) as this isolate could be produced by + // i::GetIsolateForPtrCompr(HeapObject). + Object prop = raw_properties_or_hash(isolate); if (prop.IsSmi()) { - return GetReadOnlyRoots().empty_property_dictionary(); + return GetReadOnlyRoots(isolate).empty_property_dictionary(); } - return NameDictionary::cast(prop); } // TODO(gsathya): Pass isolate directly to this function and access // the heap from this. -PropertyArray JSReceiver::property_array() const { - DCHECK(HasFastProperties()); - - Object prop = raw_properties_or_hash(); - if (prop.IsSmi() || prop == GetReadOnlyRoots().empty_fixed_array()) { - return GetReadOnlyRoots().empty_property_array(); +DEF_GETTER(JSReceiver, property_array, PropertyArray) { + DCHECK(HasFastProperties(isolate)); + // Can't use ReadOnlyRoots(isolate) as this isolate could be produced by + // i::GetIsolateForPtrCompr(HeapObject). + Object prop = raw_properties_or_hash(isolate); + if (prop.IsSmi() || prop == GetReadOnlyRoots(isolate).empty_fixed_array()) { + return GetReadOnlyRoots(isolate).empty_property_array(); } - return PropertyArray::cast(prop); } diff --git a/chromium/v8/src/objects/js-objects.cc b/chromium/v8/src/objects/js-objects.cc index a0dc33909a9..5c4db162067 100644 --- a/chromium/v8/src/objects/js-objects.cc +++ b/chromium/v8/src/objects/js-objects.cc @@ -8,6 +8,7 @@ #include "src/codegen/compiler.h" #include "src/date/date.h" #include "src/execution/arguments.h" +#include "src/execution/frames.h" #include "src/execution/isolate.h" #include "src/handles/handles-inl.h" #include "src/handles/maybe-handles.h" @@ -194,15 +195,16 @@ V8_WARN_UNUSED_RESULT Maybe<bool> FastAssign( return Just(!source->IsString() || String::cast(*source).length() == 0); } + Isolate* isolate = target->GetIsolate(); + // If the target is deprecated, the object will be updated on first store. If // the source for that store equals the target, this will invalidate the // cached representation of the source. Preventively upgrade the target. // Do this on each iteration since any property load could cause deprecation. if (target->map().is_deprecated()) { - JSObject::MigrateInstance(Handle<JSObject>::cast(target)); + JSObject::MigrateInstance(isolate, Handle<JSObject>::cast(target)); } - Isolate* isolate = target->GetIsolate(); Handle<Map> map(JSReceiver::cast(*source).map(), isolate); if (!map->IsJSObjectMap()) return Just(false); @@ -374,8 +376,8 @@ String JSReceiver::class_name() { TYPED_ARRAYS(SWITCH_KIND) #undef SWITCH_KIND } - if (IsJSValue()) { - Object value = JSValue::cast(*this).value(); + if (IsJSPrimitiveWrapper()) { + Object value = JSPrimitiveWrapper::cast(*this).value(); if (value.IsBoolean()) return roots.Boolean_string(); if (value.IsString()) return roots.String_string(); if (value.IsNumber()) return roots.Number_string(); @@ -1092,7 +1094,8 @@ Maybe<bool> SetPropertyWithInterceptorInternal( Maybe<bool> DefinePropertyWithInterceptorInternal( LookupIterator* it, Handle<InterceptorInfo> interceptor, - Maybe<ShouldThrow> should_throw, PropertyDescriptor& desc) { + Maybe<ShouldThrow> should_throw, + PropertyDescriptor& desc) { // NOLINT(runtime/references) Isolate* isolate = it->isolate(); // Make sure that the top context does not change when doing callbacks or // interceptor calls. @@ -1827,6 +1830,13 @@ V8_WARN_UNUSED_RESULT Maybe<bool> FastGetOwnValuesOrEntries( int number_of_own_descriptors = map->NumberOfOwnDescriptors(); int number_of_own_elements = object->GetElementsAccessor()->GetCapacity(*object, object->elements()); + + if (number_of_own_elements > + FixedArray::kMaxLength - number_of_own_descriptors) { + isolate->Throw(*isolate->factory()->NewRangeError( + MessageTemplate::kInvalidArrayLength)); + return Nothing<bool>(); + } Handle<FixedArray> values_or_entries = isolate->factory()->NewFixedArray( number_of_own_descriptors + number_of_own_elements); int count = 0; @@ -1918,7 +1928,8 @@ MaybeHandle<FixedArray> GetOwnValuesOrEntries(Isolate* isolate, int length = 0; for (int i = 0; i < keys->length(); ++i) { - Handle<Name> key = Handle<Name>::cast(handle(keys->get(i), isolate)); + Handle<Name> key = + Handle<Name>::cast(handle(keys->get(isolate, i), isolate)); if (filter & ONLY_ENUMERABLE) { PropertyDescriptor descriptor; @@ -2002,13 +2013,9 @@ MaybeHandle<JSObject> JSObject::New(Handle<JSFunction> constructor, ASSIGN_RETURN_ON_EXCEPTION( isolate, initial_map, JSFunction::GetDerivedMap(isolate, constructor, new_target), JSObject); - Handle<JSObject> result = isolate->factory()->NewJSObjectFromMap( - initial_map, AllocationType::kYoung, site); - if (initial_map->is_dictionary_map()) { - Handle<NameDictionary> dictionary = - NameDictionary::New(isolate, NameDictionary::kInitialCapacity); - result->SetProperties(*dictionary); - } + Handle<JSObject> result = isolate->factory()->NewFastOrSlowJSObjectFromMap( + initial_map, NameDictionary::kInitialCapacity, AllocationType::kYoung, + site); isolate->counters()->constructed_objects()->Increment(); isolate->counters()->constructed_objects_runtime()->Increment(); return result; @@ -2026,13 +2033,7 @@ MaybeHandle<JSObject> JSObject::ObjectCreate(Isolate* isolate, Map::GetObjectCreateMap(isolate, Handle<HeapObject>::cast(prototype)); // Actually allocate the object. - Handle<JSObject> object; - if (map->is_dictionary_map()) { - object = isolate->factory()->NewSlowJSObjectFromMap(map); - } else { - object = isolate->factory()->NewJSObjectFromMap(map); - } - return object; + return isolate->factory()->NewFastOrSlowJSObjectFromMap(map); } void JSObject::EnsureWritableFastElements(Handle<JSObject> object) { @@ -2072,8 +2073,8 @@ int JSObject::GetHeaderSize(InstanceType type, return JSBoundFunction::kSize; case JS_FUNCTION_TYPE: return JSFunction::GetHeaderSize(function_has_prototype_slot); - case JS_VALUE_TYPE: - return JSValue::kSize; + case JS_PRIMITIVE_WRAPPER_TYPE: + return JSPrimitiveWrapper::kSize; case JS_DATE_TYPE: return JSDate::kSize; case JS_ARRAY_TYPE: @@ -2423,7 +2424,7 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) { } // All other JSObjects are rather similar to each other (JSObject, - // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSValue). + // JSGlobalProxy, JSGlobalObject, JSUndetectable, JSPrimitiveWrapper). default: { Map map_of_this = map(); Heap* heap = GetHeap(); @@ -2457,9 +2458,9 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) { accumulator->Add("<JS%sObject", global_object ? "Global " : ""); } } - if (IsJSValue()) { + if (IsJSPrimitiveWrapper()) { accumulator->Add(" value = "); - JSValue::cast(*this).value().ShortPrint(accumulator); + JSPrimitiveWrapper::cast(*this).value().ShortPrint(accumulator); } accumulator->Put('>'); break; @@ -2595,11 +2596,11 @@ namespace { // to temporarily store the inobject properties. // * If there are properties left in the backing store, install the backing // store. -void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { - Isolate* isolate = object->GetIsolate(); +void MigrateFastToFast(Isolate* isolate, Handle<JSObject> object, + Handle<Map> new_map) { Handle<Map> old_map(object->map(), isolate); // In case of a regular transition. - if (new_map->GetBackPointer() == *old_map) { + if (new_map->GetBackPointer(isolate) == *old_map) { // If the map does not add named properties, simply set the map. if (old_map->NumberOfOwnDescriptors() == new_map->NumberOfOwnDescriptors()) { @@ -2608,7 +2609,7 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { } // If the map adds a new kDescriptor property, simply set the map. - PropertyDetails details = new_map->GetLastDescriptorDetails(); + PropertyDetails details = new_map->GetLastDescriptorDetails(isolate); if (details.location() == kDescriptor) { object->synchronized_set_map(*new_map); return; @@ -2618,14 +2619,14 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { // can also simply set the map (modulo a special case for mutable // double boxes). FieldIndex index = - FieldIndex::ForDescriptor(*new_map, new_map->LastAdded()); - if (index.is_inobject() || - index.outobject_array_index() < object->property_array().length()) { + FieldIndex::ForDescriptor(isolate, *new_map, new_map->LastAdded()); + if (index.is_inobject() || index.outobject_array_index() < + object->property_array(isolate).length()) { // We still need to allocate MutableHeapNumbers for double fields // if either double field unboxing is disabled or the double field // is in the PropertyArray backing store (where we don't support // double field unboxing). - if (index.is_double() && !new_map->IsUnboxedDoubleField(index)) { + if (index.is_double() && !new_map->IsUnboxedDoubleField(isolate, index)) { auto value = isolate->factory()->NewMutableHeapNumberWithHoleNaN(); object->RawFastPropertyAtPut(index, *value); } @@ -2636,7 +2637,7 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { // This migration is a transition from a map that has run out of property // space. Extend the backing store. int grow_by = new_map->UnusedPropertyFields() + 1; - Handle<PropertyArray> old_storage(object->property_array(), isolate); + Handle<PropertyArray> old_storage(object->property_array(isolate), isolate); Handle<PropertyArray> new_storage = isolate->factory()->CopyPropertyArrayAndGrow(old_storage, grow_by); @@ -2682,10 +2683,10 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { Handle<FixedArray> inobject_props = isolate->factory()->NewFixedArray(inobject); - Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors(), - isolate); - Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors(), - isolate); + Handle<DescriptorArray> old_descriptors( + old_map->instance_descriptors(isolate), isolate); + Handle<DescriptorArray> new_descriptors( + new_map->instance_descriptors(isolate), isolate); int old_nof = old_map->NumberOfOwnDescriptors(); int new_nof = new_map->NumberOfOwnDescriptors(); @@ -2713,13 +2714,13 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { } } else { DCHECK_EQ(kData, old_details.kind()); - value = handle(old_descriptors->GetStrongValue(i), isolate); + value = handle(old_descriptors->GetStrongValue(isolate, i), isolate); DCHECK(!old_representation.IsDouble() && !representation.IsDouble()); } } else { DCHECK_EQ(kField, old_details.location()); - FieldIndex index = FieldIndex::ForDescriptor(*old_map, i); - if (object->IsUnboxedDoubleField(index)) { + FieldIndex index = FieldIndex::ForDescriptor(isolate, *old_map, i); + if (object->IsUnboxedDoubleField(isolate, index)) { uint64_t old_bits = object->RawFastDoublePropertyAsBitsAt(index); if (representation.IsDouble()) { value = isolate->factory()->NewMutableHeapNumberFromBits(old_bits); @@ -2727,7 +2728,7 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { value = isolate->factory()->NewHeapNumberFromBits(old_bits); } } else { - value = handle(object->RawFastPropertyAt(index), isolate); + value = handle(object->RawFastPropertyAt(isolate, index), isolate); if (!old_representation.IsDouble() && representation.IsDouble()) { DCHECK_IMPLIES(old_representation.IsNone(), value->IsUninitialized(isolate)); @@ -2779,11 +2780,11 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { int limit = Min(inobject, number_of_fields); for (int i = 0; i < limit; i++) { FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i); - Object value = inobject_props->get(i); + Object value = inobject_props->get(isolate, i); // Can't use JSObject::FastPropertyAtPut() because proper map was not set // yet. - if (new_map->IsUnboxedDoubleField(index)) { - DCHECK(value.IsMutableHeapNumber()); + if (new_map->IsUnboxedDoubleField(isolate, index)) { + DCHECK(value.IsMutableHeapNumber(isolate)); // Ensure that all bits of the double value are preserved. object->RawFastDoublePropertyAsBitsAtPut( index, MutableHeapNumber::cast(value).value_as_bits()); @@ -2818,19 +2819,19 @@ void MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) { object->synchronized_set_map(*new_map); } -void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map, +void MigrateFastToSlow(Isolate* isolate, Handle<JSObject> object, + Handle<Map> new_map, int expected_additional_properties) { // The global object is always normalized. - DCHECK(!object->IsJSGlobalObject()); + DCHECK(!object->IsJSGlobalObject(isolate)); // JSGlobalProxy must never be normalized - DCHECK(!object->IsJSGlobalProxy()); + DCHECK(!object->IsJSGlobalProxy(isolate)); DCHECK_IMPLIES(new_map->is_prototype_map(), Map::IsPrototypeChainInvalidated(*new_map)); - Isolate* isolate = object->GetIsolate(); HandleScope scope(isolate); - Handle<Map> map(object->map(), isolate); + Handle<Map> map(object->map(isolate), isolate); // Allocate new content. int real_size = map->NumberOfOwnDescriptors(); @@ -2844,33 +2845,33 @@ void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map, Handle<NameDictionary> dictionary = NameDictionary::New(isolate, property_count); - Handle<DescriptorArray> descs(map->instance_descriptors(), isolate); + Handle<DescriptorArray> descs(map->instance_descriptors(isolate), isolate); for (int i = 0; i < real_size; i++) { PropertyDetails details = descs->GetDetails(i); - Handle<Name> key(descs->GetKey(i), isolate); + Handle<Name> key(descs->GetKey(isolate, i), isolate); Handle<Object> value; if (details.location() == kField) { - FieldIndex index = FieldIndex::ForDescriptor(*map, i); + FieldIndex index = FieldIndex::ForDescriptor(isolate, *map, i); if (details.kind() == kData) { - if (object->IsUnboxedDoubleField(index)) { + if (object->IsUnboxedDoubleField(isolate, index)) { double old_value = object->RawFastDoublePropertyAt(index); value = isolate->factory()->NewHeapNumber(old_value); } else { - value = handle(object->RawFastPropertyAt(index), isolate); + value = handle(object->RawFastPropertyAt(isolate, index), isolate); if (details.representation().IsDouble()) { - DCHECK(value->IsMutableHeapNumber()); + DCHECK(value->IsMutableHeapNumber(isolate)); double old_value = Handle<MutableHeapNumber>::cast(value)->value(); value = isolate->factory()->NewHeapNumber(old_value); } } } else { DCHECK_EQ(kAccessor, details.kind()); - value = handle(object->RawFastPropertyAt(index), isolate); + value = handle(object->RawFastPropertyAt(isolate, index), isolate); } } else { DCHECK_EQ(kDescriptor, details.location()); - value = handle(descs->GetStrongValue(i), isolate); + value = handle(descs->GetStrongValue(isolate, i), isolate); } DCHECK(!value.is_null()); PropertyDetails d(details.kind(), details.attributes(), @@ -2932,11 +2933,12 @@ void MigrateFastToSlow(Handle<JSObject> object, Handle<Map> new_map, } // namespace -void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, +void JSObject::MigrateToMap(Isolate* isolate, Handle<JSObject> object, + Handle<Map> new_map, int expected_additional_properties) { - if (object->map() == *new_map) return; - Handle<Map> old_map(object->map(), object->GetIsolate()); - NotifyMapChange(old_map, new_map, object->GetIsolate()); + if (object->map(isolate) == *new_map) return; + Handle<Map> old_map(object->map(isolate), isolate); + NotifyMapChange(old_map, new_map, isolate); if (old_map->is_dictionary_map()) { // For slow-to-fast migrations JSObject::MigrateSlowToFast() @@ -2946,7 +2948,7 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, // Slow-to-slow migration is trivial. object->synchronized_set_map(*new_map); } else if (!new_map->is_dictionary_map()) { - MigrateFastToFast(object, new_map); + MigrateFastToFast(isolate, object, new_map); if (old_map->is_prototype_map()) { DCHECK(!old_map->is_stable()); DCHECK(new_map->is_stable()); @@ -2958,13 +2960,12 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, old_map->set_owns_descriptors(false); DCHECK(old_map->is_abandoned_prototype_map()); // Ensure that no transition was inserted for prototype migrations. - DCHECK_EQ(0, TransitionsAccessor(object->GetIsolate(), old_map) - .NumberOfTransitions()); - DCHECK(new_map->GetBackPointer().IsUndefined()); - DCHECK(object->map() != *old_map); + DCHECK_EQ(0, TransitionsAccessor(isolate, old_map).NumberOfTransitions()); + DCHECK(new_map->GetBackPointer(isolate).IsUndefined(isolate)); + DCHECK(object->map(isolate) != *old_map); } } else { - MigrateFastToSlow(object, new_map, expected_additional_properties); + MigrateFastToSlow(isolate, object, new_map, expected_additional_properties); } // Careful: Don't allocate here! @@ -2978,11 +2979,11 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map, void JSObject::ForceSetPrototype(Handle<JSObject> object, Handle<HeapObject> proto) { // object.__proto__ = proto; - Handle<Map> old_map = Handle<Map>(object->map(), object->GetIsolate()); - Handle<Map> new_map = - Map::Copy(object->GetIsolate(), old_map, "ForceSetPrototype"); - Map::SetPrototype(object->GetIsolate(), new_map, proto); - JSObject::MigrateToMap(object, new_map); + Isolate* isolate = object->GetIsolate(); + Handle<Map> old_map = Handle<Map>(object->map(), isolate); + Handle<Map> new_map = Map::Copy(isolate, old_map, "ForceSetPrototype"); + Map::SetPrototype(isolate, new_map, proto); + JSObject::MigrateToMap(isolate, object, new_map); } Maybe<bool> JSObject::SetPropertyWithInterceptor( @@ -3068,31 +3069,30 @@ void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) { object->synchronized_set_map(*map); } -void JSObject::MigrateInstance(Handle<JSObject> object) { - Handle<Map> original_map(object->map(), object->GetIsolate()); - Handle<Map> map = Map::Update(object->GetIsolate(), original_map); +void JSObject::MigrateInstance(Isolate* isolate, Handle<JSObject> object) { + Handle<Map> original_map(object->map(), isolate); + Handle<Map> map = Map::Update(isolate, original_map); map->set_is_migration_target(true); - MigrateToMap(object, map); + JSObject::MigrateToMap(isolate, object, map); if (FLAG_trace_migration) { object->PrintInstanceMigration(stdout, *original_map, *map); } #if VERIFY_HEAP if (FLAG_verify_heap) { - object->JSObjectVerify(object->GetIsolate()); + object->JSObjectVerify(isolate); } #endif } // static -bool JSObject::TryMigrateInstance(Handle<JSObject> object) { - Isolate* isolate = object->GetIsolate(); +bool JSObject::TryMigrateInstance(Isolate* isolate, Handle<JSObject> object) { DisallowDeoptimization no_deoptimization(isolate); Handle<Map> original_map(object->map(), isolate); Handle<Map> new_map; if (!Map::TryUpdate(isolate, original_map).ToHandle(&new_map)) { return false; } - JSObject::MigrateToMap(object, new_map); + JSObject::MigrateToMap(isolate, object, new_map); if (FLAG_trace_migration && *original_map != object->map()) { object->PrintInstanceMigration(stdout, *original_map, object->map()); } @@ -3263,16 +3263,18 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( return GetPropertyAttributesWithInterceptorInternal(it, it->GetInterceptor()); } -void JSObject::NormalizeProperties(Handle<JSObject> object, +void JSObject::NormalizeProperties(Isolate* isolate, Handle<JSObject> object, PropertyNormalizationMode mode, int expected_additional_properties, const char* reason) { if (!object->HasFastProperties()) return; - Handle<Map> map(object->map(), object->GetIsolate()); - Handle<Map> new_map = Map::Normalize(object->GetIsolate(), map, mode, reason); + Handle<Map> map(object->map(), isolate); + Handle<Map> new_map = + Map::Normalize(isolate, map, map->elements_kind(), mode, reason); - MigrateToMap(object, new_map, expected_additional_properties); + JSObject::MigrateToMap(isolate, object, new_map, + expected_additional_properties); } void JSObject::MigrateSlowToFast(Handle<JSObject> object, @@ -3475,7 +3477,7 @@ Handle<NumberDictionary> JSObject::NormalizeElements(Handle<JSObject> object) { : DICTIONARY_ELEMENTS; Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, target_kind); // Set the new map first to satify the elements type assert in set_elements(). - JSObject::MigrateToMap(object, new_map); + JSObject::MigrateToMap(isolate, object, new_map); if (is_sloppy_arguments) { SloppyArgumentsElements::cast(object->elements()) @@ -3710,7 +3712,7 @@ Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object, Map::Copy(isolate, handle(object->map(), isolate), "PreventExtensions"); new_map->set_is_extensible(false); - JSObject::MigrateToMap(object, new_map); + JSObject::MigrateToMap(isolate, object, new_map); DCHECK(!object->map().is_extensible()); return Just(true); @@ -3752,6 +3754,25 @@ void JSObject::ApplyAttributesToDictionary( } } +template void JSObject::ApplyAttributesToDictionary( + Isolate* isolate, ReadOnlyRoots roots, Handle<NumberDictionary> dictionary, + const PropertyAttributes attributes); + +Handle<NumberDictionary> CreateElementDictionary(Isolate* isolate, + Handle<JSObject> object) { + Handle<NumberDictionary> new_element_dictionary; + if (!object->HasTypedArrayElements() && !object->HasDictionaryElements() && + !object->HasSlowStringWrapperElements()) { + int length = object->IsJSArray() + ? Smi::ToInt(Handle<JSArray>::cast(object)->length()) + : object->elements().length(); + new_element_dictionary = + length == 0 ? isolate->factory()->empty_slow_element_dictionary() + : object->GetElementsAccessor()->Normalize(object); + } + return new_element_dictionary; +} + template <PropertyAttributes attrs> Maybe<bool> JSObject::PreventExtensionsWithTransition( Handle<JSObject> object, ShouldThrow should_throw) { @@ -3772,10 +3793,12 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition( } if (attrs == NONE && !object->map().is_extensible()) return Just(true); - ElementsKind old_elements_kind = object->map().elements_kind(); - if (attrs != FROZEN && IsSealedElementsKind(old_elements_kind)) - return Just(true); - if (old_elements_kind == PACKED_FROZEN_ELEMENTS) return Just(true); + { + ElementsKind old_elements_kind = object->map().elements_kind(); + if (attrs != FROZEN && IsSealedElementsKind(old_elements_kind)) + return Just(true); + if (old_elements_kind == PACKED_FROZEN_ELEMENTS) return Just(true); + } if (object->IsJSGlobalProxy()) { PrototypeIterator iter(isolate, object); @@ -3804,17 +3827,6 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition( RETURN_FAILURE(isolate, should_throw, NewTypeError(message)); } - Handle<NumberDictionary> new_element_dictionary; - if (!object->HasTypedArrayElements() && !object->HasDictionaryElements() && - !object->HasSlowStringWrapperElements()) { - int length = object->IsJSArray() - ? Smi::ToInt(Handle<JSArray>::cast(object)->length()) - : object->elements().length(); - new_element_dictionary = - length == 0 ? isolate->factory()->empty_slow_element_dictionary() - : object->GetElementsAccessor()->Normalize(object); - } - Handle<Symbol> transition_marker; if (attrs == NONE) { transition_marker = isolate->factory()->nonextensible_symbol(); @@ -3825,6 +3837,31 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition( transition_marker = isolate->factory()->frozen_symbol(); } + // Currently, there are only have sealed/frozen Object element kinds and + // Map::MigrateToMap doesn't handle properties' attributes reconfiguring and + // elements kind change in one go. If seal or freeze with Smi or Double + // elements kind, we will transition to Object elements kind first to make + // sure of valid element access. + if (FLAG_enable_sealed_frozen_elements_kind && + (attrs == SEALED || attrs == FROZEN)) { + switch (object->map().elements_kind()) { + case PACKED_SMI_ELEMENTS: + case PACKED_DOUBLE_ELEMENTS: + JSObject::TransitionElementsKind(object, PACKED_ELEMENTS); + break; + case HOLEY_SMI_ELEMENTS: + case HOLEY_DOUBLE_ELEMENTS: + JSObject::TransitionElementsKind(object, HOLEY_ELEMENTS); + break; + default: + break; + } + } + + // Make sure we only use this element dictionary in case we can't transition + // to sealed, frozen elements kind. + Handle<NumberDictionary> new_element_dictionary; + Handle<Map> old_map(object->map(), isolate); old_map = Map::Update(isolate, old_map); TransitionsAccessor transitions(isolate, old_map); @@ -3836,16 +3873,22 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition( transition_map->elements_kind() == SLOW_STRING_WRAPPER_ELEMENTS || transition_map->has_frozen_or_sealed_elements()); DCHECK(!transition_map->is_extensible()); - JSObject::MigrateToMap(object, transition_map); + if (!transition_map->has_frozen_or_sealed_elements()) { + new_element_dictionary = CreateElementDictionary(isolate, object); + } + JSObject::MigrateToMap(isolate, object, transition_map); } else if (transitions.CanHaveMoreTransitions()) { // Create a new descriptor array with the appropriate property attributes Handle<Map> new_map = Map::CopyForPreventExtensions( isolate, old_map, attrs, transition_marker, "CopyForPreventExtensions"); - JSObject::MigrateToMap(object, new_map); + if (!new_map->has_frozen_or_sealed_elements()) { + new_element_dictionary = CreateElementDictionary(isolate, object); + } + JSObject::MigrateToMap(isolate, object, new_map); } else { DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map()); // Slow path: need to normalize properties for safety - NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0, + NormalizeProperties(isolate, object, CLEAR_INOBJECT_PROPERTIES, 0, "SlowPreventExtensions"); // Create a new map, since other objects with this map may be extensible. @@ -3853,6 +3896,7 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition( Handle<Map> new_map = Map::Copy(isolate, handle(object->map(), isolate), "SlowCopyForPreventExtensions"); new_map->set_is_extensible(false); + new_element_dictionary = CreateElementDictionary(isolate, object); if (!new_element_dictionary.is_null()) { ElementsKind new_kind = IsStringWrapperElementsKind(old_map->elements_kind()) @@ -3860,7 +3904,7 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition( : DICTIONARY_ELEMENTS; new_map->set_elements_kind(new_kind); } - JSObject::MigrateToMap(object, new_map); + JSObject::MigrateToMap(isolate, object, new_map); if (attrs != NONE) { ReadOnlyRoots roots(isolate); @@ -3879,6 +3923,7 @@ Maybe<bool> JSObject::PreventExtensionsWithTransition( } if (object->map().has_frozen_or_sealed_elements()) { + DCHECK(new_element_dictionary.is_null()); return Just(true); } @@ -3986,7 +4031,7 @@ bool JSObject::HasEnumerableElements() { return true; case FAST_STRING_WRAPPER_ELEMENTS: case SLOW_STRING_WRAPPER_ELEMENTS: - if (String::cast(JSValue::cast(object).value()).length() > 0) { + if (String::cast(JSPrimitiveWrapper::cast(object).value()).length() > 0) { return true; } return object.elements().length() > 0; @@ -4173,10 +4218,11 @@ static bool PrototypeBenefitsFromNormalization(Handle<JSObject> object) { // static void JSObject::OptimizeAsPrototype(Handle<JSObject> object, bool enable_setup_mode) { + Isolate* isolate = object->GetIsolate(); if (object->IsJSGlobalObject()) return; if (enable_setup_mode && PrototypeBenefitsFromNormalization(object)) { // First normalize to ensure all JSFunctions are DATA_CONSTANT. - JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0, + JSObject::NormalizeProperties(isolate, object, KEEP_INOBJECT_PROPERTIES, 0, "NormalizeAsPrototype"); } if (object->map().is_prototype_map()) { @@ -4185,10 +4231,9 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object, JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype"); } } else { - Handle<Map> new_map = Map::Copy(object->GetIsolate(), - handle(object->map(), object->GetIsolate()), - "CopyAsPrototype"); - JSObject::MigrateToMap(object, new_map); + Handle<Map> new_map = + Map::Copy(isolate, handle(object->map(), isolate), "CopyAsPrototype"); + JSObject::MigrateToMap(isolate, object, new_map); object->map().set_is_prototype_map(true); // Replace the pointer to the exact constructor with the Object function @@ -4447,7 +4492,7 @@ Maybe<bool> JSObject::SetPrototype(Handle<JSObject> object, Handle<Map> new_map = Map::TransitionToPrototype(isolate, map, Handle<HeapObject>::cast(value)); DCHECK(new_map->prototype() == *value); - JSObject::MigrateToMap(real_receiver, new_map); + JSObject::MigrateToMap(isolate, real_receiver, new_map); DCHECK(size == object->Size()); return Just(true); @@ -4477,10 +4522,6 @@ void JSObject::EnsureCanContainElements(Handle<JSObject> object, object, args->slot_at(first_arg + arg_count - 1), arg_count, mode); } -ElementsAccessor* JSObject::GetElementsAccessor() { - return ElementsAccessor::ForKind(GetElementsKind()); -} - void JSObject::ValidateElements(JSObject object) { #ifdef ENABLE_SLOW_DCHECKS if (FLAG_enable_slow_asserts) { @@ -4556,22 +4597,22 @@ static ElementsKind BestFittingFastElementsKind(JSObject object) { void JSObject::AddDataElement(Handle<JSObject> object, uint32_t index, Handle<Object> value, PropertyAttributes attributes) { - DCHECK(object->map().is_extensible()); - Isolate* isolate = object->GetIsolate(); + DCHECK(object->map(isolate).is_extensible()); + uint32_t old_length = 0; uint32_t new_capacity = 0; - if (object->IsJSArray()) { + if (object->IsJSArray(isolate)) { CHECK(JSArray::cast(*object).length().ToArrayLength(&old_length)); } - ElementsKind kind = object->GetElementsKind(); - FixedArrayBase elements = object->elements(); + ElementsKind kind = object->GetElementsKind(isolate); + FixedArrayBase elements = object->elements(isolate); ElementsKind dictionary_kind = DICTIONARY_ELEMENTS; if (IsSloppyArgumentsElementsKind(kind)) { - elements = SloppyArgumentsElements::cast(elements).arguments(); + elements = SloppyArgumentsElements::cast(elements).arguments(isolate); dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS; } else if (IsStringWrapperElementsKind(kind)) { dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS; @@ -4579,7 +4620,7 @@ void JSObject::AddDataElement(Handle<JSObject> object, uint32_t index, if (attributes != NONE) { kind = dictionary_kind; - } else if (elements.IsNumberDictionary()) { + } else if (elements.IsNumberDictionary(isolate)) { kind = ShouldConvertToFastElements( *object, NumberDictionary::cast(elements), index, &new_capacity) ? BestFittingFastElementsKind(*object) @@ -4590,8 +4631,9 @@ void JSObject::AddDataElement(Handle<JSObject> object, uint32_t index, kind = dictionary_kind; } - ElementsKind to = value->OptimalElementsKind(); - if (IsHoleyElementsKind(kind) || !object->IsJSArray() || index > old_length) { + ElementsKind to = value->OptimalElementsKind(isolate); + if (IsHoleyElementsKind(kind) || !object->IsJSArray(isolate) || + index > old_length) { to = GetHoleyElementsKind(to); kind = GetHoleyElementsKind(kind); } @@ -4599,7 +4641,7 @@ void JSObject::AddDataElement(Handle<JSObject> object, uint32_t index, ElementsAccessor* accessor = ElementsAccessor::ForKind(to); accessor->Add(object, index, value, attributes, new_capacity); - if (object->IsJSArray() && index >= old_length) { + if (object->IsJSArray(isolate) && index >= old_length) { Handle<Object> new_length = isolate->factory()->NewNumberFromUint(index + 1); JSArray::cast(*object).set_length(*new_length); @@ -4654,14 +4696,15 @@ void JSObject::TransitionElementsKind(Handle<JSObject> object, DCHECK_NE(TERMINAL_FAST_ELEMENTS_KIND, from_kind); UpdateAllocationSite(object, to_kind); - if (object->elements() == object->GetReadOnlyRoots().empty_fixed_array() || + Isolate* isolate = object->GetIsolate(); + if (object->elements() == ReadOnlyRoots(isolate).empty_fixed_array() || IsDoubleElementsKind(from_kind) == IsDoubleElementsKind(to_kind)) { // No change is needed to the elements() buffer, the transition // only requires a map change. Handle<Map> new_map = GetElementsTransitionMap(object, to_kind); - MigrateToMap(object, new_map); + JSObject::MigrateToMap(isolate, object, new_map); if (FLAG_trace_elements_transitions) { - Handle<FixedArrayBase> elms(object->elements(), object->GetIsolate()); + Handle<FixedArrayBase> elms(object->elements(), isolate); PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms); } } else { @@ -4942,6 +4985,17 @@ void JSFunction::EnsureFeedbackVector(Handle<JSFunction> function) { // static void JSFunction::InitializeFeedbackCell(Handle<JSFunction> function) { Isolate* const isolate = function->GetIsolate(); + + if (function->has_feedback_vector()) { + // TODO(984344): Make this a CHECK that feedback vectors are identical to + // what we expect once we have removed all bytecode generation differences + // between eager and lazy compilation. For now just reset if they aren't + // identical + FeedbackVector vector = function->feedback_vector(); + if (vector.length() == vector.metadata().slot_count()) return; + function->raw_feedback_cell().reset(); + } + bool needs_feedback_vector = !FLAG_lazy_feedback_allocation; // We need feedback vector for certain log events, collecting type profile // and more precise code coverage. @@ -4991,7 +5045,7 @@ void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function, native_context->get(Context::ARRAY_FUNCTION_INDEX), isolate); if (array_function->IsJSFunction() && *function == JSFunction::cast(*array_function)) { - CacheInitialJSArrayMaps(native_context, new_map); + CacheInitialJSArrayMaps(isolate, native_context, new_map); } } @@ -5030,7 +5084,7 @@ void JSFunction::SetPrototype(Handle<JSFunction> function, Handle<Map> new_map = Map::Copy(isolate, handle(function->map(), isolate), "SetPrototype"); - JSObject::MigrateToMap(function, new_map); + JSObject::MigrateToMap(isolate, function, new_map); new_map->SetConstructor(*value); new_map->set_has_non_instance_prototype(true); @@ -5141,14 +5195,16 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) { case JS_MESSAGE_OBJECT_TYPE: case JS_OBJECT_TYPE: case JS_ERROR_TYPE: + case JS_FINALIZATION_GROUP_TYPE: case JS_ARGUMENTS_TYPE: case JS_PROMISE_TYPE: case JS_REGEXP_TYPE: case JS_SET_TYPE: case JS_SPECIAL_API_OBJECT_TYPE: case JS_TYPED_ARRAY_TYPE: - case JS_VALUE_TYPE: + case JS_PRIMITIVE_WRAPPER_TYPE: case JS_WEAK_MAP_TYPE: + case JS_WEAK_REF_TYPE: case JS_WEAK_SET_TYPE: case WASM_GLOBAL_TYPE: case WASM_INSTANCE_TYPE: @@ -5526,7 +5582,7 @@ void JSFunction::ClearTypeFeedbackInfo() { FeedbackVector vector = feedback_vector(); Isolate* isolate = GetIsolate(); if (vector.ClearSlots(isolate)) { - IC::OnFeedbackChanged(isolate, vector, FeedbackSlot::Invalid(), *this, + IC::OnFeedbackChanged(isolate, vector, FeedbackSlot::Invalid(), "ClearTypeFeedbackInfo"); } } diff --git a/chromium/v8/src/objects/js-objects.h b/chromium/v8/src/objects/js-objects.h index 5ac1751c483..bcea3a28df2 100644 --- a/chromium/v8/src/objects/js-objects.h +++ b/chromium/v8/src/objects/js-objects.h @@ -8,6 +8,7 @@ #include "src/objects/embedder-data-slot.h" #include "src/objects/objects.h" #include "src/objects/property-array.h" +#include "torque-generated/class-definitions-tq.h" #include "torque-generated/field-offsets-tq.h" // Has to be the last include (doesn't have include guards): @@ -27,16 +28,16 @@ class JSReceiver : public HeapObject { public: NEVER_READ_ONLY_SPACE // Returns true if there is no slow (ie, dictionary) backing store. - inline bool HasFastProperties() const; + DECL_GETTER(HasFastProperties, bool) // Returns the properties array backing store if it // exists. Otherwise, returns an empty_property_array when there's a // Smi (hash code) or an empty_fixed_array for a fast properties // map. - inline PropertyArray property_array() const; + DECL_GETTER(property_array, PropertyArray) // Gets slow properties for non-global objects. - inline NameDictionary property_dictionary() const; + DECL_GETTER(property_dictionary, NameDictionary) // Sets the properties backing store and makes sure any existing hash is moved // to the new properties store. To clear out the properties store, pass in the @@ -62,12 +63,13 @@ class JSReceiver : public HeapObject { // above typed getters and setters to access the properties. DECL_ACCESSORS(raw_properties_or_hash, Object) - inline void initialize_properties(); + inline void initialize_properties(Isolate* isolate); // Deletes an existing named property in a normalized object. static void DeleteNormalizedProperty(Handle<JSReceiver> object, int entry); DECL_CAST(JSReceiver) + DECL_VERIFIER(JSReceiver) // ES6 section 7.1.1 ToPrimitive V8_WARN_UNUSED_RESULT static MaybeHandle<Object> ToPrimitive( @@ -275,7 +277,7 @@ class JSReceiver : public HeapObject { // properties. // Note that the map of JSObject changes during execution to enable inline // caching. -class JSObject : public JSReceiver { +class JSObject : public TorqueGeneratedJSObject<JSObject, JSReceiver> { public: static bool IsUnmodifiedApiObject(FullObjectSlot o); @@ -290,78 +292,63 @@ class JSObject : public JSReceiver { static V8_WARN_UNUSED_RESULT MaybeHandle<JSObject> ObjectCreate( Isolate* isolate, Handle<Object> prototype); - // [elements]: The elements (properties with names that are integers). - // - // Elements can be in two general modes: fast and slow. Each mode - // corresponds to a set of object representations of elements that - // have something in common. - // - // In the fast mode elements is a FixedArray and so each element can be - // quickly accessed. The elements array can have one of several maps in this - // mode: fixed_array_map, fixed_double_array_map, - // sloppy_arguments_elements_map or fixed_cow_array_map (for copy-on-write - // arrays). In the latter case the elements array may be shared by a few - // objects and so before writing to any element the array must be copied. Use - // EnsureWritableFastElements in this case. - // - // In the slow mode the elements is either a NumberDictionary or a - // FixedArray parameter map for a (sloppy) arguments object. - DECL_ACCESSORS(elements, FixedArrayBase) inline void initialize_elements(); static inline void SetMapAndElements(Handle<JSObject> object, Handle<Map> map, Handle<FixedArrayBase> elements); - inline ElementsKind GetElementsKind() const; - V8_EXPORT_PRIVATE ElementsAccessor* GetElementsAccessor(); + DECL_GETTER(GetElementsKind, ElementsKind) + DECL_GETTER(GetElementsAccessor, ElementsAccessor*) + // Returns true if an object has elements of PACKED_SMI_ELEMENTS or // HOLEY_SMI_ELEMENTS ElementsKind. - inline bool HasSmiElements(); + DECL_GETTER(HasSmiElements, bool) // Returns true if an object has elements of PACKED_ELEMENTS or // HOLEY_ELEMENTS ElementsKind. - inline bool HasObjectElements(); + DECL_GETTER(HasObjectElements, bool) // Returns true if an object has elements of PACKED_SMI_ELEMENTS, // HOLEY_SMI_ELEMENTS, PACKED_ELEMENTS, or HOLEY_ELEMENTS. - inline bool HasSmiOrObjectElements(); + DECL_GETTER(HasSmiOrObjectElements, bool) // Returns true if an object has any of the "fast" elements kinds. - inline bool HasFastElements(); + DECL_GETTER(HasFastElements, bool) // Returns true if an object has any of the PACKED elements kinds. - inline bool HasFastPackedElements(); + DECL_GETTER(HasFastPackedElements, bool) // Returns true if an object has elements of PACKED_DOUBLE_ELEMENTS or // HOLEY_DOUBLE_ELEMENTS ElementsKind. - inline bool HasDoubleElements(); + DECL_GETTER(HasDoubleElements, bool) // Returns true if an object has elements of HOLEY_SMI_ELEMENTS, // HOLEY_DOUBLE_ELEMENTS, or HOLEY_ELEMENTS ElementsKind. - inline bool HasHoleyElements(); - inline bool HasSloppyArgumentsElements(); - inline bool HasStringWrapperElements(); - inline bool HasDictionaryElements(); + DECL_GETTER(HasHoleyElements, bool) + DECL_GETTER(HasSloppyArgumentsElements, bool) + DECL_GETTER(HasStringWrapperElements, bool) + DECL_GETTER(HasDictionaryElements, bool) // Returns true if an object has elements of PACKED_ELEMENTS - inline bool HasPackedElements(); - inline bool HasFrozenOrSealedElements(); - inline bool HasSealedElements(); - - inline bool HasTypedArrayElements(); - - inline bool HasFixedUint8ClampedElements(); - inline bool HasFixedArrayElements(); - inline bool HasFixedInt8Elements(); - inline bool HasFixedUint8Elements(); - inline bool HasFixedInt16Elements(); - inline bool HasFixedUint16Elements(); - inline bool HasFixedInt32Elements(); - inline bool HasFixedUint32Elements(); - inline bool HasFixedFloat32Elements(); - inline bool HasFixedFloat64Elements(); - inline bool HasFixedBigInt64Elements(); - inline bool HasFixedBigUint64Elements(); - - inline bool HasFastArgumentsElements(); - inline bool HasSlowArgumentsElements(); - inline bool HasFastStringWrapperElements(); - inline bool HasSlowStringWrapperElements(); + DECL_GETTER(HasPackedElements, bool) + DECL_GETTER(HasFrozenOrSealedElements, bool) + DECL_GETTER(HasSealedElements, bool) + + DECL_GETTER(HasTypedArrayElements, bool) + + DECL_GETTER(HasFixedUint8ClampedElements, bool) + DECL_GETTER(HasFixedArrayElements, bool) + DECL_GETTER(HasFixedInt8Elements, bool) + DECL_GETTER(HasFixedUint8Elements, bool) + DECL_GETTER(HasFixedInt16Elements, bool) + DECL_GETTER(HasFixedUint16Elements, bool) + DECL_GETTER(HasFixedInt32Elements, bool) + DECL_GETTER(HasFixedUint32Elements, bool) + DECL_GETTER(HasFixedFloat32Elements, bool) + DECL_GETTER(HasFixedFloat64Elements, bool) + DECL_GETTER(HasFixedBigInt64Elements, bool) + DECL_GETTER(HasFixedBigUint64Elements, bool) + + DECL_GETTER(HasFastArgumentsElements, bool) + DECL_GETTER(HasSlowArgumentsElements, bool) + DECL_GETTER(HasFastStringWrapperElements, bool) + DECL_GETTER(HasSlowStringWrapperElements, bool) bool HasEnumerableElements(); - inline NumberDictionary element_dictionary(); // Gets slow elements. + // Gets slow elements. + DECL_GETTER(element_dictionary, NumberDictionary) // Requires: HasFastElements(). static void EnsureWritableFastElements(Handle<JSObject> object); @@ -431,11 +418,11 @@ class JSObject : public JSReceiver { // Migrates the given object to a map whose field representations are the // lowest upper bound of all known representations for that field. - static void MigrateInstance(Handle<JSObject> instance); + static void MigrateInstance(Isolate* isolate, Handle<JSObject> instance); // Migrates the given object only if the target map is already available, // or returns false if such a map is not yet available. - static bool TryMigrateInstance(Handle<JSObject> instance); + static bool TryMigrateInstance(Isolate* isolate, Handle<JSObject> instance); // Sets the property value in a normalized object given (key, value, details). // Handles the special representation of JS global objects. @@ -476,8 +463,8 @@ class JSObject : public JSReceiver { int old_index, int new_index); // Retrieve interceptors. - inline InterceptorInfo GetNamedInterceptor(); - inline InterceptorInfo GetIndexedInterceptor(); + DECL_GETTER(GetNamedInterceptor, InterceptorInfo) + DECL_GETTER(GetIndexedInterceptor, InterceptorInfo) // Used from JSReceiver. V8_WARN_UNUSED_RESULT static Maybe<PropertyAttributes> @@ -546,8 +533,8 @@ class JSObject : public JSReceiver { // Lookup interceptors are used for handling properties controlled by host // objects. - inline bool HasNamedInterceptor(); - inline bool HasIndexedInterceptor(); + DECL_GETTER(HasNamedInterceptor, bool) + DECL_GETTER(HasIndexedInterceptor, bool) // Support functions for v8 api (needed for correct interceptor behavior). V8_WARN_UNUSED_RESULT static Maybe<bool> HasRealNamedProperty( @@ -563,13 +550,12 @@ class JSObject : public JSReceiver { // JSFunction objects. static int GetHeaderSize(InstanceType instance_type, bool function_has_prototype_slot = false); - static inline int GetHeaderSize(const Map map); - inline int GetHeaderSize() const; + static inline int GetHeaderSize(Map map); - static inline int GetEmbedderFieldsStartOffset(const Map map); + static inline int GetEmbedderFieldsStartOffset(Map map); inline int GetEmbedderFieldsStartOffset(); - static inline int GetEmbedderFieldCount(const Map map); + static inline int GetEmbedderFieldCount(Map map); inline int GetEmbedderFieldCount() const; inline int GetEmbedderFieldOffset(int index); inline Object GetEmbedderField(int index); @@ -596,7 +582,7 @@ class JSObject : public JSReceiver { // |expected_additional_properties| is only used for fast-to-slow transitions // and ignored otherwise. V8_EXPORT_PRIVATE static void MigrateToMap( - Handle<JSObject> object, Handle<Map> new_map, + Isolate* isolate, Handle<JSObject> object, Handle<Map> new_map, int expected_additional_properties = 0); // Forces a prototype without any of the checks that the regular SetPrototype @@ -609,7 +595,7 @@ class JSObject : public JSReceiver { // added this number can be indicated to have the backing store allocated to // an initial capacity for holding these properties. V8_EXPORT_PRIVATE static void NormalizeProperties( - Handle<JSObject> object, PropertyNormalizationMode mode, + Isolate* isolate, Handle<JSObject> object, PropertyNormalizationMode mode, int expected_additional_properties, const char* reason); // Convert and update the elements backing store to be a @@ -624,15 +610,17 @@ class JSObject : public JSReceiver { int unused_property_fields, const char* reason); - inline bool IsUnboxedDoubleField(FieldIndex index); + inline bool IsUnboxedDoubleField(FieldIndex index) const; + inline bool IsUnboxedDoubleField(Isolate* isolate, FieldIndex index) const; // Access fast-case object properties at index. static Handle<Object> FastPropertyAt(Handle<JSObject> object, Representation representation, FieldIndex index); - inline Object RawFastPropertyAt(FieldIndex index); - inline double RawFastDoublePropertyAt(FieldIndex index); - inline uint64_t RawFastDoublePropertyAsBitsAt(FieldIndex index); + inline Object RawFastPropertyAt(FieldIndex index) const; + inline Object RawFastPropertyAt(Isolate* isolate, FieldIndex index) const; + inline double RawFastDoublePropertyAt(FieldIndex index) const; + inline uint64_t RawFastDoublePropertyAsBitsAt(FieldIndex index) const; inline void FastPropertyAtPut(FieldIndex index, Object value); inline void RawFastPropertyAtPut( @@ -679,8 +667,6 @@ class JSObject : public JSReceiver { static bool IsExtensible(Handle<JSObject> object); - DECL_CAST(JSObject) - // Dispatched behavior. void JSObjectShortPrint(StringStream* accumulator); DECL_PRINTER(JSObject) @@ -727,7 +713,7 @@ class JSObject : public JSReceiver { // If a GC was caused while constructing this object, the elements pointer // may point to a one pointer filler map. The object won't be rooted, but // our heap verification code could stumble across it. - V8_EXPORT_PRIVATE bool ElementsAreSafeToExamine() const; + V8_EXPORT_PRIVATE bool ElementsAreSafeToExamine(Isolate* isolate) const; #endif Object SlowReverseLookup(Object value); @@ -764,15 +750,6 @@ class JSObject : public JSReceiver { STATIC_ASSERT(kMaxNumberOfDescriptors + kFieldsAdded <= PropertyArray::kMaxLength); -// Layout description. -#define JS_OBJECT_FIELDS(V) \ - V(kElementsOffset, kTaggedSize) \ - /* Header size. */ \ - V(kHeaderSize, 0) - - DEFINE_FIELD_OFFSET_CONSTANTS(JSReceiver::kHeaderSize, JS_OBJECT_FIELDS) -#undef JS_OBJECT_FIELDS - STATIC_ASSERT(kHeaderSize == Internals::kJSObjectHeaderSize); static const int kMaxInObjectProperties = (kMaxInstanceSize - kHeaderSize) >> kTaggedSizeLog2; @@ -825,7 +802,7 @@ class JSObject : public JSReceiver { V8_WARN_UNUSED_RESULT static Maybe<bool> PreventExtensionsWithTransition( Handle<JSObject> object, ShouldThrow should_throw); - OBJECT_CONSTRUCTORS(JSObject, JSReceiver); + TQ_OBJECT_CONSTRUCTORS(JSObject) }; // JSAccessorPropertyDescriptor is just a JSObject with a specific initial @@ -835,9 +812,17 @@ class JSObject : public JSReceiver { class JSAccessorPropertyDescriptor : public JSObject { public: // Layout description. - DEFINE_FIELD_OFFSET_CONSTANTS( - JSObject::kHeaderSize, - TORQUE_GENERATED_JSACCESSOR_PROPERTY_DESCRIPTOR_FIELDS) +#define JS_ACCESSOR_PROPERTY_DESCRIPTOR_FIELDS(V) \ + V(kGetOffset, kTaggedSize) \ + V(kSetOffset, kTaggedSize) \ + V(kEnumerableOffset, kTaggedSize) \ + V(kConfigurableOffset, kTaggedSize) \ + /* Total size. */ \ + V(kSize, 0) + + DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, + JS_ACCESSOR_PROPERTY_DESCRIPTOR_FIELDS) +#undef JS_ACCESSOR_PROPERTY_DESCRIPTOR_FIELDS // Indices of in-object properties. static const int kGetIndex = 0; @@ -855,8 +840,18 @@ class JSAccessorPropertyDescriptor : public JSObject { // FromPropertyDescriptor function for regular data properties. class JSDataPropertyDescriptor : public JSObject { public: - DEFINE_FIELD_OFFSET_CONSTANTS( - JSObject::kHeaderSize, TORQUE_GENERATED_JSDATA_PROPERTY_DESCRIPTOR_FIELDS) + // Layout description. +#define JS_DATA_PROPERTY_DESCRIPTOR_FIELDS(V) \ + V(kValueOffset, kTaggedSize) \ + V(kWritableOffset, kTaggedSize) \ + V(kEnumerableOffset, kTaggedSize) \ + V(kConfigurableOffset, kTaggedSize) \ + /* Total size. */ \ + V(kSize, 0) + + DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, + JS_DATA_PROPERTY_DESCRIPTOR_FIELDS) +#undef JS_DATA_PROPERTY_DESCRIPTOR_FIELDS // Indices of in-object properties. static const int kValueIndex = 0; @@ -870,7 +865,7 @@ class JSDataPropertyDescriptor : public JSObject { // JSIteratorResult is just a JSObject with a specific initial map. // This initial map adds in-object properties for "done" and "value", -// as specified by ES6 section 25.1.1.3 The IteratorResult Interface +// as specified by ES6 section 25.1.1.3 The IteratorResult Interface. class JSIteratorResult : public JSObject { public: DECL_ACCESSORS(value, Object) @@ -878,8 +873,15 @@ class JSIteratorResult : public JSObject { DECL_ACCESSORS(done, Object) // Layout description. +#define JS_ITERATOR_RESULT_FIELDS(V) \ + V(kValueOffset, kTaggedSize) \ + V(kDoneOffset, kTaggedSize) \ + /* Total size. */ \ + V(kSize, 0) + DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, - TORQUE_GENERATED_JSITERATOR_RESULT_FIELDS) + JS_ITERATOR_RESULT_FIELDS) +#undef JS_ITERATOR_RESULT_FIELDS // Indices of in-object properties. static const int kValueIndex = 0; @@ -894,7 +896,6 @@ class JSIteratorResult : public JSObject { class JSBoundFunction : public JSObject { public: // [bound_target_function]: The wrapped function object. - inline Object raw_bound_target_function() const; DECL_ACCESSORS(bound_target_function, JSReceiver) // [bound_this]: The value that is always passed as the this value when @@ -933,7 +934,7 @@ class JSBoundFunction : public JSObject { class JSFunction : public JSObject { public: // [prototype_or_initial_map]: - DECL_ACCESSORS(prototype_or_initial_map, Object) + DECL_ACCESSORS(prototype_or_initial_map, HeapObject) // [shared]: The information about the function that // can be shared by instances. @@ -947,7 +948,7 @@ class JSFunction : public JSObject { // [context]: The context for this function. inline Context context(); inline bool has_context() const; - inline void set_context(Object context); + inline void set_context(HeapObject context); inline JSGlobalProxy global_proxy(); inline NativeContext native_context(); inline int length(); @@ -1055,13 +1056,14 @@ class JSFunction : public JSObject { inline bool NeedsResetDueToFlushedBytecode(); inline void ResetIfBytecodeFlushed(); - inline bool has_prototype_slot() const; + DECL_GETTER(has_prototype_slot, bool) // The initial map for an object created by this constructor. - inline Map initial_map(); + DECL_GETTER(initial_map, Map) + static void SetInitialMap(Handle<JSFunction> function, Handle<Map> map, Handle<HeapObject> prototype); - inline bool has_initial_map(); + DECL_GETTER(has_initial_map, bool) V8_EXPORT_PRIVATE static void EnsureHasInitialMap( Handle<JSFunction> function); @@ -1076,12 +1078,12 @@ class JSFunction : public JSObject { // function has an initial map the prototype is set on the initial // map. Otherwise, the prototype is put in the initial map field // until an initial map is needed. - inline bool has_prototype(); - inline bool has_instance_prototype(); - inline Object prototype(); - inline HeapObject instance_prototype(); - inline bool has_prototype_property(); - inline bool PrototypeRequiresRuntimeLookup(); + DECL_GETTER(has_prototype, bool) + DECL_GETTER(has_instance_prototype, bool) + DECL_GETTER(prototype, Object) + DECL_GETTER(instance_prototype, HeapObject) + DECL_GETTER(has_prototype_property, bool) + DECL_GETTER(PrototypeRequiresRuntimeLookup, bool) static void SetPrototype(Handle<JSFunction> function, Handle<Object> value); // Returns if this function has been compiled to native code yet. @@ -1149,14 +1151,9 @@ class JSFunction : public JSObject { // // Accessing a JSGlobalProxy requires security check. -class JSGlobalProxy : public JSObject { +class JSGlobalProxy + : public TorqueGeneratedJSGlobalProxy<JSGlobalProxy, JSObject> { public: - // [native_context]: the owner native context of this global proxy object. - // It is null value if this object is not used by any context. - DECL_ACCESSORS(native_context, Object) - - DECL_CAST(JSGlobalProxy) - inline bool IsDetachedFrom(JSGlobalObject global) const; static int SizeWithEmbedderFields(int embedder_field_count); @@ -1165,11 +1162,7 @@ class JSGlobalProxy : public JSObject { DECL_PRINTER(JSGlobalProxy) DECL_VERIFIER(JSGlobalProxy) - // Layout description. - DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, - TORQUE_GENERATED_JSGLOBAL_PROXY_FIELDS) - - OBJECT_CONSTRUCTORS(JSGlobalProxy, JSObject); + TQ_OBJECT_CONSTRUCTORS(JSGlobalProxy) }; // JavaScript global object. @@ -1182,7 +1175,7 @@ class JSGlobalObject : public JSObject { DECL_ACCESSORS(global_proxy, JSGlobalProxy) // Gets global object properties. - inline GlobalDictionary global_dictionary(); + DECL_GETTER(global_dictionary, GlobalDictionary) inline void set_global_dictionary(GlobalDictionary dictionary); static void InvalidatePropertyCell(Handle<JSGlobalObject> object, @@ -1208,22 +1201,13 @@ class JSGlobalObject : public JSObject { }; // Representation for JS Wrapper objects, String, Number, Boolean, etc. -class JSValue : public JSObject { +class JSPrimitiveWrapper + : public TorqueGeneratedJSPrimitiveWrapper<JSPrimitiveWrapper, JSObject> { public: - // [value]: the object being wrapped. - DECL_ACCESSORS(value, Object) - - DECL_CAST(JSValue) - // Dispatched behavior. - DECL_PRINTER(JSValue) - DECL_VERIFIER(JSValue) + DECL_PRINTER(JSPrimitiveWrapper) - // Layout description. - DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, - TORQUE_GENERATED_JSVALUE_FIELDS) - - OBJECT_CONSTRUCTORS(JSValue, JSObject); + TQ_OBJECT_CONSTRUCTORS(JSPrimitiveWrapper) }; class DateCache; @@ -1367,8 +1351,7 @@ class JSMessageObject : public JSObject { // EnsureSourcePositionsAvailable must have been called before calling this. Handle<String> GetSourceLine() const; - inline int error_level() const; - inline void set_error_level(int level); + DECL_INT_ACCESSORS(error_level) DECL_CAST(JSMessageObject) @@ -1384,8 +1367,6 @@ class JSMessageObject : public JSObject { using BodyDescriptor = FixedBodyDescriptor<HeapObject::kMapOffset, kPointerFieldsEndOffset, kSize>; - OBJECT_CONSTRUCTORS(JSMessageObject, JSObject); - private: friend class Factory; @@ -1400,12 +1381,14 @@ class JSMessageObject : public JSObject { DECL_ACCESSORS(bytecode_offset, Smi) // [start_position]: the start position in the script for the error message. - inline int start_position() const; - inline void set_start_position(int value); + DECL_INT_ACCESSORS(start_position) // [end_position]: the end position in the script for the error message. - inline int end_position() const; - inline void set_end_position(int value); + DECL_INT_ACCESSORS(end_position) + + DECL_INT_ACCESSORS(raw_type) + + OBJECT_CONSTRUCTORS(JSMessageObject, JSObject); }; // The [Async-from-Sync Iterator] object diff --git a/chromium/v8/src/objects/js-plural-rules-inl.h b/chromium/v8/src/objects/js-plural-rules-inl.h index 1924bdc4ff3..b8fe7f50f01 100644 --- a/chromium/v8/src/objects/js-plural-rules-inl.h +++ b/chromium/v8/src/objects/js-plural-rules-inl.h @@ -25,11 +25,12 @@ ACCESSORS(JSPluralRules, locale, String, kLocaleOffset) SMI_ACCESSORS(JSPluralRules, flags, kFlagsOffset) ACCESSORS(JSPluralRules, icu_plural_rules, Managed<icu::PluralRules>, kIcuPluralRulesOffset) -ACCESSORS(JSPluralRules, icu_decimal_format, Managed<icu::DecimalFormat>, - kIcuDecimalFormatOffset) +ACCESSORS(JSPluralRules, icu_number_formatter, + Managed<icu::number::LocalizedNumberFormatter>, + kIcuNumberFormatterOffset) inline void JSPluralRules::set_type(Type type) { - DCHECK_LT(type, Type::COUNT); + DCHECK_LE(type, TypeBits::kMax); int hints = flags(); hints = TypeBits::update(hints, type); set_flags(hints); diff --git a/chromium/v8/src/objects/js-plural-rules.cc b/chromium/v8/src/objects/js-plural-rules.cc index 8daf5db64af..84fe9b6d52a 100644 --- a/chromium/v8/src/objects/js-plural-rules.cc +++ b/chromium/v8/src/objects/js-plural-rules.cc @@ -10,11 +10,12 @@ #include "src/execution/isolate-inl.h" #include "src/objects/intl-objects.h" +#include "src/objects/js-number-format.h" #include "src/objects/js-plural-rules-inl.h" -#include "unicode/decimfmt.h" #include "unicode/locid.h" -#include "unicode/numfmt.h" +#include "unicode/numberformatter.h" #include "unicode/plurrule.h" +#include "unicode/unumberformatter.h" namespace v8 { namespace internal { @@ -23,8 +24,7 @@ namespace { bool CreateICUPluralRules(Isolate* isolate, const icu::Locale& icu_locale, JSPluralRules::Type type, - std::unique_ptr<icu::PluralRules>* pl, - std::unique_ptr<icu::DecimalFormat>* nf) { + std::unique_ptr<icu::PluralRules>* pl) { // Make formatter from options. Numbering system is added // to the locale as Unicode extension (if it was specified at all). UErrorCode status = U_ZERO_ERROR; @@ -43,41 +43,10 @@ bool CreateICUPluralRules(Isolate* isolate, const icu::Locale& icu_locale, } CHECK_NOT_NULL(plural_rules.get()); - std::unique_ptr<icu::DecimalFormat> number_format( - static_cast<icu::DecimalFormat*>( - icu::NumberFormat::createInstance(icu_locale, UNUM_DECIMAL, status))); - if (U_FAILURE(status)) { - return false; - } - CHECK_NOT_NULL(number_format.get()); - *pl = std::move(plural_rules); - *nf = std::move(number_format); - return true; } -void InitializeICUPluralRules( - Isolate* isolate, const icu::Locale& icu_locale, JSPluralRules::Type type, - std::unique_ptr<icu::PluralRules>* plural_rules, - std::unique_ptr<icu::DecimalFormat>* number_format) { - bool success = CreateICUPluralRules(isolate, icu_locale, type, plural_rules, - number_format); - if (!success) { - // Remove extensions and try again. - icu::Locale no_extension_locale(icu_locale.getBaseName()); - success = CreateICUPluralRules(isolate, no_extension_locale, type, - plural_rules, number_format); - - if (!success) { - FATAL("Failed to create ICU PluralRules, are ICU data files missing?"); - } - } - - CHECK_NOT_NULL((*plural_rules).get()); - CHECK_NOT_NULL((*number_format).get()); -} - } // namespace Handle<String> JSPluralRules::TypeAsString() const { @@ -86,16 +55,14 @@ Handle<String> JSPluralRules::TypeAsString() const { return GetReadOnlyRoots().cardinal_string_handle(); case Type::ORDINAL: return GetReadOnlyRoots().ordinal_string_handle(); - case Type::COUNT: - UNREACHABLE(); } + UNREACHABLE(); } // static -MaybeHandle<JSPluralRules> JSPluralRules::Initialize( - Isolate* isolate, Handle<JSPluralRules> plural_rules, - Handle<Object> locales, Handle<Object> options_obj) { - plural_rules->set_flags(0); +MaybeHandle<JSPluralRules> JSPluralRules::New(Isolate* isolate, Handle<Map> map, + Handle<Object> locales, + Handle<Object> options_obj) { // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales). Maybe<std::vector<std::string>> maybe_requested_locales = Intl::CanonicalizeLocaleList(isolate, locales); @@ -135,9 +102,6 @@ MaybeHandle<JSPluralRules> JSPluralRules::Initialize( MAYBE_RETURN(maybe_type, MaybeHandle<JSPluralRules>()); Type type = maybe_type.FromJust(); - // 8. Set pluralRules.[[Type]] to t. - plural_rules->set_type(type); - // Note: The spec says we should do ResolveLocale after performing // SetNumberFormatDigitOptions but we need the locale to create all // the ICU data structures. @@ -150,48 +114,64 @@ MaybeHandle<JSPluralRules> JSPluralRules::Initialize( Intl::ResolvedLocale r = Intl::ResolveLocale(isolate, JSPluralRules::GetAvailableLocales(), requested_locales, matcher, {}); - - // 12. Set pluralRules.[[Locale]] to the value of r.[[locale]]. Handle<String> locale_str = isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str()); - plural_rules->set_locale(*locale_str); + + icu::number::LocalizedNumberFormatter icu_number_formatter = + icu::number::NumberFormatter::withLocale(r.icu_locale) + .roundingMode(UNUM_ROUND_HALFUP); std::unique_ptr<icu::PluralRules> icu_plural_rules; - std::unique_ptr<icu::DecimalFormat> icu_decimal_format; - InitializeICUPluralRules(isolate, r.icu_locale, type, &icu_plural_rules, - &icu_decimal_format); + bool success = + CreateICUPluralRules(isolate, r.icu_locale, type, &icu_plural_rules); + if (!success) { + // Remove extensions and try again. + icu::Locale no_extension_locale(r.icu_locale.getBaseName()); + success = CreateICUPluralRules(isolate, no_extension_locale, type, + &icu_plural_rules); + icu_number_formatter = + icu::number::NumberFormatter::withLocale(no_extension_locale) + .roundingMode(UNUM_ROUND_HALFUP); + + if (!success) { + FATAL("Failed to create ICU PluralRules, are ICU data files missing?"); + } + } + CHECK_NOT_NULL(icu_plural_rules.get()); - CHECK_NOT_NULL(icu_decimal_format.get()); // 9. Perform ? SetNumberFormatDigitOptions(pluralRules, options, 0, 3). Maybe<Intl::NumberFormatDigitOptions> maybe_digit_options = - Intl::SetNumberFormatDigitOptions(isolate, options, 0, 3); + Intl::SetNumberFormatDigitOptions(isolate, options, 0, 3, false); MAYBE_RETURN(maybe_digit_options, MaybeHandle<JSPluralRules>()); Intl::NumberFormatDigitOptions digit_options = maybe_digit_options.FromJust(); - - icu_decimal_format->setRoundingMode(icu::DecimalFormat::kRoundHalfUp); - icu_decimal_format->setMinimumIntegerDigits( - digit_options.minimum_integer_digits); - icu_decimal_format->setMinimumFractionDigits( - digit_options.minimum_fraction_digits); - icu_decimal_format->setMaximumFractionDigits( - digit_options.maximum_fraction_digits); - if (digit_options.minimum_significant_digits > 0) { - icu_decimal_format->setMinimumSignificantDigits( - digit_options.minimum_significant_digits); - icu_decimal_format->setMaximumSignificantDigits( - digit_options.maximum_significant_digits); - } + icu_number_formatter = JSNumberFormat::SetDigitOptionsToFormatter( + icu_number_formatter, digit_options); Handle<Managed<icu::PluralRules>> managed_plural_rules = Managed<icu::PluralRules>::FromUniquePtr(isolate, 0, std::move(icu_plural_rules)); - plural_rules->set_icu_plural_rules(*managed_plural_rules); - Handle<Managed<icu::DecimalFormat>> managed_decimal_format = - Managed<icu::DecimalFormat>::FromUniquePtr(isolate, 0, - std::move(icu_decimal_format)); - plural_rules->set_icu_decimal_format(*managed_decimal_format); + Handle<Managed<icu::number::LocalizedNumberFormatter>> + managed_number_formatter = + Managed<icu::number::LocalizedNumberFormatter>::FromRawPtr( + isolate, 0, + new icu::number::LocalizedNumberFormatter(icu_number_formatter)); + + // Now all properties are ready, so we can allocate the result object. + Handle<JSPluralRules> plural_rules = Handle<JSPluralRules>::cast( + isolate->factory()->NewFastOrSlowJSObjectFromMap(map)); + DisallowHeapAllocation no_gc; + plural_rules->set_flags(0); + + // 8. Set pluralRules.[[Type]] to t. + plural_rules->set_type(type); + + // 12. Set pluralRules.[[Locale]] to the value of r.[[locale]]. + plural_rules->set_locale(*locale_str); + + plural_rules->set_icu_plural_rules(*managed_plural_rules); + plural_rules->set_icu_number_formatter(*managed_number_formatter); // 13. Return pluralRules. return plural_rules; @@ -202,31 +182,20 @@ MaybeHandle<String> JSPluralRules::ResolvePlural( icu::PluralRules* icu_plural_rules = plural_rules->icu_plural_rules().raw(); CHECK_NOT_NULL(icu_plural_rules); - icu::DecimalFormat* icu_decimal_format = - plural_rules->icu_decimal_format().raw(); - CHECK_NOT_NULL(icu_decimal_format); + icu::number::LocalizedNumberFormatter* fmt = + plural_rules->icu_number_formatter().raw(); + CHECK_NOT_NULL(fmt); - // Currently, PluralRules doesn't implement all the options for rounding that - // the Intl spec provides; format and parse the number to round to the - // appropriate amount, then apply PluralRules. - // - // TODO(littledan): If a future ICU version supports an extended API to avoid - // this step, then switch to that API. Bug thread: - // http://bugs.icu-project.org/trac/ticket/12763 - icu::UnicodeString rounded_string; - icu_decimal_format->format(number, rounded_string); - - icu::Formattable formattable; UErrorCode status = U_ZERO_ERROR; - icu_decimal_format->parse(rounded_string, formattable, status); + icu::number::FormattedNumber formatted_number = + fmt->formatDouble(number, status); CHECK(U_SUCCESS(status)); - double rounded = formattable.getDouble(status); + icu::UnicodeString result = + icu_plural_rules->select(formatted_number, status); CHECK(U_SUCCESS(status)); - icu::UnicodeString result = icu_plural_rules->select(rounded); - return isolate->factory()->NewStringFromTwoByte(Vector<const uint16_t>( - reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length())); + return Intl::ToString(isolate, result); } namespace { @@ -261,36 +230,27 @@ Handle<JSObject> JSPluralRules::ResolvedOptions( CreateDataPropertyForOptions(isolate, options, plural_rules->TypeAsString(), "type"); - icu::DecimalFormat* icu_decimal_format = - plural_rules->icu_decimal_format().raw(); - CHECK_NOT_NULL(icu_decimal_format); - - // This is a safe upcast as icu::DecimalFormat inherits from - // icu::NumberFormat. - icu::NumberFormat* icu_number_format = - static_cast<icu::NumberFormat*>(icu_decimal_format); + UErrorCode status = U_ZERO_ERROR; + icu::number::LocalizedNumberFormatter* icu_number_formatter = + plural_rules->icu_number_formatter().raw(); + icu::UnicodeString skeleton = icu_number_formatter->toSkeleton(status); + CHECK(U_SUCCESS(status)); - int min_int_digits = icu_number_format->getMinimumIntegerDigits(); - CreateDataPropertyForOptions(isolate, options, min_int_digits, - "minimumIntegerDigits"); + CreateDataPropertyForOptions( + isolate, options, + JSNumberFormat::MinimumIntegerDigitsFromSkeleton(skeleton), + "minimumIntegerDigits"); + int32_t min = 0, max = 0; + JSNumberFormat::FractionDigitsFromSkeleton(skeleton, &min, &max); - int min_fraction_digits = icu_number_format->getMinimumFractionDigits(); - CreateDataPropertyForOptions(isolate, options, min_fraction_digits, - "minimumFractionDigits"); + CreateDataPropertyForOptions(isolate, options, min, "minimumFractionDigits"); - int max_fraction_digits = icu_number_format->getMaximumFractionDigits(); - CreateDataPropertyForOptions(isolate, options, max_fraction_digits, - "maximumFractionDigits"); + CreateDataPropertyForOptions(isolate, options, max, "maximumFractionDigits"); - if (icu_decimal_format->areSignificantDigitsUsed()) { - int min_significant_digits = - icu_decimal_format->getMinimumSignificantDigits(); - CreateDataPropertyForOptions(isolate, options, min_significant_digits, + if (JSNumberFormat::SignificantDigitsFromSkeleton(skeleton, &min, &max)) { + CreateDataPropertyForOptions(isolate, options, min, "minimumSignificantDigits"); - - int max_significant_digits = - icu_decimal_format->getMaximumSignificantDigits(); - CreateDataPropertyForOptions(isolate, options, max_significant_digits, + CreateDataPropertyForOptions(isolate, options, max, "maximumSignificantDigits"); } @@ -299,7 +259,6 @@ Handle<JSObject> JSPluralRules::ResolvedOptions( icu::PluralRules* icu_plural_rules = plural_rules->icu_plural_rules().raw(); CHECK_NOT_NULL(icu_plural_rules); - UErrorCode status = U_ZERO_ERROR; std::unique_ptr<icu::StringEnumeration> categories( icu_plural_rules->getKeywords(status)); CHECK(U_SUCCESS(status)); @@ -329,13 +288,39 @@ Handle<JSObject> JSPluralRules::ResolvedOptions( return options; } +namespace { + +class PluralRulesAvailableLocales { + public: + PluralRulesAvailableLocales() { + UErrorCode status = U_ZERO_ERROR; + std::unique_ptr<icu::StringEnumeration> locales( + icu::PluralRules::getAvailableLocales(status)); + CHECK(U_SUCCESS(status)); + int32_t len = 0; + const char* locale = nullptr; + while ((locale = locales->next(&len, status)) != nullptr && + U_SUCCESS(status)) { + std::string str(locale); + if (len > 3) { + std::replace(str.begin(), str.end(), '_', '-'); + } + set_.insert(std::move(str)); + } + } + const std::set<std::string>& Get() const { return set_; } + + private: + std::set<std::string> set_; +}; + +} // namespace + const std::set<std::string>& JSPluralRules::GetAvailableLocales() { - // TODO(ftang): For PluralRules, filter out locales that - // don't support PluralRules. - // PluralRules is missing an appropriate getAvailableLocales method, - // so we should filter from all locales, but it's not clear how; see - // https://ssl.icu-project.org/trac/ticket/12756 - return Intl::GetAvailableLocalesForLocale(); + static base::LazyInstance<PluralRulesAvailableLocales>::type + available_locales = LAZY_INSTANCE_INITIALIZER; + return available_locales.Pointer()->Get(); + // return Intl::GetAvailableLocalesForLocale(); } } // namespace internal diff --git a/chromium/v8/src/objects/js-plural-rules.h b/chromium/v8/src/objects/js-plural-rules.h index 249090bdf68..840efb07ed4 100644 --- a/chromium/v8/src/objects/js-plural-rules.h +++ b/chromium/v8/src/objects/js-plural-rules.h @@ -22,8 +22,10 @@ #include "src/objects/object-macros.h" namespace U_ICU_NAMESPACE { -class DecimalFormat; class PluralRules; +namespace number { +class LocalizedNumberFormatter; +} // namespace number } // namespace U_ICU_NAMESPACE namespace v8 { @@ -31,9 +33,9 @@ namespace internal { class JSPluralRules : public JSObject { public: - V8_WARN_UNUSED_RESULT static MaybeHandle<JSPluralRules> Initialize( - Isolate* isolate, Handle<JSPluralRules> plural_rules, - Handle<Object> locales, Handle<Object> options); + V8_WARN_UNUSED_RESULT static MaybeHandle<JSPluralRules> New( + Isolate* isolate, Handle<Map> map, Handle<Object> locales, + Handle<Object> options); static Handle<JSObject> ResolvedOptions(Isolate* isolate, Handle<JSPluralRules> plural_rules); @@ -45,12 +47,7 @@ class JSPluralRules : public JSObject { // [[Type]] is one of the values "cardinal" or "ordinal", // identifying the plural rules used. - enum class Type { - CARDINAL, - ORDINAL, - - COUNT - }; + enum class Type { CARDINAL, ORDINAL }; inline void set_type(Type type); inline Type type() const; @@ -76,7 +73,8 @@ class JSPluralRules : public JSObject { DECL_ACCESSORS(locale, String) DECL_INT_ACCESSORS(flags) DECL_ACCESSORS(icu_plural_rules, Managed<icu::PluralRules>) - DECL_ACCESSORS(icu_decimal_format, Managed<icu::DecimalFormat>) + DECL_ACCESSORS(icu_number_formatter, + Managed<icu::number::LocalizedNumberFormatter>) OBJECT_CONSTRUCTORS(JSPluralRules, JSObject); }; diff --git a/chromium/v8/src/objects/js-proxy-inl.h b/chromium/v8/src/objects/js-proxy-inl.h index f33628b5c26..0683cfeec86 100644 --- a/chromium/v8/src/objects/js-proxy-inl.h +++ b/chromium/v8/src/objects/js-proxy-inl.h @@ -15,12 +15,7 @@ namespace v8 { namespace internal { -OBJECT_CONSTRUCTORS_IMPL(JSProxy, JSReceiver) - -CAST_ACCESSOR(JSProxy) - -ACCESSORS(JSProxy, target, Object, kTargetOffset) -ACCESSORS(JSProxy, handler, Object, kHandlerOffset) +TQ_OBJECT_CONSTRUCTORS_IMPL(JSProxy) bool JSProxy::IsRevoked() const { return !handler().IsJSReceiver(); } diff --git a/chromium/v8/src/objects/js-proxy.h b/chromium/v8/src/objects/js-proxy.h index c4f98927e9b..8e29c08bc14 100644 --- a/chromium/v8/src/objects/js-proxy.h +++ b/chromium/v8/src/objects/js-proxy.h @@ -15,21 +15,14 @@ namespace v8 { namespace internal { // The JSProxy describes EcmaScript Harmony proxies -class JSProxy : public JSReceiver { +class JSProxy : public TorqueGeneratedJSProxy<JSProxy, JSReceiver> { public: V8_WARN_UNUSED_RESULT static MaybeHandle<JSProxy> New(Isolate* isolate, Handle<Object>, Handle<Object>); - // [handler]: The handler property. - DECL_ACCESSORS(handler, Object) - // [target]: The target property. - DECL_ACCESSORS(target, Object) - static MaybeHandle<NativeContext> GetFunctionRealm(Handle<JSProxy> proxy); - DECL_CAST(JSProxy) - V8_INLINE bool IsRevoked() const; static void Revoke(Handle<JSProxy> proxy); @@ -70,6 +63,10 @@ class JSProxy : public JSReceiver { V8_WARN_UNUSED_RESULT static Maybe<bool> CheckHasTrap( Isolate* isolate, Handle<Name> name, Handle<JSReceiver> target); + // ES6 9.5.10 + V8_WARN_UNUSED_RESULT static Maybe<bool> CheckDeleteTrap( + Isolate* isolate, Handle<Name> name, Handle<JSReceiver> target); + // ES6 9.5.8 V8_WARN_UNUSED_RESULT static MaybeHandle<Object> GetProperty( Isolate* isolate, Handle<JSProxy> proxy, Handle<Name> name, @@ -106,10 +103,6 @@ class JSProxy : public JSReceiver { static const int kMaxIterationLimit = 100 * 1024; - // Layout description. - DEFINE_FIELD_OFFSET_CONSTANTS(JSReceiver::kHeaderSize, - TORQUE_GENERATED_JSPROXY_FIELDS) - // kTargetOffset aliases with the elements of JSObject. The fact that // JSProxy::target is a Javascript value which cannot be confused with an // elements backing store is exploited by loading from this offset from an @@ -125,7 +118,7 @@ class JSProxy : public JSReceiver { PropertyDescriptor* desc, Maybe<ShouldThrow> should_throw); - OBJECT_CONSTRUCTORS(JSProxy, JSReceiver); + TQ_OBJECT_CONSTRUCTORS(JSProxy) }; // JSProxyRevocableResult is just a JSObject with a specific initial map. diff --git a/chromium/v8/src/objects/js-regexp.h b/chromium/v8/src/objects/js-regexp.h index e525c66e3e1..18355079f8e 100644 --- a/chromium/v8/src/objects/js-regexp.h +++ b/chromium/v8/src/objects/js-regexp.h @@ -37,13 +37,13 @@ class JSRegExp : public JSObject { // IRREGEXP: Compiled with Irregexp. enum Type { NOT_COMPILED, ATOM, IRREGEXP }; struct FlagShiftBit { - static const int kGlobal = 0; - static const int kIgnoreCase = 1; - static const int kMultiline = 2; - static const int kSticky = 3; - static const int kUnicode = 4; - static const int kDotAll = 5; - static const int kInvalid = 7; + static constexpr int kGlobal = 0; + static constexpr int kIgnoreCase = 1; + static constexpr int kMultiline = 2; + static constexpr int kSticky = 3; + static constexpr int kUnicode = 4; + static constexpr int kDotAll = 5; + static constexpr int kInvalid = 6; }; enum Flag : uint8_t { kNone = 0, @@ -57,28 +57,31 @@ class JSRegExp : public JSObject { kInvalid = 1 << FlagShiftBit::kInvalid, // Not included in FlagCount. }; using Flags = base::Flags<Flag>; - static constexpr int FlagCount() { return 6; } - - static int FlagShiftBits(Flag flag) { - switch (flag) { - case kGlobal: - return FlagShiftBit::kGlobal; - case kIgnoreCase: - return FlagShiftBit::kIgnoreCase; - case kMultiline: - return FlagShiftBit::kMultiline; - case kSticky: - return FlagShiftBit::kSticky; - case kUnicode: - return FlagShiftBit::kUnicode; - case kDotAll: - return FlagShiftBit::kDotAll; - default: - STATIC_ASSERT(FlagCount() == 6); - UNREACHABLE(); - } + + static constexpr int kFlagCount = 6; + + static constexpr Flag FlagFromChar(char c) { + STATIC_ASSERT(kFlagCount == 6); + // clang-format off + return c == 'g' ? kGlobal + : c == 'i' ? kIgnoreCase + : c == 'm' ? kMultiline + : c == 'y' ? kSticky + : c == 'u' ? kUnicode + : c == 's' ? kDotAll + : kInvalid; + // clang-format on } + STATIC_ASSERT(static_cast<int>(kNone) == v8::RegExp::kNone); + STATIC_ASSERT(static_cast<int>(kGlobal) == v8::RegExp::kGlobal); + STATIC_ASSERT(static_cast<int>(kIgnoreCase) == v8::RegExp::kIgnoreCase); + STATIC_ASSERT(static_cast<int>(kMultiline) == v8::RegExp::kMultiline); + STATIC_ASSERT(static_cast<int>(kSticky) == v8::RegExp::kSticky); + STATIC_ASSERT(static_cast<int>(kUnicode) == v8::RegExp::kUnicode); + STATIC_ASSERT(static_cast<int>(kDotAll) == v8::RegExp::kDotAll); + STATIC_ASSERT(kFlagCount == v8::RegExp::kFlagCount); + DECL_ACCESSORS(data, Object) DECL_ACCESSORS(flags, Object) DECL_ACCESSORS(last_index, Object) diff --git a/chromium/v8/src/objects/js-relative-time-format-inl.h b/chromium/v8/src/objects/js-relative-time-format-inl.h index 1ff66b1a12d..fac3439b31f 100644 --- a/chromium/v8/src/objects/js-relative-time-format-inl.h +++ b/chromium/v8/src/objects/js-relative-time-format-inl.h @@ -27,7 +27,7 @@ ACCESSORS(JSRelativeTimeFormat, icu_formatter, SMI_ACCESSORS(JSRelativeTimeFormat, flags, kFlagsOffset) inline void JSRelativeTimeFormat::set_style(Style style) { - DCHECK_GT(Style::COUNT, style); + DCHECK_GE(StyleBits::kMax, style); int hints = flags(); hints = StyleBits::update(hints, style); set_flags(hints); @@ -38,7 +38,7 @@ inline JSRelativeTimeFormat::Style JSRelativeTimeFormat::style() const { } inline void JSRelativeTimeFormat::set_numeric(Numeric numeric) { - DCHECK_GT(Numeric::COUNT, numeric); + DCHECK_GE(NumericBits::kMax, numeric); int hints = flags(); hints = NumericBits::update(hints, numeric); set_flags(hints); diff --git a/chromium/v8/src/objects/js-relative-time-format.cc b/chromium/v8/src/objects/js-relative-time-format.cc index 59a3bf7ea0f..28f8c757ee1 100644 --- a/chromium/v8/src/objects/js-relative-time-format.cc +++ b/chromium/v8/src/objects/js-relative-time-format.cc @@ -34,9 +34,8 @@ UDateRelativeDateTimeFormatterStyle getIcuStyle( return UDAT_STYLE_SHORT; case JSRelativeTimeFormat::Style::NARROW: return UDAT_STYLE_NARROW; - case JSRelativeTimeFormat::Style::COUNT: - UNREACHABLE(); } + UNREACHABLE(); } } // namespace @@ -54,11 +53,9 @@ JSRelativeTimeFormat::Numeric JSRelativeTimeFormat::getNumeric( UNREACHABLE(); } -MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::Initialize( - Isolate* isolate, Handle<JSRelativeTimeFormat> relative_time_format_holder, - Handle<Object> locales, Handle<Object> input_options) { - relative_time_format_holder->set_flags(0); - +MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::New( + Isolate* isolate, Handle<Map> map, Handle<Object> locales, + Handle<Object> input_options) { // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales). Maybe<std::vector<std::string>> maybe_requested_locales = Intl::CanonicalizeLocaleList(isolate, locales); @@ -125,7 +122,6 @@ MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::Initialize( Handle<String> locale_str = isolate->factory()->NewStringFromAsciiChecked( maybe_locale_str.FromJust().c_str()); - relative_time_format_holder->set_locale(*locale_str); // 15. Let s be ? GetOption(options, "style", "string", // «"long", "short", "narrow"», "long"). @@ -136,9 +132,6 @@ MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::Initialize( MAYBE_RETURN(maybe_style, MaybeHandle<JSRelativeTimeFormat>()); Style style_enum = maybe_style.FromJust(); - // 16. Set relativeTimeFormat.[[Style]] to s. - relative_time_format_holder->set_style(style_enum); - // 17. Let numeric be ? GetOption(options, "numeric", "string", // «"always", "auto"», "always"). Maybe<Numeric> maybe_numeric = Intl::GetStringOption<Numeric>( @@ -147,9 +140,6 @@ MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::Initialize( MAYBE_RETURN(maybe_numeric, MaybeHandle<JSRelativeTimeFormat>()); Numeric numeric_enum = maybe_numeric.FromJust(); - // 18. Set relativeTimeFormat.[[Numeric]] to numeric. - relative_time_format_holder->set_numeric(numeric_enum); - // 19. Let relativeTimeFormat.[[NumberFormat]] be // ? Construct(%NumberFormat%, « nfLocale, nfOptions »). icu::NumberFormat* number_format = @@ -179,6 +169,21 @@ MaybeHandle<JSRelativeTimeFormat> JSRelativeTimeFormat::Initialize( Managed<icu::RelativeDateTimeFormatter>::FromRawPtr(isolate, 0, icu_formatter); + // Now all properties are ready, so we can allocate the result object. + Handle<JSRelativeTimeFormat> relative_time_format_holder = + Handle<JSRelativeTimeFormat>::cast( + isolate->factory()->NewFastOrSlowJSObjectFromMap(map)); + DisallowHeapAllocation no_gc; + relative_time_format_holder->set_flags(0); + + relative_time_format_holder->set_locale(*locale_str); + + // 16. Set relativeTimeFormat.[[Style]] to s. + relative_time_format_holder->set_style(style_enum); + + // 18. Set relativeTimeFormat.[[Numeric]] to numeric. + relative_time_format_holder->set_numeric(numeric_enum); + // 21. Set relativeTimeFormat.[[InitializedRelativeTimeFormat]] to true. relative_time_format_holder->set_icu_formatter(*managed_formatter); @@ -214,9 +219,8 @@ Handle<String> JSRelativeTimeFormat::StyleAsString() const { return GetReadOnlyRoots().short_string_handle(); case Style::NARROW: return GetReadOnlyRoots().narrow_string_handle(); - case Style::COUNT: - UNREACHABLE(); } + UNREACHABLE(); } Handle<String> JSRelativeTimeFormat::NumericAsString() const { @@ -225,9 +229,8 @@ Handle<String> JSRelativeTimeFormat::NumericAsString() const { return GetReadOnlyRoots().always_string_handle(); case Numeric::AUTO: return GetReadOnlyRoots().auto_string_handle(); - case Numeric::COUNT: - UNREACHABLE(); } + UNREACHABLE(); } namespace { diff --git a/chromium/v8/src/objects/js-relative-time-format.h b/chromium/v8/src/objects/js-relative-time-format.h index 740336c29c5..6e405e345e9 100644 --- a/chromium/v8/src/objects/js-relative-time-format.h +++ b/chromium/v8/src/objects/js-relative-time-format.h @@ -30,12 +30,11 @@ namespace internal { class JSRelativeTimeFormat : public JSObject { public: - // Initializes relative time format object with properties derived from input + // Creates relative time format object with properties derived from input // locales and options. - V8_WARN_UNUSED_RESULT static MaybeHandle<JSRelativeTimeFormat> Initialize( - Isolate* isolate, - Handle<JSRelativeTimeFormat> relative_time_format_holder, - Handle<Object> locales, Handle<Object> options); + V8_WARN_UNUSED_RESULT static MaybeHandle<JSRelativeTimeFormat> New( + Isolate* isolate, Handle<Map> map, Handle<Object> locales, + Handle<Object> options); V8_WARN_UNUSED_RESULT static Handle<JSObject> ResolvedOptions( Isolate* isolate, Handle<JSRelativeTimeFormat> format_holder); @@ -67,10 +66,9 @@ class JSRelativeTimeFormat : public JSObject { // ecma402/#sec-properties-of-intl-relativetimeformat-instances enum class Style { - LONG, // Everything spelled out. - SHORT, // Abbreviations used when possible. - NARROW, // Use the shortest possible form. - COUNT + LONG, // Everything spelled out. + SHORT, // Abbreviations used when possible. + NARROW // Use the shortest possible form. }; inline void set_style(Style style); inline Style style() const; @@ -82,9 +80,8 @@ class JSRelativeTimeFormat : public JSObject { // ecma402/#sec-properties-of-intl-relativetimeformat-instances enum class Numeric { ALWAYS, // numerical descriptions are always used ("1 day ago") - AUTO, // numerical descriptions are used only when no more specific + AUTO // numerical descriptions are used only when no more specific // version is available ("yesterday") - COUNT }; inline void set_numeric(Numeric numeric); inline Numeric numeric() const; diff --git a/chromium/v8/src/objects/js-segment-iterator-inl.h b/chromium/v8/src/objects/js-segment-iterator-inl.h index 24a827c0300..b2d745179a3 100644 --- a/chromium/v8/src/objects/js-segment-iterator-inl.h +++ b/chromium/v8/src/objects/js-segment-iterator-inl.h @@ -35,7 +35,7 @@ CAST_ACCESSOR(JSSegmentIterator) inline void JSSegmentIterator::set_granularity( JSSegmenter::Granularity granularity) { - DCHECK_GT(JSSegmenter::Granularity::COUNT, granularity); + DCHECK_GE(GranularityBits::kMax, granularity); int hints = flags(); hints = GranularityBits::update(hints, granularity); set_flags(hints); diff --git a/chromium/v8/src/objects/js-segment-iterator.cc b/chromium/v8/src/objects/js-segment-iterator.cc index 3d2b19ca5c0..509db37d440 100644 --- a/chromium/v8/src/objects/js-segment-iterator.cc +++ b/chromium/v8/src/objects/js-segment-iterator.cc @@ -37,9 +37,8 @@ Handle<String> JSSegmentIterator::GranularityAsString() const { return GetReadOnlyRoots().word_string_handle(); case JSSegmenter::Granularity::SENTENCE: return GetReadOnlyRoots().sentence_string_handle(); - case JSSegmenter::Granularity::COUNT: - UNREACHABLE(); } + UNREACHABLE(); } MaybeHandle<JSSegmentIterator> JSSegmentIterator::Create( @@ -49,22 +48,25 @@ MaybeHandle<JSSegmentIterator> JSSegmentIterator::Create( // 1. Let iterator be ObjectCreate(%SegmentIteratorPrototype%). Handle<Map> map = Handle<Map>( isolate->native_context()->intl_segment_iterator_map(), isolate); - Handle<JSObject> result = isolate->factory()->NewJSObjectFromMap(map); + Handle<Managed<icu::BreakIterator>> managed_break_iterator = + Managed<icu::BreakIterator>::FromRawPtr(isolate, 0, break_iterator); + Handle<Managed<icu::UnicodeString>> unicode_string = + Intl::SetTextToBreakIterator(isolate, text, break_iterator); + + // Now all properties are ready, so we can allocate the result object. + Handle<JSObject> result = isolate->factory()->NewJSObjectFromMap(map); + DisallowHeapAllocation no_gc; Handle<JSSegmentIterator> segment_iterator = Handle<JSSegmentIterator>::cast(result); segment_iterator->set_flags(0); segment_iterator->set_granularity(granularity); // 2. Let iterator.[[SegmentIteratorSegmenter]] be segmenter. - Handle<Managed<icu::BreakIterator>> managed_break_iterator = - Managed<icu::BreakIterator>::FromRawPtr(isolate, 0, break_iterator); segment_iterator->set_icu_break_iterator(*managed_break_iterator); // 3. Let iterator.[[SegmentIteratorString]] be string. - Managed<icu::UnicodeString> unicode_string = - Intl::SetTextToBreakIterator(isolate, text, break_iterator); - segment_iterator->set_unicode_string(unicode_string); + segment_iterator->set_unicode_string(*unicode_string); // 4. Let iterator.[[SegmentIteratorIndex]] be 0. // step 4 is stored inside break_iterator. @@ -119,9 +121,8 @@ Handle<Object> JSSegmentIterator::BreakType() const { return GetReadOnlyRoots().sep_string_handle(); } return GetReadOnlyRoots().undefined_value_handle(); - case JSSegmenter::Granularity::COUNT: - UNREACHABLE(); } + UNREACHABLE(); } // ecma402 #sec-segment-iterator-prototype-index diff --git a/chromium/v8/src/objects/js-segmenter-inl.h b/chromium/v8/src/objects/js-segmenter-inl.h index b4adf4c8e6a..a31de29c25c 100644 --- a/chromium/v8/src/objects/js-segmenter-inl.h +++ b/chromium/v8/src/objects/js-segmenter-inl.h @@ -27,7 +27,7 @@ ACCESSORS(JSSegmenter, icu_break_iterator, Managed<icu::BreakIterator>, SMI_ACCESSORS(JSSegmenter, flags, kFlagsOffset) inline void JSSegmenter::set_granularity(Granularity granularity) { - DCHECK_GT(Granularity::COUNT, granularity); + DCHECK_GE(GranularityBits::kMax, granularity); int hints = flags(); hints = GranularityBits::update(hints, granularity); set_flags(hints); diff --git a/chromium/v8/src/objects/js-segmenter.cc b/chromium/v8/src/objects/js-segmenter.cc index 5321334678d..7985cf1c99e 100644 --- a/chromium/v8/src/objects/js-segmenter.cc +++ b/chromium/v8/src/objects/js-segmenter.cc @@ -30,11 +30,9 @@ JSSegmenter::Granularity JSSegmenter::GetGranularity(const char* str) { UNREACHABLE(); } -MaybeHandle<JSSegmenter> JSSegmenter::Initialize( - Isolate* isolate, Handle<JSSegmenter> segmenter_holder, - Handle<Object> locales, Handle<Object> input_options) { - segmenter_holder->set_flags(0); - +MaybeHandle<JSSegmenter> JSSegmenter::New(Isolate* isolate, Handle<Map> map, + Handle<Object> locales, + Handle<Object> input_options) { // 3. Let requestedLocales be ? CanonicalizeLocaleList(locales). Maybe<std::vector<std::string>> maybe_requested_locales = Intl::CanonicalizeLocaleList(isolate, locales); @@ -69,11 +67,8 @@ MaybeHandle<JSSegmenter> JSSegmenter::Initialize( Intl::ResolvedLocale r = Intl::ResolveLocale(isolate, JSSegmenter::GetAvailableLocales(), requested_locales, matcher, {}); - - // 10. Set segmenter.[[Locale]] to the value of r.[[Locale]]. Handle<String> locale_str = isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str()); - segmenter_holder->set_locale(*locale_str); // 13. Let granularity be ? GetOption(options, "granularity", "string", « // "grapheme", "word", "sentence" », "grapheme"). @@ -85,9 +80,6 @@ MaybeHandle<JSSegmenter> JSSegmenter::Initialize( MAYBE_RETURN(maybe_granularity, MaybeHandle<JSSegmenter>()); Granularity granularity_enum = maybe_granularity.FromJust(); - // 14. Set segmenter.[[SegmenterGranularity]] to granularity. - segmenter_holder->set_granularity(granularity_enum); - icu::Locale icu_locale = r.icu_locale; DCHECK(!icu_locale.isBogus()); @@ -107,8 +99,6 @@ MaybeHandle<JSSegmenter> JSSegmenter::Initialize( icu_break_iterator.reset( icu::BreakIterator::createSentenceInstance(icu_locale, status)); break; - case Granularity::COUNT: - UNREACHABLE(); } CHECK(U_SUCCESS(status)); @@ -118,6 +108,18 @@ MaybeHandle<JSSegmenter> JSSegmenter::Initialize( Managed<icu::BreakIterator>::FromUniquePtr(isolate, 0, std::move(icu_break_iterator)); + // Now all properties are ready, so we can allocate the result object. + Handle<JSSegmenter> segmenter_holder = Handle<JSSegmenter>::cast( + isolate->factory()->NewFastOrSlowJSObjectFromMap(map)); + DisallowHeapAllocation no_gc; + segmenter_holder->set_flags(0); + + // 10. Set segmenter.[[Locale]] to the value of r.[[Locale]]. + segmenter_holder->set_locale(*locale_str); + + // 14. Set segmenter.[[SegmenterGranularity]] to granularity. + segmenter_holder->set_granularity(granularity_enum); + segmenter_holder->set_icu_break_iterator(*managed_break_iterator); return segmenter_holder; } @@ -157,9 +159,8 @@ Handle<String> JSSegmenter::GranularityAsString() const { return GetReadOnlyRoots().word_string_handle(); case Granularity::SENTENCE: return GetReadOnlyRoots().sentence_string_handle(); - case Granularity::COUNT: - UNREACHABLE(); } + UNREACHABLE(); } const std::set<std::string>& JSSegmenter::GetAvailableLocales() { diff --git a/chromium/v8/src/objects/js-segmenter.h b/chromium/v8/src/objects/js-segmenter.h index 423dd674971..641cf106fbd 100644 --- a/chromium/v8/src/objects/js-segmenter.h +++ b/chromium/v8/src/objects/js-segmenter.h @@ -30,11 +30,11 @@ namespace internal { class JSSegmenter : public JSObject { public: - // Initializes segmenter object with properties derived from input - // locales and options. - V8_WARN_UNUSED_RESULT static MaybeHandle<JSSegmenter> Initialize( - Isolate* isolate, Handle<JSSegmenter> segmenter_holder, - Handle<Object> locales, Handle<Object> options); + // Creates segmenter object with properties derived from input locales and + // options. + V8_WARN_UNUSED_RESULT static MaybeHandle<JSSegmenter> New( + Isolate* isolate, Handle<Map> map, Handle<Object> locales, + Handle<Object> options); V8_WARN_UNUSED_RESULT static Handle<JSObject> ResolvedOptions( Isolate* isolate, Handle<JSSegmenter> segmenter_holder); @@ -56,8 +56,7 @@ class JSSegmenter : public JSObject { enum class Granularity { GRAPHEME, // for character-breaks WORD, // for word-breaks - SENTENCE, // for sentence-breaks - COUNT + SENTENCE // for sentence-breaks }; inline void set_granularity(Granularity granularity); inline Granularity granularity() const; diff --git a/chromium/v8/src/objects/js-weak-refs-inl.h b/chromium/v8/src/objects/js-weak-refs-inl.h index 6632a310025..46f28e883ed 100644 --- a/chromium/v8/src/objects/js-weak-refs-inl.h +++ b/chromium/v8/src/objects/js-weak-refs-inl.h @@ -97,16 +97,16 @@ void JSFinalizationGroup::Register( } } -void JSFinalizationGroup::Unregister( - Handle<JSFinalizationGroup> finalization_group, Handle<Object> key, - Isolate* isolate) { +bool JSFinalizationGroup::Unregister( + Handle<JSFinalizationGroup> finalization_group, + Handle<JSReceiver> unregister_token, Isolate* isolate) { // Iterate through the doubly linked list of WeakCells associated with the // key. Each WeakCell will be in the "active_cells" or "cleared_cells" list of // its FinalizationGroup; remove it from there. if (!finalization_group->key_map().IsUndefined(isolate)) { Handle<ObjectHashTable> key_map = handle(ObjectHashTable::cast(finalization_group->key_map()), isolate); - Object value = key_map->Lookup(key); + Object value = key_map->Lookup(unregister_token); Object undefined = ReadOnlyRoots(isolate).undefined_value(); while (value.IsWeakCell()) { WeakCell weak_cell = WeakCell::cast(value); @@ -116,9 +116,13 @@ void JSFinalizationGroup::Unregister( weak_cell.set_key_list_next(undefined); } bool was_present; - key_map = ObjectHashTable::Remove(isolate, key_map, key, &was_present); + key_map = ObjectHashTable::Remove(isolate, key_map, unregister_token, + &was_present); finalization_group->set_key_map(*key_map); + return was_present; } + + return false; } bool JSFinalizationGroup::NeedsCleanup() const { diff --git a/chromium/v8/src/objects/js-weak-refs.h b/chromium/v8/src/objects/js-weak-refs.h index b846c2e6085..6a401fecee1 100644 --- a/chromium/v8/src/objects/js-weak-refs.h +++ b/chromium/v8/src/objects/js-weak-refs.h @@ -41,8 +41,9 @@ class JSFinalizationGroup : public JSObject { Handle<JSReceiver> target, Handle<Object> holdings, Handle<Object> key, Isolate* isolate); - inline static void Unregister(Handle<JSFinalizationGroup> finalization_group, - Handle<Object> key, Isolate* isolate); + inline static bool Unregister(Handle<JSFinalizationGroup> finalization_group, + Handle<JSReceiver> unregister_token, + Isolate* isolate); // Returns true if the cleared_cells list is non-empty. inline bool NeedsCleanup() const; @@ -57,24 +58,13 @@ class JSFinalizationGroup : public JSObject { // Constructs an iterator for the WeakCells in the cleared_cells list and // calls the user's cleanup function. - static void Cleanup(Handle<JSFinalizationGroup> finalization_group, - Isolate* isolate); - -// Layout description. -#define JS_FINALIZATION_GROUP_FIELDS(V) \ - V(kNativeContextOffset, kTaggedSize) \ - V(kCleanupOffset, kTaggedSize) \ - V(kActiveCellsOffset, kTaggedSize) \ - V(kClearedCellsOffset, kTaggedSize) \ - V(kKeyMapOffset, kTaggedSize) \ - V(kNextOffset, kTaggedSize) \ - V(kFlagsOffset, kTaggedSize) \ - /* Header size. */ \ - V(kSize, 0) + static void Cleanup(Isolate* isolate, + Handle<JSFinalizationGroup> finalization_group, + Handle<Object> callback); + // Layout description. DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, - JS_FINALIZATION_GROUP_FIELDS) -#undef JS_FINALIZATION_GROUP_FIELDS + TORQUE_GENERATED_JSFINALIZATION_GROUP_FIELDS) // Bitfields in flags. class ScheduledForCleanupField : public BitField<bool, 0, 1> {}; @@ -106,21 +96,9 @@ class WeakCell : public HeapObject { DECL_ACCESSORS(key_list_prev, Object) DECL_ACCESSORS(key_list_next, Object) -// Layout description. -#define WEAK_CELL_FIELDS(V) \ - V(kFinalizationGroupOffset, kTaggedSize) \ - V(kTargetOffset, kTaggedSize) \ - V(kHoldingsOffset, kTaggedSize) \ - V(kPrevOffset, kTaggedSize) \ - V(kNextOffset, kTaggedSize) \ - V(kKeyOffset, kTaggedSize) \ - V(kKeyListPrevOffset, kTaggedSize) \ - V(kKeyListNextOffset, kTaggedSize) \ - /* Header size. */ \ - V(kSize, 0) - - DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, WEAK_CELL_FIELDS) -#undef WEAK_CELL_FIELDS + // Layout description. + DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, + TORQUE_GENERATED_WEAK_CELL_FIELDS) class BodyDescriptor; @@ -146,14 +124,9 @@ class JSWeakRef : public JSObject { DECL_ACCESSORS(target, HeapObject) -// Layout description. -#define JS_WEAK_REF_FIELDS(V) \ - V(kTargetOffset, kTaggedSize) \ - /* Header size. */ \ - V(kSize, 0) - - DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, JS_WEAK_REF_FIELDS) -#undef JS_WEAK_REF_FIELDS + // Layout description. + DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, + TORQUE_GENERATED_JSWEAK_REF_FIELDS) class BodyDescriptor; @@ -189,15 +162,10 @@ class JSFinalizationGroupCleanupIterator : public JSObject { DECL_ACCESSORS(finalization_group, JSFinalizationGroup) -// Layout description. -#define JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_FIELDS(V) \ - V(kFinalizationGroupOffset, kTaggedSize) \ - /* Header size. */ \ - V(kSize, 0) - - DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, - JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_FIELDS) -#undef JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_FIELDS + // Layout description. + DEFINE_FIELD_OFFSET_CONSTANTS( + JSObject::kHeaderSize, + TORQUE_GENERATED_JSFINALIZATION_GROUP_CLEANUP_ITERATOR_FIELDS) OBJECT_CONSTRUCTORS(JSFinalizationGroupCleanupIterator, JSObject); }; diff --git a/chromium/v8/src/objects/keys.cc b/chromium/v8/src/objects/keys.cc index d3a1f6bdc29..18b38ed7447 100644 --- a/chromium/v8/src/objects/keys.cc +++ b/chromium/v8/src/objects/keys.cc @@ -395,6 +395,11 @@ MaybeHandle<FixedArray> GetOwnKeysWithElements(Isolate* isolate, MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys( GetKeysConversion keys_conversion) { + // TODO(v8:9401): We should extend the fast path of KeyAccumulator::GetKeys to + // also use fast path even when filter = SKIP_SYMBOLS. We used to pass wrong + // filter to use fast path in cases where we tried to verify all properties + // are enumerable. However these checks weren't correct and passing the wrong + // filter led to wrong behaviour. if (filter_ == ENUMERABLE_STRINGS) { Handle<FixedArray> keys; if (GetKeysFast(keys_conversion).ToHandle(&keys)) { diff --git a/chromium/v8/src/objects/layout-descriptor-inl.h b/chromium/v8/src/objects/layout-descriptor-inl.h index 49683da2674..ad0a058a92c 100644 --- a/chromium/v8/src/objects/layout-descriptor-inl.h +++ b/chromium/v8/src/objects/layout-descriptor-inl.h @@ -209,11 +209,11 @@ int LayoutDescriptor::number_of_layout_words() { } uint32_t LayoutDescriptor::get_layout_word(int index) const { - return get_uint32(index); + return get_uint32_relaxed(index); } void LayoutDescriptor::set_layout_word(int index, uint32_t value) { - set_uint32(index, value); + set_uint32_relaxed(index, value); } // LayoutDescriptorHelper is a helper class for querying whether inobject diff --git a/chromium/v8/src/objects/literal-objects-inl.h b/chromium/v8/src/objects/literal-objects-inl.h index 1ddb333cffb..32b43cd8f70 100644 --- a/chromium/v8/src/objects/literal-objects-inl.h +++ b/chromium/v8/src/objects/literal-objects-inl.h @@ -15,6 +15,10 @@ namespace v8 { namespace internal { +// +// ObjectBoilerplateDescription +// + OBJECT_CONSTRUCTORS_IMPL(ObjectBoilerplateDescription, FixedArray) CAST_ACCESSOR(ObjectBoilerplateDescription) @@ -22,6 +26,70 @@ CAST_ACCESSOR(ObjectBoilerplateDescription) SMI_ACCESSORS(ObjectBoilerplateDescription, flags, FixedArray::OffsetOfElementAt(kLiteralTypeOffset)) +Object ObjectBoilerplateDescription::name(int index) const { + Isolate* isolate = GetIsolateForPtrCompr(*this); + return name(isolate, index); +} + +Object ObjectBoilerplateDescription::name(Isolate* isolate, int index) const { + // get() already checks for out of bounds access, but we do not want to allow + // access to the last element, if it is the number of properties. + DCHECK_NE(size(), index); + return get(isolate, 2 * index + kDescriptionStartIndex); +} + +Object ObjectBoilerplateDescription::value(int index) const { + Isolate* isolate = GetIsolateForPtrCompr(*this); + return value(isolate, index); +} + +Object ObjectBoilerplateDescription::value(Isolate* isolate, int index) const { + return get(isolate, 2 * index + 1 + kDescriptionStartIndex); +} + +void ObjectBoilerplateDescription::set_key_value(int index, Object key, + Object value) { + DCHECK_LT(index, size()); + DCHECK_GE(index, 0); + set(2 * index + kDescriptionStartIndex, key); + set(2 * index + 1 + kDescriptionStartIndex, value); +} + +int ObjectBoilerplateDescription::size() const { + DCHECK_EQ(0, (length() - kDescriptionStartIndex - + (this->has_number_of_properties() ? 1 : 0)) % + 2); + // Rounding is intended. + return (length() - kDescriptionStartIndex) / 2; +} + +bool ObjectBoilerplateDescription::has_number_of_properties() const { + return (length() - kDescriptionStartIndex) % 2 != 0; +} + +int ObjectBoilerplateDescription::backing_store_size() const { + if (has_number_of_properties()) { + // If present, the last entry contains the number of properties. + return Smi::ToInt(this->get(length() - 1)); + } + // If the number is not given explicitly, we assume there are no + // properties with computed names. + return size(); +} + +void ObjectBoilerplateDescription::set_backing_store_size( + int backing_store_size) { + DCHECK(has_number_of_properties()); + DCHECK_NE(size(), backing_store_size); + CHECK(Smi::IsValid(backing_store_size)); + // TODO(ishell): move this value to the header + set(length() - 1, Smi::FromInt(backing_store_size)); +} + +// +// ClassBoilerplate +// + OBJECT_CONSTRUCTORS_IMPL(ClassBoilerplate, FixedArray) CAST_ACCESSOR(ClassBoilerplate) @@ -52,6 +120,10 @@ ACCESSORS(ClassBoilerplate, instance_elements_template, Object, ACCESSORS(ClassBoilerplate, instance_computed_properties, FixedArray, FixedArray::OffsetOfElementAt(kPrototypeComputedPropertiesIndex)) +// +// ArrayBoilerplateDescription +// + OBJECT_CONSTRUCTORS_IMPL(ArrayBoilerplateDescription, Struct) CAST_ACCESSOR(ArrayBoilerplateDescription) diff --git a/chromium/v8/src/objects/literal-objects.cc b/chromium/v8/src/objects/literal-objects.cc index bfdbd9317b4..7328c11f311 100644 --- a/chromium/v8/src/objects/literal-objects.cc +++ b/chromium/v8/src/objects/literal-objects.cc @@ -17,56 +17,6 @@ namespace v8 { namespace internal { -Object ObjectBoilerplateDescription::name(int index) const { - // get() already checks for out of bounds access, but we do not want to allow - // access to the last element, if it is the number of properties. - DCHECK_NE(size(), index); - return get(2 * index + kDescriptionStartIndex); -} - -Object ObjectBoilerplateDescription::value(int index) const { - return get(2 * index + 1 + kDescriptionStartIndex); -} - -void ObjectBoilerplateDescription::set_key_value(int index, Object key, - Object value) { - DCHECK_LT(index, size()); - DCHECK_GE(index, 0); - set(2 * index + kDescriptionStartIndex, key); - set(2 * index + 1 + kDescriptionStartIndex, value); -} - -int ObjectBoilerplateDescription::size() const { - DCHECK_EQ(0, (length() - kDescriptionStartIndex - - (this->has_number_of_properties() ? 1 : 0)) % - 2); - // Rounding is intended. - return (length() - kDescriptionStartIndex) / 2; -} - -int ObjectBoilerplateDescription::backing_store_size() const { - if (has_number_of_properties()) { - // If present, the last entry contains the number of properties. - return Smi::ToInt(this->get(length() - 1)); - } - // If the number is not given explicitly, we assume there are no - // properties with computed names. - return size(); -} - -void ObjectBoilerplateDescription::set_backing_store_size( - Isolate* isolate, int backing_store_size) { - DCHECK(has_number_of_properties()); - DCHECK_NE(size(), backing_store_size); - Handle<Object> backing_store_size_obj = - isolate->factory()->NewNumberFromInt(backing_store_size); - set(length() - 1, *backing_store_size_obj); -} - -bool ObjectBoilerplateDescription::has_number_of_properties() const { - return (length() - kDescriptionStartIndex) % 2 != 0; -} - namespace { inline int EncodeComputedEntry(ClassBoilerplate::ValueKind value_kind, @@ -306,8 +256,12 @@ class ObjectDescriptor { void IncPropertiesCount() { ++property_count_; } void IncElementsCount() { ++element_count_; } + explicit ObjectDescriptor(int property_slack) + : property_slack_(property_slack) {} + bool HasDictionaryProperties() const { - return computed_count_ > 0 || property_count_ > kMaxNumberOfDescriptors; + return computed_count_ > 0 || + (property_count_ + property_slack_) > kMaxNumberOfDescriptors; } Handle<Object> properties_template() const { @@ -324,17 +278,17 @@ class ObjectDescriptor { return computed_properties_; } - void CreateTemplates(Isolate* isolate, int slack) { + void CreateTemplates(Isolate* isolate) { Factory* factory = isolate->factory(); descriptor_array_template_ = factory->empty_descriptor_array(); properties_dictionary_template_ = factory->empty_property_dictionary(); - if (property_count_ || HasDictionaryProperties() || slack) { + if (property_count_ || computed_count_ || property_slack_) { if (HasDictionaryProperties()) { properties_dictionary_template_ = NameDictionary::New( - isolate, property_count_ + computed_count_ + slack); + isolate, property_count_ + computed_count_ + property_slack_); } else { - descriptor_array_template_ = - DescriptorArray::Allocate(isolate, 0, property_count_ + slack); + descriptor_array_template_ = DescriptorArray::Allocate( + isolate, 0, property_count_ + property_slack_); } } elements_dictionary_template_ = @@ -419,6 +373,7 @@ class ObjectDescriptor { } private: + const int property_slack_; int property_count_ = 0; int next_enumeration_index_ = PropertyDetails::kInitialIndex; int element_count_ = 0; @@ -454,8 +409,8 @@ Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate( // in CanonicalHandleScope. HandleScope scope(isolate); Factory* factory = isolate->factory(); - ObjectDescriptor static_desc; - ObjectDescriptor instance_desc; + ObjectDescriptor static_desc(kMinimumClassPropertiesCount); + ObjectDescriptor instance_desc(kMinimumPrototypePropertiesCount); for (int i = 0; i < expr->properties()->length(); i++) { ClassLiteral::Property* property = expr->properties()->at(i); @@ -475,7 +430,7 @@ Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate( // // Initialize class object template. // - static_desc.CreateTemplates(isolate, kMinimumClassPropertiesCount); + static_desc.CreateTemplates(isolate); STATIC_ASSERT(JSFunction::kLengthDescriptorIndex == 0); { // Add length_accessor. @@ -509,7 +464,7 @@ Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate( // // Initialize prototype object template. // - instance_desc.CreateTemplates(isolate, kMinimumPrototypePropertiesCount); + instance_desc.CreateTemplates(isolate); { Handle<Object> value( Smi::FromInt(ClassBoilerplate::kConstructorArgumentIndex), isolate); diff --git a/chromium/v8/src/objects/literal-objects.h b/chromium/v8/src/objects/literal-objects.h index 35ae98a05b6..f009a54f8a9 100644 --- a/chromium/v8/src/objects/literal-objects.h +++ b/chromium/v8/src/objects/literal-objects.h @@ -21,20 +21,23 @@ class ClassLiteral; // of properties in the backing store. This number includes properties with // computed names that are not // in the list. +// TODO(ishell): Don't derive from FixedArray as it already has its own map. class ObjectBoilerplateDescription : public FixedArray { public: - Object name(int index) const; - Object value(int index) const; + inline Object name(int index) const; + inline Object name(Isolate* isolate, int index) const; - void set_key_value(int index, Object key, Object value); + inline Object value(int index) const; + inline Object value(Isolate* isolate, int index) const; + + inline void set_key_value(int index, Object key, Object value); // The number of boilerplate properties. - int size() const; + inline int size() const; // Number of boilerplate properties and properties with computed names. - int backing_store_size() const; - - void set_backing_store_size(Isolate* isolate, int backing_store_size); + inline int backing_store_size() const; + inline void set_backing_store_size(int backing_store_size); // Used to encode ObjectLiteral::Flags for nested object literals // Stored as the first element of the fixed array @@ -47,7 +50,7 @@ class ObjectBoilerplateDescription : public FixedArray { DECL_PRINTER(ObjectBoilerplateDescription) private: - bool has_number_of_properties() const; + inline bool has_number_of_properties() const; OBJECT_CONSTRUCTORS(ObjectBoilerplateDescription, FixedArray); }; diff --git a/chromium/v8/src/objects/lookup-inl.h b/chromium/v8/src/objects/lookup-inl.h index 5b2dbff2582..648398be5ef 100644 --- a/chromium/v8/src/objects/lookup-inl.h +++ b/chromium/v8/src/objects/lookup-inl.h @@ -31,7 +31,7 @@ LookupIterator::LookupIterator(Handle<Object> receiver, Handle<Name> name, LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name, Handle<JSReceiver> holder, Configuration configuration) - : configuration_(ComputeConfiguration(configuration, name)), + : configuration_(ComputeConfiguration(isolate, configuration, name)), interceptor_state_(InterceptorState::kUninitialized), property_details_(PropertyDetails::Empty()), isolate_(isolate), @@ -90,7 +90,7 @@ Handle<Name> LookupIterator::GetName() { } bool LookupIterator::is_dictionary_holder() const { - return !holder_->HasFastProperties(); + return !holder_->HasFastProperties(isolate_); } Handle<Map> LookupIterator::transition_map() const { @@ -111,23 +111,23 @@ Handle<T> LookupIterator::GetHolder() const { bool LookupIterator::ExtendingNonExtensible(Handle<JSReceiver> receiver) { DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>())); - return !receiver->map().is_extensible() && - (IsElement() || !name_->IsPrivate()); + return !receiver->map(isolate_).is_extensible() && + (IsElement() || !name_->IsPrivate(isolate_)); } bool LookupIterator::IsCacheableTransition() { DCHECK_EQ(TRANSITION, state_); - return transition_->IsPropertyCell() || + return transition_->IsPropertyCell(isolate_) || (transition_map()->is_dictionary_map() && - !GetStoreTarget<JSReceiver>()->HasFastProperties()) || - transition_map()->GetBackPointer().IsMap(); + !GetStoreTarget<JSReceiver>()->HasFastProperties(isolate_)) || + transition_map()->GetBackPointer(isolate_).IsMap(isolate_); } void LookupIterator::UpdateProtector() { if (IsElement()) return; // This list must be kept in sync with // CodeStubAssembler::CheckForAssociatedProtector! - ReadOnlyRoots roots(heap()); + ReadOnlyRoots roots(isolate_); if (*name_ == roots.is_concat_spreadable_symbol() || *name_ == roots.constructor_string() || *name_ == roots.next_string() || *name_ == roots.species_symbol() || *name_ == roots.iterator_symbol() || @@ -139,52 +139,59 @@ void LookupIterator::UpdateProtector() { int LookupIterator::descriptor_number() const { DCHECK(!IsElement()); DCHECK(has_property_); - DCHECK(holder_->HasFastProperties()); + DCHECK(holder_->HasFastProperties(isolate_)); return number_; } int LookupIterator::dictionary_entry() const { DCHECK(!IsElement()); DCHECK(has_property_); - DCHECK(!holder_->HasFastProperties()); + DCHECK(!holder_->HasFastProperties(isolate_)); return number_; } +// static LookupIterator::Configuration LookupIterator::ComputeConfiguration( - Configuration configuration, Handle<Name> name) { - return name->IsPrivate() ? OWN_SKIP_INTERCEPTOR : configuration; + Isolate* isolate, Configuration configuration, Handle<Name> name) { + return name->IsPrivate(isolate) ? OWN_SKIP_INTERCEPTOR : configuration; } +// static Handle<JSReceiver> LookupIterator::GetRoot(Isolate* isolate, Handle<Object> receiver, uint32_t index) { - if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver); + if (receiver->IsJSReceiver(isolate)) + return Handle<JSReceiver>::cast(receiver); return GetRootForNonJSReceiver(isolate, receiver, index); } template <class T> Handle<T> LookupIterator::GetStoreTarget() const { - DCHECK(receiver_->IsJSReceiver()); - if (receiver_->IsJSGlobalProxy()) { - Map map = JSGlobalProxy::cast(*receiver_).map(); - if (map.has_hidden_prototype()) { - return handle(JSGlobalObject::cast(map.prototype()), isolate_); + DCHECK(receiver_->IsJSReceiver(isolate_)); + if (receiver_->IsJSGlobalProxy(isolate_)) { + HeapObject prototype = + JSGlobalProxy::cast(*receiver_).map(isolate_).prototype(isolate_); + if (prototype.IsJSGlobalObject(isolate_)) { + return handle(JSGlobalObject::cast(prototype), isolate_); } } return Handle<T>::cast(receiver_); } +// static template <bool is_element> -InterceptorInfo LookupIterator::GetInterceptor(JSObject holder) { - return is_element ? holder.GetIndexedInterceptor() - : holder.GetNamedInterceptor(); +InterceptorInfo LookupIterator::GetInterceptor(Isolate* isolate, + JSObject holder) { + return is_element ? holder.GetIndexedInterceptor(isolate) + : holder.GetNamedInterceptor(isolate); } inline Handle<InterceptorInfo> LookupIterator::GetInterceptor() const { DCHECK_EQ(INTERCEPTOR, state_); - InterceptorInfo result = - IsElement() ? GetInterceptor<true>(JSObject::cast(*holder_)) - : GetInterceptor<false>(JSObject::cast(*holder_)); + JSObject holder = JSObject::cast(*holder_); + InterceptorInfo result = IsElement() + ? GetInterceptor<true>(isolate_, holder) + : GetInterceptor<false>(isolate_, holder); return handle(result, isolate_); } diff --git a/chromium/v8/src/objects/lookup.cc b/chromium/v8/src/objects/lookup.cc index 744cf674823..33130aafe5d 100644 --- a/chromium/v8/src/objects/lookup.cc +++ b/chromium/v8/src/objects/lookup.cc @@ -80,50 +80,6 @@ LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate, return LookupIterator(isolate, receiver, name, configuration); } -// TODO(ishell): Consider removing this way of LookupIterator creation. -// static -LookupIterator LookupIterator::ForTransitionHandler( - Isolate* isolate, Handle<Object> receiver, Handle<Name> name, - Handle<Object> value, MaybeHandle<Map> maybe_transition_map) { - Handle<Map> transition_map; - if (!maybe_transition_map.ToHandle(&transition_map) || - !transition_map->IsPrototypeValidityCellValid()) { - // This map is not a valid transition handler, so full lookup is required. - return LookupIterator(isolate, receiver, name); - } - - PropertyDetails details = PropertyDetails::Empty(); - bool has_property; - if (transition_map->is_dictionary_map()) { - details = PropertyDetails(kData, NONE, PropertyCellType::kNoCell); - has_property = false; - } else { - details = transition_map->GetLastDescriptorDetails(); - has_property = true; - } -#ifdef DEBUG - if (name->IsPrivate()) { - DCHECK_EQ(DONT_ENUM, details.attributes()); - } else { - DCHECK_EQ(NONE, details.attributes()); - } -#endif - LookupIterator it(isolate, receiver, name, transition_map, details, - has_property); - - if (!transition_map->is_dictionary_map()) { - int descriptor_number = transition_map->LastAdded(); - Handle<Map> new_map = - Map::PrepareForDataProperty(isolate, transition_map, descriptor_number, - PropertyConstness::kConst, value); - // Reload information; this is no-op if nothing changed. - it.property_details_ = - new_map->instance_descriptors().GetDetails(descriptor_number); - it.transition_ = new_map; - } - return it; -} - LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name, Handle<Map> transition_map, PropertyDetails details, bool has_property) @@ -151,7 +107,7 @@ void LookupIterator::Start() { holder_ = initial_holder_; JSReceiver holder = *holder_; - Map map = holder.map(); + Map map = holder.map(isolate_); state_ = LookupInHolder<is_element>(map, holder); if (IsFound()) return; @@ -169,7 +125,7 @@ void LookupIterator::Next() { has_property_ = false; JSReceiver holder = *holder_; - Map map = holder.map(); + Map map = holder.map(isolate_); if (map.IsSpecialReceiverMap()) { state_ = IsElement() ? LookupInSpecialHolder<true>(map, holder) @@ -195,7 +151,7 @@ void LookupIterator::NextInternal(Map map, JSReceiver holder) { return; } holder = maybe_holder; - map = holder.map(); + map = holder.map(isolate_); state_ = LookupInHolder<is_element>(map, holder); } while (!IsFound()); @@ -218,17 +174,17 @@ Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver( Isolate* isolate, Handle<Object> receiver, uint32_t index) { // Strings are the only objects with properties (only elements) directly on // the wrapper. Hence we can skip generating the wrapper for all other cases. - if (receiver->IsString() && + if (receiver->IsString(isolate) && index < static_cast<uint32_t>(String::cast(*receiver).length())) { // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native // context, ensuring that we don't leak it into JS? Handle<JSFunction> constructor = isolate->string_function(); Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); - Handle<JSValue>::cast(result)->set_value(*receiver); + Handle<JSPrimitiveWrapper>::cast(result)->set_value(*receiver); return result; } - auto root = - handle(receiver->GetPrototypeChainRootMap(isolate).prototype(), isolate); + auto root = handle( + receiver->GetPrototypeChainRootMap(isolate).prototype(isolate), isolate); if (root->IsNull(isolate)) { isolate->PushStackTraceAndDie(reinterpret_cast<void*>(receiver->ptr())); } @@ -236,8 +192,8 @@ Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver( } Handle<Map> LookupIterator::GetReceiverMap() const { - if (receiver_->IsNumber()) return factory()->heap_number_map(); - return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_); + if (receiver_->IsNumber(isolate_)) return factory()->heap_number_map(); + return handle(Handle<HeapObject>::cast(receiver_)->map(isolate_), isolate_); } bool LookupIterator::HasAccess() const { @@ -250,13 +206,13 @@ template <bool is_element> void LookupIterator::ReloadPropertyInformation() { state_ = BEFORE_PROPERTY; interceptor_state_ = InterceptorState::kUninitialized; - state_ = LookupInHolder<is_element>(holder_->map(), *holder_); - DCHECK(IsFound() || !holder_->HasFastProperties()); + state_ = LookupInHolder<is_element>(holder_->map(isolate_), *holder_); + DCHECK(IsFound() || !holder_->HasFastProperties(isolate_)); } namespace { -bool IsTypedArrayFunctionInAnyContext(Isolate* isolate, JSReceiver holder) { +bool IsTypedArrayFunctionInAnyContext(Isolate* isolate, HeapObject object) { static uint32_t context_slots[] = { #define TYPED_ARRAY_CONTEXT_SLOTS(Type, type, TYPE, ctype) \ Context::TYPE##_ARRAY_FUN_INDEX, @@ -265,91 +221,99 @@ bool IsTypedArrayFunctionInAnyContext(Isolate* isolate, JSReceiver holder) { #undef TYPED_ARRAY_CONTEXT_SLOTS }; - if (!holder.IsJSFunction()) return false; + if (!object.IsJSFunction(isolate)) return false; return std::any_of( std::begin(context_slots), std::end(context_slots), - [=](uint32_t slot) { return isolate->IsInAnyContext(holder, slot); }); + [=](uint32_t slot) { return isolate->IsInAnyContext(object, slot); }); } } // namespace void LookupIterator::InternalUpdateProtector() { if (isolate_->bootstrapper()->IsActive()) return; + if (!receiver_->IsHeapObject()) return; + Handle<HeapObject> receiver = Handle<HeapObject>::cast(receiver_); - ReadOnlyRoots roots(heap()); + Handle<NativeContext> native_context = isolate_->native_context(); + + ReadOnlyRoots roots(isolate_); if (*name_ == roots.constructor_string()) { if (!isolate_->IsArraySpeciesLookupChainIntact() && !isolate_->IsPromiseSpeciesLookupChainIntact() && - !isolate_->IsRegExpSpeciesLookupChainIntact() && + !isolate_->IsRegExpSpeciesLookupChainIntact(native_context) && !isolate_->IsTypedArraySpeciesLookupChainIntact()) { return; } // Setting the constructor property could change an instance's @@species - if (holder_->IsJSArray()) { + if (receiver->IsJSArray(isolate_)) { if (!isolate_->IsArraySpeciesLookupChainIntact()) return; isolate_->CountUsage( v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified); isolate_->InvalidateArraySpeciesProtector(); return; - } else if (holder_->IsJSPromise()) { + } else if (receiver->IsJSPromise(isolate_)) { if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return; isolate_->InvalidatePromiseSpeciesProtector(); return; - } else if (holder_->IsJSRegExp()) { - if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return; - isolate_->InvalidateRegExpSpeciesProtector(); + } else if (receiver->IsJSRegExp(isolate_)) { + if (!isolate_->IsRegExpSpeciesLookupChainIntact(native_context)) return; + isolate_->InvalidateRegExpSpeciesProtector(native_context); return; - } else if (holder_->IsJSTypedArray()) { + } else if (receiver->IsJSTypedArray(isolate_)) { if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return; isolate_->InvalidateTypedArraySpeciesProtector(); return; } - if (holder_->map().is_prototype_map()) { + if (receiver->map(isolate_).is_prototype_map()) { DisallowHeapAllocation no_gc; // Setting the constructor of any prototype with the @@species protector // (of any realm) also needs to invalidate the protector. - // For typed arrays, we check a prototype of this holder since TypedArrays - // have different prototypes for each type, and their parent prototype is - // pointing the same TYPED_ARRAY_PROTOTYPE. - if (isolate_->IsInAnyContext(*holder_, + // For typed arrays, we check a prototype of this receiver since + // TypedArrays have different prototypes for each type, and their parent + // prototype is pointing the same TYPED_ARRAY_PROTOTYPE. + if (isolate_->IsInAnyContext(*receiver, Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) { if (!isolate_->IsArraySpeciesLookupChainIntact()) return; isolate_->CountUsage( v8::Isolate::UseCounterFeature::kArrayPrototypeConstructorModified); isolate_->InvalidateArraySpeciesProtector(); - } else if (isolate_->IsInAnyContext(*holder_, + } else if (isolate_->IsInAnyContext(*receiver, Context::PROMISE_PROTOTYPE_INDEX)) { if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return; isolate_->InvalidatePromiseSpeciesProtector(); - } else if (isolate_->IsInAnyContext(*holder_, + } else if (isolate_->IsInAnyContext(*receiver, Context::REGEXP_PROTOTYPE_INDEX)) { - if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return; - isolate_->InvalidateRegExpSpeciesProtector(); + if (!isolate_->IsRegExpSpeciesLookupChainIntact(native_context)) return; + isolate_->InvalidateRegExpSpeciesProtector(native_context); } else if (isolate_->IsInAnyContext( - holder_->map().prototype(), + receiver->map(isolate_).prototype(isolate_), Context::TYPED_ARRAY_PROTOTYPE_INDEX)) { if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return; isolate_->InvalidateTypedArraySpeciesProtector(); } } } else if (*name_ == roots.next_string()) { - if (isolate_->IsInAnyContext( - *holder_, Context::INITIAL_ARRAY_ITERATOR_PROTOTYPE_INDEX)) { + if (receiver->IsJSArrayIterator() || + isolate_->IsInAnyContext( + *receiver, Context::INITIAL_ARRAY_ITERATOR_PROTOTYPE_INDEX)) { // Setting the next property of %ArrayIteratorPrototype% also needs to // invalidate the array iterator protector. if (!isolate_->IsArrayIteratorLookupChainIntact()) return; isolate_->InvalidateArrayIteratorProtector(); - } else if (isolate_->IsInAnyContext( - *holder_, Context::INITIAL_MAP_ITERATOR_PROTOTYPE_INDEX)) { + } else if (receiver->IsJSMapIterator() || + isolate_->IsInAnyContext( + *receiver, Context::INITIAL_MAP_ITERATOR_PROTOTYPE_INDEX)) { if (!isolate_->IsMapIteratorLookupChainIntact()) return; isolate_->InvalidateMapIteratorProtector(); - } else if (isolate_->IsInAnyContext( - *holder_, Context::INITIAL_SET_ITERATOR_PROTOTYPE_INDEX)) { + } else if (receiver->IsJSSetIterator() || + isolate_->IsInAnyContext( + *receiver, Context::INITIAL_SET_ITERATOR_PROTOTYPE_INDEX)) { if (!isolate_->IsSetIteratorLookupChainIntact()) return; isolate_->InvalidateSetIteratorProtector(); - } else if (isolate_->IsInAnyContext( - *receiver_, + } else if (receiver->IsJSStringIterator() || + isolate_->IsInAnyContext( + *receiver, Context::INITIAL_STRING_ITERATOR_PROTOTYPE_INDEX)) { // Setting the next property of %StringIteratorPrototype% invalidates the // string iterator protector. @@ -359,26 +323,26 @@ void LookupIterator::InternalUpdateProtector() { } else if (*name_ == roots.species_symbol()) { if (!isolate_->IsArraySpeciesLookupChainIntact() && !isolate_->IsPromiseSpeciesLookupChainIntact() && - !isolate_->IsRegExpSpeciesLookupChainIntact() && + !isolate_->IsRegExpSpeciesLookupChainIntact(native_context) && !isolate_->IsTypedArraySpeciesLookupChainIntact()) { return; } // Setting the Symbol.species property of any Array, Promise or TypedArray // constructor invalidates the @@species protector - if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX)) { + if (isolate_->IsInAnyContext(*receiver, Context::ARRAY_FUNCTION_INDEX)) { if (!isolate_->IsArraySpeciesLookupChainIntact()) return; isolate_->CountUsage( v8::Isolate::UseCounterFeature::kArraySpeciesModified); isolate_->InvalidateArraySpeciesProtector(); - } else if (isolate_->IsInAnyContext(*holder_, + } else if (isolate_->IsInAnyContext(*receiver, Context::PROMISE_FUNCTION_INDEX)) { if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return; isolate_->InvalidatePromiseSpeciesProtector(); - } else if (isolate_->IsInAnyContext(*holder_, + } else if (isolate_->IsInAnyContext(*receiver, Context::REGEXP_FUNCTION_INDEX)) { - if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return; - isolate_->InvalidateRegExpSpeciesProtector(); - } else if (IsTypedArrayFunctionInAnyContext(isolate_, *holder_)) { + if (!isolate_->IsRegExpSpeciesLookupChainIntact(native_context)) return; + isolate_->InvalidateRegExpSpeciesProtector(native_context); + } else if (IsTypedArrayFunctionInAnyContext(isolate_, *receiver)) { if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return; isolate_->InvalidateTypedArraySpeciesProtector(); } @@ -386,23 +350,33 @@ void LookupIterator::InternalUpdateProtector() { if (!isolate_->IsIsConcatSpreadableLookupChainIntact()) return; isolate_->InvalidateIsConcatSpreadableProtector(); } else if (*name_ == roots.iterator_symbol()) { - if (holder_->IsJSArray()) { + if (receiver->IsJSArray(isolate_)) { if (!isolate_->IsArrayIteratorLookupChainIntact()) return; isolate_->InvalidateArrayIteratorProtector(); + } else if (receiver->IsJSSet(isolate_) || receiver->IsJSSetIterator() || + isolate_->IsInAnyContext( + *receiver, Context::INITIAL_SET_ITERATOR_PROTOTYPE_INDEX) || + isolate_->IsInAnyContext(*receiver, + Context::INITIAL_SET_PROTOTYPE_INDEX)) { + if (isolate_->IsSetIteratorLookupChainIntact()) { + isolate_->InvalidateSetIteratorProtector(); + } + } else if (receiver->IsJSMapIterator() || + isolate_->IsInAnyContext( + *receiver, Context::INITIAL_MAP_ITERATOR_PROTOTYPE_INDEX)) { + if (isolate_->IsMapIteratorLookupChainIntact()) { + isolate_->InvalidateMapIteratorProtector(); + } } else if (isolate_->IsInAnyContext( - *holder_, Context::INITIAL_ITERATOR_PROTOTYPE_INDEX)) { + *receiver, Context::INITIAL_ITERATOR_PROTOTYPE_INDEX)) { if (isolate_->IsMapIteratorLookupChainIntact()) { isolate_->InvalidateMapIteratorProtector(); } if (isolate_->IsSetIteratorLookupChainIntact()) { isolate_->InvalidateSetIteratorProtector(); } - } else if (isolate_->IsInAnyContext(*holder_, - Context::INITIAL_SET_PROTOTYPE_INDEX)) { - if (!isolate_->IsSetIteratorLookupChainIntact()) return; - isolate_->InvalidateSetIteratorProtector(); } else if (isolate_->IsInAnyContext( - *receiver_, Context::INITIAL_STRING_PROTOTYPE_INDEX)) { + *receiver, Context::INITIAL_STRING_PROTOTYPE_INDEX)) { // Setting the Symbol.iterator property of String.prototype invalidates // the string iterator protector. Symbol.iterator can also be set on a // String wrapper, but not on a primitive string. We only support @@ -414,7 +388,7 @@ void LookupIterator::InternalUpdateProtector() { if (!isolate_->IsPromiseResolveLookupChainIntact()) return; // Setting the "resolve" property on any %Promise% intrinsic object // invalidates the Promise.resolve protector. - if (isolate_->IsInAnyContext(*holder_, Context::PROMISE_FUNCTION_INDEX)) { + if (isolate_->IsInAnyContext(*receiver, Context::PROMISE_FUNCTION_INDEX)) { isolate_->InvalidatePromiseResolveProtector(); } } else if (*name_ == roots.then_string()) { @@ -426,10 +400,10 @@ void LookupIterator::InternalUpdateProtector() { // to guard the fast-path in AsyncGeneratorResolve, where we can skip // the ResolvePromise step and go directly to FulfillPromise if we // know that the Object.prototype doesn't contain a "then" method. - if (holder_->IsJSPromise() || - isolate_->IsInAnyContext(*holder_, + if (receiver->IsJSPromise(isolate_) || + isolate_->IsInAnyContext(*receiver, Context::INITIAL_OBJECT_PROTOTYPE_INDEX) || - isolate_->IsInAnyContext(*holder_, Context::PROMISE_PROTOTYPE_INDEX)) { + isolate_->IsInAnyContext(*receiver, Context::PROMISE_PROTOTYPE_INDEX)) { isolate_->InvalidatePromiseThenProtector(); } } @@ -441,15 +415,16 @@ void LookupIterator::PrepareForDataProperty(Handle<Object> value) { Handle<JSReceiver> holder = GetHolder<JSReceiver>(); // JSProxy does not have fast properties so we do an early return. - DCHECK_IMPLIES(holder->IsJSProxy(), !holder->HasFastProperties()); - DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate()); - if (holder->IsJSProxy()) return; + DCHECK_IMPLIES(holder->IsJSProxy(isolate_), + !holder->HasFastProperties(isolate_)); + DCHECK_IMPLIES(holder->IsJSProxy(isolate_), name()->IsPrivate(isolate_)); + if (holder->IsJSProxy(isolate_)) return; Handle<JSObject> holder_obj = Handle<JSObject>::cast(holder); if (IsElement()) { - ElementsKind kind = holder_obj->GetElementsKind(); - ElementsKind to = value->OptimalElementsKind(); + ElementsKind kind = holder_obj->GetElementsKind(isolate_); + ElementsKind to = value->OptimalElementsKind(isolate_); if (IsHoleyElementsKind(kind)) to = GetHoleyElementsKind(to); to = GetMoreGeneralElementsKind(kind, to); @@ -464,17 +439,18 @@ void LookupIterator::PrepareForDataProperty(Handle<Object> value) { return; } - if (holder_obj->IsJSGlobalObject()) { + if (holder_obj->IsJSGlobalObject(isolate_)) { Handle<GlobalDictionary> dictionary( - JSGlobalObject::cast(*holder_obj).global_dictionary(), isolate()); - Handle<PropertyCell> cell(dictionary->CellAt(dictionary_entry()), + JSGlobalObject::cast(*holder_obj).global_dictionary(isolate_), + isolate()); + Handle<PropertyCell> cell(dictionary->CellAt(isolate_, dictionary_entry()), isolate()); property_details_ = cell->property_details(); PropertyCell::PrepareForValue(isolate(), dictionary, dictionary_entry(), value, property_details_); return; } - if (!holder_obj->HasFastProperties()) return; + if (!holder_obj->HasFastProperties(isolate_)) return; PropertyConstness new_constness = PropertyConstness::kConst; if (constness() == PropertyConstness::kConst) { @@ -485,20 +461,28 @@ void LookupIterator::PrepareForDataProperty(Handle<Object> value) { new_constness = PropertyConstness::kMutable; } - Handle<Map> old_map(holder_obj->map(), isolate_); - Handle<Map> new_map = Map::PrepareForDataProperty( - isolate(), old_map, descriptor_number(), new_constness, value); + Handle<Map> old_map(holder_obj->map(isolate_), isolate_); + DCHECK(!old_map->is_dictionary_map()); - if (old_map.is_identical_to(new_map)) { - // Update the property details if the representation was None. - if (constness() != new_constness || representation().IsNone()) { - property_details_ = - new_map->instance_descriptors().GetDetails(descriptor_number()); + Handle<Map> new_map = Map::Update(isolate_, old_map); + if (!new_map->is_dictionary_map()) { + new_map = Map::PrepareForDataProperty( + isolate(), new_map, descriptor_number(), new_constness, value); + + if (old_map.is_identical_to(new_map)) { + // Update the property details if the representation was None. + if (constness() != new_constness || representation().IsNone()) { + property_details_ = new_map->instance_descriptors(isolate_).GetDetails( + descriptor_number()); + } + return; } - return; } + // We should only get here if the new_map is different from the old map, + // otherwise we would have falled through to the is_identical_to check above. + DCHECK_NE(*old_map, *new_map); - JSObject::MigrateToMap(holder_obj, new_map); + JSObject::MigrateToMap(isolate_, holder_obj, new_map); ReloadPropertyInformation<false>(); } @@ -510,53 +494,59 @@ void LookupIterator::ReconfigureDataProperty(Handle<Object> value, Handle<JSReceiver> holder = GetHolder<JSReceiver>(); // Property details can never change for private properties. - if (holder->IsJSProxy()) { - DCHECK(name()->IsPrivate()); + if (holder->IsJSProxy(isolate_)) { + DCHECK(name()->IsPrivate(isolate_)); return; } Handle<JSObject> holder_obj = Handle<JSObject>::cast(holder); if (IsElement()) { - DCHECK(!holder_obj->HasTypedArrayElements()); - DCHECK(attributes != NONE || !holder_obj->HasFastElements()); - Handle<FixedArrayBase> elements(holder_obj->elements(), isolate()); - holder_obj->GetElementsAccessor()->Reconfigure(holder_obj, elements, - number_, value, attributes); + DCHECK(!holder_obj->HasTypedArrayElements(isolate_)); + DCHECK(attributes != NONE || !holder_obj->HasFastElements(isolate_)); + Handle<FixedArrayBase> elements(holder_obj->elements(isolate_), isolate()); + holder_obj->GetElementsAccessor(isolate_)->Reconfigure( + holder_obj, elements, number_, value, attributes); ReloadPropertyInformation<true>(); - } else if (holder_obj->HasFastProperties()) { - Handle<Map> old_map(holder_obj->map(), isolate_); - Handle<Map> new_map = Map::ReconfigureExistingProperty( - isolate_, old_map, descriptor_number(), i::kData, attributes); + } else if (holder_obj->HasFastProperties(isolate_)) { + Handle<Map> old_map(holder_obj->map(isolate_), isolate_); // Force mutable to avoid changing constant value by reconfiguring // kData -> kAccessor -> kData. - new_map = - Map::PrepareForDataProperty(isolate(), new_map, descriptor_number(), - PropertyConstness::kMutable, value); - JSObject::MigrateToMap(holder_obj, new_map); + Handle<Map> new_map = Map::ReconfigureExistingProperty( + isolate_, old_map, descriptor_number(), i::kData, attributes, + PropertyConstness::kMutable); + if (!new_map->is_dictionary_map()) { + // Make sure that the data property has a compatible representation. + // TODO(leszeks): Do this as part of ReconfigureExistingProperty. + new_map = + Map::PrepareForDataProperty(isolate(), new_map, descriptor_number(), + PropertyConstness::kMutable, value); + } + JSObject::MigrateToMap(isolate_, holder_obj, new_map); ReloadPropertyInformation<false>(); } - if (!IsElement() && !holder_obj->HasFastProperties()) { + if (!IsElement() && !holder_obj->HasFastProperties(isolate_)) { PropertyDetails details(kData, attributes, PropertyCellType::kMutable); - if (holder_obj->map().is_prototype_map() && + if (holder_obj->map(isolate_).is_prototype_map() && (property_details_.attributes() & READ_ONLY) == 0 && (attributes & READ_ONLY) != 0) { // Invalidate prototype validity cell when a property is reconfigured // from writable to read-only as this may invalidate transitioning store // IC handlers. - JSObject::InvalidatePrototypeChains(holder->map()); + JSObject::InvalidatePrototypeChains(holder->map(isolate_)); } - if (holder_obj->IsJSGlobalObject()) { + if (holder_obj->IsJSGlobalObject(isolate_)) { Handle<GlobalDictionary> dictionary( - JSGlobalObject::cast(*holder_obj).global_dictionary(), isolate()); + JSGlobalObject::cast(*holder_obj).global_dictionary(isolate_), + isolate()); Handle<PropertyCell> cell = PropertyCell::PrepareForValue( isolate(), dictionary, dictionary_entry(), value, details); cell->set_value(*value); property_details_ = cell->property_details(); } else { - Handle<NameDictionary> dictionary(holder_obj->property_dictionary(), - isolate()); + Handle<NameDictionary> dictionary( + holder_obj->property_dictionary(isolate_), isolate()); PropertyDetails original_details = dictionary->DetailsAt(dictionary_entry()); int enumeration_index = original_details.dictionary_index(); @@ -583,21 +573,21 @@ void LookupIterator::ReconfigureDataProperty(Handle<Object> value, void LookupIterator::PrepareTransitionToDataProperty( Handle<JSReceiver> receiver, Handle<Object> value, PropertyAttributes attributes, StoreOrigin store_origin) { - DCHECK_IMPLIES(receiver->IsJSProxy(), name()->IsPrivate()); + DCHECK_IMPLIES(receiver->IsJSProxy(isolate_), name()->IsPrivate(isolate_)); DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>())); if (state_ == TRANSITION) return; - if (!IsElement() && name()->IsPrivate()) { + if (!IsElement() && name()->IsPrivate(isolate_)) { attributes = static_cast<PropertyAttributes>(attributes | DONT_ENUM); } DCHECK(state_ != LookupIterator::ACCESSOR || - (GetAccessors()->IsAccessorInfo() && + (GetAccessors()->IsAccessorInfo(isolate_) && AccessorInfo::cast(*GetAccessors()).is_special_data_property())); DCHECK_NE(INTEGER_INDEXED_EXOTIC, state_); DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype()); - Handle<Map> map(receiver->map(), isolate_); + Handle<Map> map(receiver->map(isolate_), isolate_); // Dictionary maps can always have additional data properties. if (map->is_dictionary_map()) { @@ -608,9 +598,9 @@ void LookupIterator::PrepareTransitionToDataProperty( int entry; Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell( global, name(), PropertyCellType::kUninitialized, &entry); - Handle<GlobalDictionary> dictionary(global->global_dictionary(), + Handle<GlobalDictionary> dictionary(global->global_dictionary(isolate_), isolate_); - DCHECK(cell->value().IsTheHole(isolate_)); + DCHECK(cell->value(isolate_).IsTheHole(isolate_)); DCHECK(!value->IsTheHole(isolate_)); transition_ = cell; // Assign an enumeration index to the property and update @@ -645,7 +635,7 @@ void LookupIterator::PrepareTransitionToDataProperty( property_details_ = PropertyDetails(kData, attributes, PropertyCellType::kNoCell); } else { - property_details_ = transition->GetLastDescriptorDetails(); + property_details_ = transition->GetLastDescriptorDetails(isolate_); has_property_ = true; } } @@ -656,13 +646,14 @@ void LookupIterator::ApplyTransitionToDataProperty( DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>())); holder_ = receiver; - if (receiver->IsJSGlobalObject()) { - JSObject::InvalidatePrototypeChains(receiver->map()); + if (receiver->IsJSGlobalObject(isolate_)) { + JSObject::InvalidatePrototypeChains(receiver->map(isolate_)); state_ = DATA; return; } Handle<Map> transition = transition_map(); - bool simple_transition = transition->GetBackPointer() == receiver->map(); + bool simple_transition = + transition->GetBackPointer(isolate_) == receiver->map(isolate_); if (configuration_ == DEFAULT && !transition->is_dictionary_map() && !transition->IsPrototypeValidityCellValid()) { @@ -673,21 +664,23 @@ void LookupIterator::ApplyTransitionToDataProperty( transition->set_prototype_validity_cell(*validity_cell); } - if (!receiver->IsJSProxy()) { - JSObject::MigrateToMap(Handle<JSObject>::cast(receiver), transition); + if (!receiver->IsJSProxy(isolate_)) { + JSObject::MigrateToMap(isolate_, Handle<JSObject>::cast(receiver), + transition); } if (simple_transition) { int number = transition->LastAdded(); number_ = static_cast<uint32_t>(number); - property_details_ = transition->GetLastDescriptorDetails(); + property_details_ = transition->GetLastDescriptorDetails(isolate_); state_ = DATA; - } else if (receiver->map().is_dictionary_map()) { - Handle<NameDictionary> dictionary(receiver->property_dictionary(), + } else if (receiver->map(isolate_).is_dictionary_map()) { + Handle<NameDictionary> dictionary(receiver->property_dictionary(isolate_), isolate_); int entry; - if (receiver->map().is_prototype_map() && receiver->IsJSObject()) { - JSObject::InvalidatePrototypeChains(receiver->map()); + if (receiver->map(isolate_).is_prototype_map() && + receiver->IsJSObject(isolate_)) { + JSObject::InvalidatePrototypeChains(receiver->map(isolate_)); } dictionary = NameDictionary::Add(isolate(), dictionary, name(), isolate_->factory()->uninitialized_value(), @@ -708,11 +701,11 @@ void LookupIterator::Delete() { Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_); if (IsElement()) { Handle<JSObject> object = Handle<JSObject>::cast(holder); - ElementsAccessor* accessor = object->GetElementsAccessor(); + ElementsAccessor* accessor = object->GetElementsAccessor(isolate_); accessor->Delete(object, number_); } else { - DCHECK(!name()->IsPrivateName()); - bool is_prototype_map = holder->map().is_prototype_map(); + DCHECK(!name()->IsPrivateName(isolate_)); + bool is_prototype_map = holder->map(isolate_).is_prototype_map(); RuntimeCallTimerScope stats_scope( isolate_, is_prototype_map ? RuntimeCallCounterId::kPrototypeObject_DeleteProperty @@ -721,13 +714,13 @@ void LookupIterator::Delete() { PropertyNormalizationMode mode = is_prototype_map ? KEEP_INOBJECT_PROPERTIES : CLEAR_INOBJECT_PROPERTIES; - if (holder->HasFastProperties()) { - JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0, - "DeletingProperty"); + if (holder->HasFastProperties(isolate_)) { + JSObject::NormalizeProperties(isolate_, Handle<JSObject>::cast(holder), + mode, 0, "DeletingProperty"); ReloadPropertyInformation<false>(); } JSReceiver::DeleteNormalizedProperty(holder, number_); - if (holder->IsJSObject()) { + if (holder->IsJSObject(isolate_)) { JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder)); } } @@ -742,12 +735,12 @@ void LookupIterator::TransitionToAccessorProperty( // handled via a trap. Adding properties to primitive values is not // observable. Handle<JSObject> receiver = GetStoreTarget<JSObject>(); - if (!IsElement() && name()->IsPrivate()) { + if (!IsElement() && name()->IsPrivate(isolate_)) { attributes = static_cast<PropertyAttributes>(attributes | DONT_ENUM); } - if (!IsElement() && !receiver->map().is_dictionary_map()) { - Handle<Map> old_map(receiver->map(), isolate_); + if (!IsElement() && !receiver->map(isolate_).is_dictionary_map()) { + Handle<Map> old_map(receiver->map(isolate_), isolate_); if (!holder_.is_identical_to(receiver)) { holder_ = receiver; @@ -760,13 +753,14 @@ void LookupIterator::TransitionToAccessorProperty( Handle<Map> new_map = Map::TransitionToAccessorProperty( isolate_, old_map, name_, descriptor, getter, setter, attributes); - bool simple_transition = new_map->GetBackPointer() == receiver->map(); - JSObject::MigrateToMap(receiver, new_map); + bool simple_transition = + new_map->GetBackPointer(isolate_) == receiver->map(isolate_); + JSObject::MigrateToMap(isolate_, receiver, new_map); if (simple_transition) { int number = new_map->LastAdded(); number_ = static_cast<uint32_t>(number); - property_details_ = new_map->GetLastDescriptorDetails(); + property_details_ = new_map->GetLastDescriptorDetails(isolate_); state_ = ACCESSOR; return; } @@ -776,7 +770,7 @@ void LookupIterator::TransitionToAccessorProperty( } Handle<AccessorPair> pair; - if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) { + if (state() == ACCESSOR && GetAccessors()->IsAccessorPair(isolate_)) { pair = Handle<AccessorPair>::cast(GetAccessors()); // If the component and attributes are identical, nothing has to be done. if (pair->Equals(*getter, *setter)) { @@ -818,13 +812,14 @@ void LookupIterator::TransitionToAccessorPair(Handle<Object> pair, receiver, details); receiver->RequireSlowElements(*dictionary); - if (receiver->HasSlowArgumentsElements()) { - FixedArray parameter_map = FixedArray::cast(receiver->elements()); + if (receiver->HasSlowArgumentsElements(isolate_)) { + FixedArray parameter_map = FixedArray::cast(receiver->elements(isolate_)); uint32_t length = parameter_map.length() - 2; if (number_ < length) { - parameter_map.set(number_ + 2, ReadOnlyRoots(heap()).the_hole_value()); + parameter_map.set(number_ + 2, + ReadOnlyRoots(isolate_).the_hole_value()); } - FixedArray::cast(receiver->elements()).set(1, *dictionary); + FixedArray::cast(receiver->elements(isolate_)).set(1, *dictionary); } else { receiver->set_elements(*dictionary); } @@ -832,13 +827,13 @@ void LookupIterator::TransitionToAccessorPair(Handle<Object> pair, ReloadPropertyInformation<true>(); } else { PropertyNormalizationMode mode = CLEAR_INOBJECT_PROPERTIES; - if (receiver->map().is_prototype_map()) { - JSObject::InvalidatePrototypeChains(receiver->map()); + if (receiver->map(isolate_).is_prototype_map()) { + JSObject::InvalidatePrototypeChains(receiver->map(isolate_)); mode = KEEP_INOBJECT_PROPERTIES; } // Normalize object to make this operation simple. - JSObject::NormalizeProperties(receiver, mode, 0, + JSObject::NormalizeProperties(isolate_, receiver, mode, 0, "TransitionToAccessorPair"); JSObject::SetNormalizedProperty(receiver, name_, pair, details); @@ -859,61 +854,54 @@ bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY); // Optimization that only works if configuration_ is not mutable. if (!check_prototype_chain()) return true; - DisallowHeapAllocation no_gc; if (*receiver_ == *holder_) return true; - if (!receiver_->IsJSReceiver()) return false; - JSReceiver current = JSReceiver::cast(*receiver_); - JSReceiver object = *holder_; - if (!current.map().has_hidden_prototype()) return false; - // JSProxy do not occur as hidden prototypes. - if (object.IsJSProxy()) return false; - PrototypeIterator iter(isolate(), current, kStartAtPrototype, - PrototypeIterator::END_AT_NON_HIDDEN); - while (!iter.IsAtEnd()) { - if (iter.GetCurrent<JSReceiver>() == object) return true; - iter.Advance(); - } - return false; + if (!receiver_->IsJSGlobalProxy(isolate_)) return false; + return Handle<JSGlobalProxy>::cast(receiver_)->map(isolate_).prototype( + isolate_) == *holder_; } Handle<Object> LookupIterator::FetchValue() const { Object result; if (IsElement()) { Handle<JSObject> holder = GetHolder<JSObject>(); - ElementsAccessor* accessor = holder->GetElementsAccessor(); + ElementsAccessor* accessor = holder->GetElementsAccessor(isolate_); return accessor->Get(holder, number_); - } else if (holder_->IsJSGlobalObject()) { + } else if (holder_->IsJSGlobalObject(isolate_)) { Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>(); - result = holder->global_dictionary().ValueAt(number_); - } else if (!holder_->HasFastProperties()) { - result = holder_->property_dictionary().ValueAt(number_); + result = holder->global_dictionary(isolate_).ValueAt(isolate_, number_); + } else if (!holder_->HasFastProperties(isolate_)) { + result = holder_->property_dictionary(isolate_).ValueAt(isolate_, number_); } else if (property_details_.location() == kField) { DCHECK_EQ(kData, property_details_.kind()); Handle<JSObject> holder = GetHolder<JSObject>(); - FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_); + FieldIndex field_index = + FieldIndex::ForDescriptor(holder->map(isolate_), number_); return JSObject::FastPropertyAt(holder, property_details_.representation(), field_index); } else { - result = holder_->map().instance_descriptors().GetStrongValue(number_); + result = + holder_->map(isolate_).instance_descriptors(isolate_).GetStrongValue( + isolate_, number_); } return handle(result, isolate_); } bool LookupIterator::IsConstFieldValueEqualTo(Object value) const { DCHECK(!IsElement()); - DCHECK(holder_->HasFastProperties()); + DCHECK(holder_->HasFastProperties(isolate_)); DCHECK_EQ(kField, property_details_.location()); DCHECK_EQ(PropertyConstness::kConst, property_details_.constness()); Handle<JSObject> holder = GetHolder<JSObject>(); - FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_); + FieldIndex field_index = + FieldIndex::ForDescriptor(holder->map(isolate_), number_); if (property_details_.representation().IsDouble()) { - if (!value.IsNumber()) return false; + if (!value.IsNumber(isolate_)) return false; uint64_t bits; - if (holder->IsUnboxedDoubleField(field_index)) { + if (holder->IsUnboxedDoubleField(isolate_, field_index)) { bits = holder->RawFastDoublePropertyAsBitsAt(field_index); } else { - Object current_value = holder->RawFastPropertyAt(field_index); - DCHECK(current_value.IsMutableHeapNumber()); + Object current_value = holder->RawFastPropertyAt(isolate_, field_index); + DCHECK(current_value.IsMutableHeapNumber(isolate_)); bits = MutableHeapNumber::cast(current_value).value_as_bits(); } // Use bit representation of double to to check for hole double, since @@ -927,11 +915,11 @@ bool LookupIterator::IsConstFieldValueEqualTo(Object value) const { } return Object::SameNumberValue(bit_cast<double>(bits), value.Number()); } else { - Object current_value = holder->RawFastPropertyAt(field_index); + Object current_value = holder->RawFastPropertyAt(isolate_, field_index); if (current_value.IsUninitialized(isolate()) || current_value == value) { return true; } - return current_value.IsNumber() && value.IsNumber() && + return current_value.IsNumber(isolate_) && value.IsNumber(isolate_) && Object::SameNumberValue(current_value.Number(), value.Number()); } } @@ -946,7 +934,7 @@ int LookupIterator::GetFieldDescriptorIndex() const { int LookupIterator::GetAccessorIndex() const { DCHECK(has_property_); - DCHECK(holder_->HasFastProperties()); + DCHECK(holder_->HasFastProperties(isolate_)); DCHECK_EQ(kDescriptor, property_details_.location()); DCHECK_EQ(kAccessor, property_details_.kind()); return descriptor_number(); @@ -954,36 +942,38 @@ int LookupIterator::GetAccessorIndex() const { Handle<Map> LookupIterator::GetFieldOwnerMap() const { DCHECK(has_property_); - DCHECK(holder_->HasFastProperties()); + DCHECK(holder_->HasFastProperties(isolate_)); DCHECK_EQ(kField, property_details_.location()); DCHECK(!IsElement()); - Map holder_map = holder_->map(); + Map holder_map = holder_->map(isolate_); return handle(holder_map.FindFieldOwner(isolate(), descriptor_number()), isolate_); } FieldIndex LookupIterator::GetFieldIndex() const { DCHECK(has_property_); - DCHECK(holder_->HasFastProperties()); + DCHECK(holder_->HasFastProperties(isolate_)); DCHECK_EQ(kField, property_details_.location()); DCHECK(!IsElement()); - return FieldIndex::ForDescriptor(holder_->map(), descriptor_number()); + return FieldIndex::ForDescriptor(holder_->map(isolate_), descriptor_number()); } Handle<FieldType> LookupIterator::GetFieldType() const { DCHECK(has_property_); - DCHECK(holder_->HasFastProperties()); + DCHECK(holder_->HasFastProperties(isolate_)); DCHECK_EQ(kField, property_details_.location()); return handle( - holder_->map().instance_descriptors().GetFieldType(descriptor_number()), + holder_->map(isolate_).instance_descriptors(isolate_).GetFieldType( + isolate_, descriptor_number()), isolate_); } Handle<PropertyCell> LookupIterator::GetPropertyCell() const { DCHECK(!IsElement()); Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>(); - return handle(holder->global_dictionary().CellAt(dictionary_entry()), - isolate_); + return handle( + holder->global_dictionary(isolate_).CellAt(isolate_, dictionary_entry()), + isolate_); } Handle<Object> LookupIterator::GetAccessors() const { @@ -1003,9 +993,9 @@ void LookupIterator::WriteDataValue(Handle<Object> value, Handle<JSReceiver> holder = GetHolder<JSReceiver>(); if (IsElement()) { Handle<JSObject> object = Handle<JSObject>::cast(holder); - ElementsAccessor* accessor = object->GetElementsAccessor(); + ElementsAccessor* accessor = object->GetElementsAccessor(isolate_); accessor->Set(object, number_, *value); - } else if (holder->HasFastProperties()) { + } else if (holder->HasFastProperties(isolate_)) { if (property_details_.location() == kField) { // Check that in case of VariableMode::kConst field the existing value is // equal to |value|. @@ -1018,21 +1008,22 @@ void LookupIterator::WriteDataValue(Handle<Object> value, DCHECK_EQ(kDescriptor, property_details_.location()); DCHECK_EQ(PropertyConstness::kConst, property_details_.constness()); } - } else if (holder->IsJSGlobalObject()) { + } else if (holder->IsJSGlobalObject(isolate_)) { GlobalDictionary dictionary = - JSGlobalObject::cast(*holder).global_dictionary(); - dictionary.CellAt(dictionary_entry()).set_value(*value); + JSGlobalObject::cast(*holder).global_dictionary(isolate_); + dictionary.CellAt(isolate_, dictionary_entry()).set_value(*value); } else { - DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate()); - NameDictionary dictionary = holder->property_dictionary(); + DCHECK_IMPLIES(holder->IsJSProxy(isolate_), name()->IsPrivate(isolate_)); + NameDictionary dictionary = holder->property_dictionary(isolate_); dictionary.ValueAtPut(dictionary_entry(), *value); } } template <bool is_element> bool LookupIterator::SkipInterceptor(JSObject holder) { - auto info = GetInterceptor<is_element>(holder); - if (!is_element && name_->IsSymbol() && !info.can_intercept_symbols()) { + InterceptorInfo info = GetInterceptor<is_element>(isolate_, holder); + if (!is_element && name_->IsSymbol(isolate_) && + !info.can_intercept_symbols()) { return true; } if (info.non_masking()) { @@ -1051,18 +1042,19 @@ bool LookupIterator::SkipInterceptor(JSObject holder) { JSReceiver LookupIterator::NextHolder(Map map) { DisallowHeapAllocation no_gc; - if (map.prototype() == ReadOnlyRoots(heap()).null_value()) { + if (map.prototype(isolate_) == ReadOnlyRoots(isolate_).null_value()) { return JSReceiver(); } - if (!check_prototype_chain() && !map.has_hidden_prototype()) { + if (!check_prototype_chain() && !map.IsJSGlobalProxyMap()) { return JSReceiver(); } - return JSReceiver::cast(map.prototype()); + return JSReceiver::cast(map.prototype(isolate_)); } LookupIterator::State LookupIterator::NotFound(JSReceiver const holder) const { DCHECK(!IsElement()); - if (!holder.IsJSTypedArray() || !name_->IsString()) return NOT_FOUND; + if (!holder.IsJSTypedArray(isolate_) || !name_->IsString(isolate_)) + return NOT_FOUND; return IsSpecialIndex(String::cast(*name_)) ? INTEGER_INDEXED_EXOTIC : NOT_FOUND; } @@ -1084,27 +1076,27 @@ LookupIterator::State LookupIterator::LookupInSpecialHolder( switch (state_) { case NOT_FOUND: if (map.IsJSProxyMap()) { - if (is_element || !name_->IsPrivate()) return JSPROXY; + if (is_element || !name_->IsPrivate(isolate_)) return JSPROXY; } if (map.is_access_check_needed()) { - if (is_element || !name_->IsPrivate()) return ACCESS_CHECK; + if (is_element || !name_->IsPrivate(isolate_)) return ACCESS_CHECK; } V8_FALLTHROUGH; case ACCESS_CHECK: if (check_interceptor() && HasInterceptor<is_element>(map) && !SkipInterceptor<is_element>(JSObject::cast(holder))) { - if (is_element || !name_->IsPrivate()) return INTERCEPTOR; + if (is_element || !name_->IsPrivate(isolate_)) return INTERCEPTOR; } V8_FALLTHROUGH; case INTERCEPTOR: if (!is_element && map.IsJSGlobalObjectMap()) { GlobalDictionary dict = - JSGlobalObject::cast(holder).global_dictionary(); + JSGlobalObject::cast(holder).global_dictionary(isolate_); int number = dict.FindEntry(isolate(), name_); if (number == GlobalDictionary::kNotFound) return NOT_FOUND; number_ = static_cast<uint32_t>(number); - PropertyCell cell = dict.CellAt(number_); - if (cell.value().IsTheHole(isolate_)) return NOT_FOUND; + PropertyCell cell = dict.CellAt(isolate_, number_); + if (cell.value(isolate_).IsTheHole(isolate_)) return NOT_FOUND; property_details_ = cell.property_details(); has_property_ = true; switch (property_details_.kind()) { @@ -1136,12 +1128,13 @@ LookupIterator::State LookupIterator::LookupInRegularHolder( if (is_element) { JSObject js_object = JSObject::cast(holder); - ElementsAccessor* accessor = js_object.GetElementsAccessor(); - FixedArrayBase backing_store = js_object.elements(); + ElementsAccessor* accessor = js_object.GetElementsAccessor(isolate_); + FixedArrayBase backing_store = js_object.elements(isolate_); number_ = accessor->GetEntryForIndex(isolate_, js_object, backing_store, index_); if (number_ == kMaxUInt32) { - return holder.IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND; + return holder.IsJSTypedArray(isolate_) ? INTEGER_INDEXED_EXOTIC + : NOT_FOUND; } property_details_ = accessor->GetDetails(js_object, number_); if (map.has_frozen_or_sealed_elements()) { @@ -1149,14 +1142,14 @@ LookupIterator::State LookupIterator::LookupInRegularHolder( property_details_ = property_details_.CopyAddAttributes(attrs); } } else if (!map.is_dictionary_map()) { - DescriptorArray descriptors = map.instance_descriptors(); + DescriptorArray descriptors = map.instance_descriptors(isolate_); int number = descriptors.SearchWithCache(isolate_, *name_, map); if (number == DescriptorArray::kNotFound) return NotFound(holder); number_ = static_cast<uint32_t>(number); property_details_ = descriptors.GetDetails(number_); } else { - DCHECK_IMPLIES(holder.IsJSProxy(), name()->IsPrivate()); - NameDictionary dict = holder.property_dictionary(); + DCHECK_IMPLIES(holder.IsJSProxy(isolate_), name()->IsPrivate(isolate_)); + NameDictionary dict = holder.property_dictionary(isolate_); int number = dict.FindEntry(isolate(), name_); if (number == NameDictionary::kNotFound) return NotFound(holder); number_ = static_cast<uint32_t>(number); @@ -1191,15 +1184,15 @@ Handle<InterceptorInfo> LookupIterator::GetInterceptorForFailedAccessCheck() bool LookupIterator::TryLookupCachedProperty() { return state() == LookupIterator::ACCESSOR && - GetAccessors()->IsAccessorPair() && LookupCachedProperty(); + GetAccessors()->IsAccessorPair(isolate_) && LookupCachedProperty(); } bool LookupIterator::LookupCachedProperty() { DCHECK_EQ(state(), LookupIterator::ACCESSOR); - DCHECK(GetAccessors()->IsAccessorPair()); + DCHECK(GetAccessors()->IsAccessorPair(isolate_)); AccessorPair accessor_pair = AccessorPair::cast(*GetAccessors()); - Handle<Object> getter(accessor_pair.getter(), isolate()); + Handle<Object> getter(accessor_pair.getter(isolate_), isolate()); MaybeHandle<Name> maybe_name = FunctionTemplateInfo::TryGetCachedPropertyName(isolate(), getter); if (maybe_name.is_null()) return false; diff --git a/chromium/v8/src/objects/lookup.h b/chromium/v8/src/objects/lookup.h index 820b8ef9b06..565ea4bb75b 100644 --- a/chromium/v8/src/objects/lookup.h +++ b/chromium/v8/src/objects/lookup.h @@ -93,10 +93,6 @@ class V8_EXPORT_PRIVATE LookupIterator final { Isolate* isolate, Handle<Object> receiver, Handle<Object> key, bool* success, Configuration configuration = DEFAULT); - static LookupIterator ForTransitionHandler( - Isolate* isolate, Handle<Object> receiver, Handle<Name> name, - Handle<Object> value, MaybeHandle<Map> maybe_transition_map); - void Restart() { InterceptorState state = InterceptorState::kUninitialized; IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state); @@ -239,7 +235,8 @@ class V8_EXPORT_PRIVATE LookupIterator final { template <bool is_element> bool SkipInterceptor(JSObject holder); template <bool is_element> - static inline InterceptorInfo GetInterceptor(JSObject holder); + static inline InterceptorInfo GetInterceptor(Isolate* isolate, + JSObject holder); bool check_interceptor() const { return (configuration_ & kInterceptor) != 0; @@ -247,7 +244,8 @@ class V8_EXPORT_PRIVATE LookupIterator final { inline int descriptor_number() const; inline int dictionary_entry() const; - static inline Configuration ComputeConfiguration(Configuration configuration, + static inline Configuration ComputeConfiguration(Isolate* isolate, + Configuration configuration, Handle<Name> name); static Handle<JSReceiver> GetRootForNonJSReceiver( diff --git a/chromium/v8/src/objects/map-inl.h b/chromium/v8/src/objects/map-inl.h index 8c26196fb50..6a9359e3a0d 100644 --- a/chromium/v8/src/objects/map-inl.h +++ b/chromium/v8/src/objects/map-inl.h @@ -30,20 +30,13 @@ namespace internal { OBJECT_CONSTRUCTORS_IMPL(Map, HeapObject) CAST_ACCESSOR(Map) -DescriptorArray Map::instance_descriptors() const { - return DescriptorArray::cast(READ_FIELD(*this, kInstanceDescriptorsOffset)); +DEF_GETTER(Map, instance_descriptors, DescriptorArray) { + return TaggedField<DescriptorArray, kInstanceDescriptorsOffset>::load(isolate, + *this); } -DescriptorArray Map::synchronized_instance_descriptors() const { - return DescriptorArray::cast( - ACQUIRE_READ_FIELD(*this, kInstanceDescriptorsOffset)); -} - -void Map::set_synchronized_instance_descriptors(DescriptorArray value, - WriteBarrierMode mode) { - RELEASE_WRITE_FIELD(*this, kInstanceDescriptorsOffset, value); - CONDITIONAL_WRITE_BARRIER(*this, kInstanceDescriptorsOffset, value, mode); -} +SYNCHRONIZED_ACCESSORS(Map, synchronized_instance_descriptors, DescriptorArray, + kInstanceDescriptorsOffset) // A freshly allocated layout descriptor can be set on an existing map. // We need to use release-store and acquire-load accessor pairs to ensure @@ -54,6 +47,12 @@ SYNCHRONIZED_ACCESSORS_CHECKED(Map, layout_descriptor, LayoutDescriptor, FLAG_unbox_double_fields) WEAK_ACCESSORS(Map, raw_transitions, kTransitionsOrPrototypeInfoOffset) +ACCESSORS_CHECKED2(Map, prototype, HeapObject, kPrototypeOffset, true, + value.IsNull() || value.IsJSReceiver()) + +ACCESSORS_CHECKED(Map, prototype_info, Object, + kTransitionsOrPrototypeInfoOffset, this->is_prototype_map()) + // |bit_field| fields. // Concurrent access to |has_prototype_slot| and |has_non_instance_prototype| // is explicitly whitelisted here. The former is never modified after the map @@ -74,37 +73,35 @@ BIT_FIELD_ACCESSORS(Map, relaxed_bit_field, has_prototype_slot, Map::HasPrototypeSlotBit) // |bit_field2| fields. -BIT_FIELD_ACCESSORS(Map, bit_field2, is_extensible, Map::IsExtensibleBit) -BIT_FIELD_ACCESSORS(Map, bit_field2, is_prototype_map, Map::IsPrototypeMapBit) -BIT_FIELD_ACCESSORS(Map, bit_field2, has_hidden_prototype, - Map::HasHiddenPrototypeBit) +BIT_FIELD_ACCESSORS(Map, bit_field2, new_target_is_base, + Map::NewTargetIsBaseBit) +BIT_FIELD_ACCESSORS(Map, bit_field2, is_immutable_proto, + Map::IsImmutablePrototypeBit) // |bit_field3| fields. BIT_FIELD_ACCESSORS(Map, bit_field3, owns_descriptors, Map::OwnsDescriptorsBit) BIT_FIELD_ACCESSORS(Map, bit_field3, is_deprecated, Map::IsDeprecatedBit) BIT_FIELD_ACCESSORS(Map, bit_field3, is_in_retained_map_list, Map::IsInRetainedMapListBit) +BIT_FIELD_ACCESSORS(Map, bit_field3, is_prototype_map, Map::IsPrototypeMapBit) BIT_FIELD_ACCESSORS(Map, bit_field3, is_migration_target, Map::IsMigrationTargetBit) -BIT_FIELD_ACCESSORS(Map, bit_field3, is_immutable_proto, - Map::IsImmutablePrototypeBit) -BIT_FIELD_ACCESSORS(Map, bit_field3, new_target_is_base, - Map::NewTargetIsBaseBit) +BIT_FIELD_ACCESSORS(Map, bit_field3, is_extensible, Map::IsExtensibleBit) BIT_FIELD_ACCESSORS(Map, bit_field3, may_have_interesting_symbols, Map::MayHaveInterestingSymbolsBit) BIT_FIELD_ACCESSORS(Map, bit_field3, construction_counter, Map::ConstructionCounterBits) -InterceptorInfo Map::GetNamedInterceptor() { +DEF_GETTER(Map, GetNamedInterceptor, InterceptorInfo) { DCHECK(has_named_interceptor()); - FunctionTemplateInfo info = GetFunctionTemplateInfo(); - return InterceptorInfo::cast(info.GetNamedPropertyHandler()); + FunctionTemplateInfo info = GetFunctionTemplateInfo(isolate); + return InterceptorInfo::cast(info.GetNamedPropertyHandler(isolate)); } -InterceptorInfo Map::GetIndexedInterceptor() { +DEF_GETTER(Map, GetIndexedInterceptor, InterceptorInfo) { DCHECK(has_indexed_interceptor()); - FunctionTemplateInfo info = GetFunctionTemplateInfo(); - return InterceptorInfo::cast(info.GetIndexedPropertyHandler()); + FunctionTemplateInfo info = GetFunctionTemplateInfo(isolate); + return InterceptorInfo::cast(info.GetIndexedPropertyHandler(isolate)); } bool Map::IsMostGeneralFieldType(Representation representation, @@ -113,7 +110,8 @@ bool Map::IsMostGeneralFieldType(Representation representation, } bool Map::CanHaveFastTransitionableElementsKind(InstanceType instance_type) { - return instance_type == JS_ARRAY_TYPE || instance_type == JS_VALUE_TYPE || + return instance_type == JS_ARRAY_TYPE || + instance_type == JS_PRIMITIVE_WRAPPER_TYPE || instance_type == JS_ARGUMENTS_TYPE; } @@ -136,10 +134,25 @@ void Map::GeneralizeIfCanHaveTransitionableFastElementsKind( } } +Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map, + PropertyNormalizationMode mode, const char* reason) { + return Normalize(isolate, fast_map, fast_map->elements_kind(), mode, reason); +} + +bool Map::EquivalentToForNormalization(const Map other, + PropertyNormalizationMode mode) const { + return EquivalentToForNormalization(other, elements_kind(), mode); +} + bool Map::IsUnboxedDoubleField(FieldIndex index) const { + Isolate* isolate = GetIsolateForPtrCompr(*this); + return IsUnboxedDoubleField(isolate, index); +} + +bool Map::IsUnboxedDoubleField(Isolate* isolate, FieldIndex index) const { if (!FLAG_unbox_double_fields) return false; if (!index.is_inobject()) return false; - return !layout_descriptor().IsTagged(index.property_index()); + return !layout_descriptor(isolate).IsTagged(index.property_index()); } bool Map::TooManyFastProperties(StoreOrigin store_origin) const { @@ -160,8 +173,8 @@ bool Map::TooManyFastProperties(StoreOrigin store_origin) const { } } -PropertyDetails Map::GetLastDescriptorDetails() const { - return instance_descriptors().GetDetails(LastAdded()); +PropertyDetails Map::GetLastDescriptorDetails(Isolate* isolate) const { + return instance_descriptors(isolate).GetDetails(LastAdded()); } int Map::LastAdded() const { @@ -375,7 +388,7 @@ void Map::CopyUnusedPropertyFields(Map map) { void Map::CopyUnusedPropertyFieldsAdjustedForInstanceSize(Map map) { int value = map.used_or_unused_instance_size_in_words(); - if (value >= JSValue::kFieldsAdded) { + if (value >= JSPrimitiveWrapper::kFieldsAdded) { // Unused in-object fields. Adjust the offset from the object’s start // so it matches the distance to the object’s end. value += instance_size_in_words() - map.instance_size_in_words(); @@ -570,22 +583,13 @@ bool Map::IsPrimitiveMap() const { return instance_type() <= LAST_PRIMITIVE_TYPE; } -HeapObject Map::prototype() const { - return HeapObject::cast(READ_FIELD(*this, kPrototypeOffset)); -} - -void Map::set_prototype(HeapObject value, WriteBarrierMode mode) { - DCHECK(value.IsNull() || value.IsJSReceiver()); - WRITE_FIELD(*this, kPrototypeOffset, value); - CONDITIONAL_WRITE_BARRIER(*this, kPrototypeOffset, value, mode); -} - LayoutDescriptor Map::layout_descriptor_gc_safe() const { DCHECK(FLAG_unbox_double_fields); // The loaded value can be dereferenced on background thread to load the // bitmap. We need acquire load in order to ensure that the bitmap // initializing stores are also visible to the background thread. - Object layout_desc = ACQUIRE_READ_FIELD(*this, kLayoutDescriptorOffset); + Object layout_desc = + TaggedField<Object, kLayoutDescriptorOffset>::Acquire_Load(*this); return LayoutDescriptor::cast_gc_safe(layout_desc); } @@ -593,7 +597,8 @@ bool Map::HasFastPointerLayout() const { DCHECK(FLAG_unbox_double_fields); // The loaded value is used for SMI check only and is not dereferenced, // so relaxed load is safe. - Object layout_desc = RELAXED_READ_FIELD(*this, kLayoutDescriptorOffset); + Object layout_desc = + TaggedField<Object, kLayoutDescriptorOffset>::Relaxed_Load(*this); return LayoutDescriptor::IsFastPointerLayout(layout_desc); } @@ -686,36 +691,17 @@ void Map::AppendDescriptor(Isolate* isolate, Descriptor* desc) { #endif } -HeapObject Map::GetBackPointer() const { - Object object = constructor_or_backpointer(); - if (object.IsMap()) { +DEF_GETTER(Map, GetBackPointer, HeapObject) { + Object object = constructor_or_backpointer(isolate); + if (object.IsMap(isolate)) { return Map::cast(object); } - return GetReadOnlyRoots().undefined_value(); + // Can't use ReadOnlyRoots(isolate) as this isolate could be produced by + // i::GetIsolateForPtrCompr(HeapObject). + return GetReadOnlyRoots(isolate).undefined_value(); } -Map Map::ElementsTransitionMap() { - DisallowHeapAllocation no_gc; - // TODO(delphick): While it's safe to pass nullptr for Isolate* here as - // SearchSpecial doesn't need it, this is really ugly. Perhaps factor out a - // base class for methods not requiring an Isolate? - return TransitionsAccessor(nullptr, *this, &no_gc) - .SearchSpecial(GetReadOnlyRoots().elements_transition_symbol()); -} - -Object Map::prototype_info() const { - DCHECK(is_prototype_map()); - return READ_FIELD(*this, Map::kTransitionsOrPrototypeInfoOffset); -} - -void Map::set_prototype_info(Object value, WriteBarrierMode mode) { - CHECK(is_prototype_map()); - WRITE_FIELD(*this, Map::kTransitionsOrPrototypeInfoOffset, value); - CONDITIONAL_WRITE_BARRIER(*this, Map::kTransitionsOrPrototypeInfoOffset, - value, mode); -} - -void Map::SetBackPointer(Object value, WriteBarrierMode mode) { +void Map::SetBackPointer(HeapObject value, WriteBarrierMode mode) { CHECK_GE(instance_type(), FIRST_JS_RECEIVER_TYPE); CHECK(value.IsMap()); CHECK(GetBackPointer().IsUndefined()); @@ -724,6 +710,13 @@ void Map::SetBackPointer(Object value, WriteBarrierMode mode) { set_constructor_or_backpointer(value, mode); } +// static +Map Map::ElementsTransitionMap(Isolate* isolate) { + DisallowHeapAllocation no_gc; + return TransitionsAccessor(isolate, *this, &no_gc) + .SearchSpecial(ReadOnlyRoots(isolate).elements_transition_symbol()); +} + ACCESSORS(Map, dependent_code, DependentCode, kDependentCodeOffset) ACCESSORS(Map, prototype_validity_cell, Object, kPrototypeValidityCellOffset) ACCESSORS(Map, constructor_or_backpointer, Object, @@ -736,23 +729,24 @@ bool Map::IsPrototypeValidityCellValid() const { return value == Smi::FromInt(Map::kPrototypeChainValid); } -Object Map::GetConstructor() const { - Object maybe_constructor = constructor_or_backpointer(); +DEF_GETTER(Map, GetConstructor, Object) { + Object maybe_constructor = constructor_or_backpointer(isolate); // Follow any back pointers. - while (maybe_constructor.IsMap()) { + while (maybe_constructor.IsMap(isolate)) { maybe_constructor = - Map::cast(maybe_constructor).constructor_or_backpointer(); + Map::cast(maybe_constructor).constructor_or_backpointer(isolate); } return maybe_constructor; } -FunctionTemplateInfo Map::GetFunctionTemplateInfo() const { - Object constructor = GetConstructor(); - if (constructor.IsJSFunction()) { - DCHECK(JSFunction::cast(constructor).shared().IsApiFunction()); - return JSFunction::cast(constructor).shared().get_api_func_data(); +DEF_GETTER(Map, GetFunctionTemplateInfo, FunctionTemplateInfo) { + Object constructor = GetConstructor(isolate); + if (constructor.IsJSFunction(isolate)) { + // TODO(ishell): IsApiFunction(isolate) and get_api_func_data(isolate) + DCHECK(JSFunction::cast(constructor).shared(isolate).IsApiFunction()); + return JSFunction::cast(constructor).shared(isolate).get_api_func_data(); } - DCHECK(constructor.IsFunctionTemplateInfo()); + DCHECK(constructor.IsFunctionTemplateInfo(isolate)); return FunctionTemplateInfo::cast(constructor); } @@ -805,8 +799,8 @@ int NormalizedMapCache::GetIndex(Handle<Map> map) { return map->Hash() % NormalizedMapCache::kEntries; } -bool HeapObject::IsNormalizedMapCache() const { - if (!IsWeakFixedArray()) return false; +DEF_GETTER(HeapObject, IsNormalizedMapCache, bool) { + if (!IsWeakFixedArray(isolate)) return false; if (WeakFixedArray::cast(*this).length() != NormalizedMapCache::kEntries) { return false; } diff --git a/chromium/v8/src/objects/map-updater.cc b/chromium/v8/src/objects/map-updater.cc index 855fdabdf3f..d21f0e1a129 100644 --- a/chromium/v8/src/objects/map-updater.cc +++ b/chromium/v8/src/objects/map-updater.cc @@ -201,10 +201,9 @@ void MapUpdater::GeneralizeField(Handle<Map> map, int modify_index, *old_descriptors_ == integrity_source_map_->instance_descriptors()); } -MapUpdater::State MapUpdater::CopyGeneralizeAllFields(const char* reason) { - result_map_ = Map::CopyGeneralizeAllFields( - isolate_, old_map_, new_elements_kind_, modified_descriptor_, new_kind_, - new_attributes_, reason); +MapUpdater::State MapUpdater::Normalize(const char* reason) { + result_map_ = Map::Normalize(isolate_, old_map_, new_elements_kind_, + CLEAR_INOBJECT_PROPERTIES, reason); state_ = kEnd; return state_; // Done. } @@ -310,14 +309,14 @@ MapUpdater::State MapUpdater::FindRootMap() { } if (!old_map_->EquivalentToForTransition(*root_map_)) { - return CopyGeneralizeAllFields("GenAll_NotEquivalent"); + return Normalize("Normalize_NotEquivalent"); } else if (old_map_->is_extensible() != root_map_->is_extensible()) { DCHECK(!old_map_->is_extensible()); DCHECK(root_map_->is_extensible()); // We have an integrity level transition in the tree, let us make a note // of that transition to be able to replay it later. if (!TrySaveIntegrityLevelTransitions()) { - return CopyGeneralizeAllFields("GenAll_PrivateSymbolsOnNonExtensible"); + return Normalize("Normalize_PrivateSymbolsOnNonExtensible"); } // We want to build transitions to the original element kind (before @@ -335,7 +334,7 @@ MapUpdater::State MapUpdater::FindRootMap() { to_kind != SLOW_SLOPPY_ARGUMENTS_ELEMENTS && !(IsTransitionableFastElementsKind(from_kind) && IsMoreGeneralElementsKindTransition(from_kind, to_kind))) { - return CopyGeneralizeAllFields("GenAll_InvalidElementsTransition"); + return Normalize("Normalize_InvalidElementsTransition"); } int root_nof = root_map_->NumberOfOwnDescriptors(); @@ -344,13 +343,13 @@ MapUpdater::State MapUpdater::FindRootMap() { old_descriptors_->GetDetails(modified_descriptor_); if (old_details.kind() != new_kind_ || old_details.attributes() != new_attributes_) { - return CopyGeneralizeAllFields("GenAll_RootModification1"); + return Normalize("Normalize_RootModification1"); } if (old_details.location() != kField) { - return CopyGeneralizeAllFields("GenAll_RootModification2"); + return Normalize("Normalize_RootModification2"); } if (!new_representation_.fits_into(old_details.representation())) { - return CopyGeneralizeAllFields("GenAll_RootModification4"); + return Normalize("Normalize_RootModification4"); } DCHECK_EQ(kData, old_details.kind()); @@ -394,7 +393,7 @@ MapUpdater::State MapUpdater::FindTargetMap() { !EqualImmutableValues(GetValue(i), tmp_descriptors->GetStrongValue(i))) { // TODO(ishell): mutable accessors are not implemented yet. - return CopyGeneralizeAllFields("GenAll_Incompatible"); + return Normalize("Normalize_Incompatible"); } if (!IsGeneralizableTo(old_details.location(), tmp_details.location())) { break; @@ -484,7 +483,7 @@ MapUpdater::State MapUpdater::FindTargetMap() { if (old_details.kind() == kAccessor && !EqualImmutableValues(GetValue(i), tmp_descriptors->GetStrongValue(i))) { - return CopyGeneralizeAllFields("GenAll_Incompatible"); + return Normalize("Normalize_Incompatible"); } DCHECK(!tmp_map->is_deprecated()); target_map_ = tmp_map; @@ -723,7 +722,7 @@ MapUpdater::State MapUpdater::ConstructNewMap() { // contains entry for given descriptor. This means that the transition // could be inserted regardless of whether transitions array is full or not. if (maybe_transition.is_null() && !transitions.CanHaveMoreTransitions()) { - return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions"); + return Normalize("Normalize_CantHaveMoreTransitions"); } old_map_->NotifyLeafMapLayoutChange(isolate_); @@ -787,7 +786,7 @@ MapUpdater::State MapUpdater::ConstructNewMapWithIntegrityLevelTransition() { TransitionsAccessor transitions(isolate_, target_map_); if (!transitions.CanHaveMoreTransitions()) { - return CopyGeneralizeAllFields("GenAll_CantHaveMoreTransitions"); + return Normalize("Normalize_CantHaveMoreTransitions"); } result_map_ = Map::CopyForPreventExtensions( diff --git a/chromium/v8/src/objects/map-updater.h b/chromium/v8/src/objects/map-updater.h index 3ba86eacbc0..6ee373cbdf3 100644 --- a/chromium/v8/src/objects/map-updater.h +++ b/chromium/v8/src/objects/map-updater.h @@ -123,9 +123,8 @@ class MapUpdater { State ConstructNewMapWithIntegrityLevelTransition(); // When a requested reconfiguration can not be done the result is a copy - // of |old_map_| where every field has |Tagged| representation and |Any| - // field type. This map is disconnected from the transition tree. - State CopyGeneralizeAllFields(const char* reason); + // of |old_map_| in dictionary mode. + State Normalize(const char* reason); // Returns name of a |descriptor| property. inline Name GetKey(int descriptor) const; diff --git a/chromium/v8/src/objects/map.cc b/chromium/v8/src/objects/map.cc index 43d8c305c51..7b4f1abd05f 100644 --- a/chromium/v8/src/objects/map.cc +++ b/chromium/v8/src/objects/map.cc @@ -85,6 +85,21 @@ void Map::PrintReconfiguration(Isolate* isolate, FILE* file, int modify_index, os << "]\n"; } +Map Map::GetStructMap(Isolate* isolate, InstanceType type) { + Map map; + switch (type) { +#define MAKE_CASE(TYPE, Name, name) \ + case TYPE: \ + map = ReadOnlyRoots(isolate).name##_map(); \ + break; + STRUCT_LIST(MAKE_CASE) +#undef MAKE_CASE + default: + UNREACHABLE(); + } + return map; +} + VisitorId Map::GetVisitorId(Map map) { STATIC_ASSERT(kVisitorIdCount <= 256); @@ -262,7 +277,7 @@ VisitorId Map::GetVisitorId(Map map) { case JS_ASYNC_FUNCTION_OBJECT_TYPE: case JS_ASYNC_GENERATOR_OBJECT_TYPE: case JS_MODULE_NAMESPACE_TYPE: - case JS_VALUE_TYPE: + case JS_PRIMITIVE_WRAPPER_TYPE: case JS_DATE_TYPE: case JS_ARRAY_ITERATOR_TYPE: case JS_ARRAY_TYPE: @@ -337,12 +352,20 @@ VisitorId Map::GetVisitorId(Map map) { if (instance_type == WASM_CAPI_FUNCTION_DATA_TYPE) { return kVisitWasmCapiFunctionData; } + if (instance_type == WASM_INDIRECT_FUNCTION_TABLE_TYPE) { + return kVisitWasmIndirectFunctionTable; + } return kVisitStruct; case LOAD_HANDLER_TYPE: case STORE_HANDLER_TYPE: return kVisitDataHandler; + case SOURCE_TEXT_MODULE_TYPE: + return kVisitSourceTextModule; + case SYNTHETIC_MODULE_TYPE: + return kVisitSyntheticModule; + default: UNREACHABLE(); } @@ -458,7 +481,7 @@ MaybeHandle<Map> Map::CopyWithConstant(Isolate* isolate, Handle<Map> map, return MaybeHandle<Map>(); } - Representation representation = constant->OptimalRepresentation(); + Representation representation = constant->OptimalRepresentation(isolate); Handle<FieldType> type = constant->OptimalType(isolate, representation); return CopyWithField(isolate, map, name, type, attributes, PropertyConstness::kConst, representation, flag); @@ -570,61 +593,6 @@ bool Map::HasOutOfObjectProperties() const { return GetInObjectProperties() < NumberOfFields(); } -Handle<Map> Map::CopyGeneralizeAllFields(Isolate* isolate, Handle<Map> map, - ElementsKind elements_kind, - int modify_index, PropertyKind kind, - PropertyAttributes attributes, - const char* reason) { - Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate); - int number_of_own_descriptors = map->NumberOfOwnDescriptors(); - Handle<DescriptorArray> descriptors = DescriptorArray::CopyUpTo( - isolate, old_descriptors, number_of_own_descriptors); - descriptors->GeneralizeAllFields(); - - Handle<LayoutDescriptor> new_layout_descriptor( - LayoutDescriptor::FastPointerLayout(), isolate); - Handle<Map> new_map = CopyReplaceDescriptors( - isolate, map, descriptors, new_layout_descriptor, OMIT_TRANSITION, - MaybeHandle<Name>(), reason, SPECIAL_TRANSITION); - - // Unless the instance is being migrated, ensure that modify_index is a field. - if (modify_index >= 0) { - PropertyDetails details = descriptors->GetDetails(modify_index); - if (details.constness() != PropertyConstness::kMutable || - details.location() != kField || details.attributes() != attributes) { - int field_index = details.location() == kField - ? details.field_index() - : new_map->NumberOfFields(); - Descriptor d = Descriptor::DataField( - isolate, handle(descriptors->GetKey(modify_index), isolate), - field_index, attributes, Representation::Tagged()); - descriptors->Replace(modify_index, &d); - if (details.location() != kField) { - new_map->AccountAddedPropertyField(); - } - } else { - DCHECK(details.attributes() == attributes); - } - - if (FLAG_trace_generalization) { - MaybeHandle<FieldType> field_type = FieldType::None(isolate); - if (details.location() == kField) { - field_type = handle( - map->instance_descriptors().GetFieldType(modify_index), isolate); - } - map->PrintGeneralization( - isolate, stdout, reason, modify_index, - new_map->NumberOfOwnDescriptors(), new_map->NumberOfOwnDescriptors(), - details.location() == kDescriptor, details.representation(), - Representation::Tagged(), details.constness(), details.constness(), - field_type, MaybeHandle<Object>(), FieldType::Any(isolate), - MaybeHandle<Object>()); - } - } - new_map->set_elements_kind(elements_kind); - return new_map; -} - void Map::DeprecateTransitionTree(Isolate* isolate) { if (is_deprecated()) return; DisallowHeapAllocation no_gc; @@ -648,7 +616,8 @@ void Map::DeprecateTransitionTree(Isolate* isolate) { void Map::ReplaceDescriptors(Isolate* isolate, DescriptorArray new_descriptors, LayoutDescriptor new_layout_descriptor) { // Don't overwrite the empty descriptor array or initial map's descriptors. - if (NumberOfOwnDescriptors() == 0 || GetBackPointer().IsUndefined(isolate)) { + if (NumberOfOwnDescriptors() == 0 || + GetBackPointer(isolate).IsUndefined(isolate)) { return; } @@ -659,8 +628,8 @@ void Map::ReplaceDescriptors(Isolate* isolate, DescriptorArray new_descriptors, Map current = *this; MarkingBarrierForDescriptorArray(isolate->heap(), current, to_replace, to_replace.number_of_descriptors()); - while (current.instance_descriptors() == to_replace) { - Object next = current.GetBackPointer(); + while (current.instance_descriptors(isolate) == to_replace) { + Object next = current.GetBackPointer(isolate); if (next.IsUndefined(isolate)) break; // Stop overwriting at initial map. current.SetEnumLength(kInvalidEnumCacheSentinel); current.UpdateDescriptors(isolate, new_descriptors, new_layout_descriptor, @@ -673,7 +642,7 @@ void Map::ReplaceDescriptors(Isolate* isolate, DescriptorArray new_descriptors, Map Map::FindRootMap(Isolate* isolate) const { Map result = *this; while (true) { - Object back = result.GetBackPointer(); + Object back = result.GetBackPointer(isolate); if (back.IsUndefined(isolate)) { // Initial map always owns descriptors and doesn't have unused entries // in the descriptor array. @@ -688,10 +657,11 @@ Map Map::FindRootMap(Isolate* isolate) const { Map Map::FindFieldOwner(Isolate* isolate, int descriptor) const { DisallowHeapAllocation no_allocation; - DCHECK_EQ(kField, instance_descriptors().GetDetails(descriptor).location()); + DCHECK_EQ(kField, + instance_descriptors(isolate).GetDetails(descriptor).location()); Map result = *this; while (true) { - Object back = result.GetBackPointer(); + Object back = result.GetBackPointer(isolate); if (back.IsUndefined(isolate)) break; const Map parent = Map::cast(back); if (parent.NumberOfOwnDescriptors() <= descriptor) break; @@ -927,7 +897,7 @@ IntegrityLevelTransitionInfo DetectIntegrityLevelTransitions( // Figure out the most restrictive integrity level transition (it should // be the last one in the transition tree). DCHECK(!map.is_extensible()); - Map previous = Map::cast(map.GetBackPointer()); + Map previous = Map::cast(map.GetBackPointer(isolate)); TransitionsAccessor last_transitions(isolate, previous, no_allocation); if (!last_transitions.HasIntegrityLevelTransitionTo( map, &(info.integrity_level_symbol), &(info.integrity_level))) { @@ -945,7 +915,7 @@ IntegrityLevelTransitionInfo DetectIntegrityLevelTransitions( // transitions. If we encounter any non-integrity level transition interleaved // with integrity level transitions, just bail out. while (!source_map.is_extensible()) { - previous = Map::cast(source_map.GetBackPointer()); + previous = Map::cast(source_map.GetBackPointer(isolate)); TransitionsAccessor transitions(isolate, previous, no_allocation); if (!transitions.HasIntegrityLevelTransitionTo(source_map)) { return info; @@ -1234,9 +1204,9 @@ Map Map::FindElementsKindTransitionedMap(Isolate* isolate, // Starting from the next existing elements kind transition try to // replay the property transitions that does not involve instance rewriting // (ElementsTransitionAndStoreStub does not support that). - for (root_map = root_map.ElementsTransitionMap(); + for (root_map = root_map.ElementsTransitionMap(isolate); !root_map.is_null() && root_map.has_fast_elements(); - root_map = root_map.ElementsTransitionMap()) { + root_map = root_map.ElementsTransitionMap(isolate)) { // If root_map's elements kind doesn't match any of the elements kind in // the candidates there is no need to do any additional work. if (!HasElementsKind(candidates, root_map.elements_kind())) continue; @@ -1263,7 +1233,7 @@ static Map FindClosestElementsTransition(Isolate* isolate, Map map, ElementsKind kind = map.elements_kind(); while (kind != to_kind) { - Map next_map = current_map.ElementsTransitionMap(); + Map next_map = current_map.ElementsTransitionMap(isolate); if (next_map.is_null()) return current_map; kind = next_map.elements_kind(); current_map = next_map; @@ -1401,25 +1371,23 @@ int Map::NumberOfEnumerableProperties() const { } int Map::NextFreePropertyIndex() const { - int free_index = 0; int number_of_own_descriptors = NumberOfOwnDescriptors(); DescriptorArray descs = instance_descriptors(); - for (int i = 0; i < number_of_own_descriptors; i++) { + // Search properties backwards to find the last field. + for (int i = number_of_own_descriptors - 1; i >= 0; --i) { PropertyDetails details = descs.GetDetails(i); if (details.location() == kField) { - int candidate = details.field_index() + details.field_width_in_words(); - if (candidate > free_index) free_index = candidate; + return details.field_index() + details.field_width_in_words(); } } - return free_index; + return 0; } bool Map::OnlyHasSimpleProperties() const { // Wrapped string elements aren't explicitly stored in the elements backing // store, but are loaded indirectly from the underlying string. return !IsStringWrapperElementsKind(elements_kind()) && - !IsSpecialReceiverMap() && !has_hidden_prototype() && - !is_dictionary_map(); + !IsSpecialReceiverMap() && !is_dictionary_map(); } bool Map::DictionaryElementsInPrototypeChainOnly(Isolate* isolate) { @@ -1478,6 +1446,7 @@ Handle<Map> Map::RawCopy(Isolate* isolate, Handle<Map> map, int instance_size, } Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map, + ElementsKind new_elements_kind, PropertyNormalizationMode mode, const char* reason) { DCHECK(!fast_map->is_dictionary_map()); @@ -1489,7 +1458,8 @@ Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map, if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache); Handle<Map> new_map; - if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) { + if (use_cache && + cache->Get(fast_map, new_elements_kind, mode).ToHandle(&new_map)) { #ifdef VERIFY_HEAP if (FLAG_verify_heap) new_map->DictionaryMapVerify(isolate); #endif @@ -1499,6 +1469,7 @@ Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map, // except for the code cache, which can contain some ICs which can be // applied to the shared map, dependent code and weak cell cache. Handle<Map> fresh = Map::CopyNormalized(isolate, fast_map, mode); + fresh->set_elements_kind(new_elements_kind); STATIC_ASSERT(Map::kPrototypeValidityCellOffset == Map::kDependentCodeOffset + kTaggedSize); @@ -1508,8 +1479,12 @@ Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map, // The IsInRetainedMapListBit might be different if the {new_map} // that we got from the {cache} was already embedded into optimized // code somewhere. - DCHECK_EQ(fresh->bit_field3() & ~IsInRetainedMapListBit::kMask, - new_map->bit_field3() & ~IsInRetainedMapListBit::kMask); + // The IsMigrationTargetBit might be different if the {new_map} from + // {cache} has already been marked as a migration target. + constexpr int ignored_bit_field3_bits = + IsInRetainedMapListBit::kMask | IsMigrationTargetBit::kMask; + DCHECK_EQ(fresh->bit_field3() & ~ignored_bit_field3_bits, + new_map->bit_field3() & ~ignored_bit_field3_bits); int offset = Map::kBitField3Offset + kInt32Size; DCHECK_EQ(0, memcmp(reinterpret_cast<void*>(fresh->address() + offset), reinterpret_cast<void*>(new_map->address() + offset), @@ -1530,13 +1505,14 @@ Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map, #endif } else { new_map = Map::CopyNormalized(isolate, fast_map, mode); + new_map->set_elements_kind(new_elements_kind); if (use_cache) { cache->Set(fast_map, new_map); isolate->counters()->maps_normalized()->Increment(); } - if (FLAG_trace_maps) { - LOG(isolate, MapEvent("Normalize", *fast_map, *new_map, reason)); - } + } + if (FLAG_trace_maps) { + LOG(isolate, MapEvent("Normalize", *fast_map, *new_map, reason)); } fast_map->NotifyLeafMapLayoutChange(isolate); return new_map; @@ -1870,7 +1846,7 @@ Handle<Map> Map::CopyAsElementsKind(Isolate* isolate, Handle<Map> map, DCHECK_EQ(map->FindRootMap(isolate).NumberOfOwnDescriptors(), map->NumberOfOwnDescriptors()); - maybe_elements_transition_map = map->ElementsTransitionMap(); + maybe_elements_transition_map = map->ElementsTransitionMap(isolate); DCHECK( maybe_elements_transition_map.is_null() || (maybe_elements_transition_map.elements_kind() == DICTIONARY_ELEMENTS && @@ -2093,7 +2069,7 @@ Handle<Map> UpdateDescriptorForValue(Isolate* isolate, Handle<Map> map, PropertyAttributes attributes = map->instance_descriptors().GetDetails(descriptor).attributes(); - Representation representation = value->OptimalRepresentation(); + Representation representation = value->OptimalRepresentation(isolate); Handle<FieldType> type = value->OptimalType(isolate, representation); MapUpdater mu(isolate, map); @@ -2108,11 +2084,11 @@ Handle<Map> Map::PrepareForDataProperty(Isolate* isolate, Handle<Map> map, int descriptor, PropertyConstness constness, Handle<Object> value) { + // Update to the newest map before storing the property. + map = Update(isolate, map); // Dictionaries can store any property value. DCHECK(!map->is_dictionary_map()); - // Update to the newest map before storing the property. - return UpdateDescriptorForValue(isolate, Update(isolate, map), descriptor, - constness, value); + return UpdateDescriptorForValue(isolate, map, descriptor, constness, value); } Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map, @@ -2152,7 +2128,7 @@ Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map, isolate->bootstrapper()->IsActive() ? OMIT_TRANSITION : INSERT_TRANSITION; MaybeHandle<Map> maybe_map; if (!map->TooManyFastProperties(store_origin)) { - Representation representation = value->OptimalRepresentation(); + Representation representation = value->OptimalRepresentation(isolate); Handle<FieldType> type = value->OptimalType(isolate, representation); maybe_map = Map::CopyWithField(isolate, map, name, type, attributes, constness, representation, flag); @@ -2204,16 +2180,16 @@ Handle<Map> Map::TransitionToDataProperty(Isolate* isolate, Handle<Map> map, Handle<Map> Map::ReconfigureExistingProperty(Isolate* isolate, Handle<Map> map, int descriptor, PropertyKind kind, - PropertyAttributes attributes) { + PropertyAttributes attributes, + PropertyConstness constness) { // Dictionaries have to be reconfigured in-place. DCHECK(!map->is_dictionary_map()); if (!map->GetBackPointer().IsMap()) { // There is no benefit from reconstructing transition tree for maps without - // back pointers. - return CopyGeneralizeAllFields(isolate, map, map->elements_kind(), - descriptor, kind, attributes, - "GenAll_AttributesMismatchProtoMap"); + // back pointers, normalize and try to hit the map cache instead. + return Map::Normalize(isolate, map, CLEAR_INOBJECT_PROPERTIES, + "Normalize_AttributesMismatchProtoMap"); } if (FLAG_trace_generalization) { @@ -2223,7 +2199,7 @@ Handle<Map> Map::ReconfigureExistingProperty(Isolate* isolate, Handle<Map> map, MapUpdater mu(isolate, map); DCHECK_EQ(kData, kind); // Only kData case is supported so far. Handle<Map> new_map = mu.ReconfigureToDataField( - descriptor, attributes, PropertyConstness::kConst, Representation::None(), + descriptor, attributes, constness, Representation::None(), FieldType::None(isolate)); return new_map; } @@ -2243,12 +2219,12 @@ Handle<Map> Map::TransitionToAccessorProperty(Isolate* isolate, Handle<Map> map, DCHECK(!getter->IsNull(isolate) || !setter->IsNull(isolate)); DCHECK(name->IsUniqueName()); - // Dictionary maps can always have additional data properties. - if (map->is_dictionary_map()) return map; - // Migrate to the newest map before transitioning to the new property. map = Update(isolate, map); + // Dictionary maps can always have additional data properties. + if (map->is_dictionary_map()) return map; + PropertyNormalizationMode mode = map->is_prototype_map() ? KEEP_INOBJECT_PROPERTIES : CLEAR_INOBJECT_PROPERTIES; @@ -2433,8 +2409,7 @@ bool CheckEquivalent(const Map first, const Map second) { first.instance_type() == second.instance_type() && first.bit_field() == second.bit_field() && first.is_extensible() == second.is_extensible() && - first.new_target_is_base() == second.new_target_is_base() && - first.has_hidden_prototype() == second.has_hidden_prototype(); + first.new_target_is_base() == second.new_target_is_base(); } } // namespace @@ -2442,7 +2417,6 @@ bool CheckEquivalent(const Map first, const Map second) { bool Map::EquivalentToForTransition(const Map other) const { CHECK_EQ(GetConstructor(), other.GetConstructor()); CHECK_EQ(instance_type(), other.instance_type()); - CHECK_EQ(has_hidden_prototype(), other.has_hidden_prototype()); if (bit_field() != other.bit_field()) return false; if (new_target_is_base() != other.new_target_is_base()) return false; @@ -2477,10 +2451,16 @@ bool Map::EquivalentToForElementsKindTransition(const Map other) const { } bool Map::EquivalentToForNormalization(const Map other, + ElementsKind elements_kind, PropertyNormalizationMode mode) const { int properties = mode == CLEAR_INOBJECT_PROPERTIES ? 0 : other.GetInObjectProperties(); - return CheckEquivalent(*this, other) && bit_field2() == other.bit_field2() && + // Make sure the elements_kind bits are in bit_field2. + DCHECK_EQ(this->elements_kind(), Map::ElementsKindBits::decode(bit_field2())); + int adjusted_other_bit_field2 = + Map::ElementsKindBits::update(other.bit_field2(), elements_kind); + return CheckEquivalent(*this, other) && + bit_field2() == adjusted_other_bit_field2 && GetInObjectProperties() == properties && JSObject::GetEmbedderFieldCount(*this) == JSObject::GetEmbedderFieldCount(other); @@ -2639,7 +2619,6 @@ void Map::SetPrototype(Isolate* isolate, Handle<Map> map, } else { DCHECK(prototype->IsNull(isolate) || prototype->IsJSProxy()); } - map->set_has_hidden_prototype(prototype->IsJSGlobalObject()); WriteBarrierMode wb_mode = prototype->IsNull(isolate) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; @@ -2672,6 +2651,7 @@ Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) { } MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map, + ElementsKind elements_kind, PropertyNormalizationMode mode) { DisallowHeapAllocation no_gc; MaybeObject value = WeakFixedArray::Get(GetIndex(fast_map)); @@ -2681,7 +2661,8 @@ MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map, } Map normalized_map = Map::cast(heap_object); - if (!normalized_map.EquivalentToForNormalization(*fast_map, mode)) { + if (!normalized_map.EquivalentToForNormalization(*fast_map, elements_kind, + mode)) { return MaybeHandle<Map>(); } return handle(normalized_map, GetIsolate()); diff --git a/chromium/v8/src/objects/map.h b/chromium/v8/src/objects/map.h index 814f8ed3bec..c9da19b3e30 100644 --- a/chromium/v8/src/objects/map.h +++ b/chromium/v8/src/objects/map.h @@ -65,13 +65,16 @@ enum InstanceType : uint16_t; V(SmallOrderedHashMap) \ V(SmallOrderedHashSet) \ V(SmallOrderedNameDictionary) \ + V(SourceTextModule) \ V(Struct) \ V(Symbol) \ + V(SyntheticModule) \ V(ThinString) \ V(TransitionArray) \ V(UncompiledDataWithoutPreparseData) \ V(UncompiledDataWithPreparseData) \ V(WasmCapiFunctionData) \ + V(WasmIndirectFunctionTable) \ V(WasmInstanceObject) \ V(WeakArray) \ V(WeakCell) @@ -138,22 +141,22 @@ using MapHandles = std::vector<Handle<Map>>; // | | - has_prototype_slot (bit 7) | // +----------+---------------------------------------------+ // | Byte | [bit_field2] | -// | | - is_extensible (bit 0) | -// | | - is_prototype_map (bit 1) | -// | | - has_hidden_prototype (bit 2) | +// | | - new_target_is_base (bit 0) | +// | | - is_immutable_proto (bit 1) | +// | | - unused bit (bit 2) | // | | - elements_kind (bits 3..7) | // +----+----------+---------------------------------------------+ // | Int | [bit_field3] | // | | - enum_length (bit 0..9) | // | | - number_of_own_descriptors (bit 10..19) | -// | | - is_dictionary_map (bit 20) | -// | | - owns_descriptors (bit 21) | -// | | - is_in_retained_map_list (bit 22) | -// | | - is_deprecated (bit 23) | -// | | - is_unstable (bit 24) | -// | | - is_migration_target (bit 25) | -// | | - is_immutable_proto (bit 26) | -// | | - new_target_is_base (bit 27) | +// | | - is_prototype_map (bit 20) | +// | | - is_dictionary_map (bit 21) | +// | | - owns_descriptors (bit 22) | +// | | - is_in_retained_map_list (bit 23) | +// | | - is_deprecated (bit 24) | +// | | - is_unstable (bit 25) | +// | | - is_migration_target (bit 26) | +// | | - is_extensible (bit 28) | // | | - may_have_interesting_symbols (bit 28) | // | | - construction_counter (bit 29..31) | // | | | @@ -212,8 +215,8 @@ class Map : public HeapObject { Handle<Map> map, Handle<Context> native_context); // Retrieve interceptors. - inline InterceptorInfo GetNamedInterceptor(); - inline InterceptorInfo GetIndexedInterceptor(); + DECL_GETTER(GetNamedInterceptor, InterceptorInfo) + DECL_GETTER(GetIndexedInterceptor, InterceptorInfo) // Instance type. DECL_PRIMITIVE_ACCESSORS(instance_type, InstanceType) @@ -265,10 +268,10 @@ class Map : public HeapObject { DECL_PRIMITIVE_ACCESSORS(bit_field2, byte) // Bit positions for |bit_field2|. -#define MAP_BIT_FIELD2_FIELDS(V, _) \ - V(IsExtensibleBit, bool, 1, _) \ - V(IsPrototypeMapBit, bool, 1, _) \ - V(HasHiddenPrototypeBit, bool, 1, _) \ +#define MAP_BIT_FIELD2_FIELDS(V, _) \ + V(NewTargetIsBaseBit, bool, 1, _) \ + V(IsImmutablePrototypeBit, bool, 1, _) \ + V(UnusedBit, bool, 1, _) \ V(ElementsKindBits, ElementsKind, 5, _) DEFINE_BIT_FIELDS(MAP_BIT_FIELD2_FIELDS) @@ -287,14 +290,14 @@ class Map : public HeapObject { #define MAP_BIT_FIELD3_FIELDS(V, _) \ V(EnumLengthBits, int, kDescriptorIndexBitCount, _) \ V(NumberOfOwnDescriptorsBits, int, kDescriptorIndexBitCount, _) \ + V(IsPrototypeMapBit, bool, 1, _) \ V(IsDictionaryMapBit, bool, 1, _) \ V(OwnsDescriptorsBit, bool, 1, _) \ V(IsInRetainedMapListBit, bool, 1, _) \ V(IsDeprecatedBit, bool, 1, _) \ V(IsUnstableBit, bool, 1, _) \ V(IsMigrationTargetBit, bool, 1, _) \ - V(IsImmutablePrototypeBit, bool, 1, _) \ - V(NewTargetIsBaseBit, bool, 1, _) \ + V(IsExtensibleBit, bool, 1, _) \ V(MayHaveInterestingSymbolsBit, bool, 1, _) \ V(ConstructionCounterBits, int, 3, _) @@ -378,9 +381,6 @@ class Map : public HeapObject { DECL_BOOLEAN_ACCESSORS(has_prototype_slot) - // Tells whether the instance with this map has a hidden prototype. - DECL_BOOLEAN_ACCESSORS(has_hidden_prototype) - // Records and queries whether the instance has a named interceptor. DECL_BOOLEAN_ACCESSORS(has_named_interceptor) @@ -431,7 +431,7 @@ class Map : public HeapObject { // map with DICTIONARY_ELEMENTS was found in the prototype chain. bool DictionaryElementsInPrototypeChainOnly(Isolate* isolate); - inline Map ElementsTransitionMap(); + inline Map ElementsTransitionMap(Isolate* isolate); inline FixedArrayBase GetInitialElements() const; @@ -545,9 +545,14 @@ class Map : public HeapObject { V8_EXPORT_PRIVATE static Handle<Map> Normalize(Isolate* isolate, Handle<Map> map, + ElementsKind new_elements_kind, PropertyNormalizationMode mode, const char* reason); + inline static Handle<Map> Normalize(Isolate* isolate, Handle<Map> fast_map, + PropertyNormalizationMode mode, + const char* reason); + // Tells whether the map is used for JSObjects in dictionary mode (ie // normalized objects, ie objects for which HasFastProperties returns false). // A map can never be used for both dictionary mode and fast mode JSObjects. @@ -573,19 +578,18 @@ class Map : public HeapObject { // Returns null_value if there's neither a constructor function nor a // FunctionTemplateInfo available. DECL_ACCESSORS(constructor_or_backpointer, Object) - inline Object GetConstructor() const; - inline FunctionTemplateInfo GetFunctionTemplateInfo() const; + DECL_GETTER(GetConstructor, Object) + DECL_GETTER(GetFunctionTemplateInfo, FunctionTemplateInfo) inline void SetConstructor(Object constructor, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); // [back pointer]: points back to the parent map from which a transition // leads to this map. The field overlaps with the constructor (see above). - inline HeapObject GetBackPointer() const; - inline void SetBackPointer(Object value, + DECL_GETTER(GetBackPointer, HeapObject) + inline void SetBackPointer(HeapObject value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); // [instance descriptors]: describes the object. - inline DescriptorArray instance_descriptors() const; - inline DescriptorArray synchronized_instance_descriptors() const; + DECL_GETTER(instance_descriptors, DescriptorArray) V8_EXPORT_PRIVATE void SetInstanceDescriptors(Isolate* isolate, DescriptorArray descriptors, int number_of_own_descriptors); @@ -629,7 +633,7 @@ class Map : public HeapObject { // chain state. inline bool IsPrototypeValidityCellValid() const; - inline PropertyDetails GetLastDescriptorDetails() const; + inline PropertyDetails GetLastDescriptorDetails(Isolate* isolate) const; inline int LastAdded() const; @@ -742,7 +746,7 @@ class Map : public HeapObject { PropertyAttributes attributes); V8_EXPORT_PRIVATE static Handle<Map> ReconfigureExistingProperty( Isolate* isolate, Handle<Map> map, int descriptor, PropertyKind kind, - PropertyAttributes attributes); + PropertyAttributes attributes, PropertyConstness constness); inline void AppendDescriptor(Isolate* isolate, Descriptor* desc); @@ -794,6 +798,8 @@ class Map : public HeapObject { inline bool CanTransition() const; + static Map GetStructMap(Isolate* isolate, InstanceType type); + #define DECL_TESTER(Type, ...) inline bool Is##Type##Map() const; INSTANCE_TYPE_CHECKERS(DECL_TESTER) #undef DECL_TESTER @@ -836,15 +842,19 @@ class Map : public HeapObject { class BodyDescriptor; - // Compares this map to another to see if they describe equivalent objects. + // Compares this map to another to see if they describe equivalent objects, + // up to the given |elements_kind|. // If |mode| is set to CLEAR_INOBJECT_PROPERTIES, |other| is treated as if // it had exactly zero inobject properties. // The "shared" flags of both this map and |other| are ignored. - bool EquivalentToForNormalization(const Map other, + bool EquivalentToForNormalization(const Map other, ElementsKind elements_kind, PropertyNormalizationMode mode) const; + inline bool EquivalentToForNormalization( + const Map other, PropertyNormalizationMode mode) const; // Returns true if given field is unboxed double. inline bool IsUnboxedDoubleField(FieldIndex index) const; + inline bool IsUnboxedDoubleField(Isolate* isolate, FieldIndex index) const; void PrintMapDetails(std::ostream& os); @@ -932,14 +942,6 @@ class Map : public HeapObject { static Handle<Map> CopyNormalized(Isolate* isolate, Handle<Map> map, PropertyNormalizationMode mode); - // TODO(ishell): Move to MapUpdater. - static Handle<Map> CopyGeneralizeAllFields(Isolate* isolate, Handle<Map> map, - ElementsKind elements_kind, - int modify_index, - PropertyKind kind, - PropertyAttributes attributes, - const char* reason); - void DeprecateTransitionTree(Isolate* isolate); void ReplaceDescriptors(Isolate* isolate, DescriptorArray new_descriptors, @@ -966,13 +968,13 @@ class Map : public HeapObject { MaybeHandle<FieldType> new_field_type, MaybeHandle<Object> new_value); // Use the high-level instance_descriptors/SetInstanceDescriptors instead. - inline void set_synchronized_instance_descriptors( - DescriptorArray array, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + DECL_ACCESSORS(synchronized_instance_descriptors, DescriptorArray) static const int kFastPropertiesSoftLimit = 12; static const int kMaxFastProperties = 128; friend class MapUpdater; + friend class ConcurrentMarkingVisitor; OBJECT_CONSTRUCTORS(Map, HeapObject); }; @@ -986,6 +988,7 @@ class NormalizedMapCache : public WeakFixedArray { static Handle<NormalizedMapCache> New(Isolate* isolate); V8_WARN_UNUSED_RESULT MaybeHandle<Map> Get(Handle<Map> fast_map, + ElementsKind elements_kind, PropertyNormalizationMode mode); void Set(Handle<Map> fast_map, Handle<Map> normalized_map); @@ -993,7 +996,7 @@ class NormalizedMapCache : public WeakFixedArray { DECL_VERIFIER(NormalizedMapCache) private: - friend bool HeapObject::IsNormalizedMapCache() const; + friend bool HeapObject::IsNormalizedMapCache(Isolate* isolate) const; static const int kEntries = 64; diff --git a/chromium/v8/src/objects/maybe-object.h b/chromium/v8/src/objects/maybe-object.h index a1645c06046..304cf90d28a 100644 --- a/chromium/v8/src/objects/maybe-object.h +++ b/chromium/v8/src/objects/maybe-object.h @@ -30,6 +30,10 @@ class MaybeObject : public TaggedImpl<HeapObjectReferenceType::WEAK, Address> { #ifdef VERIFY_HEAP static void VerifyMaybeObjectPointer(Isolate* isolate, MaybeObject p); #endif + + private: + template <typename TFieldType, int kFieldOffset> + friend class TaggedField; }; // A HeapObjectReference is either a strong reference to a HeapObject, a weak diff --git a/chromium/v8/src/objects/module-inl.h b/chromium/v8/src/objects/module-inl.h index a3bc31b63a2..1ab9b9fb045 100644 --- a/chromium/v8/src/objects/module-inl.h +++ b/chromium/v8/src/objects/module-inl.h @@ -6,9 +6,12 @@ #define V8_OBJECTS_MODULE_INL_H_ #include "src/objects/module.h" +#include "src/objects/source-text-module.h" +#include "src/objects/synthetic-module.h" #include "src/objects/objects-inl.h" // Needed for write barriers #include "src/objects/scope-info.h" +#include "src/objects/string-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -16,74 +19,86 @@ namespace v8 { namespace internal { -OBJECT_CONSTRUCTORS_IMPL(Module, Struct) -OBJECT_CONSTRUCTORS_IMPL(ModuleInfoEntry, Struct) +OBJECT_CONSTRUCTORS_IMPL(Module, HeapObject) +OBJECT_CONSTRUCTORS_IMPL(SourceTextModule, Module) +OBJECT_CONSTRUCTORS_IMPL(SourceTextModuleInfoEntry, Struct) +OBJECT_CONSTRUCTORS_IMPL(SyntheticModule, Module) OBJECT_CONSTRUCTORS_IMPL(JSModuleNamespace, JSObject) NEVER_READ_ONLY_SPACE_IMPL(Module) +NEVER_READ_ONLY_SPACE_IMPL(SourceTextModule) +NEVER_READ_ONLY_SPACE_IMPL(SyntheticModule) CAST_ACCESSOR(Module) -ACCESSORS(Module, code, Object, kCodeOffset) +CAST_ACCESSOR(SourceTextModule) +CAST_ACCESSOR(SyntheticModule) ACCESSORS(Module, exports, ObjectHashTable, kExportsOffset) -ACCESSORS(Module, regular_exports, FixedArray, kRegularExportsOffset) -ACCESSORS(Module, regular_imports, FixedArray, kRegularImportsOffset) ACCESSORS(Module, module_namespace, HeapObject, kModuleNamespaceOffset) -ACCESSORS(Module, requested_modules, FixedArray, kRequestedModulesOffset) -ACCESSORS(Module, script, Script, kScriptOffset) ACCESSORS(Module, exception, Object, kExceptionOffset) -ACCESSORS(Module, import_meta, Object, kImportMetaOffset) SMI_ACCESSORS(Module, status, kStatusOffset) -SMI_ACCESSORS(Module, dfs_index, kDfsIndexOffset) -SMI_ACCESSORS(Module, dfs_ancestor_index, kDfsAncestorIndexOffset) SMI_ACCESSORS(Module, hash, kHashOffset) -ModuleInfo Module::info() const { +ACCESSORS(SourceTextModule, code, Object, kCodeOffset) +ACCESSORS(SourceTextModule, regular_exports, FixedArray, kRegularExportsOffset) +ACCESSORS(SourceTextModule, regular_imports, FixedArray, kRegularImportsOffset) +ACCESSORS(SourceTextModule, requested_modules, FixedArray, + kRequestedModulesOffset) +ACCESSORS(SourceTextModule, script, Script, kScriptOffset) +ACCESSORS(SourceTextModule, import_meta, Object, kImportMetaOffset) +SMI_ACCESSORS(SourceTextModule, dfs_index, kDfsIndexOffset) +SMI_ACCESSORS(SourceTextModule, dfs_ancestor_index, kDfsAncestorIndexOffset) + +ACCESSORS(SyntheticModule, name, String, kNameOffset) +ACCESSORS(SyntheticModule, export_names, FixedArray, kExportNamesOffset) +ACCESSORS(SyntheticModule, evaluation_steps, Foreign, kEvaluationStepsOffset) + +SourceTextModuleInfo SourceTextModule::info() const { return (status() >= kEvaluating) - ? ModuleInfo::cast(code()) + ? SourceTextModuleInfo::cast(code()) : GetSharedFunctionInfo().scope_info().ModuleDescriptorInfo(); } CAST_ACCESSOR(JSModuleNamespace) ACCESSORS(JSModuleNamespace, module, Module, kModuleOffset) -CAST_ACCESSOR(ModuleInfoEntry) -ACCESSORS(ModuleInfoEntry, export_name, Object, kExportNameOffset) -ACCESSORS(ModuleInfoEntry, local_name, Object, kLocalNameOffset) -ACCESSORS(ModuleInfoEntry, import_name, Object, kImportNameOffset) -SMI_ACCESSORS(ModuleInfoEntry, module_request, kModuleRequestOffset) -SMI_ACCESSORS(ModuleInfoEntry, cell_index, kCellIndexOffset) -SMI_ACCESSORS(ModuleInfoEntry, beg_pos, kBegPosOffset) -SMI_ACCESSORS(ModuleInfoEntry, end_pos, kEndPosOffset) +CAST_ACCESSOR(SourceTextModuleInfoEntry) +ACCESSORS(SourceTextModuleInfoEntry, export_name, Object, kExportNameOffset) +ACCESSORS(SourceTextModuleInfoEntry, local_name, Object, kLocalNameOffset) +ACCESSORS(SourceTextModuleInfoEntry, import_name, Object, kImportNameOffset) +SMI_ACCESSORS(SourceTextModuleInfoEntry, module_request, kModuleRequestOffset) +SMI_ACCESSORS(SourceTextModuleInfoEntry, cell_index, kCellIndexOffset) +SMI_ACCESSORS(SourceTextModuleInfoEntry, beg_pos, kBegPosOffset) +SMI_ACCESSORS(SourceTextModuleInfoEntry, end_pos, kEndPosOffset) -OBJECT_CONSTRUCTORS_IMPL(ModuleInfo, FixedArray) -CAST_ACCESSOR(ModuleInfo) +OBJECT_CONSTRUCTORS_IMPL(SourceTextModuleInfo, FixedArray) +CAST_ACCESSOR(SourceTextModuleInfo) -FixedArray ModuleInfo::module_requests() const { +FixedArray SourceTextModuleInfo::module_requests() const { return FixedArray::cast(get(kModuleRequestsIndex)); } -FixedArray ModuleInfo::special_exports() const { +FixedArray SourceTextModuleInfo::special_exports() const { return FixedArray::cast(get(kSpecialExportsIndex)); } -FixedArray ModuleInfo::regular_exports() const { +FixedArray SourceTextModuleInfo::regular_exports() const { return FixedArray::cast(get(kRegularExportsIndex)); } -FixedArray ModuleInfo::regular_imports() const { +FixedArray SourceTextModuleInfo::regular_imports() const { return FixedArray::cast(get(kRegularImportsIndex)); } -FixedArray ModuleInfo::namespace_imports() const { +FixedArray SourceTextModuleInfo::namespace_imports() const { return FixedArray::cast(get(kNamespaceImportsIndex)); } -FixedArray ModuleInfo::module_request_positions() const { +FixedArray SourceTextModuleInfo::module_request_positions() const { return FixedArray::cast(get(kModuleRequestPositionsIndex)); } #ifdef DEBUG -bool ModuleInfo::Equals(ModuleInfo other) const { +bool SourceTextModuleInfo::Equals(SourceTextModuleInfo other) const { return regular_exports() == other.regular_exports() && regular_imports() == other.regular_imports() && special_exports() == other.special_exports() && @@ -93,6 +108,30 @@ bool ModuleInfo::Equals(ModuleInfo other) const { } #endif +struct ModuleHandleHash { + V8_INLINE size_t operator()(Handle<Module> module) const { + return module->hash(); + } +}; + +struct ModuleHandleEqual { + V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const { + return *lhs == *rhs; + } +}; + +class UnorderedModuleSet + : public std::unordered_set<Handle<Module>, ModuleHandleHash, + ModuleHandleEqual, + ZoneAllocator<Handle<Module>>> { + public: + explicit UnorderedModuleSet(Zone* zone) + : std::unordered_set<Handle<Module>, ModuleHandleHash, ModuleHandleEqual, + ZoneAllocator<Handle<Module>>>( + 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(), + ZoneAllocator<Handle<Module>>(zone)) {} +}; + } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/objects/module.cc b/chromium/v8/src/objects/module.cc index ea40989df1e..4e89050360c 100644 --- a/chromium/v8/src/objects/module.cc +++ b/chromium/v8/src/objects/module.cc @@ -14,169 +14,25 @@ #include "src/objects/hash-table-inl.h" #include "src/objects/js-generator-inl.h" #include "src/objects/module-inl.h" -#include "src/utils/ostreams.h" #include "src/objects/objects-inl.h" +#include "src/utils/ostreams.h" namespace v8 { namespace internal { -struct ModuleHandleHash { - V8_INLINE size_t operator()(Handle<Module> module) const { - return module->hash(); - } -}; - -struct ModuleHandleEqual { - V8_INLINE bool operator()(Handle<Module> lhs, Handle<Module> rhs) const { - return *lhs == *rhs; - } -}; - -struct StringHandleHash { - V8_INLINE size_t operator()(Handle<String> string) const { - return string->Hash(); - } -}; - -struct StringHandleEqual { - V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const { - return lhs->Equals(*rhs); - } -}; - -class UnorderedStringSet - : public std::unordered_set<Handle<String>, StringHandleHash, - StringHandleEqual, - ZoneAllocator<Handle<String>>> { - public: - explicit UnorderedStringSet(Zone* zone) - : std::unordered_set<Handle<String>, StringHandleHash, StringHandleEqual, - ZoneAllocator<Handle<String>>>( - 2 /* bucket count */, StringHandleHash(), StringHandleEqual(), - ZoneAllocator<Handle<String>>(zone)) {} -}; - -class UnorderedModuleSet - : public std::unordered_set<Handle<Module>, ModuleHandleHash, - ModuleHandleEqual, - ZoneAllocator<Handle<Module>>> { - public: - explicit UnorderedModuleSet(Zone* zone) - : std::unordered_set<Handle<Module>, ModuleHandleHash, ModuleHandleEqual, - ZoneAllocator<Handle<Module>>>( - 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(), - ZoneAllocator<Handle<Module>>(zone)) {} -}; - -class UnorderedStringMap - : public std::unordered_map< - Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual, - ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>> { - public: - explicit UnorderedStringMap(Zone* zone) - : std::unordered_map< - Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual, - ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>>( - 2 /* bucket count */, StringHandleHash(), StringHandleEqual(), - ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>( - zone)) {} -}; - -class Module::ResolveSet - : public std::unordered_map< - Handle<Module>, UnorderedStringSet*, ModuleHandleHash, - ModuleHandleEqual, - ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>> { - public: - explicit ResolveSet(Zone* zone) - : std::unordered_map<Handle<Module>, UnorderedStringSet*, - ModuleHandleHash, ModuleHandleEqual, - ZoneAllocator<std::pair<const Handle<Module>, - UnorderedStringSet*>>>( - 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(), - ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>( - zone)), - zone_(zone) {} - - Zone* zone() const { return zone_; } - - private: - Zone* zone_; -}; - -int Module::ExportIndex(int cell_index) { - DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), - ModuleDescriptor::kExport); - return cell_index - 1; -} - -int Module::ImportIndex(int cell_index) { - DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), - ModuleDescriptor::kImport); - return -cell_index - 1; -} - -void Module::CreateIndirectExport(Isolate* isolate, Handle<Module> module, - Handle<String> name, - Handle<ModuleInfoEntry> entry) { - Handle<ObjectHashTable> exports(module->exports(), isolate); - DCHECK(exports->Lookup(name).IsTheHole(isolate)); - exports = ObjectHashTable::Put(exports, name, entry); - module->set_exports(*exports); -} - -void Module::CreateExport(Isolate* isolate, Handle<Module> module, - int cell_index, Handle<FixedArray> names) { - DCHECK_LT(0, names->length()); - Handle<Cell> cell = - isolate->factory()->NewCell(isolate->factory()->undefined_value()); - module->regular_exports().set(ExportIndex(cell_index), *cell); - - Handle<ObjectHashTable> exports(module->exports(), isolate); - for (int i = 0, n = names->length(); i < n; ++i) { - Handle<String> name(String::cast(names->get(i)), isolate); - DCHECK(exports->Lookup(name).IsTheHole(isolate)); - exports = ObjectHashTable::Put(exports, name, cell); - } - module->set_exports(*exports); -} - -Cell Module::GetCell(int cell_index) { - DisallowHeapAllocation no_gc; - Object cell; - switch (ModuleDescriptor::GetCellIndexKind(cell_index)) { - case ModuleDescriptor::kImport: - cell = regular_imports().get(ImportIndex(cell_index)); - break; - case ModuleDescriptor::kExport: - cell = regular_exports().get(ExportIndex(cell_index)); - break; - case ModuleDescriptor::kInvalid: - UNREACHABLE(); - } - return Cell::cast(cell); -} - -Handle<Object> Module::LoadVariable(Isolate* isolate, Handle<Module> module, - int cell_index) { - return handle(module->GetCell(cell_index).value(), isolate); -} - -void Module::StoreVariable(Handle<Module> module, int cell_index, - Handle<Object> value) { - DisallowHeapAllocation no_gc; - DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index), - ModuleDescriptor::kExport); - module->GetCell(cell_index).set_value(*value); -} - #ifdef DEBUG void Module::PrintStatusTransition(Status new_status) { if (FLAG_trace_module_status) { StdoutStream os; os << "Changing module status from " << status() << " to " << new_status << " for "; - script().GetNameOrSourceURL().Print(os); + if (this->IsSourceTextModule()) { + Handle<Script> script(SourceTextModule::cast(*this).script(), + GetIsolate()); + script->GetNameOrSourceURL().Print(os); + } else { + SyntheticModule::cast(*this).name().Print(os); + } #ifndef OBJECT_PRINT os << "\n"; #endif // OBJECT_PRINT @@ -194,70 +50,80 @@ void Module::SetStatus(Status new_status) { set_status(new_status); } +void Module::RecordError(Isolate* isolate) { + DisallowHeapAllocation no_alloc; + DCHECK(exception().IsTheHole(isolate)); + Object the_exception = isolate->pending_exception(); + DCHECK(!the_exception.IsTheHole(isolate)); + + if (this->IsSourceTextModule()) { + Handle<SourceTextModule> self(SourceTextModule::cast(*this), GetIsolate()); + self->set_code(self->info()); + } +#ifdef DEBUG + PrintStatusTransition(Module::kErrored); +#endif // DEBUG + set_status(Module::kErrored); + set_exception(the_exception); +} + void Module::ResetGraph(Isolate* isolate, Handle<Module> module) { DCHECK_NE(module->status(), kInstantiating); DCHECK_NE(module->status(), kEvaluating); if (module->status() != kPreInstantiating) return; - Handle<FixedArray> requested_modules(module->requested_modules(), isolate); + + Handle<FixedArray> requested_modules = + module->IsSourceTextModule() + ? Handle<FixedArray>( + Handle<SourceTextModule>::cast(module)->requested_modules(), + isolate) + : Handle<FixedArray>(); Reset(isolate, module); - for (int i = 0; i < requested_modules->length(); ++i) { - Handle<Object> descendant(requested_modules->get(i), isolate); - if (descendant->IsModule()) { - ResetGraph(isolate, Handle<Module>::cast(descendant)); - } else { - DCHECK(descendant->IsUndefined(isolate)); + if (module->IsSourceTextModule()) { + for (int i = 0; i < requested_modules->length(); ++i) { + Handle<Object> descendant(requested_modules->get(i), isolate); + if (descendant->IsModule()) { + ResetGraph(isolate, Handle<Module>::cast(descendant)); + } else { + DCHECK(descendant->IsUndefined(isolate)); + } } + } else { + DCHECK(module->IsSyntheticModule()); + // Nothing else to do here. } } void Module::Reset(Isolate* isolate, Handle<Module> module) { - Factory* factory = isolate->factory(); - DCHECK(module->status() == kPreInstantiating || module->status() == kInstantiating); DCHECK(module->exception().IsTheHole(isolate)); - DCHECK(module->import_meta().IsTheHole(isolate)); // The namespace object cannot exist, because it would have been created // by RunInitializationCode, which is called only after this module's SCC // succeeds instantiation. DCHECK(!module->module_namespace().IsJSModuleNamespace()); - Handle<ObjectHashTable> exports = - ObjectHashTable::New(isolate, module->info().RegularExportCount()); - Handle<FixedArray> regular_exports = - factory->NewFixedArray(module->regular_exports().length()); - Handle<FixedArray> regular_imports = - factory->NewFixedArray(module->regular_imports().length()); - Handle<FixedArray> requested_modules = - factory->NewFixedArray(module->requested_modules().length()); - - if (module->status() == kInstantiating) { - module->set_code(JSFunction::cast(module->code()).shared()); - } #ifdef DEBUG module->PrintStatusTransition(kUninstantiated); #endif // DEBUG - module->set_status(kUninstantiated); - module->set_exports(*exports); - module->set_regular_exports(*regular_exports); - module->set_regular_imports(*regular_imports); - module->set_requested_modules(*requested_modules); - module->set_dfs_index(-1); - module->set_dfs_ancestor_index(-1); -} -void Module::RecordError(Isolate* isolate) { - DisallowHeapAllocation no_alloc; - DCHECK(exception().IsTheHole(isolate)); - Object the_exception = isolate->pending_exception(); - DCHECK(!the_exception.IsTheHole(isolate)); + int export_count; - set_code(info()); -#ifdef DEBUG - PrintStatusTransition(Module::kErrored); -#endif // DEBUG - set_status(Module::kErrored); - set_exception(the_exception); + if (module->IsSourceTextModule()) { + Handle<SourceTextModule> source_text_module = + Handle<SourceTextModule>::cast(module); + export_count = source_text_module->regular_exports().length(); + SourceTextModule::Reset(isolate, source_text_module); + } else { + export_count = + Handle<SyntheticModule>::cast(module)->export_names().length(); + // Nothing to do here. + } + + Handle<ObjectHashTable> exports = ObjectHashTable::New(isolate, export_count); + + module->set_exports(*exports); + module->set_status(kUninstantiated); } Object Module::GetException() { @@ -267,46 +133,6 @@ Object Module::GetException() { return exception(); } -SharedFunctionInfo Module::GetSharedFunctionInfo() const { - DisallowHeapAllocation no_alloc; - DCHECK_NE(status(), Module::kEvaluating); - DCHECK_NE(status(), Module::kEvaluated); - switch (status()) { - case kUninstantiated: - case kPreInstantiating: - DCHECK(code().IsSharedFunctionInfo()); - return SharedFunctionInfo::cast(code()); - case kInstantiating: - DCHECK(code().IsJSFunction()); - return JSFunction::cast(code()).shared(); - case kInstantiated: - DCHECK(code().IsJSGeneratorObject()); - return JSGeneratorObject::cast(code()).function().shared(); - case kEvaluating: - case kEvaluated: - case kErrored: - UNREACHABLE(); - } - - UNREACHABLE(); -} - -MaybeHandle<Cell> Module::ResolveImport(Isolate* isolate, Handle<Module> module, - Handle<String> name, int module_request, - MessageLocation loc, bool must_resolve, - Module::ResolveSet* resolve_set) { - Handle<Module> requested_module( - Module::cast(module->requested_modules().get(module_request)), isolate); - Handle<String> specifier( - String::cast(module->info().module_requests().get(module_request)), - isolate); - MaybeHandle<Cell> result = - Module::ResolveExport(isolate, requested_module, specifier, name, loc, - must_resolve, resolve_set); - DCHECK_IMPLIES(isolate->has_pending_exception(), result.is_null()); - return result; -} - MaybeHandle<Cell> Module::ResolveExport(Isolate* isolate, Handle<Module> module, Handle<String> module_specifier, Handle<String> export_name, @@ -314,121 +140,16 @@ MaybeHandle<Cell> Module::ResolveExport(Isolate* isolate, Handle<Module> module, Module::ResolveSet* resolve_set) { DCHECK_GE(module->status(), kPreInstantiating); DCHECK_NE(module->status(), kEvaluating); - Handle<Object> object(module->exports().Lookup(export_name), isolate); - if (object->IsCell()) { - // Already resolved (e.g. because it's a local export). - return Handle<Cell>::cast(object); - } - // Check for cycle before recursing. - { - // Attempt insertion with a null string set. - auto result = resolve_set->insert({module, nullptr}); - UnorderedStringSet*& name_set = result.first->second; - if (result.second) { - // |module| wasn't in the map previously, so allocate a new name set. - Zone* zone = resolve_set->zone(); - name_set = - new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone); - } else if (name_set->count(export_name)) { - // Cycle detected. - if (must_resolve) { - return isolate->Throw<Cell>( - isolate->factory()->NewSyntaxError( - MessageTemplate::kCyclicModuleDependency, export_name, - module_specifier), - &loc); - } - return MaybeHandle<Cell>(); - } - name_set->insert(export_name); + if (module->IsSourceTextModule()) { + return SourceTextModule::ResolveExport( + isolate, Handle<SourceTextModule>::cast(module), module_specifier, + export_name, loc, must_resolve, resolve_set); + } else { + return SyntheticModule::ResolveExport( + isolate, Handle<SyntheticModule>::cast(module), module_specifier, + export_name, loc, must_resolve); } - - if (object->IsModuleInfoEntry()) { - // Not yet resolved indirect export. - Handle<ModuleInfoEntry> entry = Handle<ModuleInfoEntry>::cast(object); - Handle<String> import_name(String::cast(entry->import_name()), isolate); - Handle<Script> script(module->script(), isolate); - MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos()); - - Handle<Cell> cell; - if (!ResolveImport(isolate, module, import_name, entry->module_request(), - new_loc, true, resolve_set) - .ToHandle(&cell)) { - DCHECK(isolate->has_pending_exception()); - return MaybeHandle<Cell>(); - } - - // The export table may have changed but the entry in question should be - // unchanged. - Handle<ObjectHashTable> exports(module->exports(), isolate); - DCHECK(exports->Lookup(export_name).IsModuleInfoEntry()); - - exports = ObjectHashTable::Put(exports, export_name, cell); - module->set_exports(*exports); - return cell; - } - - DCHECK(object->IsTheHole(isolate)); - return Module::ResolveExportUsingStarExports(isolate, module, - module_specifier, export_name, - loc, must_resolve, resolve_set); -} - -MaybeHandle<Cell> Module::ResolveExportUsingStarExports( - Isolate* isolate, Handle<Module> module, Handle<String> module_specifier, - Handle<String> export_name, MessageLocation loc, bool must_resolve, - Module::ResolveSet* resolve_set) { - if (!export_name->Equals(ReadOnlyRoots(isolate).default_string())) { - // Go through all star exports looking for the given name. If multiple star - // exports provide the name, make sure they all map it to the same cell. - Handle<Cell> unique_cell; - Handle<FixedArray> special_exports(module->info().special_exports(), - isolate); - for (int i = 0, n = special_exports->length(); i < n; ++i) { - i::Handle<i::ModuleInfoEntry> entry( - i::ModuleInfoEntry::cast(special_exports->get(i)), isolate); - if (!entry->export_name().IsUndefined(isolate)) { - continue; // Indirect export. - } - - Handle<Script> script(module->script(), isolate); - MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos()); - - Handle<Cell> cell; - if (ResolveImport(isolate, module, export_name, entry->module_request(), - new_loc, false, resolve_set) - .ToHandle(&cell)) { - if (unique_cell.is_null()) unique_cell = cell; - if (*unique_cell != *cell) { - return isolate->Throw<Cell>(isolate->factory()->NewSyntaxError( - MessageTemplate::kAmbiguousExport, - module_specifier, export_name), - &loc); - } - } else if (isolate->has_pending_exception()) { - return MaybeHandle<Cell>(); - } - } - - if (!unique_cell.is_null()) { - // Found a unique star export for this name. - Handle<ObjectHashTable> exports(module->exports(), isolate); - DCHECK(exports->Lookup(export_name).IsTheHole(isolate)); - exports = ObjectHashTable::Put(exports, export_name, unique_cell); - module->set_exports(*exports); - return unique_cell; - } - } - - // Unresolvable. - if (must_resolve) { - return isolate->Throw<Cell>( - isolate->factory()->NewSyntaxError(MessageTemplate::kUnresolvableExport, - module_specifier, export_name), - &loc); - } - return MaybeHandle<Cell>(); } bool Module::Instantiate(Isolate* isolate, Handle<Module> module, @@ -438,7 +159,14 @@ bool Module::Instantiate(Isolate* isolate, Handle<Module> module, if (FLAG_trace_module_status) { StdoutStream os; os << "Instantiating module "; - module->script().GetNameOrSourceURL().Print(os); + if (module->IsSourceTextModule()) { + Handle<SourceTextModule>::cast(module) + ->script() + .GetNameOrSourceURL() + .Print(os); + } else { + Handle<SyntheticModule>::cast(module)->name().Print(os); + } #ifndef OBJECT_PRINT os << "\n"; #endif // OBJECT_PRINT @@ -450,7 +178,7 @@ bool Module::Instantiate(Isolate* isolate, Handle<Module> module, return false; } Zone zone(isolate->allocator(), ZONE_NAME); - ZoneForwardList<Handle<Module>> stack(&zone); + ZoneForwardList<Handle<SourceTextModule>> stack(&zone); unsigned dfs_index = 0; if (!FinishInstantiate(isolate, module, &stack, &dfs_index, &zone)) { for (auto& descendant : stack) { @@ -474,188 +202,31 @@ bool Module::PrepareInstantiate(Isolate* isolate, Handle<Module> module, module->SetStatus(kPreInstantiating); STACK_CHECK(isolate, false); - // Obtain requested modules. - Handle<ModuleInfo> module_info(module->info(), isolate); - Handle<FixedArray> module_requests(module_info->module_requests(), isolate); - Handle<FixedArray> requested_modules(module->requested_modules(), isolate); - for (int i = 0, length = module_requests->length(); i < length; ++i) { - Handle<String> specifier(String::cast(module_requests->get(i)), isolate); - v8::Local<v8::Module> api_requested_module; - if (!callback(context, v8::Utils::ToLocal(specifier), - v8::Utils::ToLocal(module)) - .ToLocal(&api_requested_module)) { - isolate->PromoteScheduledException(); - return false; - } - Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module); - requested_modules->set(i, *requested_module); - } - - // Recurse. - for (int i = 0, length = requested_modules->length(); i < length; ++i) { - Handle<Module> requested_module(Module::cast(requested_modules->get(i)), - isolate); - if (!PrepareInstantiate(isolate, requested_module, context, callback)) { - return false; - } - } - - // Set up local exports. - // TODO(neis): Create regular_exports array here instead of in factory method? - for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) { - int cell_index = module_info->RegularExportCellIndex(i); - Handle<FixedArray> export_names(module_info->RegularExportExportNames(i), - isolate); - CreateExport(isolate, module, cell_index, export_names); - } - - // Partially set up indirect exports. - // For each indirect export, we create the appropriate slot in the export - // table and store its ModuleInfoEntry there. When we later find the correct - // Cell in the module that actually provides the value, we replace the - // ModuleInfoEntry by that Cell (see ResolveExport). - Handle<FixedArray> special_exports(module_info->special_exports(), isolate); - for (int i = 0, n = special_exports->length(); i < n; ++i) { - Handle<ModuleInfoEntry> entry( - ModuleInfoEntry::cast(special_exports->get(i)), isolate); - Handle<Object> export_name(entry->export_name(), isolate); - if (export_name->IsUndefined(isolate)) continue; // Star export. - CreateIndirectExport(isolate, module, Handle<String>::cast(export_name), - entry); - } - - DCHECK_EQ(module->status(), kPreInstantiating); - return true; -} - -bool Module::RunInitializationCode(Isolate* isolate, Handle<Module> module) { - DCHECK_EQ(module->status(), kInstantiating); - Handle<JSFunction> function(JSFunction::cast(module->code()), isolate); - DCHECK_EQ(MODULE_SCOPE, function->shared().scope_info().scope_type()); - Handle<Object> receiver = isolate->factory()->undefined_value(); - Handle<Object> argv[] = {module}; - MaybeHandle<Object> maybe_generator = - Execution::Call(isolate, function, receiver, arraysize(argv), argv); - Handle<Object> generator; - if (!maybe_generator.ToHandle(&generator)) { - DCHECK(isolate->has_pending_exception()); - return false; - } - DCHECK_EQ(*function, Handle<JSGeneratorObject>::cast(generator)->function()); - module->set_code(*generator); - return true; -} - -bool Module::MaybeTransitionComponent(Isolate* isolate, Handle<Module> module, - ZoneForwardList<Handle<Module>>* stack, - Status new_status) { - DCHECK(new_status == kInstantiated || new_status == kEvaluated); - SLOW_DCHECK( - // {module} is on the {stack}. - std::count_if(stack->begin(), stack->end(), - [&](Handle<Module> m) { return *m == *module; }) == 1); - DCHECK_LE(module->dfs_ancestor_index(), module->dfs_index()); - if (module->dfs_ancestor_index() == module->dfs_index()) { - // This is the root of its strongly connected component. - Handle<Module> ancestor; - do { - ancestor = stack->front(); - stack->pop_front(); - DCHECK_EQ(ancestor->status(), - new_status == kInstantiated ? kInstantiating : kEvaluating); - if (new_status == kInstantiated) { - if (!RunInitializationCode(isolate, ancestor)) return false; - } - ancestor->SetStatus(new_status); - } while (*ancestor != *module); + if (module->IsSourceTextModule()) { + return SourceTextModule::PrepareInstantiate( + isolate, Handle<SourceTextModule>::cast(module), context, callback); + } else { + return SyntheticModule::PrepareInstantiate( + isolate, Handle<SyntheticModule>::cast(module), context, callback); } - return true; } bool Module::FinishInstantiate(Isolate* isolate, Handle<Module> module, - ZoneForwardList<Handle<Module>>* stack, + ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index, Zone* zone) { DCHECK_NE(module->status(), kEvaluating); if (module->status() >= kInstantiating) return true; DCHECK_EQ(module->status(), kPreInstantiating); STACK_CHECK(isolate, false); - // Instantiate SharedFunctionInfo and mark module as instantiating for - // the recursion. - Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()), - isolate); - Handle<JSFunction> function = - isolate->factory()->NewFunctionFromSharedFunctionInfo( - shared, isolate->native_context()); - module->set_code(*function); - module->SetStatus(kInstantiating); - module->set_dfs_index(*dfs_index); - module->set_dfs_ancestor_index(*dfs_index); - stack->push_front(module); - (*dfs_index)++; - - // Recurse. - Handle<FixedArray> requested_modules(module->requested_modules(), isolate); - for (int i = 0, length = requested_modules->length(); i < length; ++i) { - Handle<Module> requested_module(Module::cast(requested_modules->get(i)), - isolate); - if (!FinishInstantiate(isolate, requested_module, stack, dfs_index, zone)) { - return false; - } - - DCHECK_NE(requested_module->status(), kEvaluating); - DCHECK_GE(requested_module->status(), kInstantiating); - SLOW_DCHECK( - // {requested_module} is instantiating iff it's on the {stack}. - (requested_module->status() == kInstantiating) == - std::count_if(stack->begin(), stack->end(), [&](Handle<Module> m) { - return *m == *requested_module; - })); - - if (requested_module->status() == kInstantiating) { - module->set_dfs_ancestor_index( - std::min(module->dfs_ancestor_index(), - requested_module->dfs_ancestor_index())); - } + if (module->IsSourceTextModule()) { + return SourceTextModule::FinishInstantiate( + isolate, Handle<SourceTextModule>::cast(module), stack, dfs_index, + zone); + } else { + return SyntheticModule::FinishInstantiate( + isolate, Handle<SyntheticModule>::cast(module)); } - - Handle<Script> script(module->script(), isolate); - Handle<ModuleInfo> module_info(module->info(), isolate); - - // Resolve imports. - Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate); - for (int i = 0, n = regular_imports->length(); i < n; ++i) { - Handle<ModuleInfoEntry> entry( - ModuleInfoEntry::cast(regular_imports->get(i)), isolate); - Handle<String> name(String::cast(entry->import_name()), isolate); - MessageLocation loc(script, entry->beg_pos(), entry->end_pos()); - ResolveSet resolve_set(zone); - Handle<Cell> cell; - if (!ResolveImport(isolate, module, name, entry->module_request(), loc, - true, &resolve_set) - .ToHandle(&cell)) { - return false; - } - module->regular_imports().set(ImportIndex(entry->cell_index()), *cell); - } - - // Resolve indirect exports. - Handle<FixedArray> special_exports(module_info->special_exports(), isolate); - for (int i = 0, n = special_exports->length(); i < n; ++i) { - Handle<ModuleInfoEntry> entry( - ModuleInfoEntry::cast(special_exports->get(i)), isolate); - Handle<Object> name(entry->export_name(), isolate); - if (name->IsUndefined(isolate)) continue; // Star export. - MessageLocation loc(script, entry->beg_pos(), entry->end_pos()); - ResolveSet resolve_set(zone); - if (ResolveExport(isolate, module, Handle<String>(), - Handle<String>::cast(name), loc, true, &resolve_set) - .is_null()) { - return false; - } - } - - return MaybeTransitionComponent(isolate, module, stack, kInstantiated); } MaybeHandle<Object> Module::Evaluate(Isolate* isolate, Handle<Module> module) { @@ -663,7 +234,14 @@ MaybeHandle<Object> Module::Evaluate(Isolate* isolate, Handle<Module> module) { if (FLAG_trace_module_status) { StdoutStream os; os << "Evaluating module "; - module->script().GetNameOrSourceURL().Print(os); + if (module->IsSourceTextModule()) { + Handle<SourceTextModule>::cast(module) + ->script() + .GetNameOrSourceURL() + .Print(os); + } else { + Handle<SyntheticModule>::cast(module)->name().Print(os); + } #ifndef OBJECT_PRINT os << "\n"; #endif // OBJECT_PRINT @@ -677,7 +255,7 @@ MaybeHandle<Object> Module::Evaluate(Isolate* isolate, Handle<Module> module) { DCHECK_GE(module->status(), kInstantiated); Zone zone(isolate->allocator(), ZONE_NAME); - ZoneForwardList<Handle<Module>> stack(&zone); + ZoneForwardList<Handle<SourceTextModule>> stack(&zone); unsigned dfs_index = 0; Handle<Object> result; if (!Evaluate(isolate, module, &stack, &dfs_index).ToHandle(&result)) { @@ -693,9 +271,9 @@ MaybeHandle<Object> Module::Evaluate(Isolate* isolate, Handle<Module> module) { return result; } -MaybeHandle<Object> Module::Evaluate(Isolate* isolate, Handle<Module> module, - ZoneForwardList<Handle<Module>>* stack, - unsigned* dfs_index) { +MaybeHandle<Object> Module::Evaluate( + Isolate* isolate, Handle<Module> module, + ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index) { if (module->status() == kErrored) { isolate->Throw(module->GetException()); return MaybeHandle<Object>(); @@ -706,134 +284,13 @@ MaybeHandle<Object> Module::Evaluate(Isolate* isolate, Handle<Module> module, DCHECK_EQ(module->status(), kInstantiated); STACK_CHECK(isolate, MaybeHandle<Object>()); - Handle<JSGeneratorObject> generator(JSGeneratorObject::cast(module->code()), - isolate); - module->set_code( - generator->function().shared().scope_info().ModuleDescriptorInfo()); - module->SetStatus(kEvaluating); - module->set_dfs_index(*dfs_index); - module->set_dfs_ancestor_index(*dfs_index); - stack->push_front(module); - (*dfs_index)++; - - // Recursion. - Handle<FixedArray> requested_modules(module->requested_modules(), isolate); - for (int i = 0, length = requested_modules->length(); i < length; ++i) { - Handle<Module> requested_module(Module::cast(requested_modules->get(i)), - isolate); - RETURN_ON_EXCEPTION( - isolate, Evaluate(isolate, requested_module, stack, dfs_index), Object); - - DCHECK_GE(requested_module->status(), kEvaluating); - DCHECK_NE(requested_module->status(), kErrored); - SLOW_DCHECK( - // {requested_module} is evaluating iff it's on the {stack}. - (requested_module->status() == kEvaluating) == - std::count_if(stack->begin(), stack->end(), [&](Handle<Module> m) { - return *m == *requested_module; - })); - - if (requested_module->status() == kEvaluating) { - module->set_dfs_ancestor_index( - std::min(module->dfs_ancestor_index(), - requested_module->dfs_ancestor_index())); - } + if (module->IsSourceTextModule()) { + return SourceTextModule::Evaluate( + isolate, Handle<SourceTextModule>::cast(module), stack, dfs_index); + } else { + return SyntheticModule::Evaluate(isolate, + Handle<SyntheticModule>::cast(module)); } - - // Evaluation of module body. - Handle<JSFunction> resume( - isolate->native_context()->generator_next_internal(), isolate); - Handle<Object> result; - ASSIGN_RETURN_ON_EXCEPTION( - isolate, result, Execution::Call(isolate, resume, generator, 0, nullptr), - Object); - DCHECK(JSIteratorResult::cast(*result).done().BooleanValue(isolate)); - - CHECK(MaybeTransitionComponent(isolate, module, stack, kEvaluated)); - return handle(JSIteratorResult::cast(*result).value(), isolate); -} - -namespace { - -void FetchStarExports(Isolate* isolate, Handle<Module> module, Zone* zone, - UnorderedModuleSet* visited) { - DCHECK_GE(module->status(), Module::kInstantiating); - - if (module->module_namespace().IsJSModuleNamespace()) return; // Shortcut. - - bool cycle = !visited->insert(module).second; - if (cycle) return; - Handle<ObjectHashTable> exports(module->exports(), isolate); - UnorderedStringMap more_exports(zone); - - // TODO(neis): Only allocate more_exports if there are star exports. - // Maybe split special_exports into indirect_exports and star_exports. - - ReadOnlyRoots roots(isolate); - Handle<FixedArray> special_exports(module->info().special_exports(), isolate); - for (int i = 0, n = special_exports->length(); i < n; ++i) { - Handle<ModuleInfoEntry> entry( - ModuleInfoEntry::cast(special_exports->get(i)), isolate); - if (!entry->export_name().IsUndefined(roots)) { - continue; // Indirect export. - } - - Handle<Module> requested_module( - Module::cast(module->requested_modules().get(entry->module_request())), - isolate); - - // Recurse. - FetchStarExports(isolate, requested_module, zone, visited); - - // Collect all of [requested_module]'s exports that must be added to - // [module]'s exports (i.e. to [exports]). We record these in - // [more_exports]. Ambiguities (conflicting exports) are marked by mapping - // the name to undefined instead of a Cell. - Handle<ObjectHashTable> requested_exports(requested_module->exports(), - isolate); - for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) { - Object key; - if (!requested_exports->ToKey(roots, i, &key)) continue; - Handle<String> name(String::cast(key), isolate); - - if (name->Equals(roots.default_string())) continue; - if (!exports->Lookup(name).IsTheHole(roots)) continue; - - Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate); - auto insert_result = more_exports.insert(std::make_pair(name, cell)); - if (!insert_result.second) { - auto it = insert_result.first; - if (*it->second == *cell || it->second->IsUndefined(roots)) { - // We already recorded this mapping before, or the name is already - // known to be ambiguous. In either case, there's nothing to do. - } else { - DCHECK(it->second->IsCell()); - // Different star exports provide different cells for this name, hence - // mark the name as ambiguous. - it->second = roots.undefined_value_handle(); - } - } - } - } - - // Copy [more_exports] into [exports]. - for (const auto& elem : more_exports) { - if (elem.second->IsUndefined(isolate)) continue; // Ambiguous export. - DCHECK(!elem.first->Equals(ReadOnlyRoots(isolate).default_string())); - DCHECK(elem.second->IsCell()); - exports = ObjectHashTable::Put(exports, elem.first, elem.second); - } - module->set_exports(*exports); -} - -} // anonymous namespace - -Handle<JSModuleNamespace> Module::GetModuleNamespace(Isolate* isolate, - Handle<Module> module, - int module_request) { - Handle<Module> requested_module( - Module::cast(module->requested_modules().get(module_request)), isolate); - return Module::GetModuleNamespace(isolate, requested_module); } Handle<JSModuleNamespace> Module::GetModuleNamespace(Isolate* isolate, @@ -848,7 +305,12 @@ Handle<JSModuleNamespace> Module::GetModuleNamespace(Isolate* isolate, // Collect the export names. Zone zone(isolate->allocator(), ZONE_NAME); UnorderedModuleSet visited(&zone); - FetchStarExports(isolate, module, &zone, &visited); + + if (module->IsSourceTextModule()) { + SourceTextModule::FetchStarExports( + isolate, Handle<SourceTextModule>::cast(module), &zone, &visited); + } + Handle<ObjectHashTable> exports(module->exports(), isolate); ZoneVector<Handle<String>> names(&zone); names.reserve(exports->NumberOfElements()); @@ -874,7 +336,7 @@ Handle<JSModuleNamespace> Module::GetModuleNamespace(Isolate* isolate, // Create the properties in the namespace object. Transition the object // to dictionary mode so that property addition is faster. PropertyAttributes attr = DONT_DELETE; - JSObject::NormalizeProperties(ns, CLEAR_INOBJECT_PROPERTIES, + JSObject::NormalizeProperties(isolate, ns, CLEAR_INOBJECT_PROPERTIES, static_cast<int>(names.size()), "JSModuleNamespace"); for (const auto& name : names) { diff --git a/chromium/v8/src/objects/module.h b/chromium/v8/src/objects/module.h index a1672dce7e9..b776ddb0be1 100644 --- a/chromium/v8/src/objects/module.h +++ b/chromium/v8/src/objects/module.h @@ -9,6 +9,7 @@ #include "src/objects/js-objects.h" #include "src/objects/objects.h" #include "src/objects/struct.h" +#include "torque-generated/field-offsets-tq.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -20,35 +21,23 @@ template <typename T> class Handle; class Isolate; class JSModuleNamespace; -class ModuleDescriptor; -class ModuleInfo; -class ModuleInfoEntry; +class SourceTextModuleDescriptor; +class SourceTextModuleInfo; +class SourceTextModuleInfoEntry; class String; class Zone; -// The runtime representation of an ECMAScript module. -class Module : public Struct { +// Module is the base class for ECMAScript module types, roughly corresponding +// to Abstract Module Record. +// https://tc39.github.io/ecma262/#sec-abstract-module-records +class Module : public HeapObject { public: NEVER_READ_ONLY_SPACE DECL_CAST(Module) DECL_VERIFIER(Module) DECL_PRINTER(Module) - // The code representing this module, or an abstraction thereof. - // This is either a SharedFunctionInfo, a JSFunction, a JSGeneratorObject, or - // a ModuleInfo, depending on the state (status) the module is in. See - // Module::ModuleVerify() for the precise invariant. - DECL_ACCESSORS(code, Object) - - // Arrays of cells corresponding to regular exports and regular imports. - // A cell's position in the array is determined by the cell index of the - // associated module entry (which coincides with the variable index of the - // associated variable). - DECL_ACCESSORS(regular_exports, FixedArray) - DECL_ACCESSORS(regular_imports, FixedArray) - // The complete export table, mapping an export name to its cell. - // TODO(neis): We may want to remove the regular exports from the table. DECL_ACCESSORS(exports, ObjectHashTable) // Hash for this object (a random non-zero Smi). @@ -67,31 +56,12 @@ class Module : public Struct { kErrored }; - // The exception in the case {status} is kErrored. - Object GetException(); - - // The shared function info in case {status} is not kEvaluating, kEvaluated or - // kErrored. - SharedFunctionInfo GetSharedFunctionInfo() const; - // The namespace object (or undefined). DECL_ACCESSORS(module_namespace, HeapObject) - // Modules imported or re-exported by this module. - // Corresponds 1-to-1 to the module specifier strings in - // ModuleInfo::module_requests. - DECL_ACCESSORS(requested_modules, FixedArray) - - // [script]: Script from which the module originates. - DECL_ACCESSORS(script, Script) - - // The value of import.meta inside of this module. - // Lazily initialized on first access. It's the hole before first access and - // a JSObject afterwards. - DECL_ACCESSORS(import_meta, Object) - - // Get the ModuleInfo associated with the code. - inline ModuleInfo info() const; + // The exception in the case {status} is kErrored. + Object GetException(); + DECL_ACCESSORS(exception, Object) // Implementation of spec operation ModuleDeclarationInstantiation. // Returns false if an exception occurred during instantiation, true @@ -105,63 +75,20 @@ class Module : public Struct { static V8_WARN_UNUSED_RESULT MaybeHandle<Object> Evaluate( Isolate* isolate, Handle<Module> module); - Cell GetCell(int cell_index); - static Handle<Object> LoadVariable(Isolate* isolate, Handle<Module> module, - int cell_index); - static void StoreVariable(Handle<Module> module, int cell_index, - Handle<Object> value); - - static int ImportIndex(int cell_index); - static int ExportIndex(int cell_index); - - // Get the namespace object for [module_request] of [module]. If it doesn't - // exist yet, it is created. - static Handle<JSModuleNamespace> GetModuleNamespace(Isolate* isolate, - Handle<Module> module, - int module_request); - // Get the namespace object for [module]. If it doesn't exist yet, it is // created. static Handle<JSModuleNamespace> GetModuleNamespace(Isolate* isolate, Handle<Module> module); // Layout description. -#define MODULE_FIELDS(V) \ - V(kCodeOffset, kTaggedSize) \ - V(kExportsOffset, kTaggedSize) \ - V(kRegularExportsOffset, kTaggedSize) \ - V(kRegularImportsOffset, kTaggedSize) \ - V(kHashOffset, kTaggedSize) \ - V(kModuleNamespaceOffset, kTaggedSize) \ - V(kRequestedModulesOffset, kTaggedSize) \ - V(kStatusOffset, kTaggedSize) \ - V(kDfsIndexOffset, kTaggedSize) \ - V(kDfsAncestorIndexOffset, kTaggedSize) \ - V(kExceptionOffset, kTaggedSize) \ - V(kScriptOffset, kTaggedSize) \ - V(kImportMetaOffset, kTaggedSize) \ - /* Total size. */ \ - V(kSize, 0) - - DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize, MODULE_FIELDS) -#undef MODULE_FIELDS - - private: - friend class Factory; - - DECL_ACCESSORS(exception, Object) - - // TODO(neis): Don't store those in the module object? - DECL_INT_ACCESSORS(dfs_index) - DECL_INT_ACCESSORS(dfs_ancestor_index) + DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize, + TORQUE_GENERATED_MODULE_FIELDS) - // Helpers for Instantiate and Evaluate. + using BodyDescriptor = + FixedBodyDescriptor<kExportsOffset, kHeaderSize, kHeaderSize>; - static void CreateExport(Isolate* isolate, Handle<Module> module, - int cell_index, Handle<FixedArray> names); - static void CreateIndirectExport(Isolate* isolate, Handle<Module> module, - Handle<String> name, - Handle<ModuleInfoEntry> entry); + protected: + friend class Factory; // The [must_resolve] argument indicates whether or not an exception should be // thrown in case the module does not provide an export named [name] @@ -176,32 +103,18 @@ class Module : public Struct { Isolate* isolate, Handle<Module> module, Handle<String> module_specifier, Handle<String> export_name, MessageLocation loc, bool must_resolve, ResolveSet* resolve_set); - static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveImport( - Isolate* isolate, Handle<Module> module, Handle<String> name, - int module_request, MessageLocation loc, bool must_resolve, - ResolveSet* resolve_set); - - static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExportUsingStarExports( - Isolate* isolate, Handle<Module> module, Handle<String> module_specifier, - Handle<String> export_name, MessageLocation loc, bool must_resolve, - ResolveSet* resolve_set); static V8_WARN_UNUSED_RESULT bool PrepareInstantiate( Isolate* isolate, Handle<Module> module, v8::Local<v8::Context> context, v8::Module::ResolveCallback callback); static V8_WARN_UNUSED_RESULT bool FinishInstantiate( Isolate* isolate, Handle<Module> module, - ZoneForwardList<Handle<Module>>* stack, unsigned* dfs_index, Zone* zone); - static V8_WARN_UNUSED_RESULT bool RunInitializationCode( - Isolate* isolate, Handle<Module> module); + ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index, + Zone* zone); static V8_WARN_UNUSED_RESULT MaybeHandle<Object> Evaluate( Isolate* isolate, Handle<Module> module, - ZoneForwardList<Handle<Module>>* stack, unsigned* dfs_index); - - static V8_WARN_UNUSED_RESULT bool MaybeTransitionComponent( - Isolate* isolate, Handle<Module> module, - ZoneForwardList<Handle<Module>>* stack, Status new_status); + ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index); // Set module's status back to kUninstantiated and reset other internal state. // This is used when instantiation fails. @@ -217,7 +130,7 @@ class Module : public Struct { void PrintStatusTransition(Status new_status); #endif // DEBUG - OBJECT_CONSTRUCTORS(Module, Struct); + OBJECT_CONSTRUCTORS(Module, HeapObject); }; // When importing a module namespace (import * as foo from "bar"), a @@ -250,93 +163,16 @@ class JSModuleNamespace : public JSObject { kInObjectFieldCount, }; -// Layout description. -#define JS_MODULE_NAMESPACE_FIELDS(V) \ - V(kModuleOffset, kTaggedSize) \ - /* Header size. */ \ - V(kHeaderSize, 0) \ - V(kInObjectFieldsOffset, kTaggedSize* kInObjectFieldCount) \ - /* Total size. */ \ - V(kSize, 0) - + // Layout description. DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, - JS_MODULE_NAMESPACE_FIELDS) -#undef JS_MODULE_NAMESPACE_FIELDS - - OBJECT_CONSTRUCTORS(JSModuleNamespace, JSObject); -}; - -// ModuleInfo is to ModuleDescriptor what ScopeInfo is to Scope. -class ModuleInfo : public FixedArray { - public: - DECL_CAST(ModuleInfo) - - static Handle<ModuleInfo> New(Isolate* isolate, Zone* zone, - ModuleDescriptor* descr); - - inline FixedArray module_requests() const; - inline FixedArray special_exports() const; - inline FixedArray regular_exports() const; - inline FixedArray regular_imports() const; - inline FixedArray namespace_imports() const; - inline FixedArray module_request_positions() const; - - // Accessors for [regular_exports]. - int RegularExportCount() const; - String RegularExportLocalName(int i) const; - int RegularExportCellIndex(int i) const; - FixedArray RegularExportExportNames(int i) const; + TORQUE_GENERATED_JSMODULE_NAMESPACE_FIELDS) -#ifdef DEBUG - inline bool Equals(ModuleInfo other) const; -#endif + // We need to include in-object fields + // TODO(v8:8944): improve handling of in-object fields + static constexpr int kSize = + kHeaderSize + (kTaggedSize * kInObjectFieldCount); - private: - friend class Factory; - friend class ModuleDescriptor; - enum { - kModuleRequestsIndex, - kSpecialExportsIndex, - kRegularExportsIndex, - kNamespaceImportsIndex, - kRegularImportsIndex, - kModuleRequestPositionsIndex, - kLength - }; - enum { - kRegularExportLocalNameOffset, - kRegularExportCellIndexOffset, - kRegularExportExportNamesOffset, - kRegularExportLength - }; - OBJECT_CONSTRUCTORS(ModuleInfo, FixedArray); -}; - -class ModuleInfoEntry : public Struct { - public: - DECL_CAST(ModuleInfoEntry) - DECL_PRINTER(ModuleInfoEntry) - DECL_VERIFIER(ModuleInfoEntry) - - DECL_ACCESSORS(export_name, Object) - DECL_ACCESSORS(local_name, Object) - DECL_ACCESSORS(import_name, Object) - DECL_INT_ACCESSORS(module_request) - DECL_INT_ACCESSORS(cell_index) - DECL_INT_ACCESSORS(beg_pos) - DECL_INT_ACCESSORS(end_pos) - - static Handle<ModuleInfoEntry> New(Isolate* isolate, - Handle<Object> export_name, - Handle<Object> local_name, - Handle<Object> import_name, - int module_request, int cell_index, - int beg_pos, int end_pos); - - DEFINE_FIELD_OFFSET_CONSTANTS(Struct::kHeaderSize, - TORQUE_GENERATED_MODULE_INFO_ENTRY_FIELDS) - - OBJECT_CONSTRUCTORS(ModuleInfoEntry, Struct); + OBJECT_CONSTRUCTORS(JSModuleNamespace, JSObject); }; } // namespace internal diff --git a/chromium/v8/src/objects/name-inl.h b/chromium/v8/src/objects/name-inl.h index b3e04bbd50a..8aded12fb5d 100644 --- a/chromium/v8/src/objects/name-inl.h +++ b/chromium/v8/src/objects/name-inl.h @@ -16,14 +16,9 @@ namespace v8 { namespace internal { -OBJECT_CONSTRUCTORS_IMPL(Name, HeapObject) -OBJECT_CONSTRUCTORS_IMPL(Symbol, Name) +TQ_OBJECT_CONSTRUCTORS_IMPL(Name) +TQ_OBJECT_CONSTRUCTORS_IMPL(Symbol) -CAST_ACCESSOR(Name) -CAST_ACCESSOR(Symbol) - -ACCESSORS(Symbol, name, Object, kNameOffset) -INT_ACCESSORS(Symbol, flags, kFlagsOffset) BIT_FIELD_ACCESSORS(Symbol, flags, is_private, Symbol::IsPrivateBit) BIT_FIELD_ACCESSORS(Symbol, flags, is_well_known_symbol, Symbol::IsWellKnownSymbolBit) @@ -44,20 +39,14 @@ void Symbol::set_is_private_name() { set_flags(Symbol::IsPrivateNameBit::update(flags(), true)); } -bool Name::IsUniqueName() const { - uint32_t type = map().instance_type(); +DEF_GETTER(Name, IsUniqueName, bool) { + uint32_t type = map(isolate).instance_type(); bool result = (type & (kIsNotStringMask | kIsNotInternalizedMask)) != (kStringTag | kNotInternalizedTag); SLOW_DCHECK(result == HeapObject::IsUniqueName()); return result; } -uint32_t Name::hash_field() { return ReadField<uint32_t>(kHashFieldOffset); } - -void Name::set_hash_field(uint32_t value) { - WriteField<uint32_t>(kHashFieldOffset, value); -} - bool Name::Equals(Name other) { if (other == *this) return true; if ((this->IsInternalizedString() && other.IsInternalizedString()) || @@ -91,17 +80,17 @@ uint32_t Name::Hash() { return String::cast(*this).ComputeAndSetHash(); } -bool Name::IsInterestingSymbol() const { - return IsSymbol() && Symbol::cast(*this).is_interesting_symbol(); +DEF_GETTER(Name, IsInterestingSymbol, bool) { + return IsSymbol(isolate) && Symbol::cast(*this).is_interesting_symbol(); } -bool Name::IsPrivate() { - return this->IsSymbol() && Symbol::cast(*this).is_private(); +DEF_GETTER(Name, IsPrivate, bool) { + return this->IsSymbol(isolate) && Symbol::cast(*this).is_private(); } -bool Name::IsPrivateName() { +DEF_GETTER(Name, IsPrivateName, bool) { bool is_private_name = - this->IsSymbol() && Symbol::cast(*this).is_private_name(); + this->IsSymbol(isolate) && Symbol::cast(*this).is_private_name(); DCHECK_IMPLIES(is_private_name, IsPrivate()); return is_private_name; } diff --git a/chromium/v8/src/objects/name.h b/chromium/v8/src/objects/name.h index 8b2a8f0a01c..b13aa30fb09 100644 --- a/chromium/v8/src/objects/name.h +++ b/chromium/v8/src/objects/name.h @@ -7,7 +7,7 @@ #include "src/objects/heap-object.h" #include "src/objects/objects.h" -#include "torque-generated/field-offsets-tq.h" +#include "torque-generated/class-definitions-tq.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -17,12 +17,8 @@ namespace internal { // The Name abstract class captures anything that can be used as a property // name, i.e., strings and symbols. All names store a hash value. -class Name : public HeapObject { +class Name : public TorqueGeneratedName<Name, HeapObject> { public: - // Get and set the hash field of the name. - inline uint32_t hash_field(); - inline void set_hash_field(uint32_t value); - // Tells whether the hash code has been computed. inline bool HasHashCode(); @@ -43,15 +39,19 @@ class Name : public HeapObject { // symbol properties are added, so we can optimize lookups on objects // that don't have the flag. inline bool IsInterestingSymbol() const; + inline bool IsInterestingSymbol(Isolate* isolate) const; // If the name is private, it can only name own properties. - inline bool IsPrivate(); + inline bool IsPrivate() const; + inline bool IsPrivate(Isolate* isolate) const; // If the name is a private name, it should behave like a private // symbol but also throw on property access miss. - inline bool IsPrivateName(); + inline bool IsPrivateName() const; + inline bool IsPrivateName(Isolate* isolate) const; inline bool IsUniqueName() const; + inline bool IsUniqueName(Isolate* isolate) const; static inline bool ContainsCachedArrayIndex(uint32_t hash); @@ -62,15 +62,10 @@ class Name : public HeapObject { V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToFunctionName( Isolate* isolate, Handle<Name> name, Handle<String> prefix); - DECL_CAST(Name) - DECL_PRINTER(Name) void NameShortPrint(); int NameShortPrint(Vector<char> str); - DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, - TORQUE_GENERATED_NAME_FIELDS) - // Mask constant for checking if a name has a computed hash code // and if it is a string that is an array index. The least significant bit // indicates whether a hash code has been computed. If the hash code has @@ -131,17 +126,12 @@ class Name : public HeapObject { protected: static inline bool IsHashFieldComputed(uint32_t field); - OBJECT_CONSTRUCTORS(Name, HeapObject); + TQ_OBJECT_CONSTRUCTORS(Name) }; // ES6 symbols. -class Symbol : public Name { +class Symbol : public TorqueGeneratedSymbol<Symbol, Name> { public: - // [name]: The print name of a symbol, or undefined if none. - DECL_ACCESSORS(name, Object) - - DECL_INT_ACCESSORS(flags) - // [is_private]: Whether this is a private symbol. Private symbols can only // be used to designate own properties of objects. DECL_BOOLEAN_ACCESSORS(is_private) @@ -169,15 +159,10 @@ class Symbol : public Name { inline bool is_private_name() const; inline void set_is_private_name(); - DECL_CAST(Symbol) - // Dispatched behavior. DECL_PRINTER(Symbol) DECL_VERIFIER(Symbol) - DEFINE_FIELD_OFFSET_CONSTANTS(Name::kHeaderSize, - TORQUE_GENERATED_SYMBOL_FIELDS) - // Flags layout. #define FLAGS_BIT_FIELDS(V, _) \ V(IsPrivateBit, bool, 1, _) \ @@ -199,7 +184,7 @@ class Symbol : public Name { // TODO(cbruni): remove once the new maptracer is in place. friend class Name; // For PrivateSymbolToName. - OBJECT_CONSTRUCTORS(Symbol, Name); + TQ_OBJECT_CONSTRUCTORS(Symbol) }; } // namespace internal diff --git a/chromium/v8/src/objects/object-list-macros.h b/chromium/v8/src/objects/object-list-macros.h index 78452de5027..c15b212eeca 100644 --- a/chromium/v8/src/objects/object-list-macros.h +++ b/chromium/v8/src/objects/object-list-macros.h @@ -27,6 +27,7 @@ class FunctionLiteral; class FunctionTemplateInfo; class JSAsyncGeneratorObject; class JSGlobalProxy; +class SourceTextModule; class JSPromise; class JSProxy; class JSProxyRevocableResult; @@ -35,7 +36,7 @@ class LayoutDescriptor; class LookupIterator; class FieldType; class Module; -class ModuleInfoEntry; +class SourceTextModuleInfoEntry; class MutableHeapNumber; class ObjectHashTable; class ObjectTemplateInfo; @@ -53,6 +54,7 @@ class ScriptContextTable; class SharedFunctionInfo; class StringStream; class Symbol; +class SyntheticModule; class FeedbackCell; class FeedbackMetadata; class FeedbackVector; @@ -134,10 +136,13 @@ class ZoneForwardList; V(JSAsyncGeneratorObject) \ V(JSBoundFunction) \ V(JSCollection) \ + V(JSCollectionIterator) \ V(JSContextExtensionObject) \ V(JSDataView) \ V(JSDate) \ V(JSError) \ + V(JSFinalizationGroup) \ + V(JSFinalizationGroupCleanupIterator) \ V(JSFunction) \ V(JSGeneratorObject) \ V(JSGlobalObject) \ @@ -147,6 +152,7 @@ class ZoneForwardList; V(JSMessageObject) \ V(JSModuleNamespace) \ V(JSObject) \ + V(JSPrimitiveWrapper) \ V(JSPromise) \ V(JSProxy) \ V(JSReceiver) \ @@ -158,18 +164,15 @@ class ZoneForwardList; V(JSSloppyArgumentsObject) \ V(JSStringIterator) \ V(JSTypedArray) \ - V(JSValue) \ - V(JSWeakRef) \ V(JSWeakCollection) \ - V(JSFinalizationGroup) \ - V(JSFinalizationGroupCleanupIterator) \ + V(JSWeakRef) \ V(JSWeakMap) \ V(JSWeakSet) \ V(LoadHandler) \ V(Map) \ V(MapCache) \ + V(Module) \ V(Microtask) \ - V(ModuleInfo) \ V(MutableHeapNumber) \ V(Name) \ V(NameDictionary) \ @@ -202,6 +205,8 @@ class ZoneForwardList; V(SmallOrderedHashMap) \ V(SmallOrderedHashSet) \ V(SmallOrderedNameDictionary) \ + V(SourceTextModule) \ + V(SourceTextModuleInfo) \ V(StoreHandler) \ V(String) \ V(StringSet) \ @@ -210,6 +215,7 @@ class ZoneForwardList; V(Struct) \ V(Symbol) \ V(SymbolWrapper) \ + V(SyntheticModule) \ V(TemplateInfo) \ V(TemplateList) \ V(ThinString) \ @@ -248,9 +254,17 @@ class ZoneForwardList; #define HEAP_OBJECT_TEMPLATE_TYPE_LIST(V) V(HashTable) +// Logical sub-types of heap objects that don't correspond to a C++ class but +// represent some specialization in terms of additional constraints. +#define HEAP_OBJECT_SPECIALIZED_TYPE_LIST(V) \ + V(CallableApiObject) \ + V(CallableJSProxy) \ + V(NonNullForeign) + #define HEAP_OBJECT_TYPE_LIST(V) \ HEAP_OBJECT_ORDINARY_TYPE_LIST(V) \ - HEAP_OBJECT_TEMPLATE_TYPE_LIST(V) + HEAP_OBJECT_TEMPLATE_TYPE_LIST(V) \ + HEAP_OBJECT_SPECIALIZED_TYPE_LIST(V) #define ODDBALL_LIST(V) \ V(Undefined, undefined_value) \ diff --git a/chromium/v8/src/objects/object-macros-undef.h b/chromium/v8/src/objects/object-macros-undef.h index c8ebf57ce7a..b96c03c00f8 100644 --- a/chromium/v8/src/objects/object-macros-undef.h +++ b/chromium/v8/src/objects/object-macros-undef.h @@ -11,12 +11,16 @@ #undef NEVER_READ_ONLY_SPACE #undef NEVER_READ_ONLY_SPACE_IMPL #undef DECL_PRIMITIVE_ACCESSORS +#undef DECL_SYNCHRONIZED_PRIMITIVE_ACCESSORS #undef DECL_BOOLEAN_ACCESSORS #undef DECL_INT_ACCESSORS +#undef DECL_SYNCHRONIZED_INT_ACCESSORS #undef DECL_INT32_ACCESSORS #undef DECL_UINT16_ACCESSORS #undef DECL_INT16_ACCESSORS #undef DECL_UINT8_ACCESSORS +#undef DECL_GETTER +#undef DEF_GETTER #undef DECL_ACCESSORS #undef DECL_CAST #undef CAST_ACCESSOR @@ -45,13 +49,10 @@ #undef TYPE_CHECKER #undef RELAXED_INT16_ACCESSORS #undef FIELD_ADDR -#undef READ_FIELD -#undef READ_WEAK_FIELD #undef ACQUIRE_READ_FIELD #undef RELAXED_READ_FIELD #undef RELAXED_READ_WEAK_FIELD #undef WRITE_FIELD -#undef WRITE_WEAK_FIELD #undef RELEASE_WRITE_FIELD #undef RELAXED_WRITE_FIELD #undef RELAXED_WRITE_WEAK_FIELD diff --git a/chromium/v8/src/objects/object-macros.h b/chromium/v8/src/objects/object-macros.h index 1f499d4fba0..8f9e51ca9ef 100644 --- a/chromium/v8/src/objects/object-macros.h +++ b/chromium/v8/src/objects/object-macros.h @@ -14,15 +14,18 @@ // for fields that can be written to and read from multiple threads at the same // time. See comments in src/base/atomicops.h for the memory ordering sematics. -#include "src/common/v8memory.h" +#include "src/base/memory.h" // Since this changes visibility, it should always be last in a class // definition. -#define OBJECT_CONSTRUCTORS(Type, ...) \ - public: \ - constexpr Type() : __VA_ARGS__() {} \ - \ - protected: \ +#define OBJECT_CONSTRUCTORS(Type, ...) \ + public: \ + constexpr Type() : __VA_ARGS__() {} \ + \ + protected: \ + template <typename TFieldType, int kFieldOffset> \ + friend class TaggedField; \ + \ explicit inline Type(Address ptr) #define OBJECT_CONSTRUCTORS_IMPL(Type, Super) \ @@ -34,22 +37,27 @@ // TODO(leszeks): Add checks in the factory that we never allocate these // objects in RO space. -#define NEVER_READ_ONLY_SPACE_IMPL(Type) \ - Heap* Type::GetHeap() const { \ - return NeverReadOnlySpaceObject::GetHeap(*this); \ - } \ - Isolate* Type::GetIsolate() const { \ - return NeverReadOnlySpaceObject::GetIsolate(*this); \ +#define NEVER_READ_ONLY_SPACE_IMPL(Type) \ + Heap* Type::GetHeap() const { return GetHeapFromWritableObject(*this); } \ + Isolate* Type::GetIsolate() const { \ + return GetIsolateFromWritableObject(*this); \ } #define DECL_PRIMITIVE_ACCESSORS(name, type) \ inline type name() const; \ inline void set_##name(type value); +#define DECL_SYNCHRONIZED_PRIMITIVE_ACCESSORS(name, type) \ + inline type synchronized_##name() const; \ + inline void synchronized_set_##name(type value); + #define DECL_BOOLEAN_ACCESSORS(name) DECL_PRIMITIVE_ACCESSORS(name, bool) #define DECL_INT_ACCESSORS(name) DECL_PRIMITIVE_ACCESSORS(name, int) +#define DECL_SYNCHRONIZED_INT_ACCESSORS(name) \ + DECL_SYNCHRONIZED_PRIMITIVE_ACCESSORS(name, int) + #define DECL_INT32_ACCESSORS(name) DECL_PRIMITIVE_ACCESSORS(name, int32_t) #define DECL_UINT16_ACCESSORS(name) \ @@ -64,8 +72,22 @@ inline uint8_t name() const; \ inline void set_##name(int value); +// TODO(ishell): eventually isolate-less getters should not be used anymore. +// For full pointer-mode the C++ compiler should optimize away unused isolate +// parameter. +#define DECL_GETTER(name, type) \ + inline type name() const; \ + inline type name(Isolate* isolate) const; + +#define DEF_GETTER(holder, name, type) \ + type holder::name() const { \ + Isolate* isolate = GetIsolateForPtrCompr(*this); \ + return holder::name(isolate); \ + } \ + type holder::name(Isolate* isolate) const + #define DECL_ACCESSORS(name, type) \ - inline type name() const; \ + DECL_GETTER(name, type) \ inline void set_##name(type value, \ WriteBarrierMode mode = UPDATE_WRITE_BARRIER); @@ -112,14 +134,14 @@ #define ACCESSORS_CHECKED2(holder, name, type, offset, get_condition, \ set_condition) \ - type holder::name() const { \ - type value = type::cast(READ_FIELD(*this, offset)); \ + DEF_GETTER(holder, name, type) { \ + type value = TaggedField<type, offset>::load(isolate, *this); \ DCHECK(get_condition); \ return value; \ } \ void holder::set_##name(type value, WriteBarrierMode mode) { \ DCHECK(set_condition); \ - WRITE_FIELD(*this, offset, value); \ + TaggedField<type, offset>::store(*this, value); \ CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode); \ } @@ -129,17 +151,17 @@ #define ACCESSORS(holder, name, type, offset) \ ACCESSORS_CHECKED(holder, name, type, offset, true) -#define SYNCHRONIZED_ACCESSORS_CHECKED2(holder, name, type, offset, \ - get_condition, set_condition) \ - type holder::name() const { \ - type value = type::cast(ACQUIRE_READ_FIELD(*this, offset)); \ - DCHECK(get_condition); \ - return value; \ - } \ - void holder::set_##name(type value, WriteBarrierMode mode) { \ - DCHECK(set_condition); \ - RELEASE_WRITE_FIELD(*this, offset, value); \ - CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode); \ +#define SYNCHRONIZED_ACCESSORS_CHECKED2(holder, name, type, offset, \ + get_condition, set_condition) \ + DEF_GETTER(holder, name, type) { \ + type value = TaggedField<type, offset>::Acquire_Load(isolate, *this); \ + DCHECK(get_condition); \ + return value; \ + } \ + void holder::set_##name(type value, WriteBarrierMode mode) { \ + DCHECK(set_condition); \ + TaggedField<type, offset>::Release_Store(*this, value); \ + CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode); \ } #define SYNCHRONIZED_ACCESSORS_CHECKED(holder, name, type, offset, condition) \ @@ -151,14 +173,15 @@ #define WEAK_ACCESSORS_CHECKED2(holder, name, offset, get_condition, \ set_condition) \ - MaybeObject holder::name() const { \ - MaybeObject value = READ_WEAK_FIELD(*this, offset); \ + DEF_GETTER(holder, name, MaybeObject) { \ + MaybeObject value = \ + TaggedField<MaybeObject, offset>::load(isolate, *this); \ DCHECK(get_condition); \ return value; \ } \ void holder::set_##name(MaybeObject value, WriteBarrierMode mode) { \ DCHECK(set_condition); \ - WRITE_WEAK_FIELD(*this, offset, value); \ + TaggedField<MaybeObject, offset>::store(*this, value); \ CONDITIONAL_WEAK_WRITE_BARRIER(*this, offset, value, mode); \ } @@ -169,36 +192,44 @@ WEAK_ACCESSORS_CHECKED(holder, name, offset, true) // Getter that returns a Smi as an int and writes an int as a Smi. -#define SMI_ACCESSORS_CHECKED(holder, name, offset, condition) \ - int holder::name() const { \ - DCHECK(condition); \ - Object value = READ_FIELD(*this, offset); \ - return Smi::ToInt(value); \ - } \ - void holder::set_##name(int value) { \ - DCHECK(condition); \ - WRITE_FIELD(*this, offset, Smi::FromInt(value)); \ +#define SMI_ACCESSORS_CHECKED(holder, name, offset, condition) \ + int holder::name() const { \ + DCHECK(condition); \ + Smi value = TaggedField<Smi, offset>::load(*this); \ + return value.value(); \ + } \ + void holder::set_##name(int value) { \ + DCHECK(condition); \ + TaggedField<Smi, offset>::store(*this, Smi::FromInt(value)); \ } #define SMI_ACCESSORS(holder, name, offset) \ SMI_ACCESSORS_CHECKED(holder, name, offset, true) -#define SYNCHRONIZED_SMI_ACCESSORS(holder, name, offset) \ - int holder::synchronized_##name() const { \ - Object value = ACQUIRE_READ_FIELD(*this, offset); \ - return Smi::ToInt(value); \ - } \ - void holder::synchronized_set_##name(int value) { \ - RELEASE_WRITE_FIELD(*this, offset, Smi::FromInt(value)); \ +#define SYNCHRONIZED_SMI_ACCESSORS(holder, name, offset) \ + int holder::synchronized_##name() const { \ + Smi value = TaggedField<Smi, offset>::Acquire_Load(*this); \ + return value.value(); \ + } \ + void holder::synchronized_set_##name(int value) { \ + TaggedField<Smi, offset>::Release_Store(*this, Smi::FromInt(value)); \ + } + +#define RELAXED_SMI_ACCESSORS(holder, name, offset) \ + int holder::relaxed_read_##name() const { \ + Smi value = TaggedField<Smi, offset>::Relaxed_Load(*this); \ + return value.value(); \ + } \ + void holder::relaxed_write_##name(int value) { \ + TaggedField<Smi, offset>::Relaxed_Store(*this, Smi::FromInt(value)); \ } -#define RELAXED_SMI_ACCESSORS(holder, name, offset) \ - int holder::relaxed_read_##name() const { \ - Object value = RELAXED_READ_FIELD(*this, offset); \ - return Smi::ToInt(value); \ - } \ - void holder::relaxed_write_##name(int value) { \ - RELAXED_WRITE_FIELD(*this, offset, Smi::FromInt(value)); \ +#define TQ_SMI_ACCESSORS(holder, name) \ + int holder::name() const { \ + return TorqueGenerated##holder<holder, Super>::name().value(); \ + } \ + void holder::set_##name(int value) { \ + TorqueGenerated##holder<holder, Super>::set_##name(Smi::FromInt(value)); \ } #define BOOL_GETTER(holder, field, name, offset) \ @@ -223,9 +254,9 @@ return instance_type == forinstancetype; \ } -#define TYPE_CHECKER(type, ...) \ - bool HeapObject::Is##type() const { \ - return InstanceTypeChecker::Is##type(map().instance_type()); \ +#define TYPE_CHECKER(type, ...) \ + DEF_GETTER(HeapObject, Is##type, bool) { \ + return InstanceTypeChecker::Is##type(map(isolate).instance_type()); \ } #define RELAXED_INT16_ACCESSORS(holder, name, offset) \ @@ -238,39 +269,26 @@ #define FIELD_ADDR(p, offset) ((p).ptr() + offset - kHeapObjectTag) -#define READ_FIELD(p, offset) (*ObjectSlot(FIELD_ADDR(p, offset))) - -#define READ_WEAK_FIELD(p, offset) (*MaybeObjectSlot(FIELD_ADDR(p, offset))) - #define ACQUIRE_READ_FIELD(p, offset) \ - ObjectSlot(FIELD_ADDR(p, offset)).Acquire_Load() + TaggedField<Object>::Acquire_Load(p, offset) #define RELAXED_READ_FIELD(p, offset) \ - ObjectSlot(FIELD_ADDR(p, offset)).Relaxed_Load() + TaggedField<Object>::Relaxed_Load(p, offset) #define RELAXED_READ_WEAK_FIELD(p, offset) \ - MaybeObjectSlot(FIELD_ADDR(p, offset)).Relaxed_Load() + TaggedField<MaybeObject>::Relaxed_Load(p, offset) -#ifdef V8_CONCURRENT_MARKING -#define WRITE_FIELD(p, offset, value) \ - ObjectSlot(FIELD_ADDR(p, offset)).Relaxed_Store(value) -#define WRITE_WEAK_FIELD(p, offset, value) \ - MaybeObjectSlot(FIELD_ADDR(p, offset)).Relaxed_Store(value) -#else #define WRITE_FIELD(p, offset, value) \ - ObjectSlot(FIELD_ADDR(p, offset)).store(value) -#define WRITE_WEAK_FIELD(p, offset, value) \ - MaybeObjectSlot(FIELD_ADDR(p, offset)).store(value) -#endif + TaggedField<Object>::store(p, offset, value) #define RELEASE_WRITE_FIELD(p, offset, value) \ - ObjectSlot(FIELD_ADDR(p, offset)).Release_Store(value) + TaggedField<Object>::Release_Store(p, offset, value) #define RELAXED_WRITE_FIELD(p, offset, value) \ - ObjectSlot(FIELD_ADDR(p, offset)).Relaxed_Store(value) + TaggedField<Object>::Relaxed_Store(p, offset, value) #define RELAXED_WRITE_WEAK_FIELD(p, offset, value) \ - MaybeObjectSlot(FIELD_ADDR(p, offset)).Relaxed_Store(value) + TaggedField<MaybeObject>::Relaxed_Store(p, offset, value) #define WRITE_BARRIER(object, offset, value) \ do { \ @@ -412,12 +430,15 @@ set(IndexForEntry(i) + k##name##Offset, value); \ } -#define TQ_OBJECT_CONSTRUCTORS(Type) \ - public: \ - constexpr Type() = default; \ - \ - protected: \ - inline explicit Type(Address ptr); \ +#define TQ_OBJECT_CONSTRUCTORS(Type) \ + public: \ + constexpr Type() = default; \ + \ + protected: \ + template <typename TFieldType, int kFieldOffset> \ + friend class TaggedField; \ + \ + inline explicit Type(Address ptr); \ friend class TorqueGenerated##Type<Type, Super>; #define TQ_OBJECT_CONSTRUCTORS_IMPL(Type) \ diff --git a/chromium/v8/src/objects/objects-body-descriptors-inl.h b/chromium/v8/src/objects/objects-body-descriptors-inl.h index 86261656478..51e380695ef 100644 --- a/chromium/v8/src/objects/objects-body-descriptors-inl.h +++ b/chromium/v8/src/objects/objects-body-descriptors-inl.h @@ -19,6 +19,8 @@ #include "src/objects/js-weak-refs.h" #include "src/objects/oddball.h" #include "src/objects/ordered-hash-table.h" +#include "src/objects/source-text-module.h" +#include "src/objects/synthetic-module.h" #include "src/objects/transitions.h" #include "src/wasm/wasm-objects-inl.h" @@ -918,7 +920,7 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) { case JS_GENERATOR_OBJECT_TYPE: case JS_ASYNC_FUNCTION_OBJECT_TYPE: case JS_ASYNC_GENERATOR_OBJECT_TYPE: - case JS_VALUE_TYPE: + case JS_PRIMITIVE_WRAPPER_TYPE: case JS_DATE_TYPE: case JS_ARRAY_TYPE: case JS_ARRAY_ITERATOR_TYPE: @@ -1043,6 +1045,9 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) { } else if (type == WASM_CAPI_FUNCTION_DATA_TYPE) { return Op::template apply<WasmCapiFunctionData::BodyDescriptor>(p1, p2, p3, p4); + } else if (type == WASM_INDIRECT_FUNCTION_TABLE_TYPE) { + return Op::template apply<WasmIndirectFunctionTable::BodyDescriptor>( + p1, p2, p3, p4); } else { return Op::template apply<StructBodyDescriptor>(p1, p2, p3, p4); } @@ -1051,6 +1056,12 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) { case LOAD_HANDLER_TYPE: case STORE_HANDLER_TYPE: return Op::template apply<DataHandler::BodyDescriptor>(p1, p2, p3, p4); + case SOURCE_TEXT_MODULE_TYPE: + return Op::template apply<SourceTextModule::BodyDescriptor>(p1, p2, p3, + p4); + case SYNTHETIC_MODULE_TYPE: + return Op::template apply<SyntheticModule::BodyDescriptor>(p1, p2, p3, + p4); default: PrintF("Unknown type: %d\n", type); UNREACHABLE(); diff --git a/chromium/v8/src/objects/objects-definitions.h b/chromium/v8/src/objects/objects-definitions.h index 90824c68efe..b4c8591e5cc 100644 --- a/chromium/v8/src/objects/objects-definitions.h +++ b/chromium/v8/src/objects/objects-definitions.h @@ -7,6 +7,8 @@ #include "src/init/heap-symbols.h" +#include "torque-generated/instance-types-tq.h" + namespace v8 { namespace internal { @@ -31,7 +33,7 @@ namespace internal { // HeapObject::Size, HeapObject::IterateBody, the typeof operator, and // Object::IsString. // -// NOTE: Everything following JS_VALUE_TYPE is considered a +// NOTE: Everything following JS_PRIMITIVE_WRAPPER_TYPE is considered a // JSObject for GC purposes. The first four entries here have typeof // 'object', whereas JS_FUNCTION_TYPE has typeof 'function'. // @@ -80,6 +82,7 @@ namespace internal { V(ACCESSOR_PAIR_TYPE) \ V(ALIASED_ARGUMENTS_ENTRY_TYPE) \ V(ALLOCATION_MEMENTO_TYPE) \ + V(ARRAY_BOILERPLATE_DESCRIPTION_TYPE) \ V(ASM_WASM_DATA_TYPE) \ V(ASYNC_GENERATOR_REQUEST_TYPE) \ V(CLASS_POSITIONS_TYPE) \ @@ -89,24 +92,23 @@ namespace internal { V(FUNCTION_TEMPLATE_RARE_DATA_TYPE) \ V(INTERCEPTOR_INFO_TYPE) \ V(INTERPRETER_DATA_TYPE) \ - V(MODULE_INFO_ENTRY_TYPE) \ - V(MODULE_TYPE) \ V(OBJECT_TEMPLATE_INFO_TYPE) \ V(PROMISE_CAPABILITY_TYPE) \ V(PROMISE_REACTION_TYPE) \ V(PROTOTYPE_INFO_TYPE) \ V(SCRIPT_TYPE) \ V(SOURCE_POSITION_TABLE_WITH_FRAME_CACHE_TYPE) \ + V(SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE) \ V(STACK_FRAME_INFO_TYPE) \ V(STACK_TRACE_FRAME_TYPE) \ V(TEMPLATE_OBJECT_DESCRIPTION_TYPE) \ V(TUPLE2_TYPE) \ V(TUPLE3_TYPE) \ - V(ARRAY_BOILERPLATE_DESCRIPTION_TYPE) \ V(WASM_CAPI_FUNCTION_DATA_TYPE) \ V(WASM_DEBUG_INFO_TYPE) \ V(WASM_EXCEPTION_TAG_TYPE) \ V(WASM_EXPORTED_FUNCTION_DATA_TYPE) \ + V(WASM_INDIRECT_FUNCTION_TABLE_TYPE) \ V(WASM_JS_FUNCTION_DATA_TYPE) \ \ V(CALLABLE_TASK_TYPE) \ @@ -116,6 +118,11 @@ namespace internal { V(PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE) \ V(FINALIZATION_GROUP_CLEANUP_JOB_TASK_TYPE) \ \ + TORQUE_DEFINED_INSTANCE_TYPES(V) \ + \ + V(SOURCE_TEXT_MODULE_TYPE) \ + V(SYNTHETIC_MODULE_TYPE) \ + \ V(ALLOCATION_SITE_TYPE) \ V(EMBEDDER_DATA_ARRAY_TYPE) \ \ @@ -174,7 +181,7 @@ namespace internal { V(JS_GLOBAL_PROXY_TYPE) \ V(JS_MODULE_NAMESPACE_TYPE) \ V(JS_SPECIAL_API_OBJECT_TYPE) \ - V(JS_VALUE_TYPE) \ + V(JS_PRIMITIVE_WRAPPER_TYPE) \ V(JS_API_OBJECT_TYPE) \ V(JS_OBJECT_TYPE) \ \ @@ -296,6 +303,8 @@ namespace internal { V(_, ALIASED_ARGUMENTS_ENTRY_TYPE, AliasedArgumentsEntry, \ aliased_arguments_entry) \ V(_, ALLOCATION_MEMENTO_TYPE, AllocationMemento, allocation_memento) \ + V(_, ARRAY_BOILERPLATE_DESCRIPTION_TYPE, ArrayBoilerplateDescription, \ + array_boilerplate_description) \ V(_, ASM_WASM_DATA_TYPE, AsmWasmData, asm_wasm_data) \ V(_, ASYNC_GENERATOR_REQUEST_TYPE, AsyncGeneratorRequest, \ async_generator_request) \ @@ -308,8 +317,6 @@ namespace internal { function_template_rare_data) \ V(_, INTERCEPTOR_INFO_TYPE, InterceptorInfo, interceptor_info) \ V(_, INTERPRETER_DATA_TYPE, InterpreterData, interpreter_data) \ - V(_, MODULE_INFO_ENTRY_TYPE, ModuleInfoEntry, module_info_entry) \ - V(_, MODULE_TYPE, Module, module) \ V(_, OBJECT_TEMPLATE_INFO_TYPE, ObjectTemplateInfo, object_template_info) \ V(_, PROMISE_CAPABILITY_TYPE, PromiseCapability, promise_capability) \ V(_, PROMISE_REACTION_TYPE, PromiseReaction, promise_reaction) \ @@ -317,20 +324,22 @@ namespace internal { V(_, SCRIPT_TYPE, Script, script) \ V(_, SOURCE_POSITION_TABLE_WITH_FRAME_CACHE_TYPE, \ SourcePositionTableWithFrameCache, source_position_table_with_frame_cache) \ + V(_, SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE, SourceTextModuleInfoEntry, \ + module_info_entry) \ V(_, STACK_FRAME_INFO_TYPE, StackFrameInfo, stack_frame_info) \ V(_, STACK_TRACE_FRAME_TYPE, StackTraceFrame, stack_trace_frame) \ V(_, TEMPLATE_OBJECT_DESCRIPTION_TYPE, TemplateObjectDescription, \ template_object_description) \ V(_, TUPLE2_TYPE, Tuple2, tuple2) \ V(_, TUPLE3_TYPE, Tuple3, tuple3) \ - V(_, ARRAY_BOILERPLATE_DESCRIPTION_TYPE, ArrayBoilerplateDescription, \ - array_boilerplate_description) \ V(_, WASM_CAPI_FUNCTION_DATA_TYPE, WasmCapiFunctionData, \ wasm_capi_function_data) \ V(_, WASM_DEBUG_INFO_TYPE, WasmDebugInfo, wasm_debug_info) \ V(_, WASM_EXCEPTION_TAG_TYPE, WasmExceptionTag, wasm_exception_tag) \ V(_, WASM_EXPORTED_FUNCTION_DATA_TYPE, WasmExportedFunctionData, \ wasm_exported_function_data) \ + V(_, WASM_INDIRECT_FUNCTION_TABLE_TYPE, WasmIndirectFunctionTable, \ + wasm_indirect_function_table) \ V(_, WASM_JS_FUNCTION_DATA_TYPE, WasmJSFunctionData, wasm_js_function_data) \ V(_, CALLABLE_TASK_TYPE, CallableTask, callable_task) \ V(_, CALLBACK_TASK_TYPE, CallbackTask, callback_task) \ @@ -347,14 +356,18 @@ namespace internal { #define STRUCT_LIST_ADAPTER(V, NAME, Name, name) V(NAME, Name, name) // Produces (NAME, Name, name) entries. -#define STRUCT_LIST(V) STRUCT_LIST_GENERATOR(STRUCT_LIST_ADAPTER, V) +#define STRUCT_LIST(V) \ + STRUCT_LIST_GENERATOR(STRUCT_LIST_ADAPTER, V) \ + TORQUE_STRUCT_LIST_GENERATOR(STRUCT_LIST_ADAPTER, V) // Adapts one STRUCT_LIST_GENERATOR entry to the STRUCT_MAPS_LIST entry #define STRUCT_MAPS_LIST_ADAPTER(V, NAME, Name, name) \ V(Map, name##_map, Name##Map) // Produces (Map, struct_name_map, StructNameMap) entries -#define STRUCT_MAPS_LIST(V) STRUCT_LIST_GENERATOR(STRUCT_MAPS_LIST_ADAPTER, V) +#define STRUCT_MAPS_LIST(V) \ + STRUCT_LIST_GENERATOR(STRUCT_MAPS_LIST_ADAPTER, V) \ + TORQUE_STRUCT_LIST_GENERATOR(STRUCT_MAPS_LIST_ADAPTER, V) // // The following macros define list of allocation size objects and list of diff --git a/chromium/v8/src/objects/objects-inl.h b/chromium/v8/src/objects/objects-inl.h index ce92d64f2fd..b6748401c07 100644 --- a/chromium/v8/src/objects/objects-inl.h +++ b/chromium/v8/src/objects/objects-inl.h @@ -15,11 +15,12 @@ #include "src/objects/objects.h" #include "src/base/bits.h" +#include "src/base/memory.h" #include "src/builtins/builtins.h" -#include "src/common/v8memory.h" #include "src/handles/handles-inl.h" #include "src/heap/factory.h" #include "src/heap/heap-write-barrier-inl.h" +#include "src/heap/read-only-heap-inl.h" #include "src/numbers/conversions.h" #include "src/numbers/double.h" #include "src/objects/bigint.h" @@ -37,6 +38,7 @@ #include "src/objects/shared-function-info.h" #include "src/objects/slots-inl.h" #include "src/objects/smi-inl.h" +#include "src/objects/tagged-field-inl.h" #include "src/objects/tagged-impl-inl.h" #include "src/objects/templates.h" #include "src/sanitizer/tsan.h" @@ -64,30 +66,37 @@ int PropertyDetails::field_width_in_words() const { return representation().IsDouble() ? kDoubleSize / kTaggedSize : 1; } -bool HeapObject::IsSloppyArgumentsElements() const { - return IsFixedArrayExact(); +DEF_GETTER(HeapObject, IsSloppyArgumentsElements, bool) { + return IsFixedArrayExact(isolate); } -bool HeapObject::IsJSSloppyArgumentsObject() const { - return IsJSArgumentsObject(); +DEF_GETTER(HeapObject, IsJSSloppyArgumentsObject, bool) { + return IsJSArgumentsObject(isolate); } -bool HeapObject::IsJSGeneratorObject() const { - return map().instance_type() == JS_GENERATOR_OBJECT_TYPE || - IsJSAsyncFunctionObject() || IsJSAsyncGeneratorObject(); +DEF_GETTER(HeapObject, IsJSGeneratorObject, bool) { + return map(isolate).instance_type() == JS_GENERATOR_OBJECT_TYPE || + IsJSAsyncFunctionObject(isolate) || IsJSAsyncGeneratorObject(isolate); } -bool HeapObject::IsDataHandler() const { - return IsLoadHandler() || IsStoreHandler(); +DEF_GETTER(HeapObject, IsDataHandler, bool) { + return IsLoadHandler(isolate) || IsStoreHandler(isolate); } -bool HeapObject::IsClassBoilerplate() const { return IsFixedArrayExact(); } +DEF_GETTER(HeapObject, IsClassBoilerplate, bool) { + return IsFixedArrayExact(isolate); +} -#define IS_TYPE_FUNCTION_DEF(type_) \ - bool Object::Is##type_() const { \ - return IsHeapObject() && HeapObject::cast(*this).Is##type_(); \ +#define IS_TYPE_FUNCTION_DEF(type_) \ + bool Object::Is##type_() const { \ + return IsHeapObject() && HeapObject::cast(*this).Is##type_(); \ + } \ + bool Object::Is##type_(Isolate* isolate) const { \ + return IsHeapObject() && HeapObject::cast(*this).Is##type_(isolate); \ } HEAP_OBJECT_TYPE_LIST(IS_TYPE_FUNCTION_DEF) +IS_TYPE_FUNCTION_DEF(HashTableBase) +IS_TYPE_FUNCTION_DEF(SmallOrderedHashTable) #undef IS_TYPE_FUNCTION_DEF #define IS_TYPE_FUNCTION_DEF(Type, Value) \ @@ -140,109 +149,166 @@ bool HeapObject::IsNullOrUndefined() const { return IsNullOrUndefined(GetReadOnlyRoots()); } -bool HeapObject::IsUniqueName() const { - return IsInternalizedString() || IsSymbol(); +DEF_GETTER(HeapObject, IsUniqueName, bool) { + return IsInternalizedString(isolate) || IsSymbol(isolate); } -bool HeapObject::IsFunction() const { +DEF_GETTER(HeapObject, IsFunction, bool) { STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE); - return map().instance_type() >= FIRST_FUNCTION_TYPE; + return map(isolate).instance_type() >= FIRST_FUNCTION_TYPE; } -bool HeapObject::IsCallable() const { return map().is_callable(); } +DEF_GETTER(HeapObject, IsCallable, bool) { return map(isolate).is_callable(); } -bool HeapObject::IsConstructor() const { return map().is_constructor(); } +DEF_GETTER(HeapObject, IsCallableJSProxy, bool) { + return IsCallable(isolate) && IsJSProxy(isolate); +} -bool HeapObject::IsModuleInfo() const { - return map() == GetReadOnlyRoots().module_info_map(); +DEF_GETTER(HeapObject, IsCallableApiObject, bool) { + InstanceType type = map(isolate).instance_type(); + return IsCallable(isolate) && + (type == JS_API_OBJECT_TYPE || type == JS_SPECIAL_API_OBJECT_TYPE); } -bool HeapObject::IsTemplateInfo() const { - return IsObjectTemplateInfo() || IsFunctionTemplateInfo(); +DEF_GETTER(HeapObject, IsNonNullForeign, bool) { + return IsForeign(isolate) && + Foreign::cast(*this).foreign_address() != kNullAddress; } -bool HeapObject::IsConsString() const { - if (!IsString()) return false; - return StringShape(String::cast(*this)).IsCons(); +DEF_GETTER(HeapObject, IsConstructor, bool) { + return map(isolate).is_constructor(); } -bool HeapObject::IsThinString() const { - if (!IsString()) return false; - return StringShape(String::cast(*this)).IsThin(); +DEF_GETTER(HeapObject, IsSourceTextModuleInfo, bool) { + // Can't use ReadOnlyRoots(isolate) as this isolate could be produced by + // i::GetIsolateForPtrCompr(HeapObject). + return map(isolate) == GetReadOnlyRoots(isolate).module_info_map(); } -bool HeapObject::IsSlicedString() const { - if (!IsString()) return false; - return StringShape(String::cast(*this)).IsSliced(); +DEF_GETTER(HeapObject, IsTemplateInfo, bool) { + return IsObjectTemplateInfo(isolate) || IsFunctionTemplateInfo(isolate); } -bool HeapObject::IsSeqString() const { - if (!IsString()) return false; - return StringShape(String::cast(*this)).IsSequential(); +DEF_GETTER(HeapObject, IsConsString, bool) { + if (!IsString(isolate)) return false; + return StringShape(String::cast(*this).map(isolate)).IsCons(); } -bool HeapObject::IsSeqOneByteString() const { - if (!IsString()) return false; - return StringShape(String::cast(*this)).IsSequential() && - String::cast(*this).IsOneByteRepresentation(); +DEF_GETTER(HeapObject, IsThinString, bool) { + if (!IsString(isolate)) return false; + return StringShape(String::cast(*this).map(isolate)).IsThin(); } -bool HeapObject::IsSeqTwoByteString() const { - if (!IsString()) return false; - return StringShape(String::cast(*this)).IsSequential() && - String::cast(*this).IsTwoByteRepresentation(); +DEF_GETTER(HeapObject, IsSlicedString, bool) { + if (!IsString(isolate)) return false; + return StringShape(String::cast(*this).map(isolate)).IsSliced(); } -bool HeapObject::IsExternalString() const { - if (!IsString()) return false; - return StringShape(String::cast(*this)).IsExternal(); +DEF_GETTER(HeapObject, IsSeqString, bool) { + if (!IsString(isolate)) return false; + return StringShape(String::cast(*this).map(isolate)).IsSequential(); } -bool HeapObject::IsExternalOneByteString() const { - if (!IsString()) return false; - return StringShape(String::cast(*this)).IsExternal() && - String::cast(*this).IsOneByteRepresentation(); +DEF_GETTER(HeapObject, IsSeqOneByteString, bool) { + if (!IsString(isolate)) return false; + return StringShape(String::cast(*this).map(isolate)).IsSequential() && + String::cast(*this).IsOneByteRepresentation(isolate); } -bool HeapObject::IsExternalTwoByteString() const { - if (!IsString()) return false; - return StringShape(String::cast(*this)).IsExternal() && - String::cast(*this).IsTwoByteRepresentation(); +DEF_GETTER(HeapObject, IsSeqTwoByteString, bool) { + if (!IsString(isolate)) return false; + return StringShape(String::cast(*this).map(isolate)).IsSequential() && + String::cast(*this).IsTwoByteRepresentation(isolate); } -bool Object::IsNumber() const { return IsSmi() || IsHeapNumber(); } +DEF_GETTER(HeapObject, IsExternalString, bool) { + if (!IsString(isolate)) return false; + return StringShape(String::cast(*this).map(isolate)).IsExternal(); +} -bool Object::IsNumeric() const { return IsNumber() || IsBigInt(); } +DEF_GETTER(HeapObject, IsExternalOneByteString, bool) { + if (!IsString(isolate)) return false; + return StringShape(String::cast(*this).map(isolate)).IsExternal() && + String::cast(*this).IsOneByteRepresentation(isolate); +} -bool HeapObject::IsFiller() const { - InstanceType instance_type = map().instance_type(); +DEF_GETTER(HeapObject, IsExternalTwoByteString, bool) { + if (!IsString(isolate)) return false; + return StringShape(String::cast(*this).map(isolate)).IsExternal() && + String::cast(*this).IsTwoByteRepresentation(isolate); +} + +bool Object::IsNumber() const { + if (IsSmi()) return true; + HeapObject this_heap_object = HeapObject::cast(*this); + Isolate* isolate = GetIsolateForPtrCompr(this_heap_object); + return this_heap_object.IsHeapNumber(isolate); +} + +bool Object::IsNumber(Isolate* isolate) const { + return IsSmi() || IsHeapNumber(isolate); +} + +bool Object::IsNumeric() const { + if (IsSmi()) return true; + HeapObject this_heap_object = HeapObject::cast(*this); + Isolate* isolate = GetIsolateForPtrCompr(this_heap_object); + return this_heap_object.IsHeapNumber(isolate) || + this_heap_object.IsBigInt(isolate); +} + +bool Object::IsNumeric(Isolate* isolate) const { + return IsNumber(isolate) || IsBigInt(isolate); +} + +DEF_GETTER(HeapObject, IsFiller, bool) { + InstanceType instance_type = map(isolate).instance_type(); return instance_type == FREE_SPACE_TYPE || instance_type == FILLER_TYPE; } -bool HeapObject::IsJSWeakCollection() const { - return IsJSWeakMap() || IsJSWeakSet(); +DEF_GETTER(HeapObject, IsJSWeakCollection, bool) { + return IsJSWeakMap(isolate) || IsJSWeakSet(isolate); +} + +DEF_GETTER(HeapObject, IsJSCollection, bool) { + return IsJSMap(isolate) || IsJSSet(isolate); } -bool HeapObject::IsJSCollection() const { return IsJSMap() || IsJSSet(); } +DEF_GETTER(HeapObject, IsPromiseReactionJobTask, bool) { + return IsPromiseFulfillReactionJobTask(isolate) || + IsPromiseRejectReactionJobTask(isolate); +} -bool HeapObject::IsPromiseReactionJobTask() const { - return IsPromiseFulfillReactionJobTask() || IsPromiseRejectReactionJobTask(); +DEF_GETTER(HeapObject, IsFrameArray, bool) { + return IsFixedArrayExact(isolate); } -bool HeapObject::IsFrameArray() const { return IsFixedArrayExact(); } +DEF_GETTER(HeapObject, IsArrayList, bool) { + // Can't use ReadOnlyRoots(isolate) as this isolate could be produced by + // i::GetIsolateForPtrCompr(HeapObject). + ReadOnlyRoots roots = GetReadOnlyRoots(isolate); + return *this == roots.empty_fixed_array() || + map(isolate) == roots.array_list_map(); +} -bool HeapObject::IsArrayList() const { - return map() == GetReadOnlyRoots().array_list_map() || - *this == GetReadOnlyRoots().empty_fixed_array(); +DEF_GETTER(HeapObject, IsRegExpMatchInfo, bool) { + return IsFixedArrayExact(isolate); } -bool HeapObject::IsRegExpMatchInfo() const { return IsFixedArrayExact(); } +bool Object::IsLayoutDescriptor() const { + if (IsSmi()) return true; + HeapObject this_heap_object = HeapObject::cast(*this); + Isolate* isolate = GetIsolateForPtrCompr(this_heap_object); + return this_heap_object.IsByteArray(isolate); +} -bool Object::IsLayoutDescriptor() const { return IsSmi() || IsByteArray(); } +bool Object::IsLayoutDescriptor(Isolate* isolate) const { + return IsSmi() || IsByteArray(isolate); +} -bool HeapObject::IsDeoptimizationData() const { +DEF_GETTER(HeapObject, IsDeoptimizationData, bool) { // Must be a fixed array. - if (!IsFixedArrayExact()) return false; + if (!IsFixedArrayExact(isolate)) return false; // There's no sure way to detect the difference between a fixed array and // a deoptimization data array. Since this is used for asserts we can @@ -255,79 +321,98 @@ bool HeapObject::IsDeoptimizationData() const { return length >= 0 && length % DeoptimizationData::kDeoptEntrySize == 0; } -bool HeapObject::IsHandlerTable() const { - if (!IsFixedArrayExact()) return false; +DEF_GETTER(HeapObject, IsHandlerTable, bool) { + if (!IsFixedArrayExact(isolate)) return false; // There's actually no way to see the difference between a fixed array and // a handler table array. return true; } -bool HeapObject::IsTemplateList() const { - if (!IsFixedArrayExact()) return false; +DEF_GETTER(HeapObject, IsTemplateList, bool) { + if (!IsFixedArrayExact(isolate)) return false; // There's actually no way to see the difference between a fixed array and // a template list. if (FixedArray::cast(*this).length() < 1) return false; return true; } -bool HeapObject::IsDependentCode() const { - if (!IsWeakFixedArray()) return false; +DEF_GETTER(HeapObject, IsDependentCode, bool) { + if (!IsWeakFixedArray(isolate)) return false; // There's actually no way to see the difference between a weak fixed array // and a dependent codes array. return true; } -bool HeapObject::IsAbstractCode() const { - return IsBytecodeArray() || IsCode(); +DEF_GETTER(HeapObject, IsAbstractCode, bool) { + return IsBytecodeArray(isolate) || IsCode(isolate); } -bool HeapObject::IsStringWrapper() const { - return IsJSValue() && JSValue::cast(*this).value().IsString(); +DEF_GETTER(HeapObject, IsStringWrapper, bool) { + return IsJSPrimitiveWrapper(isolate) && + JSPrimitiveWrapper::cast(*this).value().IsString(isolate); } -bool HeapObject::IsBooleanWrapper() const { - return IsJSValue() && JSValue::cast(*this).value().IsBoolean(); +DEF_GETTER(HeapObject, IsBooleanWrapper, bool) { + return IsJSPrimitiveWrapper(isolate) && + JSPrimitiveWrapper::cast(*this).value().IsBoolean(isolate); } -bool HeapObject::IsScriptWrapper() const { - return IsJSValue() && JSValue::cast(*this).value().IsScript(); +DEF_GETTER(HeapObject, IsScriptWrapper, bool) { + return IsJSPrimitiveWrapper(isolate) && + JSPrimitiveWrapper::cast(*this).value().IsScript(isolate); } -bool HeapObject::IsNumberWrapper() const { - return IsJSValue() && JSValue::cast(*this).value().IsNumber(); +DEF_GETTER(HeapObject, IsNumberWrapper, bool) { + return IsJSPrimitiveWrapper(isolate) && + JSPrimitiveWrapper::cast(*this).value().IsNumber(isolate); } -bool HeapObject::IsBigIntWrapper() const { - return IsJSValue() && JSValue::cast(*this).value().IsBigInt(); +DEF_GETTER(HeapObject, IsBigIntWrapper, bool) { + return IsJSPrimitiveWrapper(isolate) && + JSPrimitiveWrapper::cast(*this).value().IsBigInt(isolate); } -bool HeapObject::IsSymbolWrapper() const { - return IsJSValue() && JSValue::cast(*this).value().IsSymbol(); +DEF_GETTER(HeapObject, IsSymbolWrapper, bool) { + return IsJSPrimitiveWrapper(isolate) && + JSPrimitiveWrapper::cast(*this).value().IsSymbol(isolate); } -bool HeapObject::IsJSArrayBufferView() const { - return IsJSDataView() || IsJSTypedArray(); +DEF_GETTER(HeapObject, IsJSArrayBufferView, bool) { + return IsJSDataView(isolate) || IsJSTypedArray(isolate); } -bool HeapObject::IsStringSet() const { return IsHashTable(); } +DEF_GETTER(HeapObject, IsJSCollectionIterator, bool) { + return IsJSMapIterator(isolate) || IsJSSetIterator(isolate); +} -bool HeapObject::IsObjectHashSet() const { return IsHashTable(); } +DEF_GETTER(HeapObject, IsStringSet, bool) { return IsHashTable(isolate); } -bool HeapObject::IsCompilationCacheTable() const { return IsHashTable(); } +DEF_GETTER(HeapObject, IsObjectHashSet, bool) { return IsHashTable(isolate); } -bool HeapObject::IsMapCache() const { return IsHashTable(); } +DEF_GETTER(HeapObject, IsCompilationCacheTable, bool) { + return IsHashTable(isolate); +} -bool HeapObject::IsObjectHashTable() const { return IsHashTable(); } +DEF_GETTER(HeapObject, IsMapCache, bool) { return IsHashTable(isolate); } -bool Object::IsHashTableBase() const { return IsHashTable(); } +DEF_GETTER(HeapObject, IsObjectHashTable, bool) { return IsHashTable(isolate); } -bool Object::IsSmallOrderedHashTable() const { - return IsSmallOrderedHashSet() || IsSmallOrderedHashMap() || - IsSmallOrderedNameDictionary(); +DEF_GETTER(HeapObject, IsHashTableBase, bool) { return IsHashTable(isolate); } + +DEF_GETTER(HeapObject, IsSmallOrderedHashTable, bool) { + return IsSmallOrderedHashSet(isolate) || IsSmallOrderedHashMap(isolate) || + IsSmallOrderedNameDictionary(isolate); } bool Object::IsPrimitive() const { - return IsSmi() || HeapObject::cast(*this).map().IsPrimitiveMap(); + if (IsSmi()) return true; + HeapObject this_heap_object = HeapObject::cast(*this); + Isolate* isolate = GetIsolateForPtrCompr(this_heap_object); + return this_heap_object.map(isolate).IsPrimitiveMap(); +} + +bool Object::IsPrimitive(Isolate* isolate) const { + return IsSmi() || HeapObject::cast(*this).map(isolate).IsPrimitiveMap(); } // static @@ -339,19 +424,21 @@ Maybe<bool> Object::IsArray(Handle<Object> object) { return JSProxy::IsArray(Handle<JSProxy>::cast(object)); } -bool HeapObject::IsUndetectable() const { return map().is_undetectable(); } +DEF_GETTER(HeapObject, IsUndetectable, bool) { + return map(isolate).is_undetectable(); +} -bool HeapObject::IsAccessCheckNeeded() const { - if (IsJSGlobalProxy()) { +DEF_GETTER(HeapObject, IsAccessCheckNeeded, bool) { + if (IsJSGlobalProxy(isolate)) { const JSGlobalProxy proxy = JSGlobalProxy::cast(*this); JSGlobalObject global = proxy.GetIsolate()->context().global_object(); return proxy.IsDetachedFrom(global); } - return map().is_access_check_needed(); + return map(isolate).is_access_check_needed(); } -bool HeapObject::IsStruct() const { - switch (map().instance_type()) { +DEF_GETTER(HeapObject, IsStruct, bool) { + switch (map(isolate).instance_type()) { #define MAKE_STRUCT_CASE(TYPE, Name, name) \ case TYPE: \ return true; @@ -374,10 +461,13 @@ bool HeapObject::IsStruct() const { } } -#define MAKE_STRUCT_PREDICATE(NAME, Name, name) \ - bool Object::Is##Name() const { \ - return IsHeapObject() && HeapObject::cast(*this).Is##Name(); \ - } \ +#define MAKE_STRUCT_PREDICATE(NAME, Name, name) \ + bool Object::Is##Name() const { \ + return IsHeapObject() && HeapObject::cast(*this).Is##Name(); \ + } \ + bool Object::Is##Name(Isolate* isolate) const { \ + return IsHeapObject() && HeapObject::cast(*this).Is##Name(isolate); \ + } \ TYPE_CHECKER(Name) STRUCT_LIST(MAKE_STRUCT_PREDICATE) #undef MAKE_STRUCT_PREDICATE @@ -441,25 +531,28 @@ bool Object::FilterKey(PropertyFilter filter) { return false; } -Representation Object::OptimalRepresentation() { +Representation Object::OptimalRepresentation(Isolate* isolate) const { if (!FLAG_track_fields) return Representation::Tagged(); if (IsSmi()) { return Representation::Smi(); - } else if (FLAG_track_double_fields && IsHeapNumber()) { + } + HeapObject heap_object = HeapObject::cast(*this); + if (FLAG_track_double_fields && heap_object.IsHeapNumber(isolate)) { return Representation::Double(); - } else if (FLAG_track_computed_fields && IsUninitialized()) { + } else if (FLAG_track_computed_fields && + heap_object.IsUninitialized( + heap_object.GetReadOnlyRoots(isolate))) { return Representation::None(); } else if (FLAG_track_heap_object_fields) { - DCHECK(IsHeapObject()); return Representation::HeapObject(); } else { return Representation::Tagged(); } } -ElementsKind Object::OptimalElementsKind() { +ElementsKind Object::OptimalElementsKind(Isolate* isolate) const { if (IsSmi()) return PACKED_SMI_ELEMENTS; - if (IsNumber()) return PACKED_DOUBLE_ELEMENTS; + if (IsNumber(isolate)) return PACKED_DOUBLE_ELEMENTS; return PACKED_ELEMENTS; } @@ -618,18 +711,18 @@ HeapObject MapWord::ToForwardingAddress() { #ifdef VERIFY_HEAP void HeapObject::VerifyObjectField(Isolate* isolate, int offset) { - VerifyPointer(isolate, READ_FIELD(*this, offset)); + VerifyPointer(isolate, TaggedField<Object>::load(isolate, *this, offset)); STATIC_ASSERT(!COMPRESS_POINTERS_BOOL || kTaggedSize == kInt32Size); } void HeapObject::VerifyMaybeObjectField(Isolate* isolate, int offset) { - MaybeObject::VerifyMaybeObjectPointer(isolate, - READ_WEAK_FIELD(*this, offset)); + MaybeObject::VerifyMaybeObjectPointer( + isolate, TaggedField<MaybeObject>::load(isolate, *this, offset)); STATIC_ASSERT(!COMPRESS_POINTERS_BOOL || kTaggedSize == kInt32Size); } void HeapObject::VerifySmiField(int offset) { - CHECK(READ_FIELD(*this, offset).IsSmi()); + CHECK(TaggedField<Object>::load(*this, offset).IsSmi()); STATIC_ASSERT(!COMPRESS_POINTERS_BOOL || kTaggedSize == kInt32Size); } @@ -639,7 +732,15 @@ ReadOnlyRoots HeapObject::GetReadOnlyRoots() const { return ReadOnlyHeap::GetReadOnlyRoots(*this); } -Map HeapObject::map() const { return map_word().ToMap(); } +ReadOnlyRoots HeapObject::GetReadOnlyRoots(Isolate* isolate) const { +#ifdef V8_COMPRESS_POINTERS + return ReadOnlyRoots(isolate); +#else + return GetReadOnlyRoots(); +#endif +} + +DEF_GETTER(HeapObject, map, Map) { return map_word(isolate).ToMap(); } void HeapObject::set_map(Map value) { if (!value.is_null()) { @@ -655,8 +756,8 @@ void HeapObject::set_map(Map value) { } } -Map HeapObject::synchronized_map() const { - return synchronized_map_word().ToMap(); +DEF_GETTER(HeapObject, synchronized_map, Map) { + return synchronized_map_word(isolate).ToMap(); } void HeapObject::synchronized_set_map(Map value) { @@ -693,24 +794,31 @@ void HeapObject::set_map_after_allocation(Map value, WriteBarrierMode mode) { } } -MapWordSlot HeapObject::map_slot() const { - return MapWordSlot(FIELD_ADDR(*this, kMapOffset)); +ObjectSlot HeapObject::map_slot() const { + return ObjectSlot(MapField::address(*this)); } -MapWord HeapObject::map_word() const { - return MapWord(map_slot().Relaxed_Load().ptr()); +DEF_GETTER(HeapObject, map_word, MapWord) { + return MapField::Relaxed_Load(isolate, *this); } void HeapObject::set_map_word(MapWord map_word) { - map_slot().Relaxed_Store(Object(map_word.value_)); + MapField::Relaxed_Store(*this, map_word); } -MapWord HeapObject::synchronized_map_word() const { - return MapWord(map_slot().Acquire_Load().ptr()); +DEF_GETTER(HeapObject, synchronized_map_word, MapWord) { + return MapField::Acquire_Load(isolate, *this); } void HeapObject::synchronized_set_map_word(MapWord map_word) { - map_slot().Release_Store(Object(map_word.value_)); + MapField::Release_Store(*this, map_word); +} + +bool HeapObject::synchronized_compare_and_swap_map_word(MapWord old_map_word, + MapWord new_map_word) { + Tagged_t result = + MapField::Release_CompareAndSwap(*this, old_map_word, new_map_word); + return result == static_cast<Tagged_t>(old_map_word.ptr()); } int HeapObject::Size() const { return SizeFromMap(map()); } diff --git a/chromium/v8/src/objects/objects.cc b/chromium/v8/src/objects/objects.cc index 8cc22fa0e5c..9963cba4727 100644 --- a/chromium/v8/src/objects/objects.cc +++ b/chromium/v8/src/objects/objects.cc @@ -25,13 +25,13 @@ #include "src/builtins/builtins.h" #include "src/codegen/compiler.h" #include "src/common/globals.h" +#include "src/common/message-template.h" #include "src/date/date.h" #include "src/debug/debug.h" #include "src/execution/arguments.h" #include "src/execution/execution.h" #include "src/execution/frames-inl.h" #include "src/execution/isolate-inl.h" -#include "src/execution/message-template.h" #include "src/execution/microtask-queue.h" #include "src/heap/heap-inl.h" #include "src/heap/read-only-heap.h" @@ -104,7 +104,7 @@ #include "src/objects/template-objects-inl.h" #include "src/objects/transitions-inl.h" #include "src/parsing/preparse-data.h" -#include "src/regexp/jsregexp.h" +#include "src/regexp/regexp.h" #include "src/strings/string-builder-inl.h" #include "src/strings/string-search.h" #include "src/strings/string-stream.h" @@ -116,6 +116,9 @@ #include "src/wasm/wasm-objects.h" #include "src/zone/zone.h" +#include "torque-generated/class-definitions-tq-inl.h" +#include "torque-generated/internal-class-definitions-tq-inl.h" + namespace v8 { namespace internal { @@ -209,8 +212,8 @@ Handle<Object> Object::WrapForRead(Isolate* isolate, Handle<Object> object, DCHECK(object->FitsRepresentation(representation)); return object; } - return isolate->factory()->NewHeapNumber( - MutableHeapNumber::cast(*object).value()); + return isolate->factory()->NewHeapNumberFromBits( + MutableHeapNumber::cast(*object).value_as_bits()); } MaybeHandle<JSReceiver> Object::ToObjectImpl(Isolate* isolate, @@ -242,7 +245,7 @@ MaybeHandle<JSReceiver> Object::ToObjectImpl(Isolate* isolate, isolate); } Handle<JSObject> result = isolate->factory()->NewJSObject(constructor); - Handle<JSValue>::cast(result)->set_value(*object); + Handle<JSPrimitiveWrapper>::cast(result)->set_value(*object); return result; } @@ -2387,9 +2390,9 @@ void DescriptorArray::GeneralizeAllFields() { if (details.location() == kField) { DCHECK_EQ(kData, details.kind()); details = details.CopyWithConstness(PropertyConstness::kMutable); - SetValue(i, FieldType::Any()); + SetValue(i, MaybeObject::FromObject(FieldType::Any())); } - set(ToDetailsIndex(i), MaybeObject::FromObject(details.AsSmi())); + SetDetails(i, details); } } @@ -3043,27 +3046,34 @@ Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy, } // Enforce the invariant. + return JSProxy::CheckDeleteTrap(isolate, name, target); +} + +Maybe<bool> JSProxy::CheckDeleteTrap(Isolate* isolate, Handle<Name> name, + Handle<JSReceiver> target) { + // 10. Let targetDesc be ? target.[[GetOwnProperty]](P). PropertyDescriptor target_desc; - Maybe<bool> owned = + Maybe<bool> target_found = JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); - MAYBE_RETURN(owned, Nothing<bool>()); - if (owned.FromJust()) { + MAYBE_RETURN(target_found, Nothing<bool>()); + // 11. If targetDesc is undefined, return true. + if (target_found.FromJust()) { + // 12. If targetDesc.[[Configurable]] is false, throw a TypeError exception. if (!target_desc.configurable()) { - isolate->Throw(*factory->NewTypeError( + isolate->Throw(*isolate->factory()->NewTypeError( MessageTemplate::kProxyDeletePropertyNonConfigurable, name)); return Nothing<bool>(); } // 13. Let extensibleTarget be ? IsExtensible(target). + Maybe<bool> extensible_target = JSReceiver::IsExtensible(target); + MAYBE_RETURN(extensible_target, Nothing<bool>()); // 14. If extensibleTarget is false, throw a TypeError exception. - Maybe<bool> extensible = JSReceiver::IsExtensible(target); - MAYBE_RETURN(extensible, Nothing<bool>()); - if (!extensible.FromJust()) { - isolate->Throw(*factory->NewTypeError( + if (!extensible_target.FromJust()) { + isolate->Throw(*isolate->factory()->NewTypeError( MessageTemplate::kProxyDeletePropertyNonExtensible, name)); return Nothing<bool>(); } } - return Just(true); } @@ -3269,7 +3279,11 @@ Maybe<bool> JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a, new_len_desc, should_throw); } // 13. If oldLenDesc.[[Writable]] is false, return false. - if (!old_len_desc.writable()) { + if (!old_len_desc.writable() || + // Also handle the {configurable: true} case since we later use + // JSArray::SetLength instead of OrdinaryDefineOwnProperty to change + // the length, and it doesn't have access to the descriptor anymore. + new_len_desc->configurable()) { RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw), NewTypeError(MessageTemplate::kRedefineDisallowed, isolate->factory()->length_string())); @@ -4294,8 +4308,10 @@ bool DescriptorArray::IsEqualTo(DescriptorArray other) { if (number_of_all_descriptors() != other.number_of_all_descriptors()) { return false; } - for (int i = 0; i < number_of_all_descriptors(); ++i) { - if (get(i) != other.get(i)) return false; + for (int i = 0; i < number_of_descriptors(); ++i) { + if (GetKey(i) != other.GetKey(i)) return false; + if (GetDetails(i).AsSmi() != other.GetDetails(i).AsSmi()) return false; + if (GetValue(i) != other.GetValue(i)) return false; } return true; } @@ -4500,7 +4516,8 @@ uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) { return value; } -Handle<Object> CacheInitialJSArrayMaps(Handle<Context> native_context, +Handle<Object> CacheInitialJSArrayMaps(Isolate* isolate, + Handle<Context> native_context, Handle<Map> initial_map) { // Replace all of the cached initial array maps in the native context with // the appropriate transitioned elements kind maps. @@ -4512,13 +4529,12 @@ Handle<Object> CacheInitialJSArrayMaps(Handle<Context> native_context, i < kFastElementsKindCount; ++i) { Handle<Map> new_map; ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i); - Map maybe_elements_transition = current_map->ElementsTransitionMap(); + Map maybe_elements_transition = current_map->ElementsTransitionMap(isolate); if (!maybe_elements_transition.is_null()) { - new_map = handle(maybe_elements_transition, native_context->GetIsolate()); + new_map = handle(maybe_elements_transition, isolate); } else { - new_map = - Map::CopyAsElementsKind(native_context->GetIsolate(), current_map, - next_kind, INSERT_TRANSITION); + new_map = Map::CopyAsElementsKind(isolate, current_map, next_kind, + INSERT_TRANSITION); } DCHECK_EQ(next_kind, new_map->elements_kind()); native_context->set(Context::ArrayMapIndex(next_kind), *new_map); @@ -4855,22 +4871,12 @@ std::unique_ptr<v8::tracing::TracedValue> SharedFunctionInfo::ToTracedValue( const char* SharedFunctionInfo::kTraceScope = "v8::internal::SharedFunctionInfo"; -uint64_t SharedFunctionInfo::TraceID() const { - // TODO(bmeurer): We use a combination of Script ID and function literal - // ID (within the Script) to uniquely identify SharedFunctionInfos. This - // can add significant overhead, and we should probably find a better way - // to uniquely identify SharedFunctionInfos over time. +uint64_t SharedFunctionInfo::TraceID(FunctionLiteral* literal) const { + int literal_id = + literal ? literal->function_literal_id() : function_literal_id(); Script script = Script::cast(this->script()); - WeakFixedArray script_functions = script.shared_function_infos(); - for (int i = 0; i < script_functions.length(); ++i) { - HeapObject script_function; - if (script_functions.Get(i).GetHeapObjectIfWeak(&script_function) && - script_function.address() == address()) { - return (static_cast<uint64_t>(script.id() + 1) << 32) | - (static_cast<uint64_t>(i)); - } - } - UNREACHABLE(); + return (static_cast<uint64_t>(script.id() + 1) << 32) | + (static_cast<uint64_t>(literal_id)); } std::unique_ptr<v8::tracing::TracedValue> SharedFunctionInfo::TraceIDRef() @@ -4946,21 +4952,17 @@ WasmCapiFunctionData SharedFunctionInfo::wasm_capi_function_data() const { SharedFunctionInfo::ScriptIterator::ScriptIterator(Isolate* isolate, Script script) - : ScriptIterator(isolate, handle(script.shared_function_infos(), isolate)) { -} + : ScriptIterator(handle(script.shared_function_infos(), isolate)) {} SharedFunctionInfo::ScriptIterator::ScriptIterator( - Isolate* isolate, Handle<WeakFixedArray> shared_function_infos) - : isolate_(isolate), - shared_function_infos_(shared_function_infos), - index_(0) {} + Handle<WeakFixedArray> shared_function_infos) + : shared_function_infos_(shared_function_infos), index_(0) {} SharedFunctionInfo SharedFunctionInfo::ScriptIterator::Next() { while (index_ < shared_function_infos_->length()) { MaybeObject raw = shared_function_infos_->Get(index_++); HeapObject heap_object; - if (!raw->GetHeapObject(&heap_object) || - heap_object.IsUndefined(isolate_)) { + if (!raw->GetHeapObject(&heap_object) || heap_object.IsUndefined()) { continue; } return SharedFunctionInfo::cast(heap_object); @@ -4968,13 +4970,15 @@ SharedFunctionInfo SharedFunctionInfo::ScriptIterator::Next() { return SharedFunctionInfo(); } -void SharedFunctionInfo::ScriptIterator::Reset(Script script) { - shared_function_infos_ = handle(script.shared_function_infos(), isolate_); +void SharedFunctionInfo::ScriptIterator::Reset(Isolate* isolate, + Script script) { + shared_function_infos_ = handle(script.shared_function_infos(), isolate); index_ = 0; } SharedFunctionInfo::GlobalIterator::GlobalIterator(Isolate* isolate) - : script_iterator_(isolate), + : isolate_(isolate), + script_iterator_(isolate), noscript_sfi_iterator_(isolate->heap()->noscript_shared_function_infos()), sfi_iterator_(isolate, script_iterator_.Next()) {} @@ -4986,7 +4990,7 @@ SharedFunctionInfo SharedFunctionInfo::GlobalIterator::Next() { if (!next.is_null()) return SharedFunctionInfo::cast(next); Script next_script = script_iterator_.Next(); if (next_script.is_null()) return SharedFunctionInfo(); - sfi_iterator_.Reset(next_script); + sfi_iterator_.Reset(isolate_, next_script); } } @@ -5148,7 +5152,6 @@ void SharedFunctionInfo::DiscardCompiled( handle(shared_info->inferred_name(), isolate); int start_position = shared_info->StartPosition(); int end_position = shared_info->EndPosition(); - int function_literal_id = shared_info->FunctionLiteralId(isolate); shared_info->DiscardCompiledMetadata(isolate); @@ -5163,8 +5166,7 @@ void SharedFunctionInfo::DiscardCompiled( // validity checks, since we're performing the unusual task of decompiling. Handle<UncompiledData> data = isolate->factory()->NewUncompiledDataWithoutPreparseData( - inferred_name_val, start_position, end_position, - function_literal_id); + inferred_name_val, start_position, end_position); shared_info->set_function_data(*data); } } @@ -5273,28 +5275,6 @@ bool SharedFunctionInfo::IsInlineable() { int SharedFunctionInfo::SourceSize() { return EndPosition() - StartPosition(); } -int SharedFunctionInfo::FindIndexInScript(Isolate* isolate) const { - DisallowHeapAllocation no_gc; - - Object script_obj = script(); - if (!script_obj.IsScript()) return kFunctionLiteralIdInvalid; - - WeakFixedArray shared_info_list = - Script::cast(script_obj).shared_function_infos(); - SharedFunctionInfo::ScriptIterator iterator( - isolate, - Handle<WeakFixedArray>(reinterpret_cast<Address*>(&shared_info_list))); - - for (SharedFunctionInfo shared = iterator.Next(); !shared.is_null(); - shared = iterator.Next()) { - if (shared == *this) { - return iterator.CurrentIndex(); - } - } - - return kFunctionLiteralIdInvalid; -} - // Output the source code without any allocation in the heap. std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) { const SharedFunctionInfo s = v.value; @@ -5365,6 +5345,7 @@ void SharedFunctionInfo::InitFromFunctionLiteral( shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); shared_info->set_language_mode(lit->language_mode()); shared_info->set_is_wrapped(lit->is_wrapped()); + shared_info->set_function_literal_id(lit->function_literal_id()); // shared_info->set_kind(lit->kind()); // FunctionKind must have already been set. DCHECK(lit->kind() == shared_info->kind()); @@ -5409,7 +5390,7 @@ void SharedFunctionInfo::InitFromFunctionLiteral( Handle<UncompiledData> data = isolate->factory()->NewUncompiledDataWithPreparseData( lit->inferred_name(), lit->start_position(), lit->end_position(), - lit->function_literal_id(), preparse_data); + preparse_data); shared_info->set_uncompiled_data(*data); needs_position_info = false; } @@ -5418,8 +5399,7 @@ void SharedFunctionInfo::InitFromFunctionLiteral( if (needs_position_info) { Handle<UncompiledData> data = isolate->factory()->NewUncompiledDataWithoutPreparseData( - lit->inferred_name(), lit->start_position(), lit->end_position(), - lit->function_literal_id()); + lit->inferred_name(), lit->start_position(), lit->end_position()); shared_info->set_uncompiled_data(*data); } } @@ -5510,21 +5490,6 @@ int SharedFunctionInfo::EndPosition() const { return kNoSourcePosition; } -int SharedFunctionInfo::FunctionLiteralId(Isolate* isolate) const { - // Fast path for the common case when the SFI is uncompiled and so the - // function literal id is already in the uncompiled data. - if (HasUncompiledData() && uncompiled_data().has_function_literal_id()) { - int id = uncompiled_data().function_literal_id(); - // Make sure the id is what we should have found with the slow path. - DCHECK_EQ(id, FindIndexInScript(isolate)); - return id; - } - - // Otherwise, search for the function in the SFI's script's function list, - // and return its index in that list. - return FindIndexInScript(isolate); -} - void SharedFunctionInfo::SetPosition(int start_position, int end_position) { Object maybe_scope_info = name_or_scope_info(); if (maybe_scope_info.IsScopeInfo()) { @@ -5561,16 +5526,6 @@ void SharedFunctionInfo::EnsureSourcePositionsAvailable( } } -bool BytecodeArray::IsBytecodeEqual(const BytecodeArray other) const { - if (length() != other.length()) return false; - - for (int i = 0; i < length(); ++i) { - if (get(i) != other.get(i)) return false; - } - - return true; -} - // static void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) { DCHECK_GE(capacity, 0); @@ -6128,42 +6083,14 @@ Handle<Object> JSPromise::TriggerPromiseReactions(Isolate* isolate, namespace { -constexpr JSRegExp::Flag kCharFlagValues[] = { - JSRegExp::kGlobal, // g - JSRegExp::kInvalid, // h - JSRegExp::kIgnoreCase, // i - JSRegExp::kInvalid, // j - JSRegExp::kInvalid, // k - JSRegExp::kInvalid, // l - JSRegExp::kMultiline, // m - JSRegExp::kInvalid, // n - JSRegExp::kInvalid, // o - JSRegExp::kInvalid, // p - JSRegExp::kInvalid, // q - JSRegExp::kInvalid, // r - JSRegExp::kDotAll, // s - JSRegExp::kInvalid, // t - JSRegExp::kUnicode, // u - JSRegExp::kInvalid, // v - JSRegExp::kInvalid, // w - JSRegExp::kInvalid, // x - JSRegExp::kSticky, // y -}; - -constexpr JSRegExp::Flag CharToFlag(uc16 flag_char) { - return (flag_char < 'g' || flag_char > 'y') - ? JSRegExp::kInvalid - : kCharFlagValues[flag_char - 'g']; -} - JSRegExp::Flags RegExpFlagsFromString(Isolate* isolate, Handle<String> flags, bool* success) { - STATIC_ASSERT(CharToFlag('g') == JSRegExp::kGlobal); - STATIC_ASSERT(CharToFlag('i') == JSRegExp::kIgnoreCase); - STATIC_ASSERT(CharToFlag('m') == JSRegExp::kMultiline); - STATIC_ASSERT(CharToFlag('s') == JSRegExp::kDotAll); - STATIC_ASSERT(CharToFlag('u') == JSRegExp::kUnicode); - STATIC_ASSERT(CharToFlag('y') == JSRegExp::kSticky); + STATIC_ASSERT(JSRegExp::FlagFromChar('g') == JSRegExp::kGlobal); + STATIC_ASSERT(JSRegExp::FlagFromChar('i') == JSRegExp::kIgnoreCase); + STATIC_ASSERT(JSRegExp::FlagFromChar('m') == JSRegExp::kMultiline); + STATIC_ASSERT(JSRegExp::FlagFromChar('s') == JSRegExp::kDotAll); + STATIC_ASSERT(JSRegExp::FlagFromChar('u') == JSRegExp::kUnicode); + STATIC_ASSERT(JSRegExp::FlagFromChar('y') == JSRegExp::kSticky); int length = flags->length(); if (length == 0) { @@ -6171,14 +6098,14 @@ JSRegExp::Flags RegExpFlagsFromString(Isolate* isolate, Handle<String> flags, return JSRegExp::kNone; } // A longer flags string cannot be valid. - if (length > JSRegExp::FlagCount()) return JSRegExp::Flags(0); + if (length > JSRegExp::kFlagCount) return JSRegExp::Flags(0); // Initialize {value} to {kInvalid} to allow 2-in-1 duplicate/invalid check. JSRegExp::Flags value = JSRegExp::kInvalid; if (flags->IsSeqOneByteString()) { DisallowHeapAllocation no_gc; SeqOneByteString seq_flags = SeqOneByteString::cast(*flags); for (int i = 0; i < length; i++) { - JSRegExp::Flag flag = CharToFlag(seq_flags.Get(i)); + JSRegExp::Flag flag = JSRegExp::FlagFromChar(seq_flags.Get(i)); // Duplicate or invalid flag. if (value & flag) return JSRegExp::Flags(0); value |= flag; @@ -6188,7 +6115,7 @@ JSRegExp::Flags RegExpFlagsFromString(Isolate* isolate, Handle<String> flags, DisallowHeapAllocation no_gc; String::FlatContent flags_content = flags->GetFlatContent(no_gc); for (int i = 0; i < length; i++) { - JSRegExp::Flag flag = CharToFlag(flags_content.Get(i)); + JSRegExp::Flag flag = JSRegExp::FlagFromChar(flags_content.Get(i)); // Duplicate or invalid flag. if (value & flag) return JSRegExp::Flags(0); value |= flag; @@ -6224,15 +6151,20 @@ template <typename Char> int CountRequiredEscapes(Handle<String> source) { DisallowHeapAllocation no_gc; int escapes = 0; + bool in_char_class = false; Vector<const Char> src = source->GetCharVector<Char>(no_gc); for (int i = 0; i < src.length(); i++) { const Char c = src[i]; if (c == '\\') { // Escape. Skip next character; i++; - } else if (c == '/') { + } else if (c == '/' && !in_char_class) { // Not escaped forward-slash needs escape. escapes++; + } else if (c == '[') { + in_char_class = true; + } else if (c == ']') { + in_char_class = false; } else if (c == '\n') { escapes++; } else if (c == '\r') { @@ -6245,6 +6177,7 @@ int CountRequiredEscapes(Handle<String> source) { DCHECK(!unibrow::IsLineTerminator(static_cast<unibrow::uchar>(c))); } } + DCHECK(!in_char_class); return escapes; } @@ -6262,16 +6195,19 @@ Handle<StringType> WriteEscapedRegExpSource(Handle<String> source, Vector<Char> dst(result->GetChars(no_gc), result->length()); int s = 0; int d = 0; - // TODO(v8:1982): Fully implement - // https://tc39.github.io/ecma262/#sec-escaperegexppattern + bool in_char_class = false; while (s < src.length()) { if (src[s] == '\\') { // Escape. Copy this and next character. dst[d++] = src[s++]; if (s == src.length()) break; - } else if (src[s] == '/') { + } else if (src[s] == '/' && !in_char_class) { // Not escaped forward-slash needs escape. dst[d++] = '\\'; + } else if (src[s] == '[') { + in_char_class = true; + } else if (src[s] == ']') { + in_char_class = false; } else if (src[s] == '\n') { WriteStringToCharVector(dst, &d, "\\n"); s++; @@ -6292,6 +6228,7 @@ Handle<StringType> WriteEscapedRegExpSource(Handle<String> source, dst[d++] = src[s++]; } DCHECK_EQ(result->length(), d); + DCHECK(!in_char_class); return result; } @@ -6348,13 +6285,13 @@ MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp, source = String::Flatten(isolate, source); + RETURN_ON_EXCEPTION(isolate, RegExp::Compile(isolate, regexp, source, flags), + JSRegExp); + Handle<String> escaped_source; ASSIGN_RETURN_ON_EXCEPTION(isolate, escaped_source, EscapeRegExpSource(isolate, source), JSRegExp); - RETURN_ON_EXCEPTION( - isolate, RegExpImpl::Compile(isolate, regexp, source, flags), JSRegExp); - regexp->set_source(*escaped_source); regexp->set_flags(Smi::FromInt(flags)); @@ -6701,8 +6638,8 @@ Handle<String> StringTable::LookupString(Isolate* isolate, } else { // !FLAG_thin_strings if (string->IsConsString()) { Handle<ConsString> cons = Handle<ConsString>::cast(string); - cons->set_first(isolate, *result); - cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string()); + cons->set_first(*result); + cons->set_second(ReadOnlyRoots(isolate).empty_string()); } else if (string->IsSlicedString()) { STATIC_ASSERT(static_cast<int>(ConsString::kSize) == static_cast<int>(SlicedString::kSize)); @@ -6713,8 +6650,8 @@ Handle<String> StringTable::LookupString(Isolate* isolate, : isolate->factory()->cons_string_map(); string->set_map(*map); Handle<ConsString> cons = Handle<ConsString>::cast(string); - cons->set_first(isolate, *result); - cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string()); + cons->set_first(*result); + cons->set_second(ReadOnlyRoots(isolate).empty_string()); } } return result; @@ -7925,9 +7862,13 @@ Handle<PropertyCell> PropertyCell::PrepareForValue( // static void PropertyCell::SetValueWithInvalidation(Isolate* isolate, + const char* cell_name, Handle<PropertyCell> cell, Handle<Object> new_value) { if (cell->value() != *new_value) { + if (FLAG_trace_protector_invalidation) { + isolate->TraceProtectorInvalidation(cell_name); + } cell->set_value(*new_value); cell->dependent_code().DeoptimizeDependentCodeGroup( isolate, DependentCode::kPropertyCellChangedGroup); @@ -8127,7 +8068,9 @@ HashTable<NameDictionary, NameDictionaryShape>::Shrink(Isolate* isolate, int additionalCapacity); void JSFinalizationGroup::Cleanup( - Handle<JSFinalizationGroup> finalization_group, Isolate* isolate) { + Isolate* isolate, Handle<JSFinalizationGroup> finalization_group, + Handle<Object> cleanup) { + DCHECK(cleanup->IsCallable()); // It's possible that the cleared_cells list is empty, since // FinalizationGroup.unregister() removed all its elements before this task // ran. In that case, don't call the cleanup function. @@ -8145,7 +8088,6 @@ void JSFinalizationGroup::Cleanup( Handle<AllocationSite>::null())); iterator->set_finalization_group(*finalization_group); } - Handle<Object> cleanup(finalization_group->cleanup(), isolate); v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate)); v8::Local<v8::Value> result; diff --git a/chromium/v8/src/objects/objects.h b/chromium/v8/src/objects/objects.h index 857f3ed0f6d..d706b2dfb7b 100644 --- a/chromium/v8/src/objects/objects.h +++ b/chromium/v8/src/objects/objects.h @@ -15,10 +15,11 @@ #include "src/base/build_config.h" #include "src/base/flags.h" #include "src/base/logging.h" +#include "src/base/memory.h" #include "src/codegen/constants-arch.h" #include "src/common/assert-scope.h" #include "src/common/checks.h" -#include "src/execution/message-template.h" +#include "src/common/message-template.h" #include "src/flags/flags.h" #include "src/objects/elements-kind.h" #include "src/objects/field-index.h" @@ -49,22 +50,21 @@ // - JSCollection // - JSSet // - JSMap -// - JSStringIterator -// - JSSetIterator -// - JSMapIterator -// - JSWeakCollection -// - JSWeakMap -// - JSWeakSet -// - JSRegExp +// - JSDate // - JSFunction // - JSGeneratorObject // - JSGlobalObject // - JSGlobalProxy -// - JSValue -// - JSDate +// - JSMapIterator // - JSMessageObject // - JSModuleNamespace -// - JSV8BreakIterator // If V8_INTL_SUPPORT enabled. +// - JSPrimitiveWrapper +// - JSRegExp +// - JSSetIterator +// - JSStringIterator +// - JSWeakCollection +// - JSWeakMap +// - JSWeakSet // - JSCollator // If V8_INTL_SUPPORT enabled. // - JSDateTimeFormat // If V8_INTL_SUPPORT enabled. // - JSListFormat // If V8_INTL_SUPPORT enabled. @@ -72,8 +72,9 @@ // - JSNumberFormat // If V8_INTL_SUPPORT enabled. // - JSPluralRules // If V8_INTL_SUPPORT enabled. // - JSRelativeTimeFormat // If V8_INTL_SUPPORT enabled. -// - JSSegmentIterator // If V8_INTL_SUPPORT enabled. // - JSSegmenter // If V8_INTL_SUPPORT enabled. +// - JSSegmentIterator // If V8_INTL_SUPPORT enabled. +// - JSV8BreakIterator // If V8_INTL_SUPPORT enabled. // - WasmExceptionObject // - WasmGlobalObject // - WasmInstanceObject @@ -99,7 +100,7 @@ // - TemplateList // - TransitionArray // - ScopeInfo -// - ModuleInfo +// - SourceTextModuleInfo // - ScriptContextTable // - ClosureFeedbackCellArray // - FixedDoubleArray @@ -170,7 +171,9 @@ // - PromiseRejectReactionJobTask // - PromiseResolveThenableJobTask // - Module -// - ModuleInfoEntry +// - SourceTextModule +// - SyntheticModule +// - SourceTextModuleInfoEntry // - FeedbackCell // - FeedbackVector // - PreparseData @@ -265,9 +268,13 @@ class Object : public TaggedImpl<HeapObjectReferenceType::STRONG, Address> { constexpr Object() : TaggedImpl(kNullAddress) {} explicit constexpr Object(Address ptr) : TaggedImpl(ptr) {} -#define IS_TYPE_FUNCTION_DECL(Type) V8_INLINE bool Is##Type() const; +#define IS_TYPE_FUNCTION_DECL(Type) \ + V8_INLINE bool Is##Type() const; \ + V8_INLINE bool Is##Type(Isolate* isolate) const; OBJECT_TYPE_LIST(IS_TYPE_FUNCTION_DECL) HEAP_OBJECT_TYPE_LIST(IS_TYPE_FUNCTION_DECL) + IS_TYPE_FUNCTION_DECL(HashTableBase) + IS_TYPE_FUNCTION_DECL(SmallOrderedHashTable) #undef IS_TYPE_FUNCTION_DECL // Oddball checks are faster when they are raw pointer comparisons, so the @@ -277,18 +284,17 @@ class Object : public TaggedImpl<HeapObjectReferenceType::STRONG, Address> { V8_INLINE bool Is##Type(ReadOnlyRoots roots) const; \ V8_INLINE bool Is##Type() const; ODDBALL_LIST(IS_TYPE_FUNCTION_DECL) + IS_TYPE_FUNCTION_DECL(NullOrUndefined, /* unused */) #undef IS_TYPE_FUNCTION_DECL - V8_INLINE bool IsNullOrUndefined(Isolate* isolate) const; - V8_INLINE bool IsNullOrUndefined(ReadOnlyRoots roots) const; - V8_INLINE bool IsNullOrUndefined() const; - V8_INLINE bool IsZero() const; V8_INLINE bool IsNoSharedNameSentinel() const; enum class Conversion { kToNumber, kToNumeric }; -#define DECL_STRUCT_PREDICATE(NAME, Name, name) V8_INLINE bool Is##Name() const; +#define DECL_STRUCT_PREDICATE(NAME, Name, name) \ + V8_INLINE bool Is##Name() const; \ + V8_INLINE bool Is##Name(Isolate* isolate) const; STRUCT_LIST(DECL_STRUCT_PREDICATE) #undef DECL_STRUCT_PREDICATE @@ -296,9 +302,6 @@ class Object : public TaggedImpl<HeapObjectReferenceType::STRONG, Address> { V8_INLINE V8_WARN_UNUSED_RESULT static Maybe<bool> IsArray(Handle<Object> object); - V8_INLINE bool IsHashTableBase() const; - V8_INLINE bool IsSmallOrderedHashTable() const; - // Extract the number. inline double Number() const; V8_INLINE bool IsNaN() const; @@ -306,9 +309,9 @@ class Object : public TaggedImpl<HeapObjectReferenceType::STRONG, Address> { V8_EXPORT_PRIVATE bool ToInt32(int32_t* value); inline bool ToUint32(uint32_t* value) const; - inline Representation OptimalRepresentation(); + inline Representation OptimalRepresentation(Isolate* isolate) const; - inline ElementsKind OptimalElementsKind(); + inline ElementsKind OptimalElementsKind(Isolate* isolate) const; inline bool FitsRepresentation(Representation representation); @@ -624,9 +627,9 @@ class Object : public TaggedImpl<HeapObjectReferenceType::STRONG, Address> { #endif if (std::is_same<T, double>::value || v8_pointer_compression_unaligned) { // Bug(v8:8875) Double fields may be unaligned. - return ReadUnalignedValue<T>(field_address(offset)); + return base::ReadUnalignedValue<T>(field_address(offset)); } else { - return Memory<T>(field_address(offset)); + return base::Memory<T>(field_address(offset)); } } @@ -641,9 +644,9 @@ class Object : public TaggedImpl<HeapObjectReferenceType::STRONG, Address> { #endif if (std::is_same<T, double>::value || v8_pointer_compression_unaligned) { // Bug(v8:8875) Double fields may be unaligned. - WriteUnalignedValue<T>(field_address(offset), value); + base::WriteUnalignedValue<T>(field_address(offset), value); } else { - Memory<T>(field_address(offset)) = value; + base::Memory<T>(field_address(offset)) = value; } } @@ -743,13 +746,13 @@ class MapWord { // View this map word as a forwarding address. inline HeapObject ToForwardingAddress(); - static inline MapWord FromRawValue(uintptr_t value) { return MapWord(value); } - - inline uintptr_t ToRawValue() { return value_; } + inline Address ptr() { return value_; } private: // HeapObject calls the private constructor and directly reads the value. friend class HeapObject; + template <typename TFieldType, int kFieldOffset> + friend class TaggedField; explicit MapWord(Address value) : value_(value) {} diff --git a/chromium/v8/src/objects/oddball-inl.h b/chromium/v8/src/objects/oddball-inl.h index e0d77b9043f..bcca03ddca1 100644 --- a/chromium/v8/src/objects/oddball-inl.h +++ b/chromium/v8/src/objects/oddball-inl.h @@ -22,7 +22,7 @@ TQ_OBJECT_CONSTRUCTORS_IMPL(Oddball) void Oddball::set_to_number_raw_as_bits(uint64_t bits) { // Bug(v8:8875): HeapNumber's double may be unaligned. - WriteUnalignedValue<uint64_t>(field_address(kToNumberRawOffset), bits); + base::WriteUnalignedValue<uint64_t>(field_address(kToNumberRawOffset), bits); } byte Oddball::kind() const { @@ -38,8 +38,8 @@ Handle<Object> Oddball::ToNumber(Isolate* isolate, Handle<Oddball> input) { return Handle<Object>(input->to_number(), isolate); } -bool HeapObject::IsBoolean() const { - return IsOddball() && +DEF_GETTER(HeapObject, IsBoolean, bool) { + return IsOddball(isolate) && ((Oddball::cast(*this).kind() & Oddball::kNotBooleanMask) == 0); } diff --git a/chromium/v8/src/objects/ordered-hash-table-inl.h b/chromium/v8/src/objects/ordered-hash-table-inl.h index 0eaa7567e22..a2270b0a4a1 100644 --- a/chromium/v8/src/objects/ordered-hash-table-inl.h +++ b/chromium/v8/src/objects/ordered-hash-table-inl.h @@ -54,7 +54,7 @@ template <class Derived> Object SmallOrderedHashTable<Derived>::KeyAt(int entry) const { DCHECK_LT(entry, Capacity()); Offset entry_offset = GetDataEntryOffset(entry, Derived::kKeyIndex); - return READ_FIELD(*this, entry_offset); + return TaggedField<Object>::load(*this, entry_offset); } template <class Derived> @@ -63,7 +63,7 @@ Object SmallOrderedHashTable<Derived>::GetDataEntry(int entry, DCHECK_LT(entry, Capacity()); DCHECK_LE(static_cast<unsigned>(relative_index), Derived::kEntrySize); Offset entry_offset = GetDataEntryOffset(entry, relative_index); - return READ_FIELD(*this, entry_offset); + return TaggedField<Object>::load(*this, entry_offset); } OBJECT_CONSTRUCTORS_IMPL(SmallOrderedHashSet, diff --git a/chromium/v8/src/objects/ordered-hash-table.cc b/chromium/v8/src/objects/ordered-hash-table.cc index 3d628cc4062..463d0e03848 100644 --- a/chromium/v8/src/objects/ordered-hash-table.cc +++ b/chromium/v8/src/objects/ordered-hash-table.cc @@ -508,6 +508,8 @@ void SmallOrderedHashTable<Derived>::Initialize(Isolate* isolate, SetNumberOfBuckets(num_buckets); SetNumberOfElements(0); SetNumberOfDeletedElements(0); + memset(reinterpret_cast<void*>(field_address(PaddingOffset())), 0, + PaddingSize()); Address hashtable_start = GetHashTableStartAddress(capacity); memset(reinterpret_cast<byte*>(hashtable_start), kNotFound, diff --git a/chromium/v8/src/objects/ordered-hash-table.h b/chromium/v8/src/objects/ordered-hash-table.h index a83109ed90f..66dc36e81fc 100644 --- a/chromium/v8/src/objects/ordered-hash-table.h +++ b/chromium/v8/src/objects/ordered-hash-table.h @@ -527,8 +527,16 @@ class SmallOrderedHashTable : public HeapObject { return NumberOfDeletedElementsOffset() + kOneByteSize; } + static constexpr Offset PaddingOffset() { + return NumberOfBucketsOffset() + kOneByteSize; + } + + static constexpr size_t PaddingSize() { + return RoundUp<kTaggedSize>(PaddingOffset()) - PaddingOffset(); + } + static constexpr Offset DataTableStartOffset() { - return RoundUp<kTaggedSize>(NumberOfBucketsOffset()); + return PaddingOffset() + PaddingSize(); } static constexpr int DataTableSizeFor(int capacity) { diff --git a/chromium/v8/src/objects/property-array-inl.h b/chromium/v8/src/objects/property-array-inl.h index f23e63e50d9..e9365c03a4e 100644 --- a/chromium/v8/src/objects/property-array-inl.h +++ b/chromium/v8/src/objects/property-array-inl.h @@ -21,10 +21,19 @@ namespace internal { OBJECT_CONSTRUCTORS_IMPL(PropertyArray, HeapObject) CAST_ACCESSOR(PropertyArray) +SMI_ACCESSORS(PropertyArray, length_and_hash, kLengthAndHashOffset) +SYNCHRONIZED_SMI_ACCESSORS(PropertyArray, length_and_hash, kLengthAndHashOffset) + Object PropertyArray::get(int index) const { + Isolate* isolate = GetIsolateForPtrCompr(*this); + return get(isolate, index); +} + +Object PropertyArray::get(Isolate* isolate, int index) const { DCHECK_LT(static_cast<unsigned>(index), static_cast<unsigned>(this->length())); - return RELAXED_READ_FIELD(*this, OffsetOfElementAt(index)); + return TaggedField<Object>::Relaxed_Load(isolate, *this, + OffsetOfElementAt(index)); } void PropertyArray::set(int index, Object value) { @@ -47,34 +56,24 @@ void PropertyArray::set(int index, Object value, WriteBarrierMode mode) { ObjectSlot PropertyArray::data_start() { return RawField(kHeaderSize); } int PropertyArray::length() const { - Object value_obj = READ_FIELD(*this, kLengthAndHashOffset); - int value = Smi::ToInt(value_obj); - return LengthField::decode(value); + return LengthField::decode(length_and_hash()); } void PropertyArray::initialize_length(int len) { - DCHECK_LT(static_cast<unsigned>(len), - static_cast<unsigned>(LengthField::kMax)); - WRITE_FIELD(*this, kLengthAndHashOffset, Smi::FromInt(len)); + DCHECK(LengthField::is_valid(len)); + set_length_and_hash(len); } int PropertyArray::synchronized_length() const { - Object value_obj = ACQUIRE_READ_FIELD(*this, kLengthAndHashOffset); - int value = Smi::ToInt(value_obj); - return LengthField::decode(value); + return LengthField::decode(synchronized_length_and_hash()); } -int PropertyArray::Hash() const { - Object value_obj = READ_FIELD(*this, kLengthAndHashOffset); - int value = Smi::ToInt(value_obj); - return HashField::decode(value); -} +int PropertyArray::Hash() const { return HashField::decode(length_and_hash()); } void PropertyArray::SetHash(int hash) { - Object value_obj = READ_FIELD(*this, kLengthAndHashOffset); - int value = Smi::ToInt(value_obj); + int value = length_and_hash(); value = HashField::update(value, hash); - WRITE_FIELD(*this, kLengthAndHashOffset, Smi::FromInt(value)); + set_length_and_hash(value); } void PropertyArray::CopyElements(Isolate* isolate, int dst_index, diff --git a/chromium/v8/src/objects/property-array.h b/chromium/v8/src/objects/property-array.h index 0c8b40ece20..5c71330280a 100644 --- a/chromium/v8/src/objects/property-array.h +++ b/chromium/v8/src/objects/property-array.h @@ -30,6 +30,7 @@ class PropertyArray : public HeapObject { inline int Hash() const; inline Object get(int index) const; + inline Object get(Isolate* isolate, int index) const; inline void set(int index, Object value); // Setter with explicit barrier mode. @@ -67,6 +68,11 @@ class PropertyArray : public HeapObject { static const int kNoHashSentinel = 0; + private: + DECL_INT_ACCESSORS(length_and_hash) + + DECL_SYNCHRONIZED_INT_ACCESSORS(length_and_hash) + OBJECT_CONSTRUCTORS(PropertyArray, HeapObject); }; diff --git a/chromium/v8/src/objects/property-cell.h b/chromium/v8/src/objects/property-cell.h index 75a5132728b..b336986f621 100644 --- a/chromium/v8/src/objects/property-cell.h +++ b/chromium/v8/src/objects/property-cell.h @@ -47,7 +47,7 @@ class PropertyCell : public HeapObject { static Handle<PropertyCell> InvalidateEntry( Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry); - static void SetValueWithInvalidation(Isolate* isolate, + static void SetValueWithInvalidation(Isolate* isolate, const char* cell_name, Handle<PropertyCell> cell, Handle<Object> new_value); diff --git a/chromium/v8/src/objects/property.cc b/chromium/v8/src/objects/property.cc index c226c28a76e..fba6fe34057 100644 --- a/chromium/v8/src/objects/property.cc +++ b/chromium/v8/src/objects/property.cc @@ -75,9 +75,10 @@ Descriptor Descriptor::DataField(Handle<Name> key, int field_index, Descriptor Descriptor::DataConstant(Handle<Name> key, Handle<Object> value, PropertyAttributes attributes) { + Isolate* isolate = GetIsolateForPtrCompr(*key); return Descriptor(key, MaybeObjectHandle(value), kData, attributes, kDescriptor, PropertyConstness::kConst, - value->OptimalRepresentation(), 0); + value->OptimalRepresentation(isolate), 0); } Descriptor Descriptor::DataConstant(Isolate* isolate, Handle<Name> key, diff --git a/chromium/v8/src/objects/prototype-inl.h b/chromium/v8/src/objects/prototype-inl.h index 5f7c3e23c51..2836186b125 100644 --- a/chromium/v8/src/objects/prototype-inl.h +++ b/chromium/v8/src/objects/prototype-inl.h @@ -48,7 +48,7 @@ PrototypeIterator::PrototypeIterator(Isolate* isolate, Map receiver_map, if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) { DCHECK(object_.IsJSReceiver()); Map map = JSReceiver::cast(object_).map(); - is_at_end_ = !map.has_hidden_prototype(); + is_at_end_ = !map.IsJSGlobalProxyMap(); } } @@ -63,7 +63,7 @@ PrototypeIterator::PrototypeIterator(Isolate* isolate, Handle<Map> receiver_map, if (!is_at_end_ && where_to_end_ == END_AT_NON_HIDDEN) { DCHECK(handle_->IsJSReceiver()); Map map = JSReceiver::cast(*handle_).map(); - is_at_end_ = !map.has_hidden_prototype(); + is_at_end_ = !map.IsJSGlobalProxyMap(); } } @@ -96,8 +96,9 @@ void PrototypeIterator::AdvanceIgnoringProxies() { Map map = HeapObject::cast(object).map(); HeapObject prototype = map.prototype(); - is_at_end_ = where_to_end_ == END_AT_NON_HIDDEN ? !map.has_hidden_prototype() - : prototype.IsNull(isolate_); + is_at_end_ = + prototype.IsNull(isolate_) || + (where_to_end_ == END_AT_NON_HIDDEN && !map.IsJSGlobalProxyMap()); if (handle_.is_null()) { object_ = prototype; diff --git a/chromium/v8/src/objects/scope-info.cc b/chromium/v8/src/objects/scope-info.cc index af45e86af34..eca8bc1ecd4 100644 --- a/chromium/v8/src/objects/scope-info.cc +++ b/chromium/v8/src/objects/scope-info.cc @@ -45,8 +45,9 @@ bool ScopeInfo::Equals(ScopeInfo other) const { if (!ScopeInfo::cast(entry).Equals(ScopeInfo::cast(other_entry))) { return false; } - } else if (entry.IsModuleInfo()) { - if (!ModuleInfo::cast(entry).Equals(ModuleInfo::cast(other_entry))) { + } else if (entry.IsSourceTextModuleInfo()) { + if (!SourceTextModuleInfo::cast(entry).Equals( + SourceTextModuleInfo::cast(other_entry))) { return false; } } else { @@ -217,6 +218,8 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, uint32_t info = VariableModeField::encode(var->mode()) | InitFlagField::encode(var->initialization_flag()) | + RequiresBrandCheckField::encode( + var->get_requires_brand_check_flag()) | MaybeAssignedFlagField::encode(var->maybe_assigned()) | ParameterNumberField::encode(ParameterNumberField::kMax); scope_info.set(context_local_base + local_index, *var->name(), mode); @@ -233,6 +236,8 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, VariableModeField::encode(var->mode()) | InitFlagField::encode(var->initialization_flag()) | MaybeAssignedFlagField::encode(var->maybe_assigned()) | + RequiresBrandCheckField::encode( + var->get_requires_brand_check_flag()) | ParameterNumberField::encode(ParameterNumberField::kMax); scope_info.set(module_var_entry + kModuleVariablePropertiesOffset, Smi::FromInt(properties)); @@ -271,6 +276,8 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, VariableModeField::encode(var->mode()) | InitFlagField::encode(var->initialization_flag()) | MaybeAssignedFlagField::encode(var->maybe_assigned()) | + RequiresBrandCheckField::encode( + var->get_requires_brand_check_flag()) | ParameterNumberField::encode(ParameterNumberField::kMax); scope_info.set(context_local_base + local_index, *var->name(), mode); scope_info.set(context_local_info_base + local_index, @@ -327,8 +334,8 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, // Module-specific information (only for module scopes). if (scope->is_module_scope()) { - Handle<ModuleInfo> module_info = - ModuleInfo::New(isolate, zone, scope->AsModuleScope()->module()); + Handle<SourceTextModuleInfo> module_info = SourceTextModuleInfo::New( + isolate, zone, scope->AsModuleScope()->module()); DCHECK_EQ(index, scope_info_handle->ModuleInfoIndex()); scope_info_handle->set(index++, *module_info); DCHECK_EQ(index, scope_info_handle->ModuleVariableCountIndex()); @@ -444,6 +451,7 @@ Handle<ScopeInfo> ScopeInfo::CreateForBootstrapping(Isolate* isolate, VariableModeField::encode(VariableMode::kConst) | InitFlagField::encode(kCreatedInitialized) | MaybeAssignedFlagField::encode(kNotAssigned) | + RequiresBrandCheckField::encode(kNoBrandCheck) | ParameterNumberField::encode(ParameterNumberField::kMax); scope_info->set(index++, Smi::FromInt(value)); } @@ -649,9 +657,9 @@ ScopeInfo ScopeInfo::OuterScopeInfo() const { return ScopeInfo::cast(get(OuterScopeInfoIndex())); } -ModuleInfo ScopeInfo::ModuleDescriptorInfo() const { +SourceTextModuleInfo ScopeInfo::ModuleDescriptorInfo() const { DCHECK(scope_type() == MODULE_SCOPE); - return ModuleInfo::cast(get(ModuleInfoIndex())); + return SourceTextModuleInfo::cast(get(ModuleInfoIndex())); } String ScopeInfo::ContextLocalName(int var) const { @@ -700,6 +708,14 @@ MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) const { return MaybeAssignedFlagField::decode(value); } +RequiresBrandCheckFlag ScopeInfo::RequiresBrandCheck(int var) const { + DCHECK_LE(0, var); + DCHECK_LT(var, ContextLocalCount()); + int info_index = ContextLocalInfosIndex() + var; + int value = Smi::ToInt(get(info_index)); + return RequiresBrandCheckField::decode(value); +} + // static bool ScopeInfo::VariableIsSynthetic(String name) { // There's currently no flag stored on the ScopeInfo to indicate that a @@ -739,7 +755,8 @@ int ScopeInfo::ModuleIndex(String name, VariableMode* mode, int ScopeInfo::ContextSlotIndex(ScopeInfo scope_info, String name, VariableMode* mode, InitializationFlag* init_flag, - MaybeAssignedFlag* maybe_assigned_flag) { + MaybeAssignedFlag* maybe_assigned_flag, + RequiresBrandCheckFlag* requires_brand_check) { DisallowHeapAllocation no_gc; DCHECK(name.IsInternalizedString()); DCHECK_NOT_NULL(mode); @@ -756,6 +773,7 @@ int ScopeInfo::ContextSlotIndex(ScopeInfo scope_info, String name, *mode = scope_info.ContextLocalMode(var); *init_flag = scope_info.ContextLocalInitFlag(var); *maybe_assigned_flag = scope_info.ContextLocalMaybeAssignedFlag(var); + *requires_brand_check = scope_info.RequiresBrandCheck(var); int result = Context::MIN_CONTEXT_SLOTS + var; DCHECK_LT(result, scope_info.ContextLength()); @@ -873,15 +891,13 @@ std::ostream& operator<<(std::ostream& os, return os; } -Handle<ModuleInfoEntry> ModuleInfoEntry::New(Isolate* isolate, - Handle<Object> export_name, - Handle<Object> local_name, - Handle<Object> import_name, - int module_request, int cell_index, - int beg_pos, int end_pos) { - Handle<ModuleInfoEntry> result = - Handle<ModuleInfoEntry>::cast(isolate->factory()->NewStruct( - MODULE_INFO_ENTRY_TYPE, AllocationType::kOld)); +Handle<SourceTextModuleInfoEntry> SourceTextModuleInfoEntry::New( + Isolate* isolate, Handle<Object> export_name, Handle<Object> local_name, + Handle<Object> import_name, int module_request, int cell_index, int beg_pos, + int end_pos) { + Handle<SourceTextModuleInfoEntry> result = + Handle<SourceTextModuleInfoEntry>::cast(isolate->factory()->NewStruct( + SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE, AllocationType::kOld)); result->set_export_name(*export_name); result->set_local_name(*local_name); result->set_import_name(*import_name); @@ -892,8 +908,8 @@ Handle<ModuleInfoEntry> ModuleInfoEntry::New(Isolate* isolate, return result; } -Handle<ModuleInfo> ModuleInfo::New(Isolate* isolate, Zone* zone, - ModuleDescriptor* descr) { +Handle<SourceTextModuleInfo> SourceTextModuleInfo::New( + Isolate* isolate, Zone* zone, SourceTextModuleDescriptor* descr) { // Serialize module requests. int size = static_cast<int>(descr->module_requests().size()); Handle<FixedArray> module_requests = isolate->factory()->NewFixedArray(size); @@ -911,7 +927,8 @@ Handle<ModuleInfo> ModuleInfo::New(Isolate* isolate, Zone* zone, { int i = 0; for (auto entry : descr->special_exports()) { - Handle<ModuleInfoEntry> serialized_entry = entry->Serialize(isolate); + Handle<SourceTextModuleInfoEntry> serialized_entry = + entry->Serialize(isolate); special_exports->set(i++, *serialized_entry); } } @@ -922,7 +939,8 @@ Handle<ModuleInfo> ModuleInfo::New(Isolate* isolate, Zone* zone, { int i = 0; for (auto entry : descr->namespace_imports()) { - Handle<ModuleInfoEntry> serialized_entry = entry->Serialize(isolate); + Handle<SourceTextModuleInfoEntry> serialized_entry = + entry->Serialize(isolate); namespace_imports->set(i++, *serialized_entry); } } @@ -937,13 +955,14 @@ Handle<ModuleInfo> ModuleInfo::New(Isolate* isolate, Zone* zone, { int i = 0; for (const auto& elem : descr->regular_imports()) { - Handle<ModuleInfoEntry> serialized_entry = + Handle<SourceTextModuleInfoEntry> serialized_entry = elem.second->Serialize(isolate); regular_imports->set(i++, *serialized_entry); } } - Handle<ModuleInfo> result = isolate->factory()->NewModuleInfo(); + Handle<SourceTextModuleInfo> result = + isolate->factory()->NewSourceTextModuleInfo(); result->set(kModuleRequestsIndex, *module_requests); result->set(kSpecialExportsIndex, *special_exports); result->set(kRegularExportsIndex, *regular_exports); @@ -953,22 +972,22 @@ Handle<ModuleInfo> ModuleInfo::New(Isolate* isolate, Zone* zone, return result; } -int ModuleInfo::RegularExportCount() const { +int SourceTextModuleInfo::RegularExportCount() const { DCHECK_EQ(regular_exports().length() % kRegularExportLength, 0); return regular_exports().length() / kRegularExportLength; } -String ModuleInfo::RegularExportLocalName(int i) const { +String SourceTextModuleInfo::RegularExportLocalName(int i) const { return String::cast(regular_exports().get(i * kRegularExportLength + kRegularExportLocalNameOffset)); } -int ModuleInfo::RegularExportCellIndex(int i) const { +int SourceTextModuleInfo::RegularExportCellIndex(int i) const { return Smi::ToInt(regular_exports().get(i * kRegularExportLength + kRegularExportCellIndexOffset)); } -FixedArray ModuleInfo::RegularExportExportNames(int i) const { +FixedArray SourceTextModuleInfo::RegularExportExportNames(int i) const { return FixedArray::cast(regular_exports().get( i * kRegularExportLength + kRegularExportExportNamesOffset)); } diff --git a/chromium/v8/src/objects/scope-info.h b/chromium/v8/src/objects/scope-info.h index 8d433576310..0b8eb61b001 100644 --- a/chromium/v8/src/objects/scope-info.h +++ b/chromium/v8/src/objects/scope-info.h @@ -22,7 +22,7 @@ class Handle; class Isolate; template <typename T> class MaybeHandle; -class ModuleInfo; +class SourceTextModuleInfo; class Scope; class Zone; @@ -113,7 +113,7 @@ class ScopeInfo : public FixedArray { int EndPosition() const; void SetPositionInfo(int start, int end); - ModuleInfo ModuleDescriptorInfo() const; + SourceTextModuleInfo ModuleDescriptorInfo() const; // Return the name of the given context local. String ContextLocalName(int var) const; @@ -130,6 +130,9 @@ class ScopeInfo : public FixedArray { // Return the initialization flag of the given context local. MaybeAssignedFlag ContextLocalMaybeAssignedFlag(int var) const; + // Return whether access to the variable requries a brand check. + RequiresBrandCheckFlag RequiresBrandCheck(int var) const; + // Return true if this local was introduced by the compiler, and should not be // exposed to the user in a debugger. static bool VariableIsSynthetic(String name); @@ -141,7 +144,8 @@ class ScopeInfo : public FixedArray { // mode for that variable. static int ContextSlotIndex(ScopeInfo scope_info, String name, VariableMode* mode, InitializationFlag* init_flag, - MaybeAssignedFlag* maybe_assigned_flag); + MaybeAssignedFlag* maybe_assigned_flag, + RequiresBrandCheckFlag* requires_brand_check); // Lookup metadata of a MODULE-allocated variable. Return 0 if there is no // module variable with the given name (the index value of a MODULE variable @@ -284,10 +288,10 @@ class ScopeInfo : public FixedArray { // the scope belongs to a function or script. // 7. OuterScopeInfoIndex: // The outer scope's ScopeInfo or the hole if there's none. - // 8. ModuleInfo, ModuleVariableCount, and ModuleVariables: - // For a module scope, this part contains the ModuleInfo, the number of - // MODULE-allocated variables, and the metadata of those variables. For - // non-module scopes it is empty. + // 8. SourceTextModuleInfo, ModuleVariableCount, and ModuleVariables: + // For a module scope, this part contains the SourceTextModuleInfo, the + // number of MODULE-allocated variables, and the metadata of those + // variables. For non-module scopes it is empty. int ContextLocalNamesIndex() const; int ContextLocalInfosIndex() const; int ReceiverInfoIndex() const; @@ -322,8 +326,11 @@ class ScopeInfo : public FixedArray { class VariableModeField : public BitField<VariableMode, 0, 3> {}; class InitFlagField : public BitField<InitializationFlag, 3, 1> {}; class MaybeAssignedFlagField : public BitField<MaybeAssignedFlag, 4, 1> {}; + class RequiresBrandCheckField + : public BitField<RequiresBrandCheckFlag, MaybeAssignedFlagField::kNext, + 1> {}; class ParameterNumberField - : public BitField<uint32_t, MaybeAssignedFlagField::kNext, 16> {}; + : public BitField<uint32_t, RequiresBrandCheckField::kNext, 16> {}; friend class ScopeIterator; friend std::ostream& operator<<(std::ostream& os, diff --git a/chromium/v8/src/objects/shared-function-info-inl.h b/chromium/v8/src/objects/shared-function-info-inl.h index f5413ce1de8..9778db5d908 100644 --- a/chromium/v8/src/objects/shared-function-info-inl.h +++ b/chromium/v8/src/objects/shared-function-info-inl.h @@ -91,7 +91,6 @@ CAST_ACCESSOR(UncompiledData) ACCESSORS(UncompiledData, inferred_name, String, kInferredNameOffset) INT32_ACCESSORS(UncompiledData, start_position, kStartPositionOffset) INT32_ACCESSORS(UncompiledData, end_position, kEndPositionOffset) -INT32_ACCESSORS(UncompiledData, function_literal_id, kFunctionLiteralIdOffset) void UncompiledData::clear_padding() { if (FIELD_SIZE(kOptionalPaddingOffset) == 0) return; @@ -106,9 +105,9 @@ CAST_ACCESSOR(UncompiledDataWithPreparseData) ACCESSORS(UncompiledDataWithPreparseData, preparse_data, PreparseData, kPreparseDataOffset) -bool HeapObject::IsUncompiledData() const { - return IsUncompiledDataWithoutPreparseData() || - IsUncompiledDataWithPreparseData(); +DEF_GETTER(HeapObject, IsUncompiledData, bool) { + return IsUncompiledDataWithoutPreparseData(isolate) || + IsUncompiledDataWithPreparseData(isolate); } OBJECT_CONSTRUCTORS_IMPL(InterpreterData, Struct) @@ -128,6 +127,9 @@ ACCESSORS(SharedFunctionInfo, name_or_scope_info, Object, ACCESSORS(SharedFunctionInfo, script_or_debug_info, Object, kScriptOrDebugInfoOffset) +INT32_ACCESSORS(SharedFunctionInfo, function_literal_id, + kFunctionLiteralIdOffset) + #if V8_SFI_HAS_UNIQUE_ID INT_ACCESSORS(SharedFunctionInfo, unique_id, kUniqueIdOffset) #endif @@ -629,7 +631,7 @@ void SharedFunctionInfo::ClearPreparseData() { // static void UncompiledData::Initialize( UncompiledData data, String inferred_name, int start_position, - int end_position, int function_literal_id, + int end_position, std::function<void(HeapObject object, ObjectSlot slot, HeapObject target)> gc_notify_updated_slot) { data.set_inferred_name(inferred_name); @@ -637,28 +639,22 @@ void UncompiledData::Initialize( data, data.RawField(UncompiledData::kInferredNameOffset), inferred_name); data.set_start_position(start_position); data.set_end_position(end_position); - data.set_function_literal_id(function_literal_id); data.clear_padding(); } void UncompiledDataWithPreparseData::Initialize( UncompiledDataWithPreparseData data, String inferred_name, - int start_position, int end_position, int function_literal_id, - PreparseData scope_data, + int start_position, int end_position, PreparseData scope_data, std::function<void(HeapObject object, ObjectSlot slot, HeapObject target)> gc_notify_updated_slot) { UncompiledData::Initialize(data, inferred_name, start_position, end_position, - function_literal_id, gc_notify_updated_slot); + gc_notify_updated_slot); data.set_preparse_data(scope_data); gc_notify_updated_slot( data, data.RawField(UncompiledDataWithPreparseData::kPreparseDataOffset), scope_data); } -bool UncompiledData::has_function_literal_id() { - return function_literal_id() != kFunctionLiteralIdInvalid; -} - bool SharedFunctionInfo::HasWasmExportedFunctionData() const { return function_data().IsWasmExportedFunctionData(); } diff --git a/chromium/v8/src/objects/shared-function-info.h b/chromium/v8/src/objects/shared-function-info.h index a3b84ee46ea..f7a82964b19 100644 --- a/chromium/v8/src/objects/shared-function-info.h +++ b/chromium/v8/src/objects/shared-function-info.h @@ -104,16 +104,12 @@ class UncompiledData : public HeapObject { DECL_ACCESSORS(inferred_name, String) DECL_INT32_ACCESSORS(start_position) DECL_INT32_ACCESSORS(end_position) - DECL_INT32_ACCESSORS(function_literal_id) - - // Returns true if the UncompiledData contains a valid function_literal_id. - inline bool has_function_literal_id(); DECL_CAST(UncompiledData) inline static void Initialize( UncompiledData data, String inferred_name, int start_position, - int end_position, int function_literal_id, + int end_position, std::function<void(HeapObject object, ObjectSlot slot, HeapObject target)> gc_notify_updated_slot = [](HeapObject object, ObjectSlot slot, HeapObject target) {}); @@ -126,7 +122,6 @@ class UncompiledData : public HeapObject { /* Raw data fields. */ \ V(kStartPositionOffset, kInt32Size) \ V(kEndPositionOffset, kInt32Size) \ - V(kFunctionLiteralIdOffset, kInt32Size) \ V(kOptionalPaddingOffset, POINTER_SIZE_PADDING(kOptionalPaddingOffset)) \ /* Header size. */ \ V(kSize, 0) @@ -172,8 +167,7 @@ class UncompiledDataWithPreparseData : public UncompiledData { inline static void Initialize( UncompiledDataWithPreparseData data, String inferred_name, - int start_position, int end_position, int function_literal_id, - PreparseData scope_data, + int start_position, int end_position, PreparseData scope_data, std::function<void(HeapObject object, ObjectSlot slot, HeapObject target)> gc_notify_updated_slot = [](HeapObject object, ObjectSlot slot, HeapObject target) {}); @@ -316,6 +310,11 @@ class SharedFunctionInfo : public HeapObject { // function. The value is only reliable when the function has been compiled. DECL_UINT16_ACCESSORS(expected_nof_properties) + // [function_literal_id] - uniquely identifies the FunctionLiteral this + // SharedFunctionInfo represents within its script, or -1 if this + // SharedFunctionInfo object doesn't correspond to a parsed FunctionLiteral. + DECL_INT32_ACCESSORS(function_literal_id) + #if V8_SFI_HAS_UNIQUE_ID // [unique_id] - For --trace-maps purposes, an identifier that's persistent // even if the GC moves this SharedFunctionInfo. @@ -385,9 +384,6 @@ class SharedFunctionInfo : public HeapObject { inline bool HasInferredName(); inline String inferred_name(); - // Get the function literal id associated with this function, for parsing. - V8_EXPORT_PRIVATE int FunctionLiteralId(Isolate* isolate) const; - // Break infos are contained in DebugInfo, this is a convenience method // to simplify access. V8_EXPORT_PRIVATE bool HasBreakInfo() const; @@ -624,7 +620,7 @@ class SharedFunctionInfo : public HeapObject { // Returns the unique TraceID for this SharedFunctionInfo (within the // kTraceScope, works only for functions that have a Script and start/end // position). - uint64_t TraceID() const; + uint64_t TraceID(FunctionLiteral* literal = nullptr) const; // Returns the unique trace ID reference for this SharedFunctionInfo // (based on the |TraceID()| above). @@ -634,16 +630,14 @@ class SharedFunctionInfo : public HeapObject { class ScriptIterator { public: V8_EXPORT_PRIVATE ScriptIterator(Isolate* isolate, Script script); - ScriptIterator(Isolate* isolate, - Handle<WeakFixedArray> shared_function_infos); + explicit ScriptIterator(Handle<WeakFixedArray> shared_function_infos); V8_EXPORT_PRIVATE SharedFunctionInfo Next(); int CurrentIndex() const { return index_ - 1; } // Reset the iterator to run on |script|. - void Reset(Script script); + void Reset(Isolate* isolate, Script script); private: - Isolate* isolate_; Handle<WeakFixedArray> shared_function_infos_; int index_; DISALLOW_COPY_AND_ASSIGN(ScriptIterator); @@ -656,6 +650,7 @@ class SharedFunctionInfo : public HeapObject { V8_EXPORT_PRIVATE SharedFunctionInfo Next(); private: + Isolate* isolate_; Script::Iterator script_iterator_; WeakArrayList::Iterator noscript_sfi_iterator_; SharedFunctionInfo::ScriptIterator sfi_iterator_; @@ -744,10 +739,6 @@ class SharedFunctionInfo : public HeapObject { friend class V8HeapExplorer; FRIEND_TEST(PreParserTest, LazyFunctionLength); - // Find the index of this function in the parent script. Slow path of - // FunctionLiteralId. - int FindIndexInScript(Isolate* isolate) const; - OBJECT_CONSTRUCTORS(SharedFunctionInfo, HeapObject); }; diff --git a/chromium/v8/src/objects/slots.h b/chromium/v8/src/objects/slots.h index fa8b558939b..85f65253998 100644 --- a/chromium/v8/src/objects/slots.h +++ b/chromium/v8/src/objects/slots.h @@ -5,8 +5,8 @@ #ifndef V8_OBJECTS_SLOTS_H_ #define V8_OBJECTS_SLOTS_H_ +#include "src/base/memory.h" #include "src/common/globals.h" -#include "src/common/v8memory.h" namespace v8 { namespace internal { @@ -192,11 +192,11 @@ class UnalignedSlot : public SlotBase<UnalignedSlot<T>, T, 1> { Reference(const Reference&) V8_NOEXCEPT = default; Reference& operator=(const Reference& other) V8_NOEXCEPT { - WriteUnalignedValue<T>(address_, other.value()); + base::WriteUnalignedValue<T>(address_, other.value()); return *this; } Reference& operator=(T value) { - WriteUnalignedValue<T>(address_, value); + base::WriteUnalignedValue<T>(address_, value); return *this; } @@ -206,8 +206,8 @@ class UnalignedSlot : public SlotBase<UnalignedSlot<T>, T, 1> { void swap(Reference& other) { T tmp = value(); - WriteUnalignedValue<T>(address_, other.value()); - WriteUnalignedValue<T>(other.address_, tmp); + base::WriteUnalignedValue<T>(address_, other.value()); + base::WriteUnalignedValue<T>(other.address_, tmp); } bool operator<(const Reference& other) const { @@ -219,7 +219,7 @@ class UnalignedSlot : public SlotBase<UnalignedSlot<T>, T, 1> { } private: - T value() const { return ReadUnalignedValue<T>(address_); } + T value() const { return base::ReadUnalignedValue<T>(address_); } Address address_; }; diff --git a/chromium/v8/src/objects/source-text-module.cc b/chromium/v8/src/objects/source-text-module.cc new file mode 100644 index 00000000000..e6637415c18 --- /dev/null +++ b/chromium/v8/src/objects/source-text-module.cc @@ -0,0 +1,661 @@ +// 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/objects/source-text-module.h" + +#include "src/api/api-inl.h" +#include "src/ast/modules.h" +#include "src/builtins/accessors.h" +#include "src/objects/js-generator-inl.h" +#include "src/objects/module-inl.h" +#include "src/objects/objects-inl.h" +#include "src/objects/shared-function-info.h" +#include "src/utils/ostreams.h" + +namespace v8 { +namespace internal { + +struct StringHandleHash { + V8_INLINE size_t operator()(Handle<String> string) const { + return string->Hash(); + } +}; + +struct StringHandleEqual { + V8_INLINE bool operator()(Handle<String> lhs, Handle<String> rhs) const { + return lhs->Equals(*rhs); + } +}; + +class UnorderedStringSet + : public std::unordered_set<Handle<String>, StringHandleHash, + StringHandleEqual, + ZoneAllocator<Handle<String>>> { + public: + explicit UnorderedStringSet(Zone* zone) + : std::unordered_set<Handle<String>, StringHandleHash, StringHandleEqual, + ZoneAllocator<Handle<String>>>( + 2 /* bucket count */, StringHandleHash(), StringHandleEqual(), + ZoneAllocator<Handle<String>>(zone)) {} +}; + +class UnorderedStringMap + : public std::unordered_map< + Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual, + ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>> { + public: + explicit UnorderedStringMap(Zone* zone) + : std::unordered_map< + Handle<String>, Handle<Object>, StringHandleHash, StringHandleEqual, + ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>>( + 2 /* bucket count */, StringHandleHash(), StringHandleEqual(), + ZoneAllocator<std::pair<const Handle<String>, Handle<Object>>>( + zone)) {} +}; + +class Module::ResolveSet + : public std::unordered_map< + Handle<Module>, UnorderedStringSet*, ModuleHandleHash, + ModuleHandleEqual, + ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>> { + public: + explicit ResolveSet(Zone* zone) + : std::unordered_map<Handle<Module>, UnorderedStringSet*, + ModuleHandleHash, ModuleHandleEqual, + ZoneAllocator<std::pair<const Handle<Module>, + UnorderedStringSet*>>>( + 2 /* bucket count */, ModuleHandleHash(), ModuleHandleEqual(), + ZoneAllocator<std::pair<const Handle<Module>, UnorderedStringSet*>>( + zone)), + zone_(zone) {} + + Zone* zone() const { return zone_; } + + private: + Zone* zone_; +}; + +SharedFunctionInfo SourceTextModule::GetSharedFunctionInfo() const { + DisallowHeapAllocation no_alloc; + DCHECK_NE(status(), Module::kEvaluating); + DCHECK_NE(status(), Module::kEvaluated); + switch (status()) { + case kUninstantiated: + case kPreInstantiating: + DCHECK(code().IsSharedFunctionInfo()); + return SharedFunctionInfo::cast(code()); + case kInstantiating: + DCHECK(code().IsJSFunction()); + return JSFunction::cast(code()).shared(); + case kInstantiated: + DCHECK(code().IsJSGeneratorObject()); + return JSGeneratorObject::cast(code()).function().shared(); + case kEvaluating: + case kEvaluated: + case kErrored: + UNREACHABLE(); + } + + UNREACHABLE(); +} + +int SourceTextModule::ExportIndex(int cell_index) { + DCHECK_EQ(SourceTextModuleDescriptor::GetCellIndexKind(cell_index), + SourceTextModuleDescriptor::kExport); + return cell_index - 1; +} + +int SourceTextModule::ImportIndex(int cell_index) { + DCHECK_EQ(SourceTextModuleDescriptor::GetCellIndexKind(cell_index), + SourceTextModuleDescriptor::kImport); + return -cell_index - 1; +} + +void SourceTextModule::CreateIndirectExport( + Isolate* isolate, Handle<SourceTextModule> module, Handle<String> name, + Handle<SourceTextModuleInfoEntry> entry) { + Handle<ObjectHashTable> exports(module->exports(), isolate); + DCHECK(exports->Lookup(name).IsTheHole(isolate)); + exports = ObjectHashTable::Put(exports, name, entry); + module->set_exports(*exports); +} + +void SourceTextModule::CreateExport(Isolate* isolate, + Handle<SourceTextModule> module, + int cell_index, Handle<FixedArray> names) { + DCHECK_LT(0, names->length()); + Handle<Cell> cell = + isolate->factory()->NewCell(isolate->factory()->undefined_value()); + module->regular_exports().set(ExportIndex(cell_index), *cell); + + Handle<ObjectHashTable> exports(module->exports(), isolate); + for (int i = 0, n = names->length(); i < n; ++i) { + Handle<String> name(String::cast(names->get(i)), isolate); + DCHECK(exports->Lookup(name).IsTheHole(isolate)); + exports = ObjectHashTable::Put(exports, name, cell); + } + module->set_exports(*exports); +} + +Cell SourceTextModule::GetCell(int cell_index) { + DisallowHeapAllocation no_gc; + Object cell; + switch (SourceTextModuleDescriptor::GetCellIndexKind(cell_index)) { + case SourceTextModuleDescriptor::kImport: + cell = regular_imports().get(ImportIndex(cell_index)); + break; + case SourceTextModuleDescriptor::kExport: + cell = regular_exports().get(ExportIndex(cell_index)); + break; + case SourceTextModuleDescriptor::kInvalid: + UNREACHABLE(); + break; + } + return Cell::cast(cell); +} + +Handle<Object> SourceTextModule::LoadVariable(Isolate* isolate, + Handle<SourceTextModule> module, + int cell_index) { + return handle(module->GetCell(cell_index).value(), isolate); +} + +void SourceTextModule::StoreVariable(Handle<SourceTextModule> module, + int cell_index, Handle<Object> value) { + DisallowHeapAllocation no_gc; + DCHECK_EQ(SourceTextModuleDescriptor::GetCellIndexKind(cell_index), + SourceTextModuleDescriptor::kExport); + module->GetCell(cell_index).set_value(*value); +} + +MaybeHandle<Cell> SourceTextModule::ResolveExport( + Isolate* isolate, Handle<SourceTextModule> module, + Handle<String> module_specifier, Handle<String> export_name, + MessageLocation loc, bool must_resolve, Module::ResolveSet* resolve_set) { + Handle<Object> object(module->exports().Lookup(export_name), isolate); + if (object->IsCell()) { + // Already resolved (e.g. because it's a local export). + return Handle<Cell>::cast(object); + } + + // Check for cycle before recursing. + { + // Attempt insertion with a null string set. + auto result = resolve_set->insert({module, nullptr}); + UnorderedStringSet*& name_set = result.first->second; + if (result.second) { + // |module| wasn't in the map previously, so allocate a new name set. + Zone* zone = resolve_set->zone(); + name_set = + new (zone->New(sizeof(UnorderedStringSet))) UnorderedStringSet(zone); + } else if (name_set->count(export_name)) { + // Cycle detected. + if (must_resolve) { + return isolate->Throw<Cell>( + isolate->factory()->NewSyntaxError( + MessageTemplate::kCyclicModuleDependency, export_name, + module_specifier), + &loc); + } + return MaybeHandle<Cell>(); + } + name_set->insert(export_name); + } + + if (object->IsSourceTextModuleInfoEntry()) { + // Not yet resolved indirect export. + Handle<SourceTextModuleInfoEntry> entry = + Handle<SourceTextModuleInfoEntry>::cast(object); + Handle<String> import_name(String::cast(entry->import_name()), isolate); + Handle<Script> script(module->script(), isolate); + MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos()); + + Handle<Cell> cell; + if (!ResolveImport(isolate, module, import_name, entry->module_request(), + new_loc, true, resolve_set) + .ToHandle(&cell)) { + DCHECK(isolate->has_pending_exception()); + return MaybeHandle<Cell>(); + } + + // The export table may have changed but the entry in question should be + // unchanged. + Handle<ObjectHashTable> exports(module->exports(), isolate); + DCHECK(exports->Lookup(export_name).IsSourceTextModuleInfoEntry()); + + exports = ObjectHashTable::Put(exports, export_name, cell); + module->set_exports(*exports); + return cell; + } + + DCHECK(object->IsTheHole(isolate)); + return SourceTextModule::ResolveExportUsingStarExports( + isolate, module, module_specifier, export_name, loc, must_resolve, + resolve_set); +} + +MaybeHandle<Cell> SourceTextModule::ResolveImport( + Isolate* isolate, Handle<SourceTextModule> module, Handle<String> name, + int module_request, MessageLocation loc, bool must_resolve, + Module::ResolveSet* resolve_set) { + Handle<Module> requested_module( + Module::cast(module->requested_modules().get(module_request)), isolate); + Handle<String> specifier( + String::cast(module->info().module_requests().get(module_request)), + isolate); + MaybeHandle<Cell> result = + Module::ResolveExport(isolate, requested_module, specifier, name, loc, + must_resolve, resolve_set); + DCHECK_IMPLIES(isolate->has_pending_exception(), result.is_null()); + return result; +} + +MaybeHandle<Cell> SourceTextModule::ResolveExportUsingStarExports( + Isolate* isolate, Handle<SourceTextModule> module, + Handle<String> module_specifier, Handle<String> export_name, + MessageLocation loc, bool must_resolve, Module::ResolveSet* resolve_set) { + if (!export_name->Equals(ReadOnlyRoots(isolate).default_string())) { + // Go through all star exports looking for the given name. If multiple star + // exports provide the name, make sure they all map it to the same cell. + Handle<Cell> unique_cell; + Handle<FixedArray> special_exports(module->info().special_exports(), + isolate); + for (int i = 0, n = special_exports->length(); i < n; ++i) { + i::Handle<i::SourceTextModuleInfoEntry> entry( + i::SourceTextModuleInfoEntry::cast(special_exports->get(i)), isolate); + if (!entry->export_name().IsUndefined(isolate)) { + continue; // Indirect export. + } + + Handle<Script> script(module->script(), isolate); + MessageLocation new_loc(script, entry->beg_pos(), entry->end_pos()); + + Handle<Cell> cell; + if (ResolveImport(isolate, module, export_name, entry->module_request(), + new_loc, false, resolve_set) + .ToHandle(&cell)) { + if (unique_cell.is_null()) unique_cell = cell; + if (*unique_cell != *cell) { + return isolate->Throw<Cell>(isolate->factory()->NewSyntaxError( + MessageTemplate::kAmbiguousExport, + module_specifier, export_name), + &loc); + } + } else if (isolate->has_pending_exception()) { + return MaybeHandle<Cell>(); + } + } + + if (!unique_cell.is_null()) { + // Found a unique star export for this name. + Handle<ObjectHashTable> exports(module->exports(), isolate); + DCHECK(exports->Lookup(export_name).IsTheHole(isolate)); + exports = ObjectHashTable::Put(exports, export_name, unique_cell); + module->set_exports(*exports); + return unique_cell; + } + } + + // Unresolvable. + if (must_resolve) { + return isolate->Throw<Cell>( + isolate->factory()->NewSyntaxError(MessageTemplate::kUnresolvableExport, + module_specifier, export_name), + &loc); + } + return MaybeHandle<Cell>(); +} + +bool SourceTextModule::PrepareInstantiate( + Isolate* isolate, Handle<SourceTextModule> module, + v8::Local<v8::Context> context, v8::Module::ResolveCallback callback) { + // Obtain requested modules. + Handle<SourceTextModuleInfo> module_info(module->info(), isolate); + Handle<FixedArray> module_requests(module_info->module_requests(), isolate); + Handle<FixedArray> requested_modules(module->requested_modules(), isolate); + for (int i = 0, length = module_requests->length(); i < length; ++i) { + Handle<String> specifier(String::cast(module_requests->get(i)), isolate); + v8::Local<v8::Module> api_requested_module; + if (!callback(context, v8::Utils::ToLocal(specifier), + v8::Utils::ToLocal(Handle<Module>::cast(module))) + .ToLocal(&api_requested_module)) { + isolate->PromoteScheduledException(); + return false; + } + Handle<Module> requested_module = Utils::OpenHandle(*api_requested_module); + requested_modules->set(i, *requested_module); + } + + // Recurse. + for (int i = 0, length = requested_modules->length(); i < length; ++i) { + Handle<Module> requested_module(Module::cast(requested_modules->get(i)), + isolate); + if (!Module::PrepareInstantiate(isolate, requested_module, context, + callback)) { + return false; + } + } + + // Set up local exports. + // TODO(neis): Create regular_exports array here instead of in factory method? + for (int i = 0, n = module_info->RegularExportCount(); i < n; ++i) { + int cell_index = module_info->RegularExportCellIndex(i); + Handle<FixedArray> export_names(module_info->RegularExportExportNames(i), + isolate); + CreateExport(isolate, module, cell_index, export_names); + } + + // Partially set up indirect exports. + // For each indirect export, we create the appropriate slot in the export + // table and store its SourceTextModuleInfoEntry there. When we later find + // the correct Cell in the module that actually provides the value, we replace + // the SourceTextModuleInfoEntry by that Cell (see ResolveExport). + Handle<FixedArray> special_exports(module_info->special_exports(), isolate); + for (int i = 0, n = special_exports->length(); i < n; ++i) { + Handle<SourceTextModuleInfoEntry> entry( + SourceTextModuleInfoEntry::cast(special_exports->get(i)), isolate); + Handle<Object> export_name(entry->export_name(), isolate); + if (export_name->IsUndefined(isolate)) continue; // Star export. + CreateIndirectExport(isolate, module, Handle<String>::cast(export_name), + entry); + } + + DCHECK_EQ(module->status(), kPreInstantiating); + return true; +} + +bool SourceTextModule::RunInitializationCode(Isolate* isolate, + Handle<SourceTextModule> module) { + DCHECK_EQ(module->status(), kInstantiating); + Handle<JSFunction> function(JSFunction::cast(module->code()), isolate); + DCHECK_EQ(MODULE_SCOPE, function->shared().scope_info().scope_type()); + Handle<Object> receiver = isolate->factory()->undefined_value(); + Handle<Object> argv[] = {module}; + MaybeHandle<Object> maybe_generator = + Execution::Call(isolate, function, receiver, arraysize(argv), argv); + Handle<Object> generator; + if (!maybe_generator.ToHandle(&generator)) { + DCHECK(isolate->has_pending_exception()); + return false; + } + DCHECK_EQ(*function, Handle<JSGeneratorObject>::cast(generator)->function()); + module->set_code(*generator); + return true; +} + +bool SourceTextModule::MaybeTransitionComponent( + Isolate* isolate, Handle<SourceTextModule> module, + ZoneForwardList<Handle<SourceTextModule>>* stack, Status new_status) { + DCHECK(new_status == kInstantiated || new_status == kEvaluated); + SLOW_DCHECK( + // {module} is on the {stack}. + std::count_if(stack->begin(), stack->end(), + [&](Handle<Module> m) { return *m == *module; }) == 1); + DCHECK_LE(module->dfs_ancestor_index(), module->dfs_index()); + if (module->dfs_ancestor_index() == module->dfs_index()) { + // This is the root of its strongly connected component. + Handle<SourceTextModule> ancestor; + do { + ancestor = stack->front(); + stack->pop_front(); + DCHECK_EQ(ancestor->status(), + new_status == kInstantiated ? kInstantiating : kEvaluating); + if (new_status == kInstantiated) { + if (!SourceTextModule::RunInitializationCode(isolate, ancestor)) + return false; + } + ancestor->SetStatus(new_status); + } while (*ancestor != *module); + } + return true; +} + +bool SourceTextModule::FinishInstantiate( + Isolate* isolate, Handle<SourceTextModule> module, + ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index, + Zone* zone) { + // Instantiate SharedFunctionInfo and mark module as instantiating for + // the recursion. + Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(module->code()), + isolate); + Handle<JSFunction> function = + isolate->factory()->NewFunctionFromSharedFunctionInfo( + shared, isolate->native_context()); + module->set_code(*function); + module->SetStatus(kInstantiating); + module->set_dfs_index(*dfs_index); + module->set_dfs_ancestor_index(*dfs_index); + stack->push_front(module); + (*dfs_index)++; + + // Recurse. + Handle<FixedArray> requested_modules(module->requested_modules(), isolate); + for (int i = 0, length = requested_modules->length(); i < length; ++i) { + Handle<Module> requested_module(Module::cast(requested_modules->get(i)), + isolate); + if (!Module::FinishInstantiate(isolate, requested_module, stack, dfs_index, + zone)) { + return false; + } + + DCHECK_NE(requested_module->status(), kEvaluating); + DCHECK_GE(requested_module->status(), kInstantiating); + SLOW_DCHECK( + // {requested_module} is instantiating iff it's on the {stack}. + (requested_module->status() == kInstantiating) == + std::count_if(stack->begin(), stack->end(), [&](Handle<Module> m) { + return *m == *requested_module; + })); + + if (requested_module->status() == kInstantiating) { + // SyntheticModules go straight to kInstantiated so this must be a + // SourceTextModule + module->set_dfs_ancestor_index( + std::min(module->dfs_ancestor_index(), + Handle<SourceTextModule>::cast(requested_module) + ->dfs_ancestor_index())); + } + } + + Handle<Script> script(module->script(), isolate); + Handle<SourceTextModuleInfo> module_info(module->info(), isolate); + + // Resolve imports. + Handle<FixedArray> regular_imports(module_info->regular_imports(), isolate); + for (int i = 0, n = regular_imports->length(); i < n; ++i) { + Handle<SourceTextModuleInfoEntry> entry( + SourceTextModuleInfoEntry::cast(regular_imports->get(i)), isolate); + Handle<String> name(String::cast(entry->import_name()), isolate); + MessageLocation loc(script, entry->beg_pos(), entry->end_pos()); + ResolveSet resolve_set(zone); + Handle<Cell> cell; + if (!ResolveImport(isolate, module, name, entry->module_request(), loc, + true, &resolve_set) + .ToHandle(&cell)) { + return false; + } + module->regular_imports().set(ImportIndex(entry->cell_index()), *cell); + } + + // Resolve indirect exports. + Handle<FixedArray> special_exports(module_info->special_exports(), isolate); + for (int i = 0, n = special_exports->length(); i < n; ++i) { + Handle<SourceTextModuleInfoEntry> entry( + SourceTextModuleInfoEntry::cast(special_exports->get(i)), isolate); + Handle<Object> name(entry->export_name(), isolate); + if (name->IsUndefined(isolate)) continue; // Star export. + MessageLocation loc(script, entry->beg_pos(), entry->end_pos()); + ResolveSet resolve_set(zone); + if (ResolveExport(isolate, module, Handle<String>(), + Handle<String>::cast(name), loc, true, &resolve_set) + .is_null()) { + return false; + } + } + + return MaybeTransitionComponent(isolate, module, stack, kInstantiated); +} + +void SourceTextModule::FetchStarExports(Isolate* isolate, + Handle<SourceTextModule> module, + Zone* zone, + UnorderedModuleSet* visited) { + DCHECK_GE(module->status(), Module::kInstantiating); + + if (module->module_namespace().IsJSModuleNamespace()) return; // Shortcut. + + bool cycle = !visited->insert(module).second; + if (cycle) return; + Handle<ObjectHashTable> exports(module->exports(), isolate); + UnorderedStringMap more_exports(zone); + + // TODO(neis): Only allocate more_exports if there are star exports. + // Maybe split special_exports into indirect_exports and star_exports. + + ReadOnlyRoots roots(isolate); + Handle<FixedArray> special_exports(module->info().special_exports(), isolate); + for (int i = 0, n = special_exports->length(); i < n; ++i) { + Handle<SourceTextModuleInfoEntry> entry( + SourceTextModuleInfoEntry::cast(special_exports->get(i)), isolate); + if (!entry->export_name().IsUndefined(roots)) { + continue; // Indirect export. + } + + Handle<Module> requested_module( + Module::cast(module->requested_modules().get(entry->module_request())), + isolate); + + // Recurse. + if (requested_module->IsSourceTextModule()) + FetchStarExports(isolate, + Handle<SourceTextModule>::cast(requested_module), zone, + visited); + + // Collect all of [requested_module]'s exports that must be added to + // [module]'s exports (i.e. to [exports]). We record these in + // [more_exports]. Ambiguities (conflicting exports) are marked by mapping + // the name to undefined instead of a Cell. + Handle<ObjectHashTable> requested_exports(requested_module->exports(), + isolate); + for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) { + Object key; + if (!requested_exports->ToKey(roots, i, &key)) continue; + Handle<String> name(String::cast(key), isolate); + + if (name->Equals(roots.default_string())) continue; + if (!exports->Lookup(name).IsTheHole(roots)) continue; + + Handle<Cell> cell(Cell::cast(requested_exports->ValueAt(i)), isolate); + auto insert_result = more_exports.insert(std::make_pair(name, cell)); + if (!insert_result.second) { + auto it = insert_result.first; + if (*it->second == *cell || it->second->IsUndefined(roots)) { + // We already recorded this mapping before, or the name is already + // known to be ambiguous. In either case, there's nothing to do. + } else { + DCHECK(it->second->IsCell()); + // Different star exports provide different cells for this name, hence + // mark the name as ambiguous. + it->second = roots.undefined_value_handle(); + } + } + } + } + + // Copy [more_exports] into [exports]. + for (const auto& elem : more_exports) { + if (elem.second->IsUndefined(isolate)) continue; // Ambiguous export. + DCHECK(!elem.first->Equals(ReadOnlyRoots(isolate).default_string())); + DCHECK(elem.second->IsCell()); + exports = ObjectHashTable::Put(exports, elem.first, elem.second); + } + module->set_exports(*exports); +} + +Handle<JSModuleNamespace> SourceTextModule::GetModuleNamespace( + Isolate* isolate, Handle<SourceTextModule> module, int module_request) { + Handle<Module> requested_module( + Module::cast(module->requested_modules().get(module_request)), isolate); + return Module::GetModuleNamespace(isolate, requested_module); +} + +MaybeHandle<Object> SourceTextModule::Evaluate( + Isolate* isolate, Handle<SourceTextModule> module, + ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index) { + Handle<JSGeneratorObject> generator(JSGeneratorObject::cast(module->code()), + isolate); + module->set_code( + generator->function().shared().scope_info().ModuleDescriptorInfo()); + module->SetStatus(kEvaluating); + module->set_dfs_index(*dfs_index); + module->set_dfs_ancestor_index(*dfs_index); + stack->push_front(module); + (*dfs_index)++; + + // Recursion. + Handle<FixedArray> requested_modules(module->requested_modules(), isolate); + for (int i = 0, length = requested_modules->length(); i < length; ++i) { + Handle<Module> requested_module(Module::cast(requested_modules->get(i)), + isolate); + RETURN_ON_EXCEPTION( + isolate, Module::Evaluate(isolate, requested_module, stack, dfs_index), + Object); + + DCHECK_GE(requested_module->status(), kEvaluating); + DCHECK_NE(requested_module->status(), kErrored); + SLOW_DCHECK( + // {requested_module} is evaluating iff it's on the {stack}. + (requested_module->status() == kEvaluating) == + std::count_if(stack->begin(), stack->end(), [&](Handle<Module> m) { + return *m == *requested_module; + })); + + if (requested_module->status() == kEvaluating) { + // SyntheticModules go straight to kEvaluated so this must be a + // SourceTextModule + module->set_dfs_ancestor_index( + std::min(module->dfs_ancestor_index(), + Handle<SourceTextModule>::cast(requested_module) + ->dfs_ancestor_index())); + } + } + + // Evaluation of module body. + Handle<JSFunction> resume( + isolate->native_context()->generator_next_internal(), isolate); + Handle<Object> result; + ASSIGN_RETURN_ON_EXCEPTION( + isolate, result, Execution::Call(isolate, resume, generator, 0, nullptr), + Object); + DCHECK(JSIteratorResult::cast(*result).done().BooleanValue(isolate)); + + CHECK(MaybeTransitionComponent(isolate, module, stack, kEvaluated)); + return handle(JSIteratorResult::cast(*result).value(), isolate); +} + +void SourceTextModule::Reset(Isolate* isolate, + Handle<SourceTextModule> module) { + Factory* factory = isolate->factory(); + + DCHECK(module->import_meta().IsTheHole(isolate)); + + Handle<FixedArray> regular_exports = + factory->NewFixedArray(module->regular_exports().length()); + Handle<FixedArray> regular_imports = + factory->NewFixedArray(module->regular_imports().length()); + Handle<FixedArray> requested_modules = + factory->NewFixedArray(module->requested_modules().length()); + + if (module->status() == kInstantiating) { + module->set_code(JSFunction::cast(module->code()).shared()); + } + module->set_regular_exports(*regular_exports); + module->set_regular_imports(*regular_imports); + module->set_requested_modules(*requested_modules); + module->set_dfs_index(-1); + module->set_dfs_ancestor_index(-1); +} + +} // namespace internal +} // namespace v8 diff --git a/chromium/v8/src/objects/source-text-module.h b/chromium/v8/src/objects/source-text-module.h new file mode 100644 index 00000000000..5c20b7018b4 --- /dev/null +++ b/chromium/v8/src/objects/source-text-module.h @@ -0,0 +1,220 @@ +// 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. + +#ifndef V8_OBJECTS_SOURCE_TEXT_MODULE_H_ +#define V8_OBJECTS_SOURCE_TEXT_MODULE_H_ + +#include "src/objects/module.h" + +// Has to be the last include (doesn't have include guards): +#include "src/objects/object-macros.h" + +namespace v8 { +namespace internal { + +class UnorderedModuleSet; + +// The runtime representation of an ECMAScript Source Text Module Record. +// https://tc39.github.io/ecma262/#sec-source-text-module-records +class SourceTextModule : public Module { + public: + NEVER_READ_ONLY_SPACE + DECL_CAST(SourceTextModule) + DECL_VERIFIER(SourceTextModule) + DECL_PRINTER(SourceTextModule) + + // The code representing this module, or an abstraction thereof. + // This is either a SharedFunctionInfo, a JSFunction, a JSGeneratorObject, or + // a SourceTextModuleInfo, depending on the state (status) the module is in. + // See SourceTextModule::SourceTextModuleVerify() for the precise invariant. + DECL_ACCESSORS(code, Object) + + // Arrays of cells corresponding to regular exports and regular imports. + // A cell's position in the array is determined by the cell index of the + // associated module entry (which coincides with the variable index of the + // associated variable). + DECL_ACCESSORS(regular_exports, FixedArray) + DECL_ACCESSORS(regular_imports, FixedArray) + + // The shared function info in case {status} is not kEvaluating, kEvaluated or + // kErrored. + SharedFunctionInfo GetSharedFunctionInfo() const; + + // Modules imported or re-exported by this module. + // Corresponds 1-to-1 to the module specifier strings in + // SourceTextModuleInfo::module_requests. + DECL_ACCESSORS(requested_modules, FixedArray) + + // [script]: Script from which the module originates. + DECL_ACCESSORS(script, Script) + + // The value of import.meta inside of this module. + // Lazily initialized on first access. It's the hole before first access and + // a JSObject afterwards. + DECL_ACCESSORS(import_meta, Object) + + // Get the SourceTextModuleInfo associated with the code. + inline SourceTextModuleInfo info() const; + + Cell GetCell(int cell_index); + static Handle<Object> LoadVariable(Isolate* isolate, + Handle<SourceTextModule> module, + int cell_index); + static void StoreVariable(Handle<SourceTextModule> module, int cell_index, + Handle<Object> value); + + static int ImportIndex(int cell_index); + static int ExportIndex(int cell_index); + + // Get the namespace object for [module_request] of [module]. If it doesn't + // exist yet, it is created. + static Handle<JSModuleNamespace> GetModuleNamespace( + Isolate* isolate, Handle<SourceTextModule> module, int module_request); + + // Layout description. + DEFINE_FIELD_OFFSET_CONSTANTS(Module::kHeaderSize, + TORQUE_GENERATED_SOURCE_TEXT_MODULE_FIELDS) + + using BodyDescriptor = + SubclassBodyDescriptor<Module::BodyDescriptor, + FixedBodyDescriptor<kCodeOffset, kSize, kSize>>; + + private: + friend class Factory; + friend class Module; + + // TODO(neis): Don't store those in the module object? + DECL_INT_ACCESSORS(dfs_index) + DECL_INT_ACCESSORS(dfs_ancestor_index) + + // Helpers for Instantiate and Evaluate. + + static void CreateExport(Isolate* isolate, Handle<SourceTextModule> module, + int cell_index, Handle<FixedArray> names); + static void CreateIndirectExport(Isolate* isolate, + Handle<SourceTextModule> module, + Handle<String> name, + Handle<SourceTextModuleInfoEntry> entry); + + static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExport( + Isolate* isolate, Handle<SourceTextModule> module, + Handle<String> module_specifier, Handle<String> export_name, + MessageLocation loc, bool must_resolve, ResolveSet* resolve_set); + static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveImport( + Isolate* isolate, Handle<SourceTextModule> module, Handle<String> name, + int module_request, MessageLocation loc, bool must_resolve, + ResolveSet* resolve_set); + + static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExportUsingStarExports( + Isolate* isolate, Handle<SourceTextModule> module, + Handle<String> module_specifier, Handle<String> export_name, + MessageLocation loc, bool must_resolve, ResolveSet* resolve_set); + + static V8_WARN_UNUSED_RESULT bool PrepareInstantiate( + Isolate* isolate, Handle<SourceTextModule> module, + v8::Local<v8::Context> context, v8::Module::ResolveCallback callback); + static V8_WARN_UNUSED_RESULT bool FinishInstantiate( + Isolate* isolate, Handle<SourceTextModule> module, + ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index, + Zone* zone); + static V8_WARN_UNUSED_RESULT bool RunInitializationCode( + Isolate* isolate, Handle<SourceTextModule> module); + + static void FetchStarExports(Isolate* isolate, + Handle<SourceTextModule> module, Zone* zone, + UnorderedModuleSet* visited); + + static V8_WARN_UNUSED_RESULT MaybeHandle<Object> Evaluate( + Isolate* isolate, Handle<SourceTextModule> module, + ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index); + + static V8_WARN_UNUSED_RESULT bool MaybeTransitionComponent( + Isolate* isolate, Handle<SourceTextModule> module, + ZoneForwardList<Handle<SourceTextModule>>* stack, Status new_status); + + static void Reset(Isolate* isolate, Handle<SourceTextModule> module); + + OBJECT_CONSTRUCTORS(SourceTextModule, Module); +}; + +// SourceTextModuleInfo is to SourceTextModuleDescriptor what ScopeInfo is to +// Scope. +class SourceTextModuleInfo : public FixedArray { + public: + DECL_CAST(SourceTextModuleInfo) + + static Handle<SourceTextModuleInfo> New(Isolate* isolate, Zone* zone, + SourceTextModuleDescriptor* descr); + + inline FixedArray module_requests() const; + inline FixedArray special_exports() const; + inline FixedArray regular_exports() const; + inline FixedArray regular_imports() const; + inline FixedArray namespace_imports() const; + inline FixedArray module_request_positions() const; + + // Accessors for [regular_exports]. + int RegularExportCount() const; + String RegularExportLocalName(int i) const; + int RegularExportCellIndex(int i) const; + FixedArray RegularExportExportNames(int i) const; + +#ifdef DEBUG + inline bool Equals(SourceTextModuleInfo other) const; +#endif + + private: + friend class Factory; + friend class SourceTextModuleDescriptor; + enum { + kModuleRequestsIndex, + kSpecialExportsIndex, + kRegularExportsIndex, + kNamespaceImportsIndex, + kRegularImportsIndex, + kModuleRequestPositionsIndex, + kLength + }; + enum { + kRegularExportLocalNameOffset, + kRegularExportCellIndexOffset, + kRegularExportExportNamesOffset, + kRegularExportLength + }; + + OBJECT_CONSTRUCTORS(SourceTextModuleInfo, FixedArray); +}; + +class SourceTextModuleInfoEntry : public Struct { + public: + DECL_CAST(SourceTextModuleInfoEntry) + DECL_PRINTER(SourceTextModuleInfoEntry) + DECL_VERIFIER(SourceTextModuleInfoEntry) + + DECL_ACCESSORS(export_name, Object) + DECL_ACCESSORS(local_name, Object) + DECL_ACCESSORS(import_name, Object) + DECL_INT_ACCESSORS(module_request) + DECL_INT_ACCESSORS(cell_index) + DECL_INT_ACCESSORS(beg_pos) + DECL_INT_ACCESSORS(end_pos) + + static Handle<SourceTextModuleInfoEntry> New( + Isolate* isolate, Handle<Object> export_name, Handle<Object> local_name, + Handle<Object> import_name, int module_request, int cell_index, + int beg_pos, int end_pos); + + DEFINE_FIELD_OFFSET_CONSTANTS( + Struct::kHeaderSize, + TORQUE_GENERATED_SOURCE_TEXT_MODULE_INFO_ENTRY_FIELDS) + + OBJECT_CONSTRUCTORS(SourceTextModuleInfoEntry, Struct); +}; + +} // namespace internal +} // namespace v8 + +#include "src/objects/object-macros-undef.h" + +#endif // V8_OBJECTS_SOURCE_TEXT_MODULE_H_ diff --git a/chromium/v8/src/objects/stack-frame-info-inl.h b/chromium/v8/src/objects/stack-frame-info-inl.h index 8069e6e5c9c..e72af4df94a 100644 --- a/chromium/v8/src/objects/stack-frame-info-inl.h +++ b/chromium/v8/src/objects/stack-frame-info-inl.h @@ -32,11 +32,15 @@ ACCESSORS(StackFrameInfo, script_name, Object, kScriptNameOffset) ACCESSORS(StackFrameInfo, script_name_or_source_url, Object, kScriptNameOrSourceUrlOffset) ACCESSORS(StackFrameInfo, function_name, Object, kFunctionNameOffset) +ACCESSORS(StackFrameInfo, method_name, Object, kMethodNameOffset) +ACCESSORS(StackFrameInfo, type_name, Object, kTypeNameOffset) +ACCESSORS(StackFrameInfo, eval_origin, Object, kEvalOriginOffset) ACCESSORS(StackFrameInfo, wasm_module_name, Object, kWasmModuleNameOffset) SMI_ACCESSORS(StackFrameInfo, flag, kFlagOffset) BOOL_ACCESSORS(StackFrameInfo, flag, is_eval, kIsEvalBit) BOOL_ACCESSORS(StackFrameInfo, flag, is_constructor, kIsConstructorBit) BOOL_ACCESSORS(StackFrameInfo, flag, is_wasm, kIsWasmBit) +BOOL_ACCESSORS(StackFrameInfo, flag, is_asmjs_wasm, kIsAsmJsWasmBit) BOOL_ACCESSORS(StackFrameInfo, flag, is_user_java_script, kIsUserJavaScriptBit) BOOL_ACCESSORS(StackFrameInfo, flag, is_toplevel, kIsToplevelBit) BOOL_ACCESSORS(StackFrameInfo, flag, is_async, kIsAsyncBit) diff --git a/chromium/v8/src/objects/stack-frame-info.cc b/chromium/v8/src/objects/stack-frame-info.cc index f427d7eae29..558449d85aa 100644 --- a/chromium/v8/src/objects/stack-frame-info.cc +++ b/chromium/v8/src/objects/stack-frame-info.cc @@ -5,85 +5,144 @@ #include "src/objects/stack-frame-info.h" #include "src/objects/stack-frame-info-inl.h" +#include "src/strings/string-builder-inl.h" namespace v8 { namespace internal { +// static int StackTraceFrame::GetLineNumber(Handle<StackTraceFrame> frame) { int line = GetFrameInfo(frame)->line_number(); return line != StackFrameBase::kNone ? line : Message::kNoLineNumberInfo; } +// static +int StackTraceFrame::GetOneBasedLineNumber(Handle<StackTraceFrame> frame) { + // JavaScript line numbers are already 1-based. Wasm line numbers need + // to be adjusted. + int line = StackTraceFrame::GetLineNumber(frame); + if (StackTraceFrame::IsWasm(frame) && line >= 0) line++; + return line; +} + +// static int StackTraceFrame::GetColumnNumber(Handle<StackTraceFrame> frame) { int column = GetFrameInfo(frame)->column_number(); return column != StackFrameBase::kNone ? column : Message::kNoColumnInfo; } +// static +int StackTraceFrame::GetOneBasedColumnNumber(Handle<StackTraceFrame> frame) { + // JavaScript colun numbers are already 1-based. Wasm column numbers need + // to be adjusted. + int column = StackTraceFrame::GetColumnNumber(frame); + if (StackTraceFrame::IsWasm(frame) && column >= 0) column++; + return column; +} + +// static int StackTraceFrame::GetScriptId(Handle<StackTraceFrame> frame) { int id = GetFrameInfo(frame)->script_id(); return id != StackFrameBase::kNone ? id : Message::kNoScriptIdInfo; } +// static int StackTraceFrame::GetPromiseAllIndex(Handle<StackTraceFrame> frame) { return GetFrameInfo(frame)->promise_all_index(); } +// static Handle<Object> StackTraceFrame::GetFileName(Handle<StackTraceFrame> frame) { auto name = GetFrameInfo(frame)->script_name(); return handle(name, frame->GetIsolate()); } +// static Handle<Object> StackTraceFrame::GetScriptNameOrSourceUrl( Handle<StackTraceFrame> frame) { auto name = GetFrameInfo(frame)->script_name_or_source_url(); return handle(name, frame->GetIsolate()); } +// static Handle<Object> StackTraceFrame::GetFunctionName(Handle<StackTraceFrame> frame) { auto name = GetFrameInfo(frame)->function_name(); return handle(name, frame->GetIsolate()); } +// static +Handle<Object> StackTraceFrame::GetMethodName(Handle<StackTraceFrame> frame) { + auto name = GetFrameInfo(frame)->method_name(); + return handle(name, frame->GetIsolate()); +} + +// static +Handle<Object> StackTraceFrame::GetTypeName(Handle<StackTraceFrame> frame) { + auto name = GetFrameInfo(frame)->type_name(); + return handle(name, frame->GetIsolate()); +} + +// static +Handle<Object> StackTraceFrame::GetEvalOrigin(Handle<StackTraceFrame> frame) { + auto origin = GetFrameInfo(frame)->eval_origin(); + return handle(origin, frame->GetIsolate()); +} + +// static Handle<Object> StackTraceFrame::GetWasmModuleName( Handle<StackTraceFrame> frame) { auto module = GetFrameInfo(frame)->wasm_module_name(); return handle(module, frame->GetIsolate()); } +// static bool StackTraceFrame::IsEval(Handle<StackTraceFrame> frame) { return GetFrameInfo(frame)->is_eval(); } +// static bool StackTraceFrame::IsConstructor(Handle<StackTraceFrame> frame) { return GetFrameInfo(frame)->is_constructor(); } +// static bool StackTraceFrame::IsWasm(Handle<StackTraceFrame> frame) { return GetFrameInfo(frame)->is_wasm(); } +// static +bool StackTraceFrame::IsAsmJsWasm(Handle<StackTraceFrame> frame) { + return GetFrameInfo(frame)->is_asmjs_wasm(); +} + +// static bool StackTraceFrame::IsUserJavaScript(Handle<StackTraceFrame> frame) { return GetFrameInfo(frame)->is_user_java_script(); } +// static bool StackTraceFrame::IsToplevel(Handle<StackTraceFrame> frame) { return GetFrameInfo(frame)->is_toplevel(); } +// static bool StackTraceFrame::IsAsync(Handle<StackTraceFrame> frame) { return GetFrameInfo(frame)->is_async(); } +// static bool StackTraceFrame::IsPromiseAll(Handle<StackTraceFrame> frame) { return GetFrameInfo(frame)->is_promise_all(); } +// static Handle<StackFrameInfo> StackTraceFrame::GetFrameInfo( Handle<StackTraceFrame> frame) { if (frame->frame_info().IsUndefined()) InitializeFrameInfo(frame); return handle(StackFrameInfo::cast(frame->frame_info()), frame->GetIsolate()); } +// static void StackTraceFrame::InitializeFrameInfo(Handle<StackTraceFrame> frame) { Isolate* isolate = frame->GetIsolate(); Handle<StackFrameInfo> frame_info = isolate->factory()->NewStackFrameInfo( @@ -97,5 +156,259 @@ void StackTraceFrame::InitializeFrameInfo(Handle<StackTraceFrame> frame) { frame->set_frame_index(-1); } +Handle<FrameArray> GetFrameArrayFromStackTrace(Isolate* isolate, + Handle<FixedArray> stack_trace) { + // For the empty case, a empty FrameArray needs to be allocated so the rest + // of the code doesn't has to be special cased everywhere. + if (stack_trace->length() == 0) { + return isolate->factory()->NewFrameArray(0); + } + + // Retrieve the FrameArray from the first StackTraceFrame. + DCHECK_GT(stack_trace->length(), 0); + Handle<StackTraceFrame> frame(StackTraceFrame::cast(stack_trace->get(0)), + isolate); + return handle(FrameArray::cast(frame->frame_array()), isolate); +} + +namespace { + +bool IsNonEmptyString(Handle<Object> object) { + return (object->IsString() && String::cast(*object).length() > 0); +} + +void AppendFileLocation(Isolate* isolate, Handle<StackTraceFrame> frame, + IncrementalStringBuilder* builder) { + Handle<Object> file_name = StackTraceFrame::GetScriptNameOrSourceUrl(frame); + if (!file_name->IsString() && StackTraceFrame::IsEval(frame)) { + Handle<Object> eval_origin = StackTraceFrame::GetEvalOrigin(frame); + DCHECK(eval_origin->IsString()); + builder->AppendString(Handle<String>::cast(eval_origin)); + builder->AppendCString(", "); // Expecting source position to follow. + } + + if (IsNonEmptyString(file_name)) { + builder->AppendString(Handle<String>::cast(file_name)); + } else { + // Source code does not originate from a file and is not native, but we + // can still get the source position inside the source string, e.g. in + // an eval string. + builder->AppendCString("<anonymous>"); + } + + int line_number = StackTraceFrame::GetLineNumber(frame); + if (line_number != Message::kNoLineNumberInfo) { + builder->AppendCharacter(':'); + builder->AppendInt(line_number); + + int column_number = StackTraceFrame::GetColumnNumber(frame); + if (column_number != Message::kNoColumnInfo) { + builder->AppendCharacter(':'); + builder->AppendInt(column_number); + } + } +} + +int StringIndexOf(Isolate* isolate, Handle<String> subject, + Handle<String> pattern) { + if (pattern->length() > subject->length()) return -1; + return String::IndexOf(isolate, subject, pattern, 0); +} + +// Returns true iff +// 1. the subject ends with '.' + pattern, or +// 2. subject == pattern. +bool StringEndsWithMethodName(Isolate* isolate, Handle<String> subject, + Handle<String> pattern) { + if (String::Equals(isolate, subject, pattern)) return true; + + FlatStringReader subject_reader(isolate, String::Flatten(isolate, subject)); + FlatStringReader pattern_reader(isolate, String::Flatten(isolate, pattern)); + + int pattern_index = pattern_reader.length() - 1; + int subject_index = subject_reader.length() - 1; + for (int i = 0; i <= pattern_reader.length(); i++) { // Iterate over len + 1. + if (subject_index < 0) { + return false; + } + + const uc32 subject_char = subject_reader.Get(subject_index); + if (i == pattern_reader.length()) { + if (subject_char != '.') return false; + } else if (subject_char != pattern_reader.Get(pattern_index)) { + return false; + } + + pattern_index--; + subject_index--; + } + + return true; +} + +void AppendMethodCall(Isolate* isolate, Handle<StackTraceFrame> frame, + IncrementalStringBuilder* builder) { + Handle<Object> type_name = StackTraceFrame::GetTypeName(frame); + Handle<Object> method_name = StackTraceFrame::GetMethodName(frame); + Handle<Object> function_name = StackTraceFrame::GetFunctionName(frame); + + if (IsNonEmptyString(function_name)) { + Handle<String> function_string = Handle<String>::cast(function_name); + if (IsNonEmptyString(type_name)) { + Handle<String> type_string = Handle<String>::cast(type_name); + bool starts_with_type_name = + (StringIndexOf(isolate, function_string, type_string) == 0); + if (!starts_with_type_name) { + builder->AppendString(type_string); + builder->AppendCharacter('.'); + } + } + builder->AppendString(function_string); + + if (IsNonEmptyString(method_name)) { + Handle<String> method_string = Handle<String>::cast(method_name); + if (!StringEndsWithMethodName(isolate, function_string, method_string)) { + builder->AppendCString(" [as "); + builder->AppendString(method_string); + builder->AppendCharacter(']'); + } + } + } else { + if (IsNonEmptyString(type_name)) { + builder->AppendString(Handle<String>::cast(type_name)); + builder->AppendCharacter('.'); + } + if (IsNonEmptyString(method_name)) { + builder->AppendString(Handle<String>::cast(method_name)); + } else { + builder->AppendCString("<anonymous>"); + } + } +} + +void SerializeJSStackFrame( + Isolate* isolate, Handle<StackTraceFrame> frame, + IncrementalStringBuilder& builder // NOLINT(runtime/references) +) { + Handle<Object> function_name = StackTraceFrame::GetFunctionName(frame); + + const bool is_toplevel = StackTraceFrame::IsToplevel(frame); + const bool is_async = StackTraceFrame::IsAsync(frame); + const bool is_promise_all = StackTraceFrame::IsPromiseAll(frame); + const bool is_constructor = StackTraceFrame::IsConstructor(frame); + // Note: Keep the {is_method_call} predicate in sync with the corresponding + // predicate in factory.cc where the StackFrameInfo is created. + // Otherwise necessary fields for serialzing this frame might be + // missing. + const bool is_method_call = !(is_toplevel || is_constructor); + + if (is_async) { + builder.AppendCString("async "); + } + if (is_promise_all) { + builder.AppendCString("Promise.all (index "); + builder.AppendInt(StackTraceFrame::GetPromiseAllIndex(frame)); + builder.AppendCString(")"); + return; + } + if (is_method_call) { + AppendMethodCall(isolate, frame, &builder); + } else if (is_constructor) { + builder.AppendCString("new "); + if (IsNonEmptyString(function_name)) { + builder.AppendString(Handle<String>::cast(function_name)); + } else { + builder.AppendCString("<anonymous>"); + } + } else if (IsNonEmptyString(function_name)) { + builder.AppendString(Handle<String>::cast(function_name)); + } else { + AppendFileLocation(isolate, frame, &builder); + return; + } + + builder.AppendCString(" ("); + AppendFileLocation(isolate, frame, &builder); + builder.AppendCString(")"); +} + +void SerializeAsmJsWasmStackFrame( + Isolate* isolate, Handle<StackTraceFrame> frame, + IncrementalStringBuilder& builder // NOLINT(runtime/references) +) { + // The string should look exactly as the respective javascript frame string. + // Keep this method in line to + // JSStackFrame::ToString(IncrementalStringBuilder&). + Handle<Object> function_name = StackTraceFrame::GetFunctionName(frame); + + if (IsNonEmptyString(function_name)) { + builder.AppendString(Handle<String>::cast(function_name)); + builder.AppendCString(" ("); + } + + AppendFileLocation(isolate, frame, &builder); + + if (IsNonEmptyString(function_name)) builder.AppendCString(")"); + + return; +} + +void SerializeWasmStackFrame( + Isolate* isolate, Handle<StackTraceFrame> frame, + IncrementalStringBuilder& builder // NOLINT(runtime/references) +) { + Handle<Object> module_name = StackTraceFrame::GetWasmModuleName(frame); + Handle<Object> function_name = StackTraceFrame::GetFunctionName(frame); + const bool has_name = !module_name->IsNull() || !function_name->IsNull(); + if (has_name) { + if (module_name->IsNull()) { + builder.AppendString(Handle<String>::cast(function_name)); + } else { + builder.AppendString(Handle<String>::cast(module_name)); + if (!function_name->IsNull()) { + builder.AppendCString("."); + builder.AppendString(Handle<String>::cast(function_name)); + } + } + builder.AppendCString(" ("); + } + + const int wasm_func_index = StackTraceFrame::GetLineNumber(frame); + + builder.AppendCString("wasm-function["); + builder.AppendInt(wasm_func_index); + builder.AppendCString("]:"); + + char buffer[16]; + SNPrintF(ArrayVector(buffer), "0x%x", + StackTraceFrame::GetColumnNumber(frame)); + builder.AppendCString(buffer); + + if (has_name) builder.AppendCString(")"); +} + +} // namespace + +void SerializeStackTraceFrame( + Isolate* isolate, Handle<StackTraceFrame> frame, + IncrementalStringBuilder& builder // NOLINT(runtime/references) +) { + // Ordering here is important, as AsmJs frames are also marked as Wasm. + if (StackTraceFrame::IsAsmJsWasm(frame)) { + SerializeAsmJsWasmStackFrame(isolate, frame, builder); + } else if (StackTraceFrame::IsWasm(frame)) { + SerializeWasmStackFrame(isolate, frame, builder); + } else { + SerializeJSStackFrame(isolate, frame, builder); + } +} + +MaybeHandle<String> SerializeStackTraceFrame(Isolate* isolate, + Handle<StackTraceFrame> frame) { + IncrementalStringBuilder builder(isolate); + SerializeStackTraceFrame(isolate, frame, builder); + return builder.Finish(); +} + } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/objects/stack-frame-info.h b/chromium/v8/src/objects/stack-frame-info.h index 44826f67e6b..3d91c5374f9 100644 --- a/chromium/v8/src/objects/stack-frame-info.h +++ b/chromium/v8/src/objects/stack-frame-info.h @@ -25,10 +25,14 @@ class StackFrameInfo : public Struct { DECL_ACCESSORS(script_name, Object) DECL_ACCESSORS(script_name_or_source_url, Object) DECL_ACCESSORS(function_name, Object) + DECL_ACCESSORS(method_name, Object) + DECL_ACCESSORS(type_name, Object) + DECL_ACCESSORS(eval_origin, Object) DECL_ACCESSORS(wasm_module_name, Object) DECL_BOOLEAN_ACCESSORS(is_eval) DECL_BOOLEAN_ACCESSORS(is_constructor) DECL_BOOLEAN_ACCESSORS(is_wasm) + DECL_BOOLEAN_ACCESSORS(is_asmjs_wasm) DECL_BOOLEAN_ACCESSORS(is_user_java_script) DECL_BOOLEAN_ACCESSORS(is_toplevel) DECL_BOOLEAN_ACCESSORS(is_async) @@ -49,10 +53,11 @@ class StackFrameInfo : public Struct { static const int kIsEvalBit = 0; static const int kIsConstructorBit = 1; static const int kIsWasmBit = 2; - static const int kIsUserJavaScriptBit = 3; - static const int kIsToplevelBit = 4; - static const int kIsAsyncBit = 5; - static const int kIsPromiseAllBit = 6; + static const int kIsAsmJsWasmBit = 3; + static const int kIsUserJavaScriptBit = 4; + static const int kIsToplevelBit = 5; + static const int kIsAsyncBit = 6; + static const int kIsPromiseAllBit = 7; OBJECT_CONSTRUCTORS(StackFrameInfo, Struct); }; @@ -80,18 +85,24 @@ class StackTraceFrame : public Struct { TORQUE_GENERATED_STACK_TRACE_FRAME_FIELDS) static int GetLineNumber(Handle<StackTraceFrame> frame); + static int GetOneBasedLineNumber(Handle<StackTraceFrame> frame); static int GetColumnNumber(Handle<StackTraceFrame> frame); + static int GetOneBasedColumnNumber(Handle<StackTraceFrame> frame); static int GetScriptId(Handle<StackTraceFrame> frame); static int GetPromiseAllIndex(Handle<StackTraceFrame> frame); static Handle<Object> GetFileName(Handle<StackTraceFrame> frame); static Handle<Object> GetScriptNameOrSourceUrl(Handle<StackTraceFrame> frame); static Handle<Object> GetFunctionName(Handle<StackTraceFrame> frame); + static Handle<Object> GetMethodName(Handle<StackTraceFrame> frame); + static Handle<Object> GetTypeName(Handle<StackTraceFrame> frame); + static Handle<Object> GetEvalOrigin(Handle<StackTraceFrame> frame); static Handle<Object> GetWasmModuleName(Handle<StackTraceFrame> frame); static bool IsEval(Handle<StackTraceFrame> frame); static bool IsConstructor(Handle<StackTraceFrame> frame); static bool IsWasm(Handle<StackTraceFrame> frame); + static bool IsAsmJsWasm(Handle<StackTraceFrame> frame); static bool IsUserJavaScript(Handle<StackTraceFrame> frame); static bool IsToplevel(Handle<StackTraceFrame> frame); static bool IsAsync(Handle<StackTraceFrame> frame); @@ -104,6 +115,22 @@ class StackTraceFrame : public Struct { static void InitializeFrameInfo(Handle<StackTraceFrame> frame); }; +// Small helper that retrieves the FrameArray from a stack-trace +// consisting of a FixedArray of StackTraceFrame objects. +// This helper is only temporary until all FrameArray use-sites have +// been converted to use StackTraceFrame and StackFrameInfo objects. +V8_EXPORT_PRIVATE +Handle<FrameArray> GetFrameArrayFromStackTrace(Isolate* isolate, + Handle<FixedArray> stack_trace); + +class IncrementalStringBuilder; +void SerializeStackTraceFrame( + Isolate* isolate, Handle<StackTraceFrame> frame, + IncrementalStringBuilder& builder // NOLINT(runtime/references) +); +MaybeHandle<String> SerializeStackTraceFrame(Isolate* isolate, + Handle<StackTraceFrame> frame); + } // namespace internal } // namespace v8 diff --git a/chromium/v8/src/objects/string-inl.h b/chromium/v8/src/objects/string-inl.h index 0d8f83ca867..db724e0cf14 100644 --- a/chromium/v8/src/objects/string-inl.h +++ b/chromium/v8/src/objects/string-inl.h @@ -22,8 +22,6 @@ namespace v8 { namespace internal { -INT32_ACCESSORS(String, length, kLengthOffset) - int String::synchronized_length() const { return base::AsAtomic32::Acquire_Load( reinterpret_cast<const int32_t*>(FIELD_ADDR(*this, kLengthOffset))); @@ -34,29 +32,21 @@ void String::synchronized_set_length(int value) { reinterpret_cast<int32_t*>(FIELD_ADDR(*this, kLengthOffset)), value); } -OBJECT_CONSTRUCTORS_IMPL(String, Name) -OBJECT_CONSTRUCTORS_IMPL(SeqString, String) -OBJECT_CONSTRUCTORS_IMPL(SeqOneByteString, SeqString) -OBJECT_CONSTRUCTORS_IMPL(SeqTwoByteString, SeqString) -OBJECT_CONSTRUCTORS_IMPL(InternalizedString, String) -OBJECT_CONSTRUCTORS_IMPL(ConsString, String) -OBJECT_CONSTRUCTORS_IMPL(ThinString, String) -OBJECT_CONSTRUCTORS_IMPL(SlicedString, String) +TQ_OBJECT_CONSTRUCTORS_IMPL(String) +TQ_OBJECT_CONSTRUCTORS_IMPL(SeqString) +TQ_OBJECT_CONSTRUCTORS_IMPL(SeqOneByteString) +TQ_OBJECT_CONSTRUCTORS_IMPL(SeqTwoByteString) +TQ_OBJECT_CONSTRUCTORS_IMPL(InternalizedString) +TQ_OBJECT_CONSTRUCTORS_IMPL(ConsString) +TQ_OBJECT_CONSTRUCTORS_IMPL(ThinString) +TQ_OBJECT_CONSTRUCTORS_IMPL(SlicedString) OBJECT_CONSTRUCTORS_IMPL(ExternalString, String) OBJECT_CONSTRUCTORS_IMPL(ExternalOneByteString, ExternalString) OBJECT_CONSTRUCTORS_IMPL(ExternalTwoByteString, ExternalString) -CAST_ACCESSOR(ConsString) CAST_ACCESSOR(ExternalOneByteString) CAST_ACCESSOR(ExternalString) CAST_ACCESSOR(ExternalTwoByteString) -CAST_ACCESSOR(InternalizedString) -CAST_ACCESSOR(SeqOneByteString) -CAST_ACCESSOR(SeqString) -CAST_ACCESSOR(SeqTwoByteString) -CAST_ACCESSOR(SlicedString) -CAST_ACCESSOR(String) -CAST_ACCESSOR(ThinString) StringShape::StringShape(const String str) : type_(str.map().instance_type()) { set_valid(); @@ -147,16 +137,17 @@ STATIC_ASSERT((kExternalStringTag | kTwoByteStringTag) == STATIC_ASSERT(v8::String::TWO_BYTE_ENCODING == kTwoByteStringTag); -bool String::IsOneByteRepresentation() const { - uint32_t type = map().instance_type(); +DEF_GETTER(String, IsOneByteRepresentation, bool) { + uint32_t type = map(isolate).instance_type(); return (type & kStringEncodingMask) == kOneByteStringTag; } -bool String::IsTwoByteRepresentation() const { - uint32_t type = map().instance_type(); +DEF_GETTER(String, IsTwoByteRepresentation, bool) { + uint32_t type = map(isolate).instance_type(); return (type & kStringEncodingMask) == kTwoByteStringTag; } +// static bool String::IsOneByteRepresentationUnderneath(String string) { while (true) { uint32_t type = string.map().instance_type(); @@ -398,7 +389,7 @@ String String::GetUnderlying() { STATIC_ASSERT(static_cast<int>(ConsString::kFirstOffset) == static_cast<int>(ThinString::kActualOffset)); const int kUnderlyingOffset = SlicedString::kParentOffset; - return String::cast(READ_FIELD(*this, kUnderlyingOffset)); + return TaggedField<String, kUnderlyingOffset>::load(*this); } template <class Visitor> @@ -527,49 +518,23 @@ int SeqOneByteString::SeqOneByteStringSize(InstanceType instance_type) { return SizeFor(length()); } -String SlicedString::parent() { - return String::cast(READ_FIELD(*this, kParentOffset)); -} - -void SlicedString::set_parent(Isolate* isolate, String parent, - WriteBarrierMode mode) { +void SlicedString::set_parent(String parent, WriteBarrierMode mode) { DCHECK(parent.IsSeqString() || parent.IsExternalString()); - WRITE_FIELD(*this, kParentOffset, parent); - CONDITIONAL_WRITE_BARRIER(*this, kParentOffset, parent, mode); -} - -SMI_ACCESSORS(SlicedString, offset, kOffsetOffset) - -String ConsString::first() { - return String::cast(READ_FIELD(*this, kFirstOffset)); + TorqueGeneratedSlicedString<SlicedString, Super>::set_parent(parent, mode); } -Object ConsString::unchecked_first() { return READ_FIELD(*this, kFirstOffset); } +TQ_SMI_ACCESSORS(SlicedString, offset) -void ConsString::set_first(Isolate* isolate, String value, - WriteBarrierMode mode) { - WRITE_FIELD(*this, kFirstOffset, value); - CONDITIONAL_WRITE_BARRIER(*this, kFirstOffset, value, mode); -} - -String ConsString::second() { - return String::cast(READ_FIELD(*this, kSecondOffset)); +Object ConsString::unchecked_first() { + return TaggedField<Object, kFirstOffset>::load(*this); } Object ConsString::unchecked_second() { return RELAXED_READ_FIELD(*this, kSecondOffset); } -void ConsString::set_second(Isolate* isolate, String value, - WriteBarrierMode mode) { - WRITE_FIELD(*this, kSecondOffset, value); - CONDITIONAL_WRITE_BARRIER(*this, kSecondOffset, value, mode); -} - -ACCESSORS(ThinString, actual, String, kActualOffset) - -HeapObject ThinString::unchecked_actual() const { - return HeapObject::unchecked_cast(READ_FIELD(*this, kActualOffset)); +DEF_GETTER(ThinString, unchecked_actual, HeapObject) { + return TaggedField<HeapObject, kActualOffset>::load(isolate, *this); } bool ExternalString::is_uncached() const { diff --git a/chromium/v8/src/objects/string.cc b/chromium/v8/src/objects/string.cc index cc513f88cb3..d1981fd24de 100644 --- a/chromium/v8/src/objects/string.cc +++ b/chromium/v8/src/objects/string.cc @@ -61,8 +61,8 @@ Handle<String> String::SlowFlatten(Isolate* isolate, Handle<ConsString> cons, WriteToFlat(*cons, flat->GetChars(no_gc), 0, length); result = flat; } - cons->set_first(isolate, *result); - cons->set_second(isolate, ReadOnlyRoots(isolate).empty_string()); + cons->set_first(*result); + cons->set_second(ReadOnlyRoots(isolate).empty_string()); DCHECK(result->IsFlat()); return result; } @@ -146,15 +146,15 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) { int size = this->Size(); // Byte size of the original string. // Abort if size does not allow in-place conversion. if (size < ExternalString::kUncachedSize) return false; - Isolate* isolate; // Read-only strings cannot be made external, since that would mutate the // string. - if (!GetIsolateFromWritableObject(*this, &isolate)) return false; - Heap* heap = isolate->heap(); + if (IsReadOnlyHeapObject(*this)) return false; + Isolate* isolate = GetIsolateFromWritableObject(*this); bool is_internalized = this->IsInternalizedString(); bool has_pointers = StringShape(*this).IsIndirect(); + if (has_pointers) { - heap->NotifyObjectLayoutChange(*this, size, no_allocation); + isolate->heap()->NotifyObjectLayoutChange(*this, size, no_allocation); } // Morph the string to an external string by replacing the map and // reinitializing the fields. This won't work if the space the existing @@ -163,7 +163,7 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) { // the address of the backing store. When we encounter uncached external // strings in generated code, we need to bailout to runtime. Map new_map; - ReadOnlyRoots roots(heap); + ReadOnlyRoots roots(isolate); if (size < ExternalString::kSizeOfAllExternalStrings) { if (is_internalized) { new_map = roots.uncached_external_internalized_string_map(); @@ -177,10 +177,11 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) { // Byte size of the external String object. int new_size = this->SizeFromMap(new_map); - heap->CreateFillerObjectAt(this->address() + new_size, size - new_size, - ClearRecordedSlots::kNo); + isolate->heap()->CreateFillerObjectAt( + this->address() + new_size, size - new_size, ClearRecordedSlots::kNo); if (has_pointers) { - heap->ClearRecordedSlotRange(this->address(), this->address() + new_size); + isolate->heap()->ClearRecordedSlotRange(this->address(), + this->address() + new_size); } // We are storing the new map using release store after creating a filler for @@ -189,7 +190,7 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) { ExternalTwoByteString self = ExternalTwoByteString::cast(*this); self.SetResource(isolate, resource); - heap->RegisterExternalString(*this); + isolate->heap()->RegisterExternalString(*this); if (is_internalized) self.Hash(); // Force regeneration of the hash value. return true; } @@ -218,18 +219,16 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) { int size = this->Size(); // Byte size of the original string. // Abort if size does not allow in-place conversion. if (size < ExternalString::kUncachedSize) return false; - Isolate* isolate; // Read-only strings cannot be made external, since that would mutate the // string. - if (!GetIsolateFromWritableObject(*this, &isolate)) return false; - Heap* heap = isolate->heap(); + if (IsReadOnlyHeapObject(*this)) return false; + Isolate* isolate = GetIsolateFromWritableObject(*this); bool is_internalized = this->IsInternalizedString(); bool has_pointers = StringShape(*this).IsIndirect(); if (has_pointers) { - heap->NotifyObjectLayoutChange(*this, size, no_allocation); + isolate->heap()->NotifyObjectLayoutChange(*this, size, no_allocation); } - // Morph the string to an external string by replacing the map and // reinitializing the fields. This won't work if the space the existing // string occupies is too small for a regular external string. Instead, we @@ -237,7 +236,7 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) { // the address of the backing store. When we encounter uncached external // strings in generated code, we need to bailout to runtime. Map new_map; - ReadOnlyRoots roots(heap); + ReadOnlyRoots roots(isolate); if (size < ExternalString::kSizeOfAllExternalStrings) { new_map = is_internalized ? roots.uncached_external_one_byte_internalized_string_map() @@ -250,10 +249,11 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) { // Byte size of the external String object. int new_size = this->SizeFromMap(new_map); - heap->CreateFillerObjectAt(this->address() + new_size, size - new_size, - ClearRecordedSlots::kNo); + isolate->heap()->CreateFillerObjectAt( + this->address() + new_size, size - new_size, ClearRecordedSlots::kNo); if (has_pointers) { - heap->ClearRecordedSlotRange(this->address(), this->address() + new_size); + isolate->heap()->ClearRecordedSlotRange(this->address(), + this->address() + new_size); } // We are storing the new map using release store after creating a filler for @@ -262,7 +262,7 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) { ExternalOneByteString self = ExternalOneByteString::cast(*this); self.SetResource(isolate, resource); - heap->RegisterExternalString(*this); + isolate->heap()->RegisterExternalString(*this); if (is_internalized) self.Hash(); // Force regeneration of the hash value. return true; } @@ -272,9 +272,8 @@ bool String::SupportsExternalization() { return i::ThinString::cast(*this).actual().SupportsExternalization(); } - Isolate* isolate; // RO_SPACE strings cannot be externalized. - if (!GetIsolateFromWritableObject(*this, &isolate)) { + if (IsReadOnlyHeapObject(*this)) { return false; } @@ -290,6 +289,7 @@ bool String::SupportsExternalization() { DCHECK_LE(ExternalString::kUncachedSize, this->Size()); #endif + Isolate* isolate = GetIsolateFromWritableObject(*this); return !isolate->heap()->IsInGCPostProcessing(); } diff --git a/chromium/v8/src/objects/string.h b/chromium/v8/src/objects/string.h index 74fc8fa7632..1a826eee3b5 100644 --- a/chromium/v8/src/objects/string.h +++ b/chromium/v8/src/objects/string.h @@ -79,7 +79,7 @@ class StringShape { // ordered sequence of zero or more 16-bit unsigned integer values. // // All string values have a length field. -class String : public Name { +class String : public TorqueGeneratedString<String, Name> { public: enum Encoding { ONE_BYTE_ENCODING, TWO_BYTE_ENCODING }; @@ -152,21 +152,18 @@ class String : public Name { template <typename Char> inline const Char* GetChars(const DisallowHeapAllocation& no_gc); - // Get and set the length of the string. - inline int length() const; - inline void set_length(int value); - // Get and set the length of the string using acquire loads and release // stores. - inline int synchronized_length() const; - inline void synchronized_set_length(int value); + DECL_SYNCHRONIZED_INT_ACCESSORS(length) // Returns whether this string has only one-byte chars, i.e. all of them can // be one-byte encoded. This might be the case even if the string is // two-byte. Such strings may appear when the embedder prefers // two-byte external representations even for one-byte data. inline bool IsOneByteRepresentation() const; + inline bool IsOneByteRepresentation(Isolate* isolate) const; inline bool IsTwoByteRepresentation() const; + inline bool IsTwoByteRepresentation(Isolate* isolate) const; // Cons and slices have an encoding flag that may not represent the actual // encoding of the underlying string. This is taken into account here. @@ -320,8 +317,6 @@ class String : public Name { static Handle<String> Trim(Isolate* isolate, Handle<String> string, TrimMode mode); - DECL_CAST(String) - V8_EXPORT_PRIVATE void PrintOn(FILE* out); // For use during stack traces. Performs rudimentary sanity check. @@ -338,9 +333,6 @@ class String : public Name { inline bool IsFlat(); - DEFINE_FIELD_OFFSET_CONSTANTS(Name::kHeaderSize, - TORQUE_GENERATED_STRING_FIELDS) - // Max char codes. static const int32_t kMaxOneByteCharCode = unibrow::Latin1::kMaxChar; static const uint32_t kMaxOneByteCharCodeU = unibrow::Latin1::kMaxChar; @@ -453,7 +445,7 @@ class String : public Name { // Compute and set the hash code. V8_EXPORT_PRIVATE uint32_t ComputeAndSetHash(); - OBJECT_CONSTRUCTORS(String, Name); + TQ_OBJECT_CONSTRUCTORS(String) }; // clang-format off @@ -477,30 +469,29 @@ class SubStringRange { }; // The SeqString abstract class captures sequential string values. -class SeqString : public String { +class SeqString : public TorqueGeneratedSeqString<SeqString, String> { public: - DECL_CAST(SeqString) - // Truncate the string in-place if possible and return the result. // In case of new_length == 0, the empty string is returned without // truncating the original string. V8_WARN_UNUSED_RESULT static Handle<String> Truncate(Handle<SeqString> string, int new_length); - OBJECT_CONSTRUCTORS(SeqString, String); + TQ_OBJECT_CONSTRUCTORS(SeqString) }; -class InternalizedString : public String { +class InternalizedString + : public TorqueGeneratedInternalizedString<InternalizedString, String> { public: - DECL_CAST(InternalizedString) // TODO(neis): Possibly move some stuff from String here. - OBJECT_CONSTRUCTORS(InternalizedString, String); + TQ_OBJECT_CONSTRUCTORS(InternalizedString) }; // The OneByteString class captures sequential one-byte string objects. // Each character in the OneByteString is an one-byte character. -class SeqOneByteString : public SeqString { +class SeqOneByteString + : public TorqueGeneratedSeqOneByteString<SeqOneByteString, SeqString> { public: static const bool kHasOneByteEncoding = true; using Char = uint8_t; @@ -518,8 +509,6 @@ class SeqOneByteString : public SeqString { // is deterministic. void clear_padding(); - DECL_CAST(SeqOneByteString) - // Garbage collection support. This method is called by the // garbage collector to compute the actual size of an OneByteString // instance. @@ -537,12 +526,13 @@ class SeqOneByteString : public SeqString { class BodyDescriptor; - OBJECT_CONSTRUCTORS(SeqOneByteString, SeqString); + TQ_OBJECT_CONSTRUCTORS(SeqOneByteString) }; // The TwoByteString class captures sequential unicode string objects. // Each character in the TwoByteString is a two-byte uint16_t. -class SeqTwoByteString : public SeqString { +class SeqTwoByteString + : public TorqueGeneratedSeqTwoByteString<SeqTwoByteString, SeqString> { public: static const bool kHasOneByteEncoding = false; using Char = uint16_t; @@ -560,8 +550,6 @@ class SeqTwoByteString : public SeqString { // is deterministic. void clear_padding(); - DECL_CAST(SeqTwoByteString) - // Garbage collection support. This method is called by the // garbage collector to compute the actual size of a TwoByteString // instance. @@ -580,7 +568,7 @@ class SeqTwoByteString : public SeqString { class BodyDescriptor; - OBJECT_CONSTRUCTORS(SeqTwoByteString, SeqString); + TQ_OBJECT_CONSTRUCTORS(SeqTwoByteString) }; // The ConsString class describes string values built by using the @@ -591,32 +579,19 @@ class SeqTwoByteString : public SeqString { // are non-ConsString string values. The string value represented by // a ConsString can be obtained by concatenating the leaf string // values in a left-to-right depth-first traversal of the tree. -class ConsString : public String { +class ConsString : public TorqueGeneratedConsString<ConsString, String> { public: - // First string of the cons cell. - inline String first(); // Doesn't check that the result is a string, even in debug mode. This is // useful during GC where the mark bits confuse the checks. inline Object unchecked_first(); - inline void set_first(Isolate* isolate, String first, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - // Second string of the cons cell. - inline String second(); // Doesn't check that the result is a string, even in debug mode. This is // useful during GC where the mark bits confuse the checks. inline Object unchecked_second(); - inline void set_second(Isolate* isolate, String second, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); // Dispatched behavior. V8_EXPORT_PRIVATE uint16_t Get(int index); - DECL_CAST(ConsString) - - DEFINE_FIELD_OFFSET_CONSTANTS(String::kHeaderSize, - TORQUE_GENERATED_CONS_STRING_FIELDS) - // Minimum length for a cons string. static const int kMinLength = 13; @@ -624,7 +599,7 @@ class ConsString : public String { DECL_VERIFIER(ConsString) - OBJECT_CONSTRUCTORS(ConsString, String); + TQ_OBJECT_CONSTRUCTORS(ConsString) }; // The ThinString class describes string objects that are just references @@ -634,25 +609,18 @@ class ConsString : public String { // internalized version (which is allocated as a new object). // In terms of memory layout and most algorithms operating on strings, // ThinStrings can be thought of as "one-part cons strings". -class ThinString : public String { +class ThinString : public TorqueGeneratedThinString<ThinString, String> { public: - // Actual string that this ThinString refers to. - inline String actual() const; inline HeapObject unchecked_actual() const; - inline void set_actual(String s, - WriteBarrierMode mode = UPDATE_WRITE_BARRIER); + inline HeapObject unchecked_actual(Isolate* isolate) const; V8_EXPORT_PRIVATE uint16_t Get(int index); - DECL_CAST(ThinString) DECL_VERIFIER(ThinString) - DEFINE_FIELD_OFFSET_CONSTANTS(String::kHeaderSize, - TORQUE_GENERATED_THIN_STRING_FIELDS) - using BodyDescriptor = FixedBodyDescriptor<kActualOffset, kSize, kSize>; - OBJECT_CONSTRUCTORS(ThinString, String); + TQ_OBJECT_CONSTRUCTORS(ThinString) }; // The Sliced String class describes strings that are substrings of another @@ -667,22 +635,14 @@ class ThinString : public String { // - handling externalized parent strings // - external strings as parent // - truncating sliced string to enable otherwise unneeded parent to be GC'ed. -class SlicedString : public String { +class SlicedString : public TorqueGeneratedSlicedString<SlicedString, String> { public: - inline String parent(); - inline void set_parent(Isolate* isolate, String parent, + inline void set_parent(String parent, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); - inline int offset() const; - inline void set_offset(int offset); - + DECL_INT_ACCESSORS(offset) // Dispatched behavior. V8_EXPORT_PRIVATE uint16_t Get(int index); - DECL_CAST(SlicedString) - - DEFINE_FIELD_OFFSET_CONSTANTS(String::kHeaderSize, - TORQUE_GENERATED_SLICED_STRING_FIELDS) - // Minimum length for a sliced string. static const int kMinLength = 13; @@ -690,7 +650,7 @@ class SlicedString : public String { DECL_VERIFIER(SlicedString) - OBJECT_CONSTRUCTORS(SlicedString, String); + TQ_OBJECT_CONSTRUCTORS(SlicedString) }; // The ExternalString class describes string values that are backed by @@ -705,6 +665,7 @@ class SlicedString : public String { class ExternalString : public String { public: DECL_CAST(ExternalString) + DECL_VERIFIER(ExternalString) DEFINE_FIELD_OFFSET_CONSTANTS(String::kHeaderSize, TORQUE_GENERATED_EXTERNAL_STRING_FIELDS) diff --git a/chromium/v8/src/objects/synthetic-module.cc b/chromium/v8/src/objects/synthetic-module.cc new file mode 100644 index 00000000000..0cca30a37b9 --- /dev/null +++ b/chromium/v8/src/objects/synthetic-module.cc @@ -0,0 +1,108 @@ +// 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/objects/synthetic-module.h" + +#include "src/api/api-inl.h" +#include "src/builtins/accessors.h" +#include "src/objects/js-generator-inl.h" +#include "src/objects/module-inl.h" +#include "src/objects/objects-inl.h" +#include "src/objects/shared-function-info.h" +#include "src/utils/ostreams.h" + +namespace v8 { +namespace internal { + +// Implements SetSyntheticModuleBinding: +// https://heycam.github.io/webidl/#setsyntheticmoduleexport +void SyntheticModule::SetExport(Isolate* isolate, + Handle<SyntheticModule> module, + Handle<String> export_name, + Handle<Object> export_value) { + Handle<ObjectHashTable> exports(module->exports(), isolate); + Handle<Object> export_object(exports->Lookup(export_name), isolate); + CHECK(export_object->IsCell()); + Handle<Cell> export_cell(Handle<Cell>::cast(export_object)); + // Spec step 2: Set the mutable binding of export_name to export_value + export_cell->set_value(*export_value); +} + +// Implements Synthetic Module Record's ResolveExport concrete method: +// https://heycam.github.io/webidl/#smr-resolveexport +MaybeHandle<Cell> SyntheticModule::ResolveExport( + Isolate* isolate, Handle<SyntheticModule> module, + Handle<String> module_specifier, Handle<String> export_name, + MessageLocation loc, bool must_resolve) { + Handle<Object> object(module->exports().Lookup(export_name), isolate); + if (object->IsCell()) { + return Handle<Cell>::cast(object); + } + + if (must_resolve) { + return isolate->Throw<Cell>( + isolate->factory()->NewSyntaxError(MessageTemplate::kUnresolvableExport, + module_specifier, export_name), + &loc); + } + + return MaybeHandle<Cell>(); +} + +// Implements Synthetic Module Record's Instantiate concrete method : +// https://heycam.github.io/webidl/#smr-instantiate +bool SyntheticModule::PrepareInstantiate(Isolate* isolate, + Handle<SyntheticModule> module, + v8::Local<v8::Context> context, + v8::Module::ResolveCallback callback) { + Handle<ObjectHashTable> exports(module->exports(), isolate); + Handle<FixedArray> export_names(module->export_names(), isolate); + // Spec step 7: For each export_name in module->export_names... + for (int i = 0, n = export_names->length(); i < n; ++i) { + // Spec step 7.1: Create a new mutable binding for export_name. + // Spec step 7.2: Initialize the new mutable binding to undefined. + Handle<Cell> cell = + isolate->factory()->NewCell(isolate->factory()->undefined_value()); + Handle<String> name(String::cast(export_names->get(i)), isolate); + CHECK(exports->Lookup(name).IsTheHole(isolate)); + exports = ObjectHashTable::Put(exports, name, cell); + } + module->set_exports(*exports); + return true; +} + +// Second step of module instantiation. No real work to do for SyntheticModule +// as there are no imports or indirect exports to resolve; +// just update status. +bool SyntheticModule::FinishInstantiate(Isolate* isolate, + Handle<SyntheticModule> module) { + module->SetStatus(kInstantiated); + return true; +} + +// Implements Synthetic Module Record's Evaluate concrete method: +// https://heycam.github.io/webidl/#smr-evaluate +MaybeHandle<Object> SyntheticModule::Evaluate(Isolate* isolate, + Handle<SyntheticModule> module) { + module->SetStatus(kEvaluating); + + v8::Module::SyntheticModuleEvaluationSteps evaluation_steps = + FUNCTION_CAST<v8::Module::SyntheticModuleEvaluationSteps>( + module->evaluation_steps().foreign_address()); + v8::Local<v8::Value> result; + if (!evaluation_steps( + Utils::ToLocal(Handle<Context>::cast(isolate->native_context())), + Utils::ToLocal(Handle<Module>::cast(module))) + .ToLocal(&result)) { + isolate->PromoteScheduledException(); + module->RecordError(isolate); + return MaybeHandle<Object>(); + } + + module->SetStatus(kEvaluated); + return Utils::OpenHandle(*result); +} + +} // namespace internal +} // namespace v8 diff --git a/chromium/v8/src/objects/synthetic-module.h b/chromium/v8/src/objects/synthetic-module.h new file mode 100644 index 00000000000..9f91f2ce4a4 --- /dev/null +++ b/chromium/v8/src/objects/synthetic-module.h @@ -0,0 +1,69 @@ +// 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. + +#ifndef V8_OBJECTS_SYNTHETIC_MODULE_H_ +#define V8_OBJECTS_SYNTHETIC_MODULE_H_ + +#include "src/objects/module.h" + +// Has to be the last include (doesn't have include guards): +#include "src/objects/object-macros.h" + +namespace v8 { +namespace internal { + +// The runtime representation of a Synthetic Module Record, a module that can be +// instantiated by an embedder with embedder-defined exports and evaluation +// steps. +// https://heycam.github.io/webidl/#synthetic-module-records +class SyntheticModule : public Module { + public: + NEVER_READ_ONLY_SPACE + DECL_CAST(SyntheticModule) + DECL_VERIFIER(SyntheticModule) + DECL_PRINTER(SyntheticModule) + + // The list of all names exported by this module + DECL_ACCESSORS(name, String) + DECL_ACCESSORS(export_names, FixedArray) + DECL_ACCESSORS(evaluation_steps, Foreign) + + static void SetExport(Isolate* isolate, Handle<SyntheticModule> module, + Handle<String> export_name, + Handle<Object> export_value); + + // Layout description. + DEFINE_FIELD_OFFSET_CONSTANTS(Module::kHeaderSize, + TORQUE_GENERATED_SYNTHETIC_MODULE_FIELDS) + + using BodyDescriptor = SubclassBodyDescriptor< + Module::BodyDescriptor, + FixedBodyDescriptor<kExportNamesOffset, kSize, kSize>>; + + private: + friend class Module; + + static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExport( + Isolate* isolate, Handle<SyntheticModule> module, + Handle<String> module_specifier, Handle<String> export_name, + MessageLocation loc, bool must_resolve); + + static V8_WARN_UNUSED_RESULT bool PrepareInstantiate( + Isolate* isolate, Handle<SyntheticModule> module, + v8::Local<v8::Context> context, v8::Module::ResolveCallback callback); + static V8_WARN_UNUSED_RESULT bool FinishInstantiate( + Isolate* isolate, Handle<SyntheticModule> module); + + static V8_WARN_UNUSED_RESULT MaybeHandle<Object> Evaluate( + Isolate* isolate, Handle<SyntheticModule> module); + + OBJECT_CONSTRUCTORS(SyntheticModule, Module); +}; + +} // namespace internal +} // namespace v8 + +#include "src/objects/object-macros-undef.h" + +#endif // V8_OBJECTS_SYNTHETIC_MODULE_H_ diff --git a/chromium/v8/src/objects/tagged-field-inl.h b/chromium/v8/src/objects/tagged-field-inl.h new file mode 100644 index 00000000000..3cce536a142 --- /dev/null +++ b/chromium/v8/src/objects/tagged-field-inl.h @@ -0,0 +1,162 @@ +// 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. + +#ifndef V8_OBJECTS_TAGGED_FIELD_INL_H_ +#define V8_OBJECTS_TAGGED_FIELD_INL_H_ + +#include "src/objects/tagged-field.h" + +#include "src/common/ptr-compr-inl.h" + +namespace v8 { +namespace internal { + +// static +template <typename T, int kFieldOffset> +Address TaggedField<T, kFieldOffset>::address(HeapObject host, int offset) { + return host.address() + kFieldOffset + offset; +} + +// static +template <typename T, int kFieldOffset> +Tagged_t* TaggedField<T, kFieldOffset>::location(HeapObject host, int offset) { + return reinterpret_cast<Tagged_t*>(address(host, offset)); +} + +// static +template <typename T, int kFieldOffset> +template <typename TOnHeapAddress> +Address TaggedField<T, kFieldOffset>::tagged_to_full( + TOnHeapAddress on_heap_addr, Tagged_t tagged_value) { +#ifdef V8_COMPRESS_POINTERS + if (kIsSmi) { + return DecompressTaggedSigned(tagged_value); + } else if (kIsHeapObject) { + return DecompressTaggedPointer(on_heap_addr, tagged_value); + } else { + return DecompressTaggedAny(on_heap_addr, tagged_value); + } +#else + return tagged_value; +#endif +} + +// static +template <typename T, int kFieldOffset> +Tagged_t TaggedField<T, kFieldOffset>::full_to_tagged(Address value) { +#ifdef V8_COMPRESS_POINTERS + return CompressTagged(value); +#else + return value; +#endif +} + +// static +template <typename T, int kFieldOffset> +T TaggedField<T, kFieldOffset>::load(HeapObject host, int offset) { + Tagged_t value = *location(host, offset); + return T(tagged_to_full(host.ptr(), value)); +} + +// static +template <typename T, int kFieldOffset> +T TaggedField<T, kFieldOffset>::load(Isolate* isolate, HeapObject host, + int offset) { + Tagged_t value = *location(host, offset); + return T(tagged_to_full(isolate, value)); +} + +// static +template <typename T, int kFieldOffset> +void TaggedField<T, kFieldOffset>::store(HeapObject host, T value) { +#ifdef V8_CONCURRENT_MARKING + Relaxed_Store(host, value); +#else + *location(host) = full_to_tagged(value.ptr()); +#endif +} + +// static +template <typename T, int kFieldOffset> +void TaggedField<T, kFieldOffset>::store(HeapObject host, int offset, T value) { +#ifdef V8_CONCURRENT_MARKING + Relaxed_Store(host, offset, value); +#else + *location(host, offset) = full_to_tagged(value.ptr()); +#endif +} + +// static +template <typename T, int kFieldOffset> +T TaggedField<T, kFieldOffset>::Relaxed_Load(HeapObject host, int offset) { + AtomicTagged_t value = AsAtomicTagged::Relaxed_Load(location(host, offset)); + return T(tagged_to_full(host.ptr(), value)); +} + +// static +template <typename T, int kFieldOffset> +T TaggedField<T, kFieldOffset>::Relaxed_Load(Isolate* isolate, HeapObject host, + int offset) { + AtomicTagged_t value = AsAtomicTagged::Relaxed_Load(location(host, offset)); + return T(tagged_to_full(isolate, value)); +} + +// static +template <typename T, int kFieldOffset> +void TaggedField<T, kFieldOffset>::Relaxed_Store(HeapObject host, T value) { + AsAtomicTagged::Relaxed_Store(location(host), full_to_tagged(value.ptr())); +} + +// static +template <typename T, int kFieldOffset> +void TaggedField<T, kFieldOffset>::Relaxed_Store(HeapObject host, int offset, + T value) { + AsAtomicTagged::Relaxed_Store(location(host, offset), + full_to_tagged(value.ptr())); +} + +// static +template <typename T, int kFieldOffset> +T TaggedField<T, kFieldOffset>::Acquire_Load(HeapObject host, int offset) { + AtomicTagged_t value = AsAtomicTagged::Acquire_Load(location(host, offset)); + return T(tagged_to_full(host.ptr(), value)); +} + +// static +template <typename T, int kFieldOffset> +T TaggedField<T, kFieldOffset>::Acquire_Load(Isolate* isolate, HeapObject host, + int offset) { + AtomicTagged_t value = AsAtomicTagged::Acquire_Load(location(host, offset)); + return T(tagged_to_full(isolate, value)); +} + +// static +template <typename T, int kFieldOffset> +void TaggedField<T, kFieldOffset>::Release_Store(HeapObject host, T value) { + AsAtomicTagged::Release_Store(location(host), full_to_tagged(value.ptr())); +} + +// static +template <typename T, int kFieldOffset> +void TaggedField<T, kFieldOffset>::Release_Store(HeapObject host, int offset, + T value) { + AsAtomicTagged::Release_Store(location(host, offset), + full_to_tagged(value.ptr())); +} + +// static +template <typename T, int kFieldOffset> +Tagged_t TaggedField<T, kFieldOffset>::Release_CompareAndSwap(HeapObject host, + T old, T value) { + Tagged_t old_value = full_to_tagged(old.ptr()); + Tagged_t new_value = full_to_tagged(value.ptr()); + Tagged_t result = AsAtomicTagged::Release_CompareAndSwap( + location(host), old_value, new_value); + return result; +} + +} // namespace internal +} // namespace v8 + +#endif // V8_OBJECTS_TAGGED_FIELD_INL_H_ diff --git a/chromium/v8/src/objects/tagged-field.h b/chromium/v8/src/objects/tagged-field.h new file mode 100644 index 00000000000..fbaaee59308 --- /dev/null +++ b/chromium/v8/src/objects/tagged-field.h @@ -0,0 +1,76 @@ +// 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. + +#ifndef V8_OBJECTS_TAGGED_FIELD_H_ +#define V8_OBJECTS_TAGGED_FIELD_H_ + +#include "src/common/globals.h" + +#include "src/objects/objects.h" +#include "src/objects/tagged-value.h" + +namespace v8 { +namespace internal { + +// This helper static class represents a tagged field of type T at offset +// kFieldOffset inside some host HeapObject. +// For full-pointer mode this type adds no overhead but when pointer +// compression is enabled such class allows us to use proper decompression +// function depending on the field type. +template <typename T, int kFieldOffset = 0> +class TaggedField : public AllStatic { + public: + static_assert(std::is_base_of<Object, T>::value || + std::is_same<MapWord, T>::value || + std::is_same<MaybeObject, T>::value, + "T must be strong or weak tagged type or MapWord"); + + // True for Smi fields. + static constexpr bool kIsSmi = std::is_base_of<Smi, T>::value; + + // True for HeapObject and MapWord fields. The latter may look like a Smi + // if it contains forwarding pointer but still requires tagged pointer + // decompression. + static constexpr bool kIsHeapObject = + std::is_base_of<HeapObject, T>::value || std::is_same<MapWord, T>::value; + + static inline Address address(HeapObject host, int offset = 0); + + static inline T load(HeapObject host, int offset = 0); + static inline T load(Isolate* isolate, HeapObject host, int offset = 0); + + static inline void store(HeapObject host, T value); + static inline void store(HeapObject host, int offset, T value); + + static inline T Relaxed_Load(HeapObject host, int offset = 0); + static inline T Relaxed_Load(Isolate* isolate, HeapObject host, + int offset = 0); + + static inline void Relaxed_Store(HeapObject host, T value); + static inline void Relaxed_Store(HeapObject host, int offset, T value); + + static inline T Acquire_Load(HeapObject host, int offset = 0); + static inline T Acquire_Load(Isolate* isolate, HeapObject host, + int offset = 0); + + static inline void Release_Store(HeapObject host, T value); + static inline void Release_Store(HeapObject host, int offset, T value); + + static inline Tagged_t Release_CompareAndSwap(HeapObject host, T old, + T value); + + private: + static inline Tagged_t* location(HeapObject host, int offset = 0); + + template <typename TOnHeapAddress> + static inline Address tagged_to_full(TOnHeapAddress on_heap_addr, + Tagged_t tagged_value); + + static inline Tagged_t full_to_tagged(Address value); +}; + +} // namespace internal +} // namespace v8 + +#endif // V8_OBJECTS_TAGGED_FIELD_H_ diff --git a/chromium/v8/src/objects/tagged-impl-inl.h b/chromium/v8/src/objects/tagged-impl-inl.h index f735a241a89..909f65a959e 100644 --- a/chromium/v8/src/objects/tagged-impl-inl.h +++ b/chromium/v8/src/objects/tagged-impl-inl.h @@ -52,11 +52,11 @@ bool TaggedImpl<kRefType, StorageType>::GetHeapObject( template <HeapObjectReferenceType kRefType, typename StorageType> bool TaggedImpl<kRefType, StorageType>::GetHeapObject( - ROOT_PARAM, HeapObject* result) const { + Isolate* isolate, HeapObject* result) const { if (kIsFull) return GetHeapObject(result); // Implementation for compressed pointers. if (!IsStrongOrWeak()) return false; - *result = GetHeapObject(ROOT_VALUE); + *result = GetHeapObject(isolate); return true; } @@ -79,14 +79,14 @@ bool TaggedImpl<kRefType, StorageType>::GetHeapObject( template <HeapObjectReferenceType kRefType, typename StorageType> bool TaggedImpl<kRefType, StorageType>::GetHeapObject( - ROOT_PARAM, HeapObject* result, + Isolate* isolate, HeapObject* result, HeapObjectReferenceType* reference_type) const { if (kIsFull) return GetHeapObject(result, reference_type); // Implementation for compressed pointers. if (!IsStrongOrWeak()) return false; *reference_type = IsWeakOrCleared() ? HeapObjectReferenceType::WEAK : HeapObjectReferenceType::STRONG; - *result = GetHeapObject(ROOT_VALUE); + *result = GetHeapObject(isolate); return true; } @@ -107,12 +107,12 @@ bool TaggedImpl<kRefType, StorageType>::GetHeapObjectIfStrong( template <HeapObjectReferenceType kRefType, typename StorageType> bool TaggedImpl<kRefType, StorageType>::GetHeapObjectIfStrong( - ROOT_PARAM, HeapObject* result) const { + Isolate* isolate, HeapObject* result) const { if (kIsFull) return GetHeapObjectIfStrong(result); // Implementation for compressed pointers. if (IsStrong()) { - *result = - HeapObject::cast(Object(DecompressTaggedPointer(ROOT_VALUE, ptr_))); + *result = HeapObject::cast( + Object(DecompressTaggedPointer(isolate, static_cast<Tagged_t>(ptr_)))); return true; } return false; @@ -132,11 +132,12 @@ HeapObject TaggedImpl<kRefType, StorageType>::GetHeapObjectAssumeStrong() template <HeapObjectReferenceType kRefType, typename StorageType> HeapObject TaggedImpl<kRefType, StorageType>::GetHeapObjectAssumeStrong( - ROOT_PARAM) const { + Isolate* isolate) const { if (kIsFull) return GetHeapObjectAssumeStrong(); // Implementation for compressed pointers. DCHECK(IsStrong()); - return HeapObject::cast(Object(DecompressTaggedPointer(ROOT_VALUE, ptr_))); + return HeapObject::cast( + Object(DecompressTaggedPointer(isolate, static_cast<Tagged_t>(ptr_)))); } // @@ -161,12 +162,12 @@ bool TaggedImpl<kRefType, StorageType>::GetHeapObjectIfWeak( template <HeapObjectReferenceType kRefType, typename StorageType> bool TaggedImpl<kRefType, StorageType>::GetHeapObjectIfWeak( - ROOT_PARAM, HeapObject* result) const { + Isolate* isolate, HeapObject* result) const { if (kIsFull) return GetHeapObjectIfWeak(result); // Implementation for compressed pointers. if (kCanBeWeak) { if (IsWeak()) { - *result = GetHeapObject(ROOT_VALUE); + *result = GetHeapObject(isolate); return true; } return false; @@ -189,11 +190,11 @@ HeapObject TaggedImpl<kRefType, StorageType>::GetHeapObjectAssumeWeak() const { template <HeapObjectReferenceType kRefType, typename StorageType> HeapObject TaggedImpl<kRefType, StorageType>::GetHeapObjectAssumeWeak( - ROOT_PARAM) const { + Isolate* isolate) const { if (kIsFull) return GetHeapObjectAssumeWeak(); // Implementation for compressed pointers. DCHECK(IsWeak()); - return GetHeapObject(ROOT_VALUE); + return GetHeapObject(isolate); } // @@ -214,17 +215,19 @@ HeapObject TaggedImpl<kRefType, StorageType>::GetHeapObject() const { } template <HeapObjectReferenceType kRefType, typename StorageType> -HeapObject TaggedImpl<kRefType, StorageType>::GetHeapObject(ROOT_PARAM) const { +HeapObject TaggedImpl<kRefType, StorageType>::GetHeapObject( + Isolate* isolate) const { if (kIsFull) return GetHeapObject(); // Implementation for compressed pointers. DCHECK(!IsSmi()); if (kCanBeWeak) { DCHECK(!IsCleared()); - return HeapObject::cast(Object( - DecompressTaggedPointer(ROOT_VALUE, ptr_ & ~kWeakHeapObjectMask))); + return HeapObject::cast(Object(DecompressTaggedPointer( + isolate, static_cast<Tagged_t>(ptr_) & ~kWeakHeapObjectMask))); } else { DCHECK(!HAS_WEAK_HEAP_OBJECT_TAG(ptr_)); - return HeapObject::cast(Object(DecompressTaggedPointer(ROOT_VALUE, ptr_))); + return HeapObject::cast( + Object(DecompressTaggedPointer(isolate, static_cast<Tagged_t>(ptr_)))); } } @@ -242,13 +245,14 @@ Object TaggedImpl<kRefType, StorageType>::GetHeapObjectOrSmi() const { } template <HeapObjectReferenceType kRefType, typename StorageType> -Object TaggedImpl<kRefType, StorageType>::GetHeapObjectOrSmi(ROOT_PARAM) const { +Object TaggedImpl<kRefType, StorageType>::GetHeapObjectOrSmi( + Isolate* isolate) const { if (kIsFull) return GetHeapObjectOrSmi(); // Implementation for compressed pointers. if (IsSmi()) { - return Object(DecompressTaggedSigned(ptr_)); + return Object(DecompressTaggedSigned(static_cast<Tagged_t>(ptr_))); } - return GetHeapObject(ROOT_VALUE); + return GetHeapObject(isolate); } } // namespace internal diff --git a/chromium/v8/src/objects/tagged-impl.h b/chromium/v8/src/objects/tagged-impl.h index e3d982565f4..111eabae2f4 100644 --- a/chromium/v8/src/objects/tagged-impl.h +++ b/chromium/v8/src/objects/tagged-impl.h @@ -40,16 +40,24 @@ class TaggedImpl { // Make clang on Linux catch what MSVC complains about on Windows: operator bool() const = delete; - constexpr bool operator==(TaggedImpl other) const { - return ptr_ == other.ptr_; + template <typename U> + constexpr bool operator==(TaggedImpl<kRefType, U> other) const { + static_assert( + std::is_same<U, Address>::value || std::is_same<U, Tagged_t>::value, + "U must be either Address or Tagged_t"); + return static_cast<Tagged_t>(ptr_) == static_cast<Tagged_t>(other.ptr()); } - constexpr bool operator!=(TaggedImpl other) const { - return ptr_ != other.ptr_; + template <typename U> + constexpr bool operator!=(TaggedImpl<kRefType, U> other) const { + static_assert( + std::is_same<U, Address>::value || std::is_same<U, Tagged_t>::value, + "U must be either Address or Tagged_t"); + return static_cast<Tagged_t>(ptr_) != static_cast<Tagged_t>(other.ptr()); } // For using in std::set and std::map. constexpr bool operator<(TaggedImpl other) const { - return ptr_ < other.ptr(); + return static_cast<Tagged_t>(ptr_) < static_cast<Tagged_t>(other.ptr()); } constexpr StorageType ptr() const { return ptr_; } @@ -99,50 +107,51 @@ class TaggedImpl { // // The following set of methods get HeapObject out of the tagged value - // which may involve decompression in which case the ROOT_PARAM is required. + // which may involve decompression in which case the isolate root is required. // If the pointer compression is not enabled then the variants with - // ROOT_PARAM will be exactly the same as non-ROOT_PARAM ones. + // isolate parameter will be exactly the same as the ones witout isolate + // parameter. // // If this tagged value is a strong pointer to a HeapObject, returns true and // sets *result. Otherwise returns false. inline bool GetHeapObjectIfStrong(HeapObject* result) const; - inline bool GetHeapObjectIfStrong(ROOT_PARAM, HeapObject* result) const; + inline bool GetHeapObjectIfStrong(Isolate* isolate, HeapObject* result) const; // DCHECKs that this tagged value is a strong pointer to a HeapObject and // returns the HeapObject. inline HeapObject GetHeapObjectAssumeStrong() const; - inline HeapObject GetHeapObjectAssumeStrong(ROOT_PARAM) const; + inline HeapObject GetHeapObjectAssumeStrong(Isolate* isolate) const; // If this tagged value is a weak pointer to a HeapObject, returns true and // sets *result. Otherwise returns false. inline bool GetHeapObjectIfWeak(HeapObject* result) const; - inline bool GetHeapObjectIfWeak(ROOT_PARAM, HeapObject* result) const; + inline bool GetHeapObjectIfWeak(Isolate* isolate, HeapObject* result) const; // DCHECKs that this tagged value is a weak pointer to a HeapObject and // returns the HeapObject. inline HeapObject GetHeapObjectAssumeWeak() const; - inline HeapObject GetHeapObjectAssumeWeak(ROOT_PARAM) const; + inline HeapObject GetHeapObjectAssumeWeak(Isolate* isolate) const; // If this tagged value is a strong or weak pointer to a HeapObject, returns // true and sets *result. Otherwise returns false. inline bool GetHeapObject(HeapObject* result) const; - inline bool GetHeapObject(ROOT_PARAM, HeapObject* result) const; + inline bool GetHeapObject(Isolate* isolate, HeapObject* result) const; inline bool GetHeapObject(HeapObject* result, HeapObjectReferenceType* reference_type) const; - inline bool GetHeapObject(ROOT_PARAM, HeapObject* result, + inline bool GetHeapObject(Isolate* isolate, HeapObject* result, HeapObjectReferenceType* reference_type) const; // DCHECKs that this tagged value is a strong or a weak pointer to a // HeapObject and returns the HeapObject. inline HeapObject GetHeapObject() const; - inline HeapObject GetHeapObject(ROOT_PARAM) const; + inline HeapObject GetHeapObject(Isolate* isolate) const; // DCHECKs that this tagged value is a strong or a weak pointer to a // HeapObject or a Smi and returns the HeapObject or Smi. inline Object GetHeapObjectOrSmi() const; - inline Object GetHeapObjectOrSmi(ROOT_PARAM) const; + inline Object GetHeapObjectOrSmi(Isolate* isolate) const; // Cast operation is available only for full non-weak tagged values. template <typename T> diff --git a/chromium/v8/src/objects/tagged-value-inl.h b/chromium/v8/src/objects/tagged-value-inl.h index 5eb0e209471..f409a4006bc 100644 --- a/chromium/v8/src/objects/tagged-value-inl.h +++ b/chromium/v8/src/objects/tagged-value-inl.h @@ -9,7 +9,8 @@ #include "include/v8-internal.h" #include "src/common/ptr-compr-inl.h" -#include "src/objects/heap-object-inl.h" +#include "src/objects/maybe-object.h" +#include "src/objects/objects.h" #include "src/objects/oddball.h" #include "src/objects/tagged-impl-inl.h" #include "src/roots/roots-inl.h" @@ -17,17 +18,37 @@ namespace v8 { namespace internal { -Object StrongTaggedValue::ToObject(WITH_ROOT_PARAM(StrongTaggedValue object)) { +inline StrongTaggedValue::StrongTaggedValue(Object o) + : #ifdef V8_COMPRESS_POINTERS - return Object(DecompressTaggedAny(ROOT_VALUE, object.ptr())); + TaggedImpl(CompressTagged(o.ptr())) +#else + TaggedImpl(o.ptr()) +#endif +{ +} + +Object StrongTaggedValue::ToObject(Isolate* isolate, StrongTaggedValue object) { +#ifdef V8_COMPRESS_POINTERS + return Object(DecompressTaggedAny(isolate, object.ptr())); #else return Object(object.ptr()); #endif } -MaybeObject TaggedValue::ToMaybeObject(WITH_ROOT_PARAM(TaggedValue object)) { +inline TaggedValue::TaggedValue(MaybeObject o) + : +#ifdef V8_COMPRESS_POINTERS + TaggedImpl(CompressTagged(o.ptr())) +#else + TaggedImpl(o.ptr()) +#endif +{ +} + +MaybeObject TaggedValue::ToMaybeObject(Isolate* isolate, TaggedValue object) { #ifdef V8_COMPRESS_POINTERS - return MaybeObject(DecompressTaggedAny(ROOT_VALUE, object.ptr())); + return MaybeObject(DecompressTaggedAny(isolate, object.ptr())); #else return MaybeObject(object.ptr()); #endif diff --git a/chromium/v8/src/objects/tagged-value.h b/chromium/v8/src/objects/tagged-value.h index bb7609f7c35..7b6192204a4 100644 --- a/chromium/v8/src/objects/tagged-value.h +++ b/chromium/v8/src/objects/tagged-value.h @@ -21,8 +21,9 @@ class StrongTaggedValue public: constexpr StrongTaggedValue() : TaggedImpl() {} explicit constexpr StrongTaggedValue(Tagged_t ptr) : TaggedImpl(ptr) {} + explicit StrongTaggedValue(Object o); - inline static Object ToObject(WITH_ROOT_PARAM(StrongTaggedValue object)); + inline static Object ToObject(Isolate* isolate, StrongTaggedValue object); }; // Almost same as MaybeObject but this one deals with in-heap and potentially @@ -32,8 +33,9 @@ class TaggedValue : public TaggedImpl<HeapObjectReferenceType::WEAK, Tagged_t> { public: constexpr TaggedValue() : TaggedImpl() {} explicit constexpr TaggedValue(Tagged_t ptr) : TaggedImpl(ptr) {} + explicit TaggedValue(MaybeObject o); - inline static MaybeObject ToMaybeObject(WITH_ROOT_PARAM(TaggedValue object)); + inline static MaybeObject ToMaybeObject(Isolate* isolate, TaggedValue object); }; } // namespace internal diff --git a/chromium/v8/src/objects/template-objects.cc b/chromium/v8/src/objects/template-objects.cc index 2f34a48a2ad..d5b6293afe1 100644 --- a/chromium/v8/src/objects/template-objects.cc +++ b/chromium/v8/src/objects/template-objects.cc @@ -16,11 +16,9 @@ namespace internal { // static Handle<JSArray> TemplateObjectDescription::GetTemplateObject( - Isolate* isolate, Handle<Context> native_context, + Isolate* isolate, Handle<NativeContext> native_context, Handle<TemplateObjectDescription> description, Handle<SharedFunctionInfo> shared_info, int slot_id) { - DCHECK(native_context->IsNativeContext()); - // Check the template weakmap to see if the template object already exists. Handle<EphemeronHashTable> template_weakmap = native_context->template_weakmap().IsUndefined(isolate) diff --git a/chromium/v8/src/objects/template-objects.h b/chromium/v8/src/objects/template-objects.h index 220f9dab1ea..20ad7423383 100644 --- a/chromium/v8/src/objects/template-objects.h +++ b/chromium/v8/src/objects/template-objects.h @@ -47,7 +47,7 @@ class TemplateObjectDescription final : public Struct { DECL_CAST(TemplateObjectDescription) static Handle<JSArray> GetTemplateObject( - Isolate* isolate, Handle<Context> native_context, + Isolate* isolate, Handle<NativeContext> native_context, Handle<TemplateObjectDescription> description, Handle<SharedFunctionInfo> shared_info, int slot_id); diff --git a/chromium/v8/src/objects/templates-inl.h b/chromium/v8/src/objects/templates-inl.h index a1a098ffc03..d344174a0c6 100644 --- a/chromium/v8/src/objects/templates-inl.h +++ b/chromium/v8/src/objects/templates-inl.h @@ -55,7 +55,7 @@ SMI_ACCESSORS(FunctionTemplateInfo, flag, kFlagOffset) // static FunctionTemplateRareData FunctionTemplateInfo::EnsureFunctionTemplateRareData( Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info) { - HeapObject extra = function_template_info->rare_data(); + HeapObject extra = function_template_info->rare_data(isolate); if (extra.IsUndefined(isolate)) { return AllocateFunctionTemplateRareData(isolate, function_template_info); } else { @@ -64,9 +64,9 @@ FunctionTemplateRareData FunctionTemplateInfo::EnsureFunctionTemplateRareData( } #define RARE_ACCESSORS(Name, CamelName, Type) \ - Type FunctionTemplateInfo::Get##CamelName() { \ - HeapObject extra = rare_data(); \ - HeapObject undefined = GetReadOnlyRoots().undefined_value(); \ + DEF_GETTER(FunctionTemplateInfo, Get##CamelName, Type) { \ + HeapObject extra = rare_data(isolate); \ + HeapObject undefined = GetReadOnlyRoots(isolate).undefined_value(); \ return extra == undefined ? undefined \ : FunctionTemplateRareData::cast(extra).Name(); \ } \ diff --git a/chromium/v8/src/objects/templates.h b/chromium/v8/src/objects/templates.h index 66cd0381145..99142266edf 100644 --- a/chromium/v8/src/objects/templates.h +++ b/chromium/v8/src/objects/templates.h @@ -86,7 +86,7 @@ class FunctionTemplateInfo : public TemplateInfo { DECL_ACCESSORS(rare_data, HeapObject) #define DECL_RARE_ACCESSORS(Name, CamelName, Type) \ - inline Type Get##CamelName(); \ + DECL_GETTER(Get##CamelName, Type) \ static inline void Set##CamelName( \ Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info, \ Handle<Type> Name); diff --git a/chromium/v8/src/objects/transitions-inl.h b/chromium/v8/src/objects/transitions-inl.h index 893de78dc4e..048774f49b5 100644 --- a/chromium/v8/src/objects/transitions-inl.h +++ b/chromium/v8/src/objects/transitions-inl.h @@ -102,9 +102,8 @@ PropertyDetails TransitionsAccessor::GetTargetDetails(Name name, Map target) { return descriptors.GetDetails(descriptor); } -// static PropertyDetails TransitionsAccessor::GetSimpleTargetDetails(Map transition) { - return transition.GetLastDescriptorDetails(); + return transition.GetLastDescriptorDetails(isolate_); } // static @@ -195,13 +194,13 @@ void TransitionsAccessor::Reload() { } void TransitionsAccessor::Initialize() { - raw_transitions_ = map_.raw_transitions(); + raw_transitions_ = map_.raw_transitions(isolate_); HeapObject heap_object; if (raw_transitions_->IsSmi() || raw_transitions_->IsCleared()) { encoding_ = kUninitialized; } else if (raw_transitions_->IsWeak()) { encoding_ = kWeakRef; - } else if (raw_transitions_->GetHeapObjectIfStrong(&heap_object)) { + } else if (raw_transitions_->GetHeapObjectIfStrong(isolate_, &heap_object)) { if (heap_object.IsTransitionArray()) { encoding_ = kFullTransitionArray; } else if (heap_object.IsPrototypeInfo()) { diff --git a/chromium/v8/src/objects/transitions.cc b/chromium/v8/src/objects/transitions.cc index a2cd102aaf6..843b790b7d7 100644 --- a/chromium/v8/src/objects/transitions.cc +++ b/chromium/v8/src/objects/transitions.cc @@ -226,7 +226,7 @@ MaybeHandle<Map> TransitionsAccessor::FindTransitionToDataProperty( PropertyAttributes attributes = name->IsPrivate() ? DONT_ENUM : NONE; Map target = SearchTransition(*name, kData, attributes); if (target.is_null()) return MaybeHandle<Map>(); - PropertyDetails details = target.GetLastDescriptorDetails(); + PropertyDetails details = target.GetLastDescriptorDetails(isolate_); DCHECK_EQ(attributes, details.attributes()); DCHECK_EQ(kData, details.kind()); if (requested_location == kFieldOnly && details.location() != kField) { diff --git a/chromium/v8/src/objects/transitions.h b/chromium/v8/src/objects/transitions.h index b4dadcc22a2..f21e8cd54e5 100644 --- a/chromium/v8/src/objects/transitions.h +++ b/chromium/v8/src/objects/transitions.h @@ -147,7 +147,7 @@ class V8_EXPORT_PRIVATE TransitionsAccessor { friend class MarkCompactCollector; // For HasSimpleTransitionTo. friend class TransitionArray; - static inline PropertyDetails GetSimpleTargetDetails(Map transition); + inline PropertyDetails GetSimpleTargetDetails(Map transition); static inline Name GetSimpleTransitionKey(Map transition); diff --git a/chromium/v8/src/objects/value-serializer.cc b/chromium/v8/src/objects/value-serializer.cc index 331a12b157d..5a72dd6532a 100644 --- a/chromium/v8/src/objects/value-serializer.cc +++ b/chromium/v8/src/objects/value-serializer.cc @@ -22,6 +22,7 @@ #include "src/objects/objects-inl.h" #include "src/objects/oddball-inl.h" #include "src/objects/ordered-hash-table-inl.h" +#include "src/objects/property-descriptor.h" #include "src/objects/smi.h" #include "src/objects/transitions-inl.h" #include "src/snapshot/code-serializer.h" @@ -65,9 +66,6 @@ static size_t BytesNeededForVarint(T value) { return result; } -// Note that some additional tag values are defined in Blink's -// Source/bindings/core/v8/serialization/SerializationTag.h, which must -// not clash with values defined here. enum class SerializationTag : uint8_t { // version:uint32_t (if at beginning of data, sets version > 0) kVersion = 0xFF, @@ -161,6 +159,40 @@ enum class SerializationTag : uint8_t { // A transferred WebAssembly.Memory object. maximumPages:int32_t, then by // SharedArrayBuffer tag and its data. kWasmMemoryTransfer = 'm', + // A list of (subtag: ErrorTag, [subtag dependent data]). See ErrorTag for + // details. + kError = 'r', + + // The following tags are reserved because they were in use in Chromium before + // the kHostObject tag was introduced in format version 13, at + // v8 refs/heads/master@{#43466} + // chromium/src refs/heads/master@{#453568} + // + // They must not be reused without a version check to prevent old values from + // starting to deserialize incorrectly. For simplicity, it's recommended to + // avoid them altogether. + // + // This is the set of tags that existed in SerializationTag.h at that time and + // still exist at the time of this writing (i.e., excluding those that were + // removed on the Chromium side because there should be no real user data + // containing them). + // + // It might be possible to also free up other tags which were never persisted + // (e.g. because they were used only for transfer) in the future. + kLegacyReservedMessagePort = 'M', + kLegacyReservedBlob = 'b', + kLegacyReservedBlobIndex = 'i', + kLegacyReservedFile = 'f', + kLegacyReservedFileIndex = 'e', + kLegacyReservedDOMFileSystem = 'd', + kLegacyReservedFileList = 'l', + kLegacyReservedFileListIndex = 'L', + kLegacyReservedImageData = '#', + kLegacyReservedImageBitmap = 'g', + kLegacyReservedImageBitmapTransfer = 'G', + kLegacyReservedOffscreenCanvas = 'H', + kLegacyReservedCryptoKey = 'K', + kLegacyReservedRTCCertificate = 'k', }; namespace { @@ -184,6 +216,28 @@ enum class WasmEncodingTag : uint8_t { kRawBytes = 'y', }; +// Sub-tags only meaningful for error serialization. +enum class ErrorTag : uint8_t { + // The error is a EvalError. No accompanying data. + kEvalErrorPrototype = 'E', + // The error is a RangeError. No accompanying data. + kRangeErrorPrototype = 'R', + // The error is a ReferenceError. No accompanying data. + kReferenceErrorPrototype = 'F', + // The error is a SyntaxError. No accompanying data. + kSyntaxErrorPrototype = 'S', + // The error is a TypeError. No accompanying data. + kTypeErrorPrototype = 'T', + // The error is a URIError. No accompanying data. + kUriErrorPrototype = 'U', + // Followed by message: string. + kMessage = 'm', + // Followed by stack: string. + kStack = 's', + // The end of this error information. + kEnd = '.', +}; + } // namespace ValueSerializer::ValueSerializer(Isolate* isolate, @@ -505,8 +559,9 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) { case JS_DATE_TYPE: WriteJSDate(JSDate::cast(*receiver)); return ThrowIfOutOfMemory(); - case JS_VALUE_TYPE: - return WriteJSValue(Handle<JSValue>::cast(receiver)); + case JS_PRIMITIVE_WRAPPER_TYPE: + return WriteJSPrimitiveWrapper( + Handle<JSPrimitiveWrapper>::cast(receiver)); case JS_REGEXP_TYPE: WriteJSRegExp(JSRegExp::cast(*receiver)); return ThrowIfOutOfMemory(); @@ -519,6 +574,8 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) { case JS_TYPED_ARRAY_TYPE: case JS_DATA_VIEW_TYPE: return WriteJSArrayBufferView(JSArrayBufferView::cast(*receiver)); + case JS_ERROR_TYPE: + return WriteJSError(Handle<JSObject>::cast(receiver)); case WASM_MODULE_TYPE: { auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_); if (!FLAG_wasm_disable_structured_cloning || enabled_features.threads) { @@ -720,7 +777,8 @@ void ValueSerializer::WriteJSDate(JSDate date) { WriteDouble(date.value().Number()); } -Maybe<bool> ValueSerializer::WriteJSValue(Handle<JSValue> value) { +Maybe<bool> ValueSerializer::WriteJSPrimitiveWrapper( + Handle<JSPrimitiveWrapper> value) { Object inner_value = value->value(); if (inner_value.IsTrue(isolate_)) { WriteTag(SerializationTag::kTrueObject); @@ -874,6 +932,60 @@ Maybe<bool> ValueSerializer::WriteJSArrayBufferView(JSArrayBufferView view) { return ThrowIfOutOfMemory(); } +Maybe<bool> ValueSerializer::WriteJSError(Handle<JSObject> error) { + Handle<Object> stack; + PropertyDescriptor message_desc; + Maybe<bool> message_found = JSReceiver::GetOwnPropertyDescriptor( + isolate_, error, isolate_->factory()->message_string(), &message_desc); + MAYBE_RETURN(message_found, Nothing<bool>()); + + WriteTag(SerializationTag::kError); + + Handle<HeapObject> prototype; + if (!JSObject::GetPrototype(isolate_, error).ToHandle(&prototype)) { + return Nothing<bool>(); + } + + if (*prototype == isolate_->eval_error_function()->prototype()) { + WriteVarint(static_cast<uint8_t>(ErrorTag::kEvalErrorPrototype)); + } else if (*prototype == isolate_->range_error_function()->prototype()) { + WriteVarint(static_cast<uint8_t>(ErrorTag::kRangeErrorPrototype)); + } else if (*prototype == isolate_->reference_error_function()->prototype()) { + WriteVarint(static_cast<uint8_t>(ErrorTag::kReferenceErrorPrototype)); + } else if (*prototype == isolate_->syntax_error_function()->prototype()) { + WriteVarint(static_cast<uint8_t>(ErrorTag::kSyntaxErrorPrototype)); + } else if (*prototype == isolate_->type_error_function()->prototype()) { + WriteVarint(static_cast<uint8_t>(ErrorTag::kTypeErrorPrototype)); + } else if (*prototype == isolate_->uri_error_function()->prototype()) { + WriteVarint(static_cast<uint8_t>(ErrorTag::kUriErrorPrototype)); + } else { + // The default prototype in the deserialization side is Error.prototype, so + // we don't have to do anything here. + } + + if (message_found.FromJust() && + PropertyDescriptor::IsDataDescriptor(&message_desc)) { + Handle<String> message; + if (!Object::ToString(isolate_, message_desc.value()).ToHandle(&message)) { + return Nothing<bool>(); + } + WriteVarint(static_cast<uint8_t>(ErrorTag::kMessage)); + WriteString(message); + } + + if (!Object::GetProperty(isolate_, error, isolate_->factory()->stack_string()) + .ToHandle(&stack)) { + return Nothing<bool>(); + } + if (stack->IsString()) { + WriteVarint(static_cast<uint8_t>(ErrorTag::kStack)); + WriteString(Handle<String>::cast(stack)); + } + + WriteVarint(static_cast<uint8_t>(ErrorTag::kEnd)); + return ThrowIfOutOfMemory(); +} + Maybe<bool> ValueSerializer::WriteWasmModule(Handle<WasmModuleObject> object) { if (delegate_ != nullptr) { // TODO(titzer): introduce a Utils::ToLocal for WasmModuleObject. @@ -1238,7 +1350,7 @@ MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() { case SerializationTag::kNumberObject: case SerializationTag::kBigIntObject: case SerializationTag::kStringObject: - return ReadJSValue(tag); + return ReadJSPrimitiveWrapper(tag); case SerializationTag::kRegExp: return ReadJSRegExp(); case SerializationTag::kBeginJSMap: @@ -1256,6 +1368,8 @@ MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() { const bool is_shared = true; return ReadJSArrayBuffer(is_shared); } + case SerializationTag::kError: + return ReadJSError(); case SerializationTag::kWasmModule: return ReadWasmModule(); case SerializationTag::kWasmModuleTransfer: @@ -1519,24 +1633,25 @@ MaybeHandle<JSDate> ValueDeserializer::ReadJSDate() { return date; } -MaybeHandle<JSValue> ValueDeserializer::ReadJSValue(SerializationTag tag) { +MaybeHandle<JSPrimitiveWrapper> ValueDeserializer::ReadJSPrimitiveWrapper( + SerializationTag tag) { uint32_t id = next_id_++; - Handle<JSValue> value; + Handle<JSPrimitiveWrapper> value; switch (tag) { case SerializationTag::kTrueObject: - value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject( + value = Handle<JSPrimitiveWrapper>::cast(isolate_->factory()->NewJSObject( isolate_->boolean_function(), allocation_)); value->set_value(ReadOnlyRoots(isolate_).true_value()); break; case SerializationTag::kFalseObject: - value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject( + value = Handle<JSPrimitiveWrapper>::cast(isolate_->factory()->NewJSObject( isolate_->boolean_function(), allocation_)); value->set_value(ReadOnlyRoots(isolate_).false_value()); break; case SerializationTag::kNumberObject: { double number; - if (!ReadDouble().To(&number)) return MaybeHandle<JSValue>(); - value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject( + if (!ReadDouble().To(&number)) return MaybeHandle<JSPrimitiveWrapper>(); + value = Handle<JSPrimitiveWrapper>::cast(isolate_->factory()->NewJSObject( isolate_->number_function(), allocation_)); Handle<Object> number_object = isolate_->factory()->NewNumber(number, allocation_); @@ -1545,16 +1660,18 @@ MaybeHandle<JSValue> ValueDeserializer::ReadJSValue(SerializationTag tag) { } case SerializationTag::kBigIntObject: { Handle<BigInt> bigint; - if (!ReadBigInt().ToHandle(&bigint)) return MaybeHandle<JSValue>(); - value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject( + if (!ReadBigInt().ToHandle(&bigint)) + return MaybeHandle<JSPrimitiveWrapper>(); + value = Handle<JSPrimitiveWrapper>::cast(isolate_->factory()->NewJSObject( isolate_->bigint_function(), allocation_)); value->set_value(*bigint); break; } case SerializationTag::kStringObject: { Handle<String> string; - if (!ReadString().ToHandle(&string)) return MaybeHandle<JSValue>(); - value = Handle<JSValue>::cast(isolate_->factory()->NewJSObject( + if (!ReadString().ToHandle(&string)) + return MaybeHandle<JSPrimitiveWrapper>(); + value = Handle<JSPrimitiveWrapper>::cast(isolate_->factory()->NewJSObject( isolate_->string_function(), allocation_)); value->set_value(*string); break; @@ -1578,7 +1695,7 @@ MaybeHandle<JSRegExp> ValueDeserializer::ReadJSRegExp() { // Ensure the deserialized flags are valid. // TODO(adamk): Can we remove this check now that dotAll is always-on? - uint32_t flags_mask = static_cast<uint32_t>(-1) << JSRegExp::FlagCount(); + uint32_t flags_mask = static_cast<uint32_t>(-1) << JSRegExp::kFlagCount; if ((raw_flags & flags_mask) || !JSRegExp::New(isolate_, pattern, static_cast<JSRegExp::Flags>(raw_flags)) .ToHandle(®exp)) { @@ -1768,6 +1885,78 @@ MaybeHandle<JSArrayBufferView> ValueDeserializer::ReadJSArrayBufferView( return typed_array; } +MaybeHandle<Object> ValueDeserializer::ReadJSError() { + Handle<Object> message = isolate_->factory()->undefined_value(); + Handle<Object> stack = isolate_->factory()->undefined_value(); + Handle<Object> no_caller; + auto constructor = isolate_->error_function(); + bool done = false; + + while (!done) { + uint8_t tag; + if (!ReadVarint<uint8_t>().To(&tag)) { + return MaybeHandle<JSObject>(); + } + switch (static_cast<ErrorTag>(tag)) { + case ErrorTag::kEvalErrorPrototype: + constructor = isolate_->eval_error_function(); + break; + case ErrorTag::kRangeErrorPrototype: + constructor = isolate_->range_error_function(); + break; + case ErrorTag::kReferenceErrorPrototype: + constructor = isolate_->reference_error_function(); + break; + case ErrorTag::kSyntaxErrorPrototype: + constructor = isolate_->syntax_error_function(); + break; + case ErrorTag::kTypeErrorPrototype: + constructor = isolate_->type_error_function(); + break; + case ErrorTag::kUriErrorPrototype: + constructor = isolate_->uri_error_function(); + break; + case ErrorTag::kMessage: { + Handle<String> message_string; + if (!ReadString().ToHandle(&message_string)) { + return MaybeHandle<JSObject>(); + } + message = message_string; + break; + } + case ErrorTag::kStack: { + Handle<String> stack_string; + if (!ReadString().ToHandle(&stack_string)) { + return MaybeHandle<JSObject>(); + } + stack = stack_string; + break; + } + case ErrorTag::kEnd: + done = true; + break; + default: + return MaybeHandle<JSObject>(); + } + } + + Handle<Object> error; + if (!ErrorUtils::Construct(isolate_, constructor, constructor, message, + SKIP_NONE, no_caller, + ErrorUtils::StackTraceCollection::kNone) + .ToHandle(&error)) { + return MaybeHandle<Object>(); + } + + if (Object::SetProperty( + isolate_, error, isolate_->factory()->stack_trace_symbol(), stack, + StoreOrigin::kMaybeKeyed, Just(ShouldThrow::kThrowOnError)) + .is_null()) { + return MaybeHandle<Object>(); + } + return error; +} + MaybeHandle<JSObject> ValueDeserializer::ReadWasmModuleTransfer() { auto enabled_features = wasm::WasmFeaturesFromIsolate(isolate_); if ((FLAG_wasm_disable_structured_cloning && !enabled_features.threads) || diff --git a/chromium/v8/src/objects/value-serializer.h b/chromium/v8/src/objects/value-serializer.h index b83227d9d3f..9e381d7e76d 100644 --- a/chromium/v8/src/objects/value-serializer.h +++ b/chromium/v8/src/objects/value-serializer.h @@ -11,7 +11,7 @@ #include "include/v8.h" #include "src/base/compiler-specific.h" #include "src/base/macros.h" -#include "src/execution/message-template.h" +#include "src/common/message-template.h" #include "src/handles/maybe-handles.h" #include "src/utils/identity-map.h" #include "src/utils/vector.h" @@ -27,9 +27,9 @@ class JSArrayBuffer; class JSArrayBufferView; class JSDate; class JSMap; +class JSPrimitiveWrapper; class JSRegExp; class JSSet; -class JSValue; class MutableHeapNumber; class Object; class Oddball; @@ -120,13 +120,15 @@ class ValueSerializer { Maybe<bool> WriteJSObjectSlow(Handle<JSObject> object) V8_WARN_UNUSED_RESULT; Maybe<bool> WriteJSArray(Handle<JSArray> array) V8_WARN_UNUSED_RESULT; void WriteJSDate(JSDate date); - Maybe<bool> WriteJSValue(Handle<JSValue> value) V8_WARN_UNUSED_RESULT; + Maybe<bool> WriteJSPrimitiveWrapper(Handle<JSPrimitiveWrapper> value) + V8_WARN_UNUSED_RESULT; void WriteJSRegExp(JSRegExp regexp); Maybe<bool> WriteJSMap(Handle<JSMap> map) V8_WARN_UNUSED_RESULT; Maybe<bool> WriteJSSet(Handle<JSSet> map) V8_WARN_UNUSED_RESULT; Maybe<bool> WriteJSArrayBuffer(Handle<JSArrayBuffer> array_buffer) V8_WARN_UNUSED_RESULT; Maybe<bool> WriteJSArrayBufferView(JSArrayBufferView array_buffer); + Maybe<bool> WriteJSError(Handle<JSObject> error) V8_WARN_UNUSED_RESULT; Maybe<bool> WriteWasmModule(Handle<WasmModuleObject> object) V8_WARN_UNUSED_RESULT; Maybe<bool> WriteWasmMemory(Handle<WasmMemoryObject> object) @@ -264,7 +266,8 @@ class ValueDeserializer { MaybeHandle<JSArray> ReadSparseJSArray() V8_WARN_UNUSED_RESULT; MaybeHandle<JSArray> ReadDenseJSArray() V8_WARN_UNUSED_RESULT; MaybeHandle<JSDate> ReadJSDate() V8_WARN_UNUSED_RESULT; - MaybeHandle<JSValue> ReadJSValue(SerializationTag tag) V8_WARN_UNUSED_RESULT; + MaybeHandle<JSPrimitiveWrapper> ReadJSPrimitiveWrapper(SerializationTag tag) + V8_WARN_UNUSED_RESULT; MaybeHandle<JSRegExp> ReadJSRegExp() V8_WARN_UNUSED_RESULT; MaybeHandle<JSMap> ReadJSMap() V8_WARN_UNUSED_RESULT; MaybeHandle<JSSet> ReadJSSet() V8_WARN_UNUSED_RESULT; @@ -274,6 +277,7 @@ class ValueDeserializer { V8_WARN_UNUSED_RESULT; MaybeHandle<JSArrayBufferView> ReadJSArrayBufferView( Handle<JSArrayBuffer> buffer) V8_WARN_UNUSED_RESULT; + MaybeHandle<Object> ReadJSError() V8_WARN_UNUSED_RESULT; MaybeHandle<JSObject> ReadWasmModule() V8_WARN_UNUSED_RESULT; MaybeHandle<JSObject> ReadWasmModuleTransfer() V8_WARN_UNUSED_RESULT; MaybeHandle<WasmMemoryObject> ReadWasmMemory() V8_WARN_UNUSED_RESULT; |