diff --git a/common.gypi b/common.gypi index 8d00e6864a5..11b5d3b7aeb 100644 --- a/common.gypi +++ b/common.gypi @@ -37,7 +37,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.15', + 'v8_embedder_string': '-node.16', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/include/v8-internal.h b/deps/v8/include/v8-internal.h index a0d0bfb959c..8e700a4d4d4 100644 --- a/deps/v8/include/v8-internal.h +++ b/deps/v8/include/v8-internal.h @@ -7,6 +7,7 @@ #include #include +#include #include #include "v8-version.h" // NOLINT(build/include) @@ -274,6 +275,17 @@ class Internals { V8_INLINE static T ReadRawField(internal::Address heap_object_ptr, int offset) { internal::Address addr = heap_object_ptr + offset - kHeapObjectTag; +#ifdef V8_COMPRESS_POINTERS + if (sizeof(T) > kApiTaggedSize) { + // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size + // 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. + T r; + memcpy(&r, reinterpret_cast(addr), sizeof(T)); + return r; + } +#endif return *reinterpret_cast(addr); } diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 7346e0bbbc7..7e48cd422db 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -118,6 +118,7 @@ class Arguments; class DeferredHandles; class Heap; class HeapObject; +class ExternalString; class Isolate; class LocalEmbedderHeapTracer; class MicrotaskQueue; @@ -2797,7 +2798,7 @@ class V8_EXPORT String : public Name { void operator=(const ExternalStringResourceBase&) = delete; private: - friend class internal::Heap; + friend class internal::ExternalString; friend class v8::String; friend class internal::ScopedExternalStringLock; }; diff --git a/deps/v8/src/heap/heap-inl.h b/deps/v8/src/heap/heap-inl.h index b143a33af5d..26717e2ba13 100644 --- a/deps/v8/src/heap/heap-inl.h +++ b/deps/v8/src/heap/heap-inl.h @@ -300,15 +300,7 @@ void Heap::FinalizeExternalString(String string) { ExternalBackingStoreType::kExternalString, ext_string->ExternalPayloadSize()); - v8::String::ExternalStringResourceBase** resource_addr = - reinterpret_cast( - string->address() + ExternalString::kResourceOffset); - - // Dispose of the C++ object if it has not already been disposed. - if (*resource_addr != nullptr) { - (*resource_addr)->Dispose(); - *resource_addr = nullptr; - } + ext_string->DisposeResource(); } Address Heap::NewSpaceTop() { return new_space_->top(); } diff --git a/deps/v8/src/objects/bigint.cc b/deps/v8/src/objects/bigint.cc index fb69d5847a4..7c886a7b1d5 100644 --- a/deps/v8/src/objects/bigint.cc +++ b/deps/v8/src/objects/bigint.cc @@ -205,8 +205,7 @@ class MutableBigInt : public FreshlyAllocatedBigInt { } inline void set_digit(int n, digit_t value) { SLOW_DCHECK(0 <= n && n < length()); - Address address = FIELD_ADDR(*this, kDigitsOffset + n * kDigitSize); - (*reinterpret_cast(address)) = value; + WRITE_UINTPTR_FIELD(*this, kDigitsOffset + n * kDigitSize, value); } void set_64_bits(uint64_t bits); diff --git a/deps/v8/src/objects/bigint.h b/deps/v8/src/objects/bigint.h index ae1ffe68661..4ddb57a5b22 100644 --- a/deps/v8/src/objects/bigint.h +++ b/deps/v8/src/objects/bigint.h @@ -87,8 +87,7 @@ class BigIntBase : public HeapObject { inline digit_t digit(int n) const { SLOW_DCHECK(0 <= n && n < length()); - Address address = FIELD_ADDR(*this, kDigitsOffset + n * kDigitSize); - return *reinterpret_cast(address); + return READ_UINTPTR_FIELD(*this, kDigitsOffset + n * kDigitSize); } bool is_zero() const { return length() == 0; } diff --git a/deps/v8/src/objects/embedder-data-slot-inl.h b/deps/v8/src/objects/embedder-data-slot-inl.h index 7762479cf9c..b87f31ac7d3 100644 --- a/deps/v8/src/objects/embedder-data-slot-inl.h +++ b/deps/v8/src/objects/embedder-data-slot-inl.h @@ -11,6 +11,7 @@ #include "src/objects-inl.h" #include "src/objects/embedder-data-array.h" #include "src/objects/js-objects-inl.h" +#include "src/v8memory.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" @@ -71,7 +72,15 @@ bool EmbedderDataSlot::ToAlignedPointer(void** out_pointer) const { // are accessed this way only from the main thread via API during "mutator" // phase which is propely synched with GC (concurrent marker may still look // at the tagged part of the embedder slot but read-only access is ok). +#ifdef V8_COMPRESS_POINTERS + // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size + // 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()); +#else Address raw_value = *location(); +#endif *out_pointer = reinterpret_cast(raw_value); return HAS_SMI_TAG(raw_value); } @@ -89,7 +98,15 @@ EmbedderDataSlot::RawData EmbedderDataSlot::load_raw( // are accessed this way only by serializer from the main thread when // GC is not active (concurrent marker may still look at the tagged part // of the embedder slot but read-only access is ok). +#ifdef V8_COMPRESS_POINTERS + // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size + // 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()); +#else return *location(); +#endif } void EmbedderDataSlot::store_raw(EmbedderDataSlot::RawData data, diff --git a/deps/v8/src/objects/fixed-array-inl.h b/deps/v8/src/objects/fixed-array-inl.h index dfb34102ddf..9aa65a8de6b 100644 --- a/deps/v8/src/objects/fixed-array-inl.h +++ b/deps/v8/src/objects/fixed-array-inl.h @@ -653,7 +653,17 @@ typename Traits::ElementType FixedTypedArray::get_scalar_from_data_ptr( // JavaScript memory model to have tear-free reads of overlapping accesses, // and using relaxed atomics may introduce overhead. TSAN_ANNOTATE_IGNORE_READS_BEGIN; - auto result = ptr[index]; + ElementType result; + if (COMPRESS_POINTERS_BOOL && alignof(ElementType) > kTaggedSize) { + // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size + // 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(reinterpret_cast
(ptr) + + index * sizeof(ElementType)); + } else { + result = ptr[index]; + } TSAN_ANNOTATE_IGNORE_READS_END; return result; } @@ -664,7 +674,16 @@ void FixedTypedArray::set(int index, ElementType value) { // See the comment in FixedTypedArray::get_scalar. auto* ptr = reinterpret_cast(DataPtr()); TSAN_ANNOTATE_IGNORE_WRITES_BEGIN; - ptr[index] = value; + if (COMPRESS_POINTERS_BOOL && alignof(ElementType) > kTaggedSize) { + // TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size + // 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( + reinterpret_cast
(ptr) + index * sizeof(ElementType), value); + } else { + ptr[index] = value; + } TSAN_ANNOTATE_IGNORE_WRITES_END; } diff --git a/deps/v8/src/objects/object-macros-undef.h b/deps/v8/src/objects/object-macros-undef.h index 6f243eb19fc..b5d076564dd 100644 --- a/deps/v8/src/objects/object-macros-undef.h +++ b/deps/v8/src/objects/object-macros-undef.h @@ -15,6 +15,7 @@ #undef DECL_INT_ACCESSORS #undef DECL_INT32_ACCESSORS #undef DECL_UINT16_ACCESSORS +#undef DECL_INT16_ACCESSORS #undef DECL_UINT8_ACCESSORS #undef DECL_ACCESSORS #undef DECL_CAST @@ -42,6 +43,7 @@ #undef BIT_FIELD_ACCESSORS #undef INSTANCE_TYPE_CHECKER #undef TYPE_CHECKER +#undef RELAXED_INT16_ACCESSORS #undef FIELD_ADDR #undef READ_FIELD #undef READ_WEAK_FIELD @@ -52,6 +54,7 @@ #undef WRITE_WEAK_FIELD #undef RELEASE_WRITE_FIELD #undef RELAXED_WRITE_FIELD +#undef RELAXED_WRITE_WEAK_FIELD #undef WRITE_BARRIER #undef WEAK_WRITE_BARRIER #undef CONDITIONAL_WRITE_BARRIER @@ -60,14 +63,7 @@ #undef WRITE_DOUBLE_FIELD #undef READ_INT_FIELD #undef WRITE_INT_FIELD -#undef ACQUIRE_READ_INTPTR_FIELD -#undef RELAXED_READ_INTPTR_FIELD -#undef READ_INTPTR_FIELD -#undef RELEASE_WRITE_INTPTR_FIELD -#undef RELAXED_WRITE_INTPTR_FIELD -#undef WRITE_INTPTR_FIELD -#undef READ_UINTPTR_FIELD -#undef WRITE_UINTPTR_FIELD +#undef ACQUIRE_READ_INT32_FIELD #undef READ_UINT8_FIELD #undef WRITE_UINT8_FIELD #undef RELAXED_WRITE_INT8_FIELD @@ -78,18 +74,25 @@ #undef WRITE_UINT16_FIELD #undef READ_INT16_FIELD #undef WRITE_INT16_FIELD +#undef RELAXED_READ_INT16_FIELD +#undef RELAXED_WRITE_INT16_FIELD #undef READ_UINT32_FIELD +#undef RELAXED_READ_UINT32_FIELD #undef WRITE_UINT32_FIELD +#undef RELAXED_WRITE_UINT32_FIELD #undef READ_INT32_FIELD #undef RELAXED_READ_INT32_FIELD #undef WRITE_INT32_FIELD +#undef RELEASE_WRITE_INT32_FIELD #undef RELAXED_WRITE_INT32_FIELD #undef READ_FLOAT_FIELD #undef WRITE_FLOAT_FIELD +#undef READ_INTPTR_FIELD +#undef WRITE_INTPTR_FIELD +#undef READ_UINTPTR_FIELD +#undef WRITE_UINTPTR_FIELD #undef READ_UINT64_FIELD #undef WRITE_UINT64_FIELD -#undef READ_INT64_FIELD -#undef WRITE_INT64_FIELD #undef READ_BYTE_FIELD #undef RELAXED_READ_BYTE_FIELD #undef WRITE_BYTE_FIELD diff --git a/deps/v8/src/objects/object-macros.h b/deps/v8/src/objects/object-macros.h index 3b15d63e095..941c68a6a29 100644 --- a/deps/v8/src/objects/object-macros.h +++ b/deps/v8/src/objects/object-macros.h @@ -323,40 +323,10 @@ #define WRITE_INT_FIELD(p, offset, value) \ (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) -#define ACQUIRE_READ_INTPTR_FIELD(p, offset) \ - static_cast(base::Acquire_Load( \ - reinterpret_cast(FIELD_ADDR(p, offset)))) - #define ACQUIRE_READ_INT32_FIELD(p, offset) \ static_cast(base::Acquire_Load( \ reinterpret_cast(FIELD_ADDR(p, offset)))) -#define RELAXED_READ_INTPTR_FIELD(p, offset) \ - static_cast(base::Relaxed_Load( \ - reinterpret_cast(FIELD_ADDR(p, offset)))) - -#define READ_INTPTR_FIELD(p, offset) \ - (*reinterpret_cast(FIELD_ADDR(p, offset))) - -#define RELEASE_WRITE_INTPTR_FIELD(p, offset, value) \ - base::Release_Store( \ - reinterpret_cast(FIELD_ADDR(p, offset)), \ - static_cast(value)); - -#define RELAXED_WRITE_INTPTR_FIELD(p, offset, value) \ - base::Relaxed_Store( \ - reinterpret_cast(FIELD_ADDR(p, offset)), \ - static_cast(value)); - -#define WRITE_INTPTR_FIELD(p, offset, value) \ - (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) - -#define READ_UINTPTR_FIELD(p, offset) \ - (*reinterpret_cast(FIELD_ADDR(p, offset))) - -#define WRITE_UINTPTR_FIELD(p, offset, value) \ - (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) - #define READ_UINT8_FIELD(p, offset) \ (*reinterpret_cast(FIELD_ADDR(p, offset))) @@ -439,17 +409,51 @@ #define WRITE_FLOAT_FIELD(p, offset, value) \ (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) +// TODO(ishell, v8:8875): When pointer compression is enabled 8-byte size 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. +#ifdef V8_COMPRESS_POINTERS + +#define READ_INTPTR_FIELD(p, offset) \ + ReadUnalignedValue(FIELD_ADDR(p, offset)) + +#define WRITE_INTPTR_FIELD(p, offset, value) \ + WriteUnalignedValue(FIELD_ADDR(p, offset), value) + +#define READ_UINTPTR_FIELD(p, offset) \ + ReadUnalignedValue(FIELD_ADDR(p, offset)) + +#define WRITE_UINTPTR_FIELD(p, offset, value) \ + WriteUnalignedValue(FIELD_ADDR(p, offset), value) + +#define READ_UINT64_FIELD(p, offset) \ + ReadUnalignedValue(FIELD_ADDR(p, offset)) + +#define WRITE_UINT64_FIELD(p, offset, value) \ + WriteUnalignedValue(FIELD_ADDR(p, offset), value) + +#else // V8_COMPRESS_POINTERS + +#define READ_INTPTR_FIELD(p, offset) \ + (*reinterpret_cast(FIELD_ADDR(p, offset))) + +#define WRITE_INTPTR_FIELD(p, offset, value) \ + (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) + +#define READ_UINTPTR_FIELD(p, offset) \ + (*reinterpret_cast(FIELD_ADDR(p, offset))) + +#define WRITE_UINTPTR_FIELD(p, offset, value) \ + (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) + #define READ_UINT64_FIELD(p, offset) \ (*reinterpret_cast(FIELD_ADDR(p, offset))) #define WRITE_UINT64_FIELD(p, offset, value) \ (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) -#define READ_INT64_FIELD(p, offset) \ - (*reinterpret_cast(FIELD_ADDR(p, offset))) - -#define WRITE_INT64_FIELD(p, offset, value) \ - (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) +#endif // V8_COMPRESS_POINTERS #define READ_BYTE_FIELD(p, offset) \ (*reinterpret_cast(FIELD_ADDR(p, offset))) diff --git a/deps/v8/src/objects/string-inl.h b/deps/v8/src/objects/string-inl.h index 8ae2ad405c0..440266ced19 100644 --- a/deps/v8/src/objects/string-inl.h +++ b/deps/v8/src/objects/string-inl.h @@ -553,11 +553,11 @@ bool ExternalString::is_uncached() const { } Address ExternalString::resource_as_address() { - return *reinterpret_cast(FIELD_ADDR(*this, kResourceOffset)); + return READ_UINTPTR_FIELD(*this, kResourceOffset); } void ExternalString::set_address_as_resource(Address address) { - *reinterpret_cast(FIELD_ADDR(*this, kResourceOffset)) = address; + WRITE_UINTPTR_FIELD(*this, kResourceOffset, address); if (IsExternalOneByteString()) { ExternalOneByteString::cast(*this)->update_data_cache(); } else { @@ -566,27 +566,36 @@ void ExternalString::set_address_as_resource(Address address) { } uint32_t ExternalString::resource_as_uint32() { - return static_cast( - *reinterpret_cast(FIELD_ADDR(*this, kResourceOffset))); + return static_cast(READ_UINTPTR_FIELD(*this, kResourceOffset)); } void ExternalString::set_uint32_as_resource(uint32_t value) { - *reinterpret_cast(FIELD_ADDR(*this, kResourceOffset)) = value; + WRITE_UINTPTR_FIELD(*this, kResourceOffset, value); if (is_uncached()) return; - const char** data_field = - reinterpret_cast(FIELD_ADDR(*this, kResourceDataOffset)); - *data_field = nullptr; + WRITE_UINTPTR_FIELD(*this, kResourceDataOffset, kNullAddress); +} + +void ExternalString::DisposeResource() { + v8::String::ExternalStringResourceBase* resource = + reinterpret_cast( + READ_UINTPTR_FIELD(*this, ExternalString::kResourceOffset)); + + // Dispose of the C++ object if it has not already been disposed. + if (resource != nullptr) { + resource->Dispose(); + WRITE_UINTPTR_FIELD(*this, ExternalString::kResourceOffset, kNullAddress); + } } const ExternalOneByteString::Resource* ExternalOneByteString::resource() { - return *reinterpret_cast(FIELD_ADDR(*this, kResourceOffset)); + return reinterpret_cast( + READ_UINTPTR_FIELD(*this, kResourceOffset)); } void ExternalOneByteString::update_data_cache() { if (is_uncached()) return; - const char** data_field = - reinterpret_cast(FIELD_ADDR(*this, kResourceDataOffset)); - *data_field = resource()->data(); + WRITE_UINTPTR_FIELD(*this, kResourceDataOffset, + reinterpret_cast
(resource()->data())); } void ExternalOneByteString::SetResource( @@ -600,8 +609,8 @@ void ExternalOneByteString::SetResource( void ExternalOneByteString::set_resource( const ExternalOneByteString::Resource* resource) { - *reinterpret_cast(FIELD_ADDR(*this, kResourceOffset)) = - resource; + WRITE_UINTPTR_FIELD(*this, kResourceOffset, + reinterpret_cast
(resource)); if (resource != nullptr) update_data_cache(); } @@ -615,14 +624,14 @@ uint16_t ExternalOneByteString::ExternalOneByteStringGet(int index) { } const ExternalTwoByteString::Resource* ExternalTwoByteString::resource() { - return *reinterpret_cast(FIELD_ADDR(*this, kResourceOffset)); + return reinterpret_cast( + READ_UINTPTR_FIELD(*this, kResourceOffset)); } void ExternalTwoByteString::update_data_cache() { if (is_uncached()) return; - const uint16_t** data_field = reinterpret_cast( - FIELD_ADDR(*this, kResourceDataOffset)); - *data_field = resource()->data(); + WRITE_UINTPTR_FIELD(*this, kResourceDataOffset, + reinterpret_cast
(resource()->data())); } void ExternalTwoByteString::SetResource( @@ -636,8 +645,8 @@ void ExternalTwoByteString::SetResource( void ExternalTwoByteString::set_resource( const ExternalTwoByteString::Resource* resource) { - *reinterpret_cast(FIELD_ADDR(*this, kResourceOffset)) = - resource; + WRITE_UINTPTR_FIELD(*this, kResourceOffset, + reinterpret_cast
(resource)); if (resource != nullptr) update_data_cache(); } diff --git a/deps/v8/src/objects/string.h b/deps/v8/src/objects/string.h index e0b34f7a0e4..e91f913c2b2 100644 --- a/deps/v8/src/objects/string.h +++ b/deps/v8/src/objects/string.h @@ -736,6 +736,9 @@ class ExternalString : public String { inline uint32_t resource_as_uint32(); inline void set_uint32_as_resource(uint32_t value); + // Disposes string's resource object if it has not already been disposed. + inline void DisposeResource(); + STATIC_ASSERT(kResourceOffset == Internals::kStringResourceOffset); OBJECT_CONSTRUCTORS(ExternalString, String); diff --git a/deps/v8/src/snapshot/serializer.cc b/deps/v8/src/snapshot/serializer.cc index e5b371ef285..660d2ce04ab 100644 --- a/deps/v8/src/snapshot/serializer.cc +++ b/deps/v8/src/snapshot/serializer.cc @@ -710,8 +710,8 @@ void Serializer::ObjectSerializer::VisitEmbeddedPointer(Code host, void Serializer::ObjectSerializer::VisitExternalReference(Foreign host, Address* p) { - Address target = *p; - auto encoded_reference = serializer_->EncodeExternalReference(target); + auto encoded_reference = + serializer_->EncodeExternalReference(host->foreign_address()); if (encoded_reference.is_from_api()) { sink_->Put(kApiReference, "ApiRef"); } else { diff --git a/deps/v8/src/wasm/wasm-objects-inl.h b/deps/v8/src/wasm/wasm-objects-inl.h index 9a25995203c..b5180804cf3 100644 --- a/deps/v8/src/wasm/wasm-objects-inl.h +++ b/deps/v8/src/wasm/wasm-objects-inl.h @@ -57,18 +57,30 @@ CAST_ACCESSOR(AsmWasmData) } \ ACCESSORS(holder, name, type, offset) -#define READ_PRIMITIVE_FIELD(p, type, offset) \ - (*reinterpret_cast(FIELD_ADDR(p, offset))) - -#define WRITE_PRIMITIVE_FIELD(p, type, offset, value) \ - (*reinterpret_cast(FIELD_ADDR(p, offset)) = value) - -#define PRIMITIVE_ACCESSORS(holder, name, type, offset) \ - type holder::name() const { \ - return READ_PRIMITIVE_FIELD(*this, type, offset); \ - } \ - void holder::set_##name(type value) { \ - WRITE_PRIMITIVE_FIELD(*this, type, offset, value); \ +#define PRIMITIVE_ACCESSORS(holder, name, type, offset) \ + type holder::name() const { \ + if (COMPRESS_POINTERS_BOOL && alignof(type) > kTaggedSize) { \ + /* TODO(ishell, v8:8875): When pointer compression is enabled 8-byte */ \ + /* size 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(FIELD_ADDR(*this, offset)); \ + } else { \ + return *reinterpret_cast(FIELD_ADDR(*this, offset)); \ + } \ + } \ + void holder::set_##name(type value) { \ + if (COMPRESS_POINTERS_BOOL && alignof(type) > kTaggedSize) { \ + /* TODO(ishell, v8:8875): When pointer compression is enabled 8-byte */ \ + /* size 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(FIELD_ADDR(*this, offset), value); \ + } else { \ + *reinterpret_cast(FIELD_ADDR(*this, offset)) = value; \ + } \ } // WasmModuleObject