From 7305a2d47296e71bd22eb7c804f789e2163b5596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Sun, 4 Aug 2019 11:37:46 +0200 Subject: [PATCH] deps: patch V8 to be API/ABI compatible with 7.4 (from 7.6) Reverts https://github.com/v8/v8/commit/4214933c6bb4d1815f07a40eaf008cb1e37ef217. Reverts https://github.com/v8/v8/commit/c76f377a990343b18953123c2726337b38c59812. Reverts https://github.com/v8/v8/commit/e0d7f816990ada28ebe1281ca9431236ef8c6e4f. Co-authored-by: Anna Henningsen Backport-PR-URL: https://github.com/nodejs/node/pull/29241 PR-URL: https://github.com/nodejs/node/pull/28955 --- common.gypi | 2 +- deps/v8/include/v8-internal.h | 2 + deps/v8/include/v8-profiler.h | 13 +- deps/v8/include/v8-util.h | 18 ++ deps/v8/include/v8.h | 186 +++++++++++++- deps/v8/src/api/api.cc | 139 ++++++++-- deps/v8/src/handles/global-handles.cc | 57 ++++- .../v8/src/profiler/sampling-heap-profiler.cc | 10 + deps/v8/test/cctest/heap/heap-utils.h | 16 -- .../test/cctest/heap/test-embedder-tracing.cc | 46 ++-- deps/v8/test/cctest/heap/test-heap.cc | 125 +++++++++ deps/v8/test/cctest/test-api.cc | 35 +++ deps/v8/test/cctest/test-global-handles.cc | 240 +++++++----------- 13 files changed, 665 insertions(+), 224 deletions(-) diff --git a/common.gypi b/common.gypi index 28c63873d95543..a411ad091da253 100644 --- a/common.gypi +++ b/common.gypi @@ -38,7 +38,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.18', + 'v8_embedder_string': '-node.19', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/include/v8-internal.h b/deps/v8/include/v8-internal.h index 6ecddf45d6ae92..a037210f552c7b 100644 --- a/deps/v8/include/v8-internal.h +++ b/deps/v8/include/v8-internal.h @@ -181,6 +181,8 @@ class Internals { static const int kNodeStateMask = 0x7; static const int kNodeStateIsWeakValue = 2; static const int kNodeStateIsPendingValue = 3; + static const int kNodeIsIndependentShift = 3; + static const int kNodeIsActiveShift = 4; static const int kFirstNonstringType = 0x40; static const int kOddballType = 0x43; diff --git a/deps/v8/include/v8-profiler.h b/deps/v8/include/v8-profiler.h index 360850b631c7f9..5387b394456a65 100644 --- a/deps/v8/include/v8-profiler.h +++ b/deps/v8/include/v8-profiler.h @@ -304,9 +304,12 @@ class V8_EXPORT CpuProfiler { * initialized. The profiler object must be disposed after use by calling * |Dispose| method. */ + static CpuProfiler* New(Isolate* isolate); static CpuProfiler* New(Isolate* isolate, - CpuProfilingNamingMode = kDebugNaming, - CpuProfilingLoggingMode = kLazyLogging); + CpuProfilingNamingMode mode); + static CpuProfiler* New(Isolate* isolate, + CpuProfilingNamingMode namingMode, + CpuProfilingLoggingMode loggingMode); /** * Synchronously collect current stack sample in all profilers attached to @@ -355,8 +358,10 @@ class V8_EXPORT CpuProfiler { * discarded. */ void StartProfiling( - Local title, CpuProfilingMode mode, bool record_samples = false, - unsigned max_samples = CpuProfilingOptions::kNoSampleLimit); + Local title, CpuProfilingMode mode, bool record_samples = false); + void StartProfiling( + Local title, CpuProfilingMode mode, bool record_samples, + unsigned max_samples); /** * The same as StartProfiling above, but the CpuProfilingMode defaults to * kLeafNodeLineNumbers mode, which was the previous default behavior of the diff --git a/deps/v8/include/v8-util.h b/deps/v8/include/v8-util.h index 29d813e4274d16..24962607076f78 100644 --- a/deps/v8/include/v8-util.h +++ b/deps/v8/include/v8-util.h @@ -194,6 +194,14 @@ class PersistentValueMapBase { return SetReturnValueFromVal(&returnValue, Traits::Get(&impl_, key)); } + /** + * Call V8::RegisterExternallyReferencedObject with the map value for given + * key. + */ + V8_DEPRECATED( + "Used TracedGlobal and EmbedderHeapTracer::RegisterEmbedderReference", + inline void RegisterExternallyReferencedObject(K& key)); + /** * Return value for key and remove it from the map. */ @@ -344,6 +352,16 @@ class PersistentValueMapBase { const char* label_; }; +template +inline void +PersistentValueMapBase::RegisterExternallyReferencedObject( + K& key) { + assert(Contains(key)); + V8::RegisterExternallyReferencedObject( + reinterpret_cast(FromVal(Traits::Get(&impl_, key))), + reinterpret_cast(GetIsolate())); +} + template class PersistentValueMap : public PersistentValueMapBase { public: diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 7b8f9521e42490..27bdfca7298d9f 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -123,6 +123,7 @@ class ExternalString; class Isolate; class LocalEmbedderHeapTracer; class MicrotaskQueue; +class NeverReadOnlySpaceObject; struct ScriptStreamingData; template class CustomArguments; class PropertyCallbackArguments; @@ -546,6 +547,38 @@ template class PersistentBase { */ V8_INLINE void AnnotateStrongRetainer(const char* label); + /** + * Allows the embedder to tell the v8 garbage collector that a certain object + * is alive. Only allowed when the embedder is asked to trace its heap by + * EmbedderHeapTracer. + */ + V8_DEPRECATED( + "Used TracedGlobal and EmbedderHeapTracer::RegisterEmbedderReference", + V8_INLINE void RegisterExternalReference(Isolate* isolate) const); + + /** + * Marks the reference to this object independent. Garbage collector is free + * to ignore any object groups containing this object. Weak callback for an + * independent handle should not assume that it will be preceded by a global + * GC prologue callback or followed by a global GC epilogue callback. + */ + V8_DEPRECATED( + "Weak objects are always considered independent. " + "Use TracedGlobal when trying to use EmbedderHeapTracer. " + "Use a strong handle when trying to keep an object alive.", + V8_INLINE void MarkIndependent()); + + /** + * Marks the reference to this object as active. The scavenge garbage + * collection should not reclaim the objects marked as active, even if the + * object held by the handle is otherwise unreachable. + * + * This bit is cleared after the each garbage collection pass. + */ + V8_DEPRECATED("Use TracedGlobal.", V8_INLINE void MarkActive()); + + V8_DEPRECATED("See MarkIndependent.", V8_INLINE bool IsIndependent() const); + /** Returns true if the handle's reference is weak. */ V8_INLINE bool IsWeak() const; @@ -2613,6 +2646,9 @@ class V8_EXPORT Value : public Data { V8_WARN_UNUSED_RESULT MaybeLocal ToBigInt( Local context) const; + V8_DEPRECATED("ToBoolean can never throw. Use Local version.", + V8_WARN_UNUSED_RESULT MaybeLocal ToBoolean( + Local context) const); V8_WARN_UNUSED_RESULT MaybeLocal ToNumber( Local context) const; V8_WARN_UNUSED_RESULT MaybeLocal ToString( @@ -2628,6 +2664,16 @@ class V8_EXPORT Value : public Data { V8_WARN_UNUSED_RESULT MaybeLocal ToInt32(Local context) const; Local ToBoolean(Isolate* isolate) const; + V8_DEPRECATED("Use maybe version", + Local ToNumber(Isolate* isolate) const); + V8_DEPRECATED("Use maybe version", + Local ToString(Isolate* isolate) const); + V8_DEPRECATED("Use maybe version", + Local ToObject(Isolate* isolate) const); + V8_DEPRECATED("Use maybe version", + Local ToInteger(Isolate* isolate) const); + V8_DEPRECATED("Use maybe version", + Local ToInt32(Isolate* isolate) const); /** * Attempts to convert a string to an array index. @@ -2638,6 +2684,9 @@ class V8_EXPORT Value : public Data { bool BooleanValue(Isolate* isolate) const; + V8_DEPRECATED("BooleanValue can never throw. Use Isolate version.", + V8_WARN_UNUSED_RESULT Maybe BooleanValue( + Local context) const); V8_WARN_UNUSED_RESULT Maybe NumberValue(Local context) const; V8_WARN_UNUSED_RESULT Maybe IntegerValue( Local context) const; @@ -2957,23 +3006,43 @@ class V8_EXPORT String : public Name { V8_INLINE static String* Cast(v8::Value* obj); + // TODO(dcarney): remove with deprecation of New functions. + enum NewStringType { + kNormalString = static_cast(v8::NewStringType::kNormal), + kInternalizedString = static_cast(v8::NewStringType::kInternalized) + }; + + /** Allocates a new string from UTF-8 data.*/ + static V8_DEPRECATED( + "Use maybe version", + Local NewFromUtf8(Isolate* isolate, const char* data, + NewStringType type = kNormalString, + int length = -1)); + /** Allocates a new string from UTF-8 data. Only returns an empty value when * length > kMaxLength. **/ static V8_WARN_UNUSED_RESULT MaybeLocal NewFromUtf8( - Isolate* isolate, const char* data, - NewStringType type = NewStringType::kNormal, int length = -1); + Isolate* isolate, const char* data, v8::NewStringType type, + int length = -1); /** Allocates a new string from Latin-1 data. Only returns an empty value * when length > kMaxLength. **/ static V8_WARN_UNUSED_RESULT MaybeLocal NewFromOneByte( - Isolate* isolate, const uint8_t* data, - NewStringType type = NewStringType::kNormal, int length = -1); + Isolate* isolate, const uint8_t* data, v8::NewStringType type, + int length = -1); + + /** Allocates a new string from UTF-16 data.*/ + static V8_DEPRECATED( + "Use maybe version", + Local NewFromTwoByte(Isolate* isolate, const uint16_t* data, + NewStringType type = kNormalString, + int length = -1)); /** Allocates a new string from UTF-16 data. Only returns an empty value when * length > kMaxLength. **/ static V8_WARN_UNUSED_RESULT MaybeLocal NewFromTwoByte( - Isolate* isolate, const uint16_t* data, - NewStringType type = NewStringType::kNormal, int length = -1); + Isolate* isolate, const uint16_t* data, v8::NewStringType type, + int length = -1); /** * Creates a new string by concatenating the left and the right strings @@ -3012,6 +3081,10 @@ class V8_EXPORT String : public Name { * should the underlying buffer be deallocated or modified except through the * destructor of the external string resource. */ + static V8_DEPRECATED( + "Use maybe version", + Local NewExternal(Isolate* isolate, + ExternalOneByteStringResource* resource)); static V8_WARN_UNUSED_RESULT MaybeLocal NewExternalOneByte( Isolate* isolate, ExternalOneByteStringResource* resource); @@ -3954,6 +4027,9 @@ class ReturnValue { } // Local setters template + V8_INLINE V8_DEPRECATED("Use Global<> instead", + void Set(const Persistent& handle)); + template V8_INLINE void Set(const Global& handle); template V8_INLINE void Set(const TracedGlobal& handle); @@ -5344,6 +5420,38 @@ class V8_EXPORT Date : public Object { V8_INLINE static Date* Cast(Value* obj); + /** + * Time zone redetection indicator for + * DateTimeConfigurationChangeNotification. + * + * kSkip indicates V8 that the notification should not trigger redetecting + * host time zone. kRedetect indicates V8 that host time zone should be + * redetected, and used to set the default time zone. + * + * The host time zone detection may require file system access or similar + * operations unlikely to be available inside a sandbox. If v8 is run inside a + * sandbox, the host time zone has to be detected outside the sandbox before + * calling DateTimeConfigurationChangeNotification function. + */ + enum class TimeZoneDetection { kSkip, kRedetect }; + + /** + * Notification that the embedder has changed the time zone, + * daylight savings time, or other date / time configuration + * parameters. V8 keeps a cache of various values used for + * date / time computation. This notification will reset + * those cached values for the current context so that date / + * time configuration changes would be reflected in the Date + * object. + * + * This API should not be called more than needed as it will + * negatively impact the performance of date operations. + */ + V8_DEPRECATED("Use Isolate::DateTimeConfigurationChangeNotification", + static void DateTimeConfigurationChangeNotification( + Isolate* isolate, TimeZoneDetection time_zone_detection = + TimeZoneDetection::kSkip)); + private: static void CheckCast(Value* obj); }; @@ -6057,6 +6165,21 @@ class V8_EXPORT FunctionTemplate : public Template { */ void SetAcceptAnyReceiver(bool value); + /** + * Determines whether the __proto__ accessor ignores instances of + * the function template. If instances of the function template are + * ignored, __proto__ skips all instances and instead returns the + * next object in the prototype chain. + * + * Call with a value of true to make the __proto__ accessor ignore + * instances of the function template. Call with a value of false + * to make the __proto__ accessor not ignore instances of the + * function template. By default, instances of a function template + * are not ignored. + */ + V8_DEPRECATED("This feature is incompatible with ES6+.", + void SetHiddenPrototype(bool value)); + /** * Sets the ReadOnly flag in the attributes of the 'prototype' property * of functions created from this FunctionTemplate to true. @@ -8905,9 +9028,7 @@ class V8_EXPORT V8 { * Sets V8 flags from a string. */ static void SetFlagsFromString(const char* str); - static void SetFlagsFromString(const char* str, size_t length); - V8_DEPRECATED("use size_t version", - static void SetFlagsFromString(const char* str, int length)); + static void SetFlagsFromString(const char* str, int length); /** * Sets V8 flags from the command line. @@ -9081,6 +9202,9 @@ class V8_EXPORT V8 { const char* label); static Value* Eternalize(Isolate* isolate, Value* handle); + static void RegisterExternallyReferencedObject(internal::Address* location, + internal::Isolate* isolate); + template friend class PersistentValueMapBase; @@ -10036,6 +10160,14 @@ void Persistent::Copy(const Persistent& that) { M::Copy(that, this); } +template +bool PersistentBase::IsIndependent() const { + typedef internal::Internals I; + if (this->IsEmpty()) return false; + return I::GetNodeFlag(reinterpret_cast(this->val_), + I::kNodeIsIndependentShift); +} + template bool PersistentBase::IsWeak() const { typedef internal::Internals I; @@ -10102,6 +10234,31 @@ void PersistentBase::AnnotateStrongRetainer(const char* label) { label); } +template +void PersistentBase::RegisterExternalReference(Isolate* isolate) const { + if (IsEmpty()) return; + V8::RegisterExternallyReferencedObject( + reinterpret_cast(this->val_), + reinterpret_cast(isolate)); +} + +template +void PersistentBase::MarkIndependent() { + typedef internal::Internals I; + if (this->IsEmpty()) return; + I::UpdateNodeFlag(reinterpret_cast(this->val_), true, + I::kNodeIsIndependentShift); +} + +template +void PersistentBase::MarkActive() { + typedef internal::Internals I; + if (this->IsEmpty()) return; + I::UpdateNodeFlag(reinterpret_cast(this->val_), true, + I::kNodeIsActiveShift); +} + + template void PersistentBase::SetWrapperClassId(uint16_t class_id) { typedef internal::Internals I; @@ -10252,6 +10409,17 @@ void TracedGlobal::SetFinalizationCallback( template ReturnValue::ReturnValue(internal::Address* slot) : value_(slot) {} +template +template +void ReturnValue::Set(const Persistent& handle) { + TYPE_CHECK(T, S); + if (V8_UNLIKELY(handle.IsEmpty())) { + *value_ = GetDefaultValue(); + } else { + *value_ = *reinterpret_cast(*handle); + } +} + template template void ReturnValue::Set(const Global& handle) { diff --git a/deps/v8/src/api/api.cc b/deps/v8/src/api/api.cc index ae0cf0c5b5216b..092db5c2d1056f 100644 --- a/deps/v8/src/api/api.cc +++ b/deps/v8/src/api/api.cc @@ -894,17 +894,13 @@ void V8::SetDcheckErrorHandler(DcheckErrorCallback that) { } void V8::SetFlagsFromString(const char* str) { - SetFlagsFromString(str, strlen(str)); -} - -void V8::SetFlagsFromString(const char* str, size_t length) { - i::FlagList::SetFlagsFromString(str, length); - i::FlagList::EnforceFlagImplications(); + SetFlagsFromString(str, static_cast(strlen(str))); } void V8::SetFlagsFromString(const char* str, int length) { CHECK_LE(0, length); - SetFlagsFromString(str, static_cast(length)); + i::FlagList::SetFlagsFromString(str, static_cast(length)); + i::FlagList::EnforceFlagImplications(); } void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) { @@ -1065,6 +1061,11 @@ void V8::CopyTracedGlobalReference(const internal::Address* const* from, i::GlobalHandles::CopyTracedGlobal(from, to); } +void V8::RegisterExternallyReferencedObject(i::Address* location, + i::Isolate* isolate) { + isolate->heap()->RegisterExternallyReferencedObject(location); +} + void V8::MakeWeak(i::Address* location, void* parameter, WeakCallbackInfo::Callback weak_callback, WeakCallbackType type) { @@ -1637,6 +1638,10 @@ void FunctionTemplate::SetAcceptAnyReceiver(bool value) { info->set_accept_any_receiver(value); } +void FunctionTemplate::SetHiddenPrototype(bool value) { + /* No-op for ABI compatibility. */ +} + void FunctionTemplate::ReadOnlyPrototype() { auto info = Utils::OpenHandle(this); EnsureNotInstantiated(info, "v8::FunctionTemplate::ReadOnlyPrototype"); @@ -3507,6 +3512,12 @@ MaybeLocal Value::ToString(Local context) const { RETURN_ESCAPED(result); } + +Local Value::ToString(Isolate* isolate) const { + RETURN_TO_LOCAL_UNCHECKED(ToString(isolate->GetCurrentContext()), String); +} + + MaybeLocal Value::ToDetailString(Local context) const { i::Handle obj = Utils::OpenHandle(this); if (obj->IsString()) return ToApiHandle(obj); @@ -3528,6 +3539,11 @@ MaybeLocal Value::ToObject(Local context) const { RETURN_ESCAPED(result); } + +Local Value::ToObject(Isolate* isolate) const { + RETURN_TO_LOCAL_UNCHECKED(ToObject(isolate->GetCurrentContext()), Object); +} + MaybeLocal Value::ToBigInt(Local context) const { i::Handle obj = Utils::OpenHandle(this); if (obj->IsBigInt()) return ToApiHandle(obj); @@ -3544,6 +3560,11 @@ bool Value::BooleanValue(Isolate* v8_isolate) const { reinterpret_cast(v8_isolate)); } +MaybeLocal Value::ToBoolean(Local context) const { + return ToBoolean(context->GetIsolate()); +} + + Local Value::ToBoolean(Isolate* v8_isolate) const { auto isolate = reinterpret_cast(v8_isolate); return ToApiHandle( @@ -3561,6 +3582,12 @@ MaybeLocal Value::ToNumber(Local context) const { RETURN_ESCAPED(result); } + +Local Value::ToNumber(Isolate* isolate) const { + RETURN_TO_LOCAL_UNCHECKED(ToNumber(isolate->GetCurrentContext()), Number); +} + + MaybeLocal Value::ToInteger(Local context) const { auto obj = Utils::OpenHandle(this); if (obj->IsSmi()) return ToApiHandle(obj); @@ -3572,6 +3599,12 @@ MaybeLocal Value::ToInteger(Local context) const { RETURN_ESCAPED(result); } + +Local Value::ToInteger(Isolate* isolate) const { + RETURN_TO_LOCAL_UNCHECKED(ToInteger(isolate->GetCurrentContext()), Integer); +} + + MaybeLocal Value::ToInt32(Local context) const { auto obj = Utils::OpenHandle(this); if (obj->IsSmi()) return ToApiHandle(obj); @@ -3583,6 +3616,12 @@ MaybeLocal Value::ToInt32(Local context) const { RETURN_ESCAPED(result); } + +Local Value::ToInt32(Isolate* isolate) const { + RETURN_TO_LOCAL_UNCHECKED(ToInt32(isolate->GetCurrentContext()), Int32); +} + + MaybeLocal Value::ToUint32(Local context) const { auto obj = Utils::OpenHandle(this); if (obj->IsSmi()) return ToApiHandle(obj); @@ -3809,6 +3848,13 @@ void v8::RegExp::CheckCast(v8::Value* that) { "Could not convert to regular expression"); } + +Maybe Value::BooleanValue(Local context) const { + i::Isolate* isolate = reinterpret_cast(context->GetIsolate()); + return Just(Utils::OpenHandle(this)->BooleanValue(isolate)); +} + + Maybe Value::NumberValue(Local context) const { auto obj = Utils::OpenHandle(this); if (obj->IsNumber()) return Just(obj->Number()); @@ -6139,9 +6185,9 @@ inline int StringLength(const uint16_t* string) { V8_WARN_UNUSED_RESULT inline i::MaybeHandle NewString(i::Factory* factory, - NewStringType type, + v8::NewStringType type, i::Vector string) { - if (type == NewStringType::kInternalized) { + if (type == v8::NewStringType::kInternalized) { return factory->InternalizeUtf8String(string); } return factory->NewStringFromUtf8(string); @@ -6149,9 +6195,9 @@ inline i::MaybeHandle NewString(i::Factory* factory, V8_WARN_UNUSED_RESULT inline i::MaybeHandle NewString(i::Factory* factory, - NewStringType type, + v8::NewStringType type, i::Vector string) { - if (type == NewStringType::kInternalized) { + if (type == v8::NewStringType::kInternalized) { return factory->InternalizeString(string); } return factory->NewStringFromOneByte(string); @@ -6159,14 +6205,15 @@ inline i::MaybeHandle NewString(i::Factory* factory, V8_WARN_UNUSED_RESULT inline i::MaybeHandle NewString(i::Factory* factory, - NewStringType type, + v8::NewStringType type, i::Vector string) { - if (type == NewStringType::kInternalized) { + if (type == v8::NewStringType::kInternalized) { return factory->InternalizeString(string); } return factory->NewStringFromTwoByte(string); } + STATIC_ASSERT(v8::String::kMaxLength == i::String::kMaxLength); } // anonymous namespace @@ -6191,21 +6238,43 @@ STATIC_ASSERT(v8::String::kMaxLength == i::String::kMaxLength); result = Utils::ToLocal(handle_result); \ } +Local String::NewFromUtf8(Isolate* isolate, + const char* data, + NewStringType type, + int length) { + NEW_STRING(isolate, String, NewFromUtf8, char, data, + static_cast(type), length); + RETURN_TO_LOCAL_UNCHECKED(result, String); +} + + MaybeLocal String::NewFromUtf8(Isolate* isolate, const char* data, - NewStringType type, int length) { + v8::NewStringType type, int length) { NEW_STRING(isolate, String, NewFromUtf8, char, data, type, length); return result; } + MaybeLocal String::NewFromOneByte(Isolate* isolate, const uint8_t* data, - NewStringType type, int length) { + v8::NewStringType type, int length) { NEW_STRING(isolate, String, NewFromOneByte, uint8_t, data, type, length); return result; } + +Local String::NewFromTwoByte(Isolate* isolate, + const uint16_t* data, + NewStringType type, + int length) { + NEW_STRING(isolate, String, NewFromTwoByte, uint16_t, data, + static_cast(type), length); + RETURN_TO_LOCAL_UNCHECKED(result, String); +} + + MaybeLocal String::NewFromTwoByte(Isolate* isolate, const uint16_t* data, - NewStringType type, int length) { + v8::NewStringType type, int length) { NEW_STRING(isolate, String, NewFromTwoByte, uint16_t, data, type, length); return result; } @@ -6272,6 +6341,13 @@ MaybeLocal v8::String::NewExternalOneByte( return Utils::ToLocal(string); } + +Local v8::String::NewExternal( + Isolate* isolate, v8::String::ExternalOneByteStringResource* resource) { + RETURN_TO_LOCAL_UNCHECKED(NewExternalOneByte(isolate, resource), String); +} + + bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) { i::DisallowHeapAllocation no_allocation; @@ -6545,14 +6621,23 @@ double v8::Date::ValueOf() const { // Assert that the static TimeZoneDetection cast in // DateTimeConfigurationChangeNotification is valid. -#define TIME_ZONE_DETECTION_ASSERT_EQ(value) \ - STATIC_ASSERT( \ - static_cast(v8::Isolate::TimeZoneDetection::value) == \ - static_cast(base::TimezoneCache::TimeZoneDetection::value)); +#define TIME_ZONE_DETECTION_ASSERT_EQ(value) \ + STATIC_ASSERT( \ + static_cast(v8::Isolate::TimeZoneDetection::value) == \ + static_cast(base::TimezoneCache::TimeZoneDetection::value)); \ + STATIC_ASSERT(static_cast(v8::Isolate::TimeZoneDetection::value) == \ + static_cast(v8::Date::TimeZoneDetection::value)); TIME_ZONE_DETECTION_ASSERT_EQ(kSkip) TIME_ZONE_DETECTION_ASSERT_EQ(kRedetect) #undef TIME_ZONE_DETECTION_ASSERT_EQ +// static +void v8::Date::DateTimeConfigurationChangeNotification( + Isolate* isolate, TimeZoneDetection time_zone_detection) { + isolate->DateTimeConfigurationChangeNotification( + static_cast(time_zone_detection)); +} + MaybeLocal v8::RegExp::New(Local context, Local pattern, Flags flags) { PREPARE_FOR_EXECUTION(context, RegExp, New, RegExp); @@ -9869,6 +9954,14 @@ CpuProfiler* CpuProfiler::New(Isolate* isolate, reinterpret_cast(isolate), naming_mode, logging_mode)); } +CpuProfiler* CpuProfiler::New(Isolate* isolate) { + return New(isolate, kDebugNaming, kLazyLogging); +} + +CpuProfiler* CpuProfiler::New(Isolate* isolate, CpuProfilingNamingMode mode) { + return New(isolate, mode, kLazyLogging); +} + CpuProfilingOptions::CpuProfilingOptions(CpuProfilingMode mode, unsigned max_samples, int sampling_interval_us, @@ -9926,6 +10019,12 @@ void CpuProfiler::StartProfiling(Local title, bool record_samples) { *Utils::OpenHandle(*title), options); } +void CpuProfiler::StartProfiling(Local title, CpuProfilingMode mode, + bool record_samples) { + StartProfiling(title, mode, record_samples, + CpuProfilingOptions::kNoSampleLimit); +} + void CpuProfiler::StartProfiling(Local title, CpuProfilingMode mode, bool record_samples, unsigned max_samples) { CpuProfilingOptions options(mode, record_samples ? max_samples : 0); diff --git a/deps/v8/src/handles/global-handles.cc b/deps/v8/src/handles/global-handles.cc index aed5b3fa834e84..a076be9a49ebd6 100644 --- a/deps/v8/src/handles/global-handles.cc +++ b/deps/v8/src/handles/global-handles.cc @@ -399,6 +399,10 @@ class GlobalHandles::Node final : public NodeBase { Internals::kNodeStateMask); STATIC_ASSERT(WEAK == Internals::kNodeStateIsWeakValue); STATIC_ASSERT(PENDING == Internals::kNodeStateIsPendingValue); + STATIC_ASSERT(static_cast(IsIndependent::kShift) == + Internals::kNodeIsIndependentShift); + STATIC_ASSERT(static_cast(IsActive::kShift) == + Internals::kNodeIsActiveShift); set_in_young_list(false); } @@ -418,6 +422,16 @@ class GlobalHandles::Node final : public NodeBase { State state() const { return NodeState::decode(flags_); } void set_state(State state) { flags_ = NodeState::update(flags_, state); } + bool is_independent() { return IsIndependent::decode(flags_); } + void set_independent(bool v) { flags_ = IsIndependent::update(flags_, v); } + + bool is_active() { + return IsActive::decode(flags_); + } + void set_active(bool v) { + flags_ = IsActive::update(flags_, v); + } + bool is_in_young_list() const { return IsInYoungList::decode(flags_); } void set_in_young_list(bool v) { flags_ = IsInYoungList::update(flags_, v); } @@ -565,6 +579,7 @@ class GlobalHandles::Node final : public NodeBase { // This method invokes a finalizer. Updating the method name would require // adjusting CFI blacklist as weak_callback_ is invoked on the wrong type. CHECK(IsPendingFinalizer()); + CHECK(!is_active()); set_state(NEAR_DEATH); // Check that we are not passing a finalized external string to // the callback. @@ -594,14 +609,25 @@ class GlobalHandles::Node final : public NodeBase { private: // Fields that are not used for managing node memory. - void ClearImplFields() { weak_callback_ = nullptr; } + void ClearImplFields() { + set_independent(false); + set_active(false); + weak_callback_ = nullptr; + } - void CheckImplFieldsAreCleared() { DCHECK_EQ(nullptr, weak_callback_); } + void CheckImplFieldsAreCleared() { + DCHECK(!is_independent()); + DCHECK(!is_active()); + DCHECK_EQ(nullptr, weak_callback_); + } // This stores three flags (independent, partially_dependent and // in_young_list) and a State. using NodeState = BitField8; - using IsInYoungList = NodeState::Next; + using IsIndependent = NodeState::Next; + // The following two fields are mutually exclusive + using IsActive = IsIndependent::Next; + using IsInYoungList = IsActive::Next; using NodeWeaknessType = IsInYoungList::Next; // Handle specific callback - might be a weak reference in disguise. @@ -894,6 +920,12 @@ void GlobalHandles::IterateWeakRootsIdentifyFinalizers( void GlobalHandles::IdentifyWeakUnmodifiedObjects( WeakSlotCallback is_unmodified) { + for (Node* node : young_nodes_) { + if (node->IsWeak() && !is_unmodified(node->location())) { + node->set_active(true); + } + } + LocalEmbedderHeapTracer* const tracer = isolate()->heap()->local_embedder_heap_tracer(); for (TracedNode* node : traced_young_nodes_) { @@ -910,7 +942,9 @@ void GlobalHandles::IdentifyWeakUnmodifiedObjects( void GlobalHandles::IterateYoungStrongAndDependentRoots(RootVisitor* v) { for (Node* node : young_nodes_) { - if (node->IsStrongRetainer()) { + if (node->IsStrongRetainer() || + (node->IsWeakRetainer() && !node->is_independent() && + node->is_active())) { v->VisitRootPointer(Root::kGlobalHandles, node->label(), node->location()); } @@ -926,7 +960,8 @@ void GlobalHandles::MarkYoungWeakUnmodifiedObjectsPending( WeakSlotCallbackWithHeap is_dead) { for (Node* node : young_nodes_) { DCHECK(node->is_in_young_list()); - if (node->IsWeak() && is_dead(isolate_->heap(), node->location())) { + if ((node->is_independent() || !node->is_active()) && node->IsWeak() && + is_dead(isolate_->heap(), node->location())) { if (!node->IsPhantomCallback() && !node->IsPhantomResetHandle()) { node->MarkPending(); } @@ -938,7 +973,8 @@ void GlobalHandles::IterateYoungWeakUnmodifiedRootsForFinalizers( RootVisitor* v) { for (Node* node : young_nodes_) { DCHECK(node->is_in_young_list()); - if (node->IsWeakRetainer() && (node->state() == Node::PENDING)) { + if ((node->is_independent() || !node->is_active()) && + node->IsWeakRetainer() && (node->state() == Node::PENDING)) { DCHECK(!node->IsPhantomCallback()); DCHECK(!node->IsPhantomResetHandle()); // Finalizers need to survive. @@ -952,7 +988,8 @@ void GlobalHandles::IterateYoungWeakUnmodifiedRootsForPhantomHandles( RootVisitor* v, WeakSlotCallbackWithHeap should_reset_handle) { for (Node* node : young_nodes_) { DCHECK(node->is_in_young_list()); - if (node->IsWeakRetainer() && (node->state() != Node::PENDING)) { + if ((node->is_independent() || !node->is_active()) && + node->IsWeakRetainer() && (node->state() != Node::PENDING)) { if (should_reset_handle(isolate_->heap(), node->location())) { DCHECK(node->IsPhantomResetHandle() || node->IsPhantomCallback()); if (node->IsPhantomResetHandle()) { @@ -1041,6 +1078,9 @@ size_t GlobalHandles::PostScavengeProcessing(unsigned post_processing_count) { // Filter free nodes. if (!node->IsRetainer()) continue; + // Reset active state for all affected nodes. + node->set_active(false); + if (node->IsPending()) { DCHECK(node->has_callback()); DCHECK(node->IsPendingFinalizer()); @@ -1059,6 +1099,9 @@ size_t GlobalHandles::PostMarkSweepProcessing(unsigned post_processing_count) { // Filter free nodes. if (!node->IsRetainer()) continue; + // Reset active state for all affected nodes. + node->set_active(false); + if (node->IsPending()) { DCHECK(node->has_callback()); DCHECK(node->IsPendingFinalizer()); diff --git a/deps/v8/src/profiler/sampling-heap-profiler.cc b/deps/v8/src/profiler/sampling-heap-profiler.cc index de19d39eba605c..f0a1de3164e13d 100644 --- a/deps/v8/src/profiler/sampling-heap-profiler.cc +++ b/deps/v8/src/profiler/sampling-heap-profiler.cc @@ -92,6 +92,16 @@ void SamplingHeapProfiler::SampleObject(Address soon_object, size_t size) { base::make_unique(size, node, loc, this, next_sample_id()); sample->global.SetWeak(sample.get(), OnWeakCallback, WeakCallbackType::kParameter); +#if __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +#endif + // MarkIndependent is marked deprecated but we still rely on it here + // temporarily. + sample->global.MarkIndependent(); +#if __clang__ +#pragma clang diagnostic pop +#endif samples_.emplace(sample.get(), std::move(sample)); } diff --git a/deps/v8/test/cctest/heap/heap-utils.h b/deps/v8/test/cctest/heap/heap-utils.h index dfd4094913e84d..375c2aeb13320c 100644 --- a/deps/v8/test/cctest/heap/heap-utils.h +++ b/deps/v8/test/cctest/heap/heap-utils.h @@ -12,22 +12,6 @@ namespace v8 { namespace internal { namespace heap { -class TemporaryEmbedderHeapTracerScope { - public: - TemporaryEmbedderHeapTracerScope(v8::Isolate* isolate, - v8::EmbedderHeapTracer* tracer) - : isolate_(isolate) { - isolate_->SetEmbedderHeapTracer(tracer); - } - - ~TemporaryEmbedderHeapTracerScope() { - isolate_->SetEmbedderHeapTracer(nullptr); - } - - private: - v8::Isolate* const isolate_; -}; - void SealCurrentObjects(Heap* heap); int FixedArrayLenFromSize(int size); diff --git a/deps/v8/test/cctest/heap/test-embedder-tracing.cc b/deps/v8/test/cctest/heap/test-embedder-tracing.cc index 28553266ff2ed0..de21bbd3a3848c 100644 --- a/deps/v8/test/cctest/heap/test-embedder-tracing.cc +++ b/deps/v8/test/cctest/heap/test-embedder-tracing.cc @@ -110,6 +110,22 @@ class TestEmbedderHeapTracer final : public v8::EmbedderHeapTracer { v8::Global array_; }; +class TemporaryEmbedderHeapTracerScope { + public: + TemporaryEmbedderHeapTracerScope(v8::Isolate* isolate, + EmbedderHeapTracer* tracer) + : isolate_(isolate) { + isolate_->SetEmbedderHeapTracer(tracer); + } + + ~TemporaryEmbedderHeapTracerScope() { + isolate_->SetEmbedderHeapTracer(nullptr); + } + + private: + v8::Isolate* const isolate_; +}; + } // namespace TEST(V8RegisteringEmbedderReference) { @@ -119,7 +135,7 @@ TEST(V8RegisteringEmbedderReference) { CcTest::InitializeVM(); v8::Isolate* isolate = CcTest::isolate(); TestEmbedderHeapTracer tracer; - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); v8::HandleScope scope(isolate); v8::Local context = v8::Context::New(isolate); v8::Context::Scope context_scope(context); @@ -139,7 +155,7 @@ TEST(EmbedderRegisteringV8Reference) { CcTest::InitializeVM(); v8::Isolate* isolate = CcTest::isolate(); TestEmbedderHeapTracer tracer; - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); v8::HandleScope scope(isolate); v8::Local context = v8::Context::New(isolate); v8::Context::Scope context_scope(context); @@ -172,7 +188,7 @@ TEST(TracingInRevivedSubgraph) { CcTest::InitializeVM(); v8::Isolate* isolate = CcTest::isolate(); TestEmbedderHeapTracer tracer; - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); v8::HandleScope scope(isolate); v8::Local context = v8::Context::New(isolate); v8::Context::Scope context_scope(context); @@ -200,7 +216,7 @@ TEST(TracingInEphemerons) { CcTest::InitializeVM(); v8::Isolate* isolate = CcTest::isolate(); TestEmbedderHeapTracer tracer; - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); v8::HandleScope scope(isolate); v8::Local context = v8::Context::New(isolate); v8::Context::Scope context_scope(context); @@ -231,7 +247,7 @@ TEST(FinalizeTracingIsNoopWhenNotMarking) { v8::Isolate* isolate = CcTest::isolate(); Isolate* i_isolate = CcTest::i_isolate(); TestEmbedderHeapTracer tracer; - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); // Finalize a potentially running garbage collection. i_isolate->heap()->CollectGarbage(OLD_SPACE, @@ -250,7 +266,7 @@ TEST(FinalizeTracingWhenMarking) { v8::Isolate* isolate = CcTest::isolate(); Isolate* i_isolate = CcTest::i_isolate(); TestEmbedderHeapTracer tracer; - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); // Finalize a potentially running garbage collection. i_isolate->heap()->CollectGarbage(OLD_SPACE, @@ -275,7 +291,7 @@ TEST(GarbageCollectionForTesting) { v8::Isolate* isolate = CcTest::isolate(); Isolate* i_isolate = CcTest::i_isolate(); TestEmbedderHeapTracer tracer; - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); int saved_gc_counter = i_isolate->heap()->gc_count(); tracer.GarbageCollectionForTesting(EmbedderHeapTracer::kUnknown); @@ -484,7 +500,7 @@ TEST(TracedGlobalToUnmodifiedJSObjectSurvivesScavengeWhenExcludedFromRoots) { CcTest::InitializeVM(); v8::Isolate* isolate = CcTest::isolate(); TestEmbedderHeapTracer tracer; - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); tracer.ConsiderTracedGlobalAsRoot(false); TracedGlobalTest( CcTest::isolate(), ConstructJSObject, @@ -497,7 +513,7 @@ TEST(TracedGlobalToUnmodifiedJSApiObjectSurvivesScavengePerDefault) { CcTest::InitializeVM(); v8::Isolate* isolate = CcTest::isolate(); TestEmbedderHeapTracer tracer; - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); tracer.ConsiderTracedGlobalAsRoot(true); TracedGlobalTest( CcTest::isolate(), ConstructJSApiObject, @@ -510,7 +526,7 @@ TEST(TracedGlobalToUnmodifiedJSApiObjectDiesOnScavengeWhenExcludedFromRoots) { CcTest::InitializeVM(); v8::Isolate* isolate = CcTest::isolate(); TestEmbedderHeapTracer tracer; - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); tracer.ConsiderTracedGlobalAsRoot(false); TracedGlobalTest( CcTest::isolate(), ConstructJSApiObject, @@ -524,7 +540,7 @@ TEST(TracedGlobalWrapperClassId) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); TestEmbedderHeapTracer tracer; - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); v8::TracedGlobal traced; ConstructJSObject(isolate, isolate->GetCurrentContext(), &traced); @@ -559,7 +575,7 @@ TEST(TracedGlobalIteration) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); TestEmbedderHeapTracer tracer; - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); v8::TracedGlobal traced; ConstructJSObject(isolate, isolate->GetCurrentContext(), &traced); @@ -592,7 +608,7 @@ TEST(TracedGlobalSetFinalizationCallbackScavenge) { v8::HandleScope scope(isolate); TestEmbedderHeapTracer tracer; tracer.ConsiderTracedGlobalAsRoot(false); - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); v8::TracedGlobal traced; ConstructJSApiObject(isolate, isolate->GetCurrentContext(), &traced); @@ -614,7 +630,7 @@ TEST(TracedGlobalSetFinalizationCallbackMarkSweep) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); TestEmbedderHeapTracer tracer; - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); v8::TracedGlobal traced; ConstructJSApiObject(isolate, isolate->GetCurrentContext(), &traced); @@ -644,7 +660,7 @@ TEST(TracePrologueCallingIntoV8WriteBarrier) { } TestEmbedderHeapTracer tracer(TracePrologueBehavior::kCallV8WriteBarrier, std::move(global)); - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); + TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); SimulateIncrementalMarking(CcTest::i_isolate()->heap()); // Finish GC to avoid removing the tracer while GC is running which may end up // in an infinite loop because of unprocessed objects. diff --git a/deps/v8/test/cctest/heap/test-heap.cc b/deps/v8/test/cctest/heap/test-heap.cc index fd17c0f063b5b4..48ba63a5dbf992 100644 --- a/deps/v8/test/cctest/heap/test-heap.cc +++ b/deps/v8/test/cctest/heap/test-heap.cc @@ -496,6 +496,44 @@ static void TestWeakGlobalHandleCallback( p->first->Reset(); } + +TEST(WeakGlobalHandlesScavenge) { + FLAG_stress_compaction = false; + FLAG_stress_incremental_marking = false; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + Factory* factory = isolate->factory(); + GlobalHandles* global_handles = isolate->global_handles(); + + WeakPointerCleared = false; + + Handle h1; + Handle h2; + + { + HandleScope scope(isolate); + + Handle i = factory->NewStringFromStaticChars("fisk"); + Handle u = factory->NewNumber(1.12344); + + h1 = global_handles->Create(*i); + h2 = global_handles->Create(*u); + } + + std::pair*, int> handle_and_id(&h2, 1234); + GlobalHandles::MakeWeak( + h2.location(), reinterpret_cast(&handle_and_id), + &TestWeakGlobalHandleCallback, v8::WeakCallbackType::kParameter); + + // Scavenge treats weak pointers as normal roots. + CcTest::CollectGarbage(NEW_SPACE); + CHECK((*h1).IsString()); + CHECK((*h2).IsHeapNumber()); + CHECK(!WeakPointerCleared); + GlobalHandles::Destroy(h1.location()); + GlobalHandles::Destroy(h2.location()); +} + TEST(WeakGlobalUnmodifiedApiHandlesScavenge) { CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); @@ -534,6 +572,84 @@ TEST(WeakGlobalUnmodifiedApiHandlesScavenge) { GlobalHandles::Destroy(h1.location()); } +TEST(WeakGlobalApiHandleModifiedMapScavenge) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + LocalContext context; + GlobalHandles* global_handles = isolate->global_handles(); + + WeakPointerCleared = false; + + Handle h1; + + { + HandleScope scope(isolate); + + // Create an API object which does not have the same map as constructor. + auto function_template = FunctionTemplate::New(context->GetIsolate()); + auto instance_t = function_template->InstanceTemplate(); + instance_t->Set(v8::String::NewFromUtf8(context->GetIsolate(), "a", + NewStringType::kNormal) + .ToLocalChecked(), + v8::Number::New(context->GetIsolate(), 10)); + auto function = + function_template->GetFunction(context.local()).ToLocalChecked(); + auto i = function->NewInstance(context.local()).ToLocalChecked(); + + h1 = global_handles->Create(*(reinterpret_cast(*i))); + } + + std::pair*, int> handle_and_id(&h1, 1234); + GlobalHandles::MakeWeak( + h1.location(), reinterpret_cast(&handle_and_id), + &TestWeakGlobalHandleCallback, v8::WeakCallbackType::kParameter); + + CcTest::CollectGarbage(NEW_SPACE); + CHECK(!WeakPointerCleared); + GlobalHandles::Destroy(h1.location()); +} + +TEST(WeakGlobalApiHandleWithElementsScavenge) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + LocalContext context; + GlobalHandles* global_handles = isolate->global_handles(); + + WeakPointerCleared = false; + + Handle h1; + + { + HandleScope scope(isolate); + + // Create an API object which has elements. + auto function_template = FunctionTemplate::New(context->GetIsolate()); + auto instance_t = function_template->InstanceTemplate(); + instance_t->Set(v8::String::NewFromUtf8(context->GetIsolate(), "1", + NewStringType::kNormal) + .ToLocalChecked(), + v8::Number::New(context->GetIsolate(), 10)); + instance_t->Set(v8::String::NewFromUtf8(context->GetIsolate(), "2", + NewStringType::kNormal) + .ToLocalChecked(), + v8::Number::New(context->GetIsolate(), 10)); + auto function = + function_template->GetFunction(context.local()).ToLocalChecked(); + auto i = function->NewInstance(context.local()).ToLocalChecked(); + + h1 = global_handles->Create(*(reinterpret_cast(*i))); + } + + std::pair*, int> handle_and_id(&h1, 1234); + GlobalHandles::MakeWeak( + h1.location(), reinterpret_cast(&handle_and_id), + &TestWeakGlobalHandleCallback, v8::WeakCallbackType::kParameter); + + CcTest::CollectGarbage(NEW_SPACE); + CHECK(!WeakPointerCleared); + GlobalHandles::Destroy(h1.location()); +} + TEST(WeakGlobalHandlesMark) { FLAG_stress_incremental_marking = false; CcTest::InitializeVM(); @@ -583,7 +699,9 @@ TEST(DeleteWeakGlobalHandle) { GlobalHandles* global_handles = isolate->global_handles(); WeakPointerCleared = false; + Handle h; + { HandleScope scope(isolate); @@ -595,8 +713,15 @@ TEST(DeleteWeakGlobalHandle) { GlobalHandles::MakeWeak(h.location(), reinterpret_cast(&handle_and_id), &TestWeakGlobalHandleCallback, v8::WeakCallbackType::kParameter); + + // Scanvenge does not recognize weak reference. + CcTest::CollectGarbage(NEW_SPACE); + CHECK(!WeakPointerCleared); + + // Mark-compact treats weak reference properly. CcTest::CollectGarbage(OLD_SPACE); + CHECK(WeakPointerCleared); } diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index b4bd8b66df35a8..0168b0f85a85c6 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -7632,6 +7632,18 @@ static void IndependentWeakHandle(bool global_gc, bool interlinked) { v8::WeakCallbackType::kParameter); object_b.handle.SetWeak(&object_b, &SetFlag, v8::WeakCallbackType::kParameter); +#if __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +#endif + // MarkIndependent is marked deprecated but we still rely on it temporarily. + CHECK(!object_b.handle.IsIndependent()); + object_a.handle.MarkIndependent(); + object_b.handle.MarkIndependent(); + CHECK(object_b.handle.IsIndependent()); +#if __clang__ +#pragma clang diagnostic pop +#endif if (global_gc) { CcTest::CollectAllGarbage(); } else { @@ -7782,6 +7794,19 @@ void v8::internal::heap::HeapTester::ResetWeakHandle(bool global_gc) { v8::WeakCallbackType::kParameter); object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag, v8::WeakCallbackType::kParameter); + if (!global_gc) { +#if __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +#endif + // MarkIndependent is marked deprecated but we still rely on it temporarily. + object_a.handle.MarkIndependent(); + object_b.handle.MarkIndependent(); + CHECK(object_b.handle.IsIndependent()); +#if __clang__ +#pragma clang diagnostic pop +#endif + } if (global_gc) { CcTest::PreciseCollectAllGarbage(); } else { @@ -7849,6 +7874,16 @@ THREADED_TEST(GCFromWeakCallbacks) { object.flag = false; object.handle.SetWeak(&object, gc_forcing_callback[inner_gc], v8::WeakCallbackType::kParameter); +#if __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +#endif + // MarkIndependent is marked deprecated but we still rely on it + // temporarily. + object.handle.MarkIndependent(); +#if __clang__ +#pragma clang diagnostic pop +#endif invoke_gc[outer_gc](); EmptyMessageQueues(isolate); CHECK(object.flag); diff --git a/deps/v8/test/cctest/test-global-handles.cc b/deps/v8/test/cctest/test-global-handles.cc index 417679432bf2d5..8ed862c2da11eb 100644 --- a/deps/v8/test/cctest/test-global-handles.cc +++ b/deps/v8/test/cctest/test-global-handles.cc @@ -39,25 +39,6 @@ namespace internal { namespace { -// Empty v8::EmbedderHeapTracer that never keeps objects alive on Scavenge. See -// |IsRootForNonTracingGC|. -class NonRootingEmbedderHeapTracer final : public v8::EmbedderHeapTracer { - public: - NonRootingEmbedderHeapTracer() = default; - - void RegisterV8References( - const std::vector>& embedder_fields) final {} - bool AdvanceTracing(double deadline_in_ms) final { return true; } - bool IsTracingDone() final { return true; } - void TracePrologue() final {} - void TraceEpilogue() final {} - void EnterFinalPause(EmbedderStackState) final {} - - bool IsRootForNonTracingGC(const v8::TracedGlobal& handle) final { - return false; - } -}; - void InvokeScavenge() { CcTest::CollectGarbage(i::NEW_SPACE); } void InvokeMarkSweep() { CcTest::CollectAllGarbage(); } @@ -66,23 +47,23 @@ void SimpleCallback(const v8::FunctionCallbackInfo& info) { info.GetReturnValue().Set(v8_num(0)); } -struct FlagAndGlobal { +struct FlagAndPersistent { bool flag; v8::Global handle; }; -struct TracedGlobalWrapper { - v8::TracedGlobal handle; -}; - -void ResetHandleAndSetFlag(const v8::WeakCallbackInfo& data) { +void ResetHandleAndSetFlag( + const v8::WeakCallbackInfo& data) { data.GetParameter()->handle.Reset(); data.GetParameter()->flag = true; } -template +using ConstructFunction = void (*)(v8::Isolate* isolate, + v8::Local context, + FlagAndPersistent* flag_and_persistent); + void ConstructJSObject(v8::Isolate* isolate, v8::Local context, - HandleContainer* flag_and_persistent) { + FlagAndPersistent* flag_and_persistent) { v8::HandleScope handle_scope(isolate); v8::Local object(v8::Object::New(isolate)); CHECK(!object.IsEmpty()); @@ -98,9 +79,8 @@ void ConstructJSObject(v8::Isolate* isolate, v8::Global* global) { CHECK(!global->IsEmpty()); } -template void ConstructJSApiObject(v8::Isolate* isolate, v8::Local context, - HandleContainer* flag_and_persistent) { + FlagAndPersistent* flag_and_persistent) { v8::HandleScope handle_scope(isolate); v8::Local fun = v8::FunctionTemplate::New(isolate, SimpleCallback); @@ -115,8 +95,7 @@ void ConstructJSApiObject(v8::Isolate* isolate, v8::Local context, enum class SurvivalMode { kSurvives, kDies }; -template +template void WeakHandleTest(v8::Isolate* isolate, ConstructFunction construct_function, ModifierFunction modifier_function, GCFunction gc_function, SurvivalMode survives) { @@ -124,7 +103,7 @@ void WeakHandleTest(v8::Isolate* isolate, ConstructFunction construct_function, v8::Local context = v8::Context::New(isolate); v8::Context::Scope context_scope(context); - FlagAndGlobal fp; + FlagAndPersistent fp; construct_function(isolate, context, &fp); CHECK(heap::InYoungGeneration(isolate, fp.handle)); fp.handle.SetWeak(&fp, &ResetHandleAndSetFlag, @@ -136,28 +115,6 @@ void WeakHandleTest(v8::Isolate* isolate, ConstructFunction construct_function, CHECK_IMPLIES(survives == SurvivalMode::kDies, fp.flag); } -template -void TracedGlobalTest(v8::Isolate* isolate, - ConstructFunction construct_function, - ModifierFunction modifier_function, - GCFunction gc_function, SurvivalMode survives) { - v8::HandleScope scope(isolate); - v8::Local context = v8::Context::New(isolate); - v8::Context::Scope context_scope(context); - - NonRootingEmbedderHeapTracer tracer; - heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); - - TracedGlobalWrapper fp; - construct_function(isolate, context, &fp); - CHECK(heap::InYoungGeneration(isolate, fp.handle)); - modifier_function(&fp); - gc_function(); - CHECK_IMPLIES(survives == SurvivalMode::kSurvives, !fp.handle.IsEmpty()); - CHECK_IMPLIES(survives == SurvivalMode::kDies, fp.handle.IsEmpty()); -} - void ResurrectingFinalizer( const v8::WeakCallbackInfo>& data) { data.GetParameter()->ClearWeak(); @@ -320,36 +277,25 @@ TEST(PhatomHandlesWithoutCallbacks) { CHECK_EQ(0u, isolate->NumberOfPhantomHandleResetsSinceLastCall()); } -TEST(WeakHandleToUnmodifiedJSObjectDiesOnScavenge) { +TEST(WeakHandleToUnmodifiedJSObjectSurvivesScavenge) { CcTest::InitializeVM(); WeakHandleTest( - CcTest::isolate(), &ConstructJSObject, - [](FlagAndGlobal* fp) {}, []() { InvokeScavenge(); }, - SurvivalMode::kDies); -} - -TEST(TracedGlobalToUnmodifiedJSObjectSurvivesScavenge) { - ManualGCScope manual_gc; - CcTest::InitializeVM(); - TracedGlobalTest( - CcTest::isolate(), &ConstructJSObject, - [](TracedGlobalWrapper* fp) {}, []() { InvokeScavenge(); }, - SurvivalMode::kSurvives); + CcTest::isolate(), &ConstructJSObject, [](FlagAndPersistent* fp) {}, + []() { InvokeScavenge(); }, SurvivalMode::kSurvives); } TEST(WeakHandleToUnmodifiedJSObjectDiesOnMarkCompact) { CcTest::InitializeVM(); WeakHandleTest( - CcTest::isolate(), &ConstructJSObject, - [](FlagAndGlobal* fp) {}, []() { InvokeMarkSweep(); }, - SurvivalMode::kDies); + CcTest::isolate(), &ConstructJSObject, [](FlagAndPersistent* fp) {}, + []() { InvokeMarkSweep(); }, SurvivalMode::kDies); } TEST(WeakHandleToUnmodifiedJSObjectSurvivesMarkCompactWhenInHandle) { CcTest::InitializeVM(); WeakHandleTest( - CcTest::isolate(), &ConstructJSObject, - [](FlagAndGlobal* fp) { + CcTest::isolate(), &ConstructJSObject, + [](FlagAndPersistent* fp) { v8::Local handle = v8::Local::New(CcTest::isolate(), fp->handle); USE(handle); @@ -360,30 +306,19 @@ TEST(WeakHandleToUnmodifiedJSObjectSurvivesMarkCompactWhenInHandle) { TEST(WeakHandleToUnmodifiedJSApiObjectDiesOnScavenge) { CcTest::InitializeVM(); WeakHandleTest( - CcTest::isolate(), &ConstructJSApiObject, - [](FlagAndGlobal* fp) {}, []() { InvokeScavenge(); }, - SurvivalMode::kDies); -} - -TEST(TracedGlobalToUnmodifiedJSApiObjectDiesOnScavenge) { - ManualGCScope manual_gc; - CcTest::InitializeVM(); - TracedGlobalTest( - CcTest::isolate(), &ConstructJSApiObject, - [](TracedGlobalWrapper* fp) {}, []() { InvokeScavenge(); }, - SurvivalMode::kDies); + CcTest::isolate(), &ConstructJSApiObject, [](FlagAndPersistent* fp) {}, + []() { InvokeScavenge(); }, SurvivalMode::kDies); } -TEST(TracedGlobalToJSApiObjectWithIdentityHashSurvivesScavenge) { - ManualGCScope manual_gc; +TEST(WeakHandleToJSApiObjectWithIdentityHashSurvivesScavenge) { CcTest::InitializeVM(); Isolate* i_isolate = CcTest::i_isolate(); HandleScope scope(i_isolate); Handle weakmap = i_isolate->factory()->NewJSWeakMap(); - TracedGlobalTest( - CcTest::isolate(), &ConstructJSApiObject, - [&weakmap, i_isolate](TracedGlobalWrapper* fp) { + WeakHandleTest( + CcTest::isolate(), &ConstructJSApiObject, + [&weakmap, i_isolate](FlagAndPersistent* fp) { v8::HandleScope scope(CcTest::isolate()); Handle key = Utils::OpenHandle(*fp->handle.Get(CcTest::isolate())); @@ -397,8 +332,8 @@ TEST(TracedGlobalToJSApiObjectWithIdentityHashSurvivesScavenge) { TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesScavengeWhenInHandle) { CcTest::InitializeVM(); WeakHandleTest( - CcTest::isolate(), &ConstructJSApiObject, - [](FlagAndGlobal* fp) { + CcTest::isolate(), &ConstructJSApiObject, + [](FlagAndPersistent* fp) { v8::Local handle = v8::Local::New(CcTest::isolate(), fp->handle); USE(handle); @@ -409,16 +344,15 @@ TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesScavengeWhenInHandle) { TEST(WeakHandleToUnmodifiedJSApiObjectDiesOnMarkCompact) { CcTest::InitializeVM(); WeakHandleTest( - CcTest::isolate(), &ConstructJSApiObject, - [](FlagAndGlobal* fp) {}, []() { InvokeMarkSweep(); }, - SurvivalMode::kDies); + CcTest::isolate(), &ConstructJSApiObject, [](FlagAndPersistent* fp) {}, + []() { InvokeMarkSweep(); }, SurvivalMode::kDies); } TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesMarkCompactWhenInHandle) { CcTest::InitializeVM(); WeakHandleTest( - CcTest::isolate(), &ConstructJSApiObject, - [](FlagAndGlobal* fp) { + CcTest::isolate(), &ConstructJSApiObject, + [](FlagAndPersistent* fp) { v8::Local handle = v8::Local::New(CcTest::isolate(), fp->handle); USE(handle); @@ -426,57 +360,58 @@ TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesMarkCompactWhenInHandle) { []() { InvokeMarkSweep(); }, SurvivalMode::kSurvives); } -TEST(TracedGlobalToJSApiObjectWithModifiedMapSurvivesScavenge) { +TEST(WeakHandleToActiveUnmodifiedJSApiObjectSurvivesScavenge) { CcTest::InitializeVM(); - v8::Isolate* isolate = CcTest::isolate(); - LocalContext context; - - TracedGlobal handle; - { - v8::HandleScope scope(isolate); - // Create an API object which does not have the same map as constructor. - auto function_template = FunctionTemplate::New(isolate); - auto instance_t = function_template->InstanceTemplate(); - instance_t->Set( - v8::String::NewFromUtf8(isolate, "a", NewStringType::kNormal) - .ToLocalChecked(), - v8::Number::New(isolate, 10)); - auto function = - function_template->GetFunction(context.local()).ToLocalChecked(); - auto i = function->NewInstance(context.local()).ToLocalChecked(); - handle.Reset(isolate, i); - } - InvokeScavenge(); - CHECK(!handle.IsEmpty()); + WeakHandleTest( + CcTest::isolate(), &ConstructJSApiObject, + [](FlagAndPersistent* fp) { +#if __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +#endif + fp->handle.MarkActive(); +#if __clang__ +#pragma clang diagnostic pop +#endif + }, + []() { InvokeScavenge(); }, SurvivalMode::kSurvives); } -TEST(TracedGlobalTOJsApiObjectWithElementsSurvivesScavenge) { +TEST(WeakHandleToActiveUnmodifiedJSApiObjectDiesOnMarkCompact) { CcTest::InitializeVM(); - v8::Isolate* isolate = CcTest::isolate(); - LocalContext context; - - TracedGlobal handle; - { - v8::HandleScope scope(isolate); + WeakHandleTest( + CcTest::isolate(), &ConstructJSApiObject, + [](FlagAndPersistent* fp) { +#if __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +#endif + fp->handle.MarkActive(); +#if __clang__ +#pragma clang diagnostic pop +#endif + }, + []() { InvokeMarkSweep(); }, SurvivalMode::kDies); +} - // Create an API object which has elements. - auto function_template = FunctionTemplate::New(isolate); - auto instance_t = function_template->InstanceTemplate(); - instance_t->Set( - v8::String::NewFromUtf8(isolate, "1", NewStringType::kNormal) - .ToLocalChecked(), - v8::Number::New(isolate, 10)); - instance_t->Set( - v8::String::NewFromUtf8(isolate, "2", NewStringType::kNormal) - .ToLocalChecked(), - v8::Number::New(isolate, 10)); - auto function = - function_template->GetFunction(context.local()).ToLocalChecked(); - auto i = function->NewInstance(context.local()).ToLocalChecked(); - handle.Reset(isolate, i); - } - InvokeScavenge(); - CHECK(!handle.IsEmpty()); +TEST(WeakHandleToActiveUnmodifiedJSApiObjectSurvivesMarkCompactWhenInHandle) { + CcTest::InitializeVM(); + WeakHandleTest( + CcTest::isolate(), &ConstructJSApiObject, + [](FlagAndPersistent* fp) { +#if __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +#endif + fp->handle.MarkActive(); +#if __clang__ +#pragma clang diagnostic pop +#endif + v8::Local handle = + v8::Local::New(CcTest::isolate(), fp->handle); + USE(handle); + }, + []() { InvokeMarkSweep(); }, SurvivalMode::kSurvives); } TEST(FinalizerOnUnmodifiedJSApiObjectDoesNotCrash) { @@ -487,7 +422,8 @@ TEST(FinalizerOnUnmodifiedJSApiObjectDoesNotCrash) { v8::Local context = v8::Context::New(isolate); v8::Context::Scope context_scope(context); - FlagAndGlobal fp; + FlagAndPersistent fp; + // Could use a regular object and MarkIndependent too. ConstructJSApiObject(isolate, context, &fp); fp.handle.SetWeak(&fp, &ResetHandleAndSetFlag, v8::WeakCallbackType::kFinalizer); @@ -559,22 +495,22 @@ TEST(FinalizerDiesAndKeepsPhantomAliveOnMarkCompact) { namespace { -void ForceScavenge2(const v8::WeakCallbackInfo& data) { +void ForceScavenge2(const v8::WeakCallbackInfo& data) { data.GetParameter()->flag = true; InvokeScavenge(); } -void ForceScavenge1(const v8::WeakCallbackInfo& data) { +void ForceScavenge1(const v8::WeakCallbackInfo& data) { data.GetParameter()->handle.Reset(); data.SetSecondPassCallback(ForceScavenge2); } -void ForceMarkSweep2(const v8::WeakCallbackInfo& data) { +void ForceMarkSweep2(const v8::WeakCallbackInfo& data) { data.GetParameter()->flag = true; InvokeMarkSweep(); } -void ForceMarkSweep1(const v8::WeakCallbackInfo& data) { +void ForceMarkSweep1(const v8::WeakCallbackInfo& data) { data.GetParameter()->handle.Reset(); data.SetSecondPassCallback(ForceMarkSweep2); } @@ -589,7 +525,7 @@ TEST(GCFromWeakCallbacks) { v8::Context::Scope context_scope(context); static const int kNumberOfGCTypes = 2; - using Callback = v8::WeakCallbackInfo::Callback; + typedef v8::WeakCallbackInfo::Callback Callback; Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1, &ForceMarkSweep1}; @@ -598,7 +534,7 @@ TEST(GCFromWeakCallbacks) { for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) { for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) { - FlagAndGlobal fp; + FlagAndPersistent fp; ConstructJSApiObject(isolate, context, &fp); CHECK(heap::InYoungGeneration(isolate, fp.handle)); fp.flag = false; @@ -613,11 +549,11 @@ TEST(GCFromWeakCallbacks) { namespace { -void SecondPassCallback(const v8::WeakCallbackInfo& data) { +void SecondPassCallback(const v8::WeakCallbackInfo& data) { data.GetParameter()->flag = true; } -void FirstPassCallback(const v8::WeakCallbackInfo& data) { +void FirstPassCallback(const v8::WeakCallbackInfo& data) { data.GetParameter()->handle.Reset(); data.SetSecondPassCallback(SecondPassCallback); } @@ -630,7 +566,7 @@ TEST(SecondPassPhantomCallbacks) { v8::HandleScope scope(isolate); v8::Local context = v8::Context::New(isolate); v8::Context::Scope context_scope(context); - FlagAndGlobal fp; + FlagAndPersistent fp; ConstructJSApiObject(isolate, context, &fp); fp.flag = false; fp.handle.SetWeak(&fp, FirstPassCallback, v8::WeakCallbackType::kParameter);