From bf82dcd5bad2e2014f02df34795dc34633db1f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Tue, 12 Oct 2021 20:22:20 +0200 Subject: [PATCH] deps: patch V8 to 9.5.172.21 Refs: https://github.com/v8/v8/compare/9.5.172.19...9.5.172.21 PR-URL: https://github.com/nodejs/node/pull/40432 Reviewed-By: Colin Ihrig Reviewed-By: Jiawen Geng Reviewed-By: Richard Lau Reviewed-By: Beth Griggs --- deps/v8/include/v8-version.h | 2 +- deps/v8/src/api/api.h | 4 +- deps/v8/src/debug/debug-interface.cc | 80 ++++----- deps/v8/src/debug/debug-interface.h | 16 +- deps/v8/src/inspector/inspected-context.cc | 15 +- deps/v8/src/inspector/inspected-context.h | 2 +- deps/v8/src/inspector/v8-inspector-impl.cc | 18 +- deps/v8/src/inspector/v8-inspector-impl.h | 13 +- deps/v8/src/interpreter/bytecode-generator.cc | 168 +++++++++--------- deps/v8/test/cctest/test-debug.cc | 9 +- deps/v8/test/cctest/test-inspector.cc | 36 ++++ .../mjsunit/regress/regress-crbug-1251366.js | 13 ++ 12 files changed, 207 insertions(+), 169 deletions(-) create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-1251366.js diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 1d9bd6ff149547..e58f97f9ae8502 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 9 #define V8_MINOR_VERSION 5 #define V8_BUILD_NUMBER 172 -#define V8_PATCH_LEVEL 19 +#define V8_PATCH_LEVEL 21 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/api/api.h b/deps/v8/src/api/api.h index e24c9513062934..c255dad1e64131 100644 --- a/deps/v8/src/api/api.h +++ b/deps/v8/src/api/api.h @@ -42,7 +42,7 @@ namespace debug { class AccessorPair; class GeneratorObject; class Script; -class WeakMap; +class EphemeronTable; } // namespace debug // Constants used in the implementation of the API. The most natural thing @@ -135,7 +135,7 @@ class RegisteredExtension { V(Proxy, JSProxy) \ V(debug::GeneratorObject, JSGeneratorObject) \ V(debug::Script, Script) \ - V(debug::WeakMap, JSWeakMap) \ + V(debug::EphemeronTable, EphemeronHashTable) \ V(debug::AccessorPair, AccessorPair) \ V(Promise, JSPromise) \ V(Primitive, Object) \ diff --git a/deps/v8/src/debug/debug-interface.cc b/deps/v8/src/debug/debug-interface.cc index 50c63e8f8eceb9..ed995a67b9345a 100644 --- a/deps/v8/src/debug/debug-interface.cc +++ b/deps/v8/src/debug/debug-interface.cc @@ -1177,61 +1177,43 @@ TypeProfile::ScriptData TypeProfile::GetScriptData(size_t i) const { return ScriptData(i, type_profile_); } -v8::MaybeLocal WeakMap::Get(v8::Local context, - v8::Local key) { - PREPARE_FOR_EXECUTION(context, WeakMap, Get, Value); - auto self = Utils::OpenHandle(this); - Local result; - i::Handle argv[] = {Utils::OpenHandle(*key)}; - has_pending_exception = - !ToLocal(i::Execution::CallBuiltin(isolate, isolate->weakmap_get(), - self, arraysize(argv), argv), - &result); - RETURN_ON_FAILED_EXECUTION(Value); - RETURN_ESCAPED(result); +MaybeLocal EphemeronTable::Get(v8::Isolate* isolate, + v8::Local key) { + i::Isolate* internal_isolate = reinterpret_cast(isolate); + auto self = i::Handle::cast(Utils::OpenHandle(this)); + i::Handle internal_key = Utils::OpenHandle(*key); + DCHECK(internal_key->IsJSReceiver()); + + i::Handle value(self->Lookup(internal_key), internal_isolate); + + if (value->IsTheHole()) return {}; + return Utils::ToLocal(value); } -v8::Maybe WeakMap::Delete(v8::Local context, - v8::Local key) { - PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, WeakMap, Delete, Nothing(), - InternalEscapableScope, false); - auto self = Utils::OpenHandle(this); - Local result; - i::Handle argv[] = {Utils::OpenHandle(*key)}; - has_pending_exception = !ToLocal( - i::Execution::CallBuiltin(isolate, isolate->weakmap_delete(), self, - arraysize(argv), argv), - &result); - RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool); - return Just(result->IsTrue()); -} - -v8::MaybeLocal WeakMap::Set(v8::Local context, - v8::Local key, - v8::Local value) { - PREPARE_FOR_EXECUTION(context, WeakMap, Set, WeakMap); - auto self = Utils::OpenHandle(this); - i::Handle result; - i::Handle argv[] = {Utils::OpenHandle(*key), - Utils::OpenHandle(*value)}; - has_pending_exception = - !i::Execution::CallBuiltin(isolate, isolate->weakmap_set(), self, - arraysize(argv), argv) - .ToHandle(&result); - RETURN_ON_FAILED_EXECUTION(WeakMap); - RETURN_ESCAPED(Local::Cast(Utils::ToLocal(result))); -} - -Local WeakMap::New(v8::Isolate* isolate) { +Local EphemeronTable::Set(v8::Isolate* isolate, + v8::Local key, + v8::Local value) { + auto self = i::Handle::cast(Utils::OpenHandle(this)); + i::Handle internal_key = Utils::OpenHandle(*key); + i::Handle internal_value = Utils::OpenHandle(*value); + DCHECK(internal_key->IsJSReceiver()); + + i::Handle result( + i::EphemeronHashTable::Put(self, internal_key, internal_value)); + + return ToApiHandle(result); +} + +Local EphemeronTable::New(v8::Isolate* isolate) { i::Isolate* i_isolate = reinterpret_cast(isolate); - LOG_API(i_isolate, WeakMap, New); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); - i::Handle obj = i_isolate->factory()->NewJSWeakMap(); - return ToApiHandle(obj); + i::Handle table = + i::EphemeronHashTable::New(i_isolate, 0); + return ToApiHandle(table); } -WeakMap* WeakMap::Cast(v8::Value* value) { - return static_cast(value); +EphemeronTable* EphemeronTable::Cast(v8::Value* value) { + return static_cast(value); } Local AccessorPair::getter() { diff --git a/deps/v8/src/debug/debug-interface.h b/deps/v8/src/debug/debug-interface.h index b186ab56895944..8575f168fe864b 100644 --- a/deps/v8/src/debug/debug-interface.h +++ b/deps/v8/src/debug/debug-interface.h @@ -570,19 +570,17 @@ class V8_NODISCARD DisableBreakScope { std::unique_ptr scope_; }; -class WeakMap : public v8::Object { +class EphemeronTable : public v8::Object { public: - WeakMap() = delete; + EphemeronTable() = delete; V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT v8::MaybeLocal Get( - v8::Local context, v8::Local key); - V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT v8::Maybe Delete( - v8::Local context, v8::Local key); - V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT v8::MaybeLocal Set( - v8::Local context, v8::Local key, + v8::Isolate* isolate, v8::Local key); + V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT v8::Local Set( + v8::Isolate* isolate, v8::Local key, v8::Local value); - V8_EXPORT_PRIVATE static Local New(v8::Isolate* isolate); - V8_INLINE static WeakMap* Cast(Value* obj); + V8_EXPORT_PRIVATE static Local New(v8::Isolate* isolate); + V8_INLINE static EphemeronTable* Cast(Value* obj); }; /** diff --git a/deps/v8/src/inspector/inspected-context.cc b/deps/v8/src/inspector/inspected-context.cc index 6786f06b2fd9c8..59d186e43fb632 100644 --- a/deps/v8/src/inspector/inspected-context.cc +++ b/deps/v8/src/inspector/inspected-context.cc @@ -126,12 +126,15 @@ void InspectedContext::discardInjectedScript(int sessionId) { bool InspectedContext::addInternalObject(v8::Local object, V8InternalValueType type) { if (m_internalObjects.IsEmpty()) { - m_internalObjects.Reset(isolate(), v8::debug::WeakMap::New(isolate())); + m_internalObjects.Reset(isolate(), + v8::debug::EphemeronTable::New(isolate())); } - return !m_internalObjects.Get(isolate()) - ->Set(m_context.Get(isolate()), object, - v8::Integer::New(isolate(), static_cast(type))) - .IsEmpty(); + v8::Local new_map = + m_internalObjects.Get(isolate())->Set( + isolate(), object, + v8::Integer::New(isolate(), static_cast(type))); + m_internalObjects.Reset(isolate(), new_map); + return true; } V8InternalValueType InspectedContext::getInternalType( @@ -139,7 +142,7 @@ V8InternalValueType InspectedContext::getInternalType( if (m_internalObjects.IsEmpty()) return V8InternalValueType::kNone; v8::Local typeValue; if (!m_internalObjects.Get(isolate()) - ->Get(m_context.Get(isolate()), object) + ->Get(isolate(), object) .ToLocal(&typeValue) || !typeValue->IsUint32()) { return V8InternalValueType::kNone; diff --git a/deps/v8/src/inspector/inspected-context.h b/deps/v8/src/inspector/inspected-context.h index f8811d0469000a..50e5a87bb3ae8a 100644 --- a/deps/v8/src/inspector/inspected-context.h +++ b/deps/v8/src/inspector/inspected-context.h @@ -77,7 +77,7 @@ class InspectedContext { std::unordered_set m_reportedSessionIds; std::unordered_map> m_injectedScripts; WeakCallbackData* m_weakCallbackData; - v8::Global m_internalObjects; + v8::Global m_internalObjects; }; } // namespace v8_inspector diff --git a/deps/v8/src/inspector/v8-inspector-impl.cc b/deps/v8/src/inspector/v8-inspector-impl.cc index 2da495c470c232..3f48449a99fe36 100644 --- a/deps/v8/src/inspector/v8-inspector-impl.cc +++ b/deps/v8/src/inspector/v8-inspector-impl.cc @@ -486,19 +486,17 @@ bool V8InspectorImpl::associateExceptionData(v8::Local, v8::Context::Scope contextScope(context); v8::HandleScope handles(m_isolate); if (m_exceptionMetaData.IsEmpty()) - m_exceptionMetaData.Reset(m_isolate, v8::debug::WeakMap::New(m_isolate)); + m_exceptionMetaData.Reset(m_isolate, + v8::debug::EphemeronTable::New(m_isolate)); - v8::Local map = m_exceptionMetaData.Get(m_isolate); - v8::MaybeLocal entry = map->Get(context, exception); + v8::Local map = m_exceptionMetaData.Get(m_isolate); + v8::MaybeLocal entry = map->Get(m_isolate, exception); v8::Local object; if (entry.IsEmpty() || !entry.ToLocalChecked()->IsObject()) { object = v8::Object::New(m_isolate, v8::Null(m_isolate), nullptr, nullptr, 0); - v8::MaybeLocal new_map = - map->Set(context, exception, object); - if (!new_map.IsEmpty()) { - m_exceptionMetaData.Reset(m_isolate, new_map.ToLocalChecked()); - } + m_exceptionMetaData.Reset(m_isolate, + map->Set(m_isolate, exception, object)); } else { object = entry.ToLocalChecked().As(); } @@ -518,8 +516,8 @@ v8::MaybeLocal V8InspectorImpl::getAssociatedExceptionData( !exceptionMetaDataContext().ToLocal(&context)) { return v8::MaybeLocal(); } - v8::Local map = m_exceptionMetaData.Get(m_isolate); - auto entry = map->Get(context, exception); + v8::Local map = m_exceptionMetaData.Get(m_isolate); + auto entry = map->Get(m_isolate, exception); v8::Local object; if (!entry.ToLocal(&object) || !object->IsObject()) return v8::MaybeLocal(); diff --git a/deps/v8/src/inspector/v8-inspector-impl.h b/deps/v8/src/inspector/v8-inspector-impl.h index 5c797bbfc767c1..d628c57a206128 100644 --- a/deps/v8/src/inspector/v8-inspector-impl.h +++ b/deps/v8/src/inspector/v8-inspector-impl.h @@ -56,7 +56,7 @@ class V8StackTraceImpl; class V8InspectorImpl : public V8Inspector { public: - V8InspectorImpl(v8::Isolate*, V8InspectorClient*); + V8_EXPORT_PRIVATE V8InspectorImpl(v8::Isolate*, V8InspectorClient*); ~V8InspectorImpl() override; V8InspectorImpl(const V8InspectorImpl&) = delete; V8InspectorImpl& operator=(const V8InspectorImpl&) = delete; @@ -110,10 +110,9 @@ class V8InspectorImpl : public V8Inspector { void externalAsyncTaskStarted(const V8StackTraceId& parent) override; void externalAsyncTaskFinished(const V8StackTraceId& parent) override; - bool associateExceptionData(v8::Local, - v8::Local exception, - v8::Local key, - v8::Local value) override; + V8_EXPORT_PRIVATE bool associateExceptionData( + v8::Local, v8::Local exception, + v8::Local key, v8::Local value) override; unsigned nextExceptionId() { return ++m_lastExceptionId; } void enableStackCapturingIfNeeded(); @@ -134,7 +133,7 @@ class V8InspectorImpl : public V8Inspector { int contextGroupId, const std::function& callback); int64_t generateUniqueId(); - v8::MaybeLocal getAssociatedExceptionData( + V8_EXPORT_PRIVATE v8::MaybeLocal getAssociatedExceptionData( v8::Local exception); class EvaluateScope { @@ -160,7 +159,7 @@ class V8InspectorImpl : public V8Inspector { std::unique_ptr m_debugger; v8::Global m_regexContext; v8::Global m_exceptionMetaDataContext; - v8::Global m_exceptionMetaData; + v8::Global m_exceptionMetaData; int m_capturingStackTracesCount; unsigned m_lastExceptionId; int m_lastContextId; diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc index 9536df172dd1af..001ebfd0cf5b86 100644 --- a/deps/v8/src/interpreter/bytecode-generator.cc +++ b/deps/v8/src/interpreter/bytecode-generator.cc @@ -3005,96 +3005,104 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { BuildCreateObjectLiteral(literal, flags, entry); } - // Store computed values into the literal. - AccessorTable accessor_table(zone()); - for (; property_index < expr->properties()->length(); property_index++) { - ObjectLiteral::Property* property = expr->properties()->at(property_index); - if (property->is_computed_name()) break; - if (!clone_object_spread && property->IsCompileTimeValue()) continue; - - RegisterAllocationScope inner_register_scope(this); - Literal* key = property->key()->AsLiteral(); - switch (property->kind()) { - case ObjectLiteral::Property::SPREAD: - UNREACHABLE(); - case ObjectLiteral::Property::CONSTANT: - case ObjectLiteral::Property::MATERIALIZED_LITERAL: - DCHECK(clone_object_spread || !property->value()->IsCompileTimeValue()); - V8_FALLTHROUGH; - case ObjectLiteral::Property::COMPUTED: { - // It is safe to use [[Put]] here because the boilerplate already - // contains computed properties with an uninitialized value. - if (key->IsStringLiteral()) { - DCHECK(key->IsPropertyName()); - object_literal_context_scope.SetEnteredIf( - property->value()->IsConciseMethodDefinition()); - if (property->emit_store()) { - builder()->SetExpressionPosition(property->value()); - VisitForAccumulatorValue(property->value()); - FeedbackSlot slot = feedback_spec()->AddStoreOwnICSlot(); - builder()->StoreNamedOwnProperty(literal, key->AsRawPropertyName(), - feedback_index(slot)); + // If we used CloneObject for the first element is spread case, we already + // copied accessors. Therefore skip the static initialization and treat all + // properties after the spread as dynamic. + // TOOD(v8:9888): Use new Define ICs instead of Set ICs in the clone object + // spread case. + if (!clone_object_spread) { + // Store computed values into the literal. + AccessorTable accessor_table(zone()); + for (; property_index < expr->properties()->length(); property_index++) { + ObjectLiteral::Property* property = + expr->properties()->at(property_index); + if (property->is_computed_name()) break; + if (property->IsCompileTimeValue()) continue; + + RegisterAllocationScope inner_register_scope(this); + Literal* key = property->key()->AsLiteral(); + switch (property->kind()) { + case ObjectLiteral::Property::SPREAD: + case ObjectLiteral::Property::CONSTANT: + UNREACHABLE(); + case ObjectLiteral::Property::MATERIALIZED_LITERAL: + DCHECK(!property->value()->IsCompileTimeValue()); + V8_FALLTHROUGH; + case ObjectLiteral::Property::COMPUTED: { + // It is safe to use [[Put]] here because the boilerplate already + // contains computed properties with an uninitialized value. + if (key->IsStringLiteral()) { + DCHECK(key->IsPropertyName()); + object_literal_context_scope.SetEnteredIf( + property->value()->IsConciseMethodDefinition()); + if (property->emit_store()) { + builder()->SetExpressionPosition(property->value()); + VisitForAccumulatorValue(property->value()); + FeedbackSlot slot = feedback_spec()->AddStoreOwnICSlot(); + builder()->StoreNamedOwnProperty( + literal, key->AsRawPropertyName(), feedback_index(slot)); + } else { + builder()->SetExpressionPosition(property->value()); + VisitForEffect(property->value()); + } } else { + RegisterList args = register_allocator()->NewRegisterList(3); + + builder()->MoveRegister(literal, args[0]); + builder()->SetExpressionPosition(property->key()); + VisitForRegisterValue(property->key(), args[1]); + + object_literal_context_scope.SetEnteredIf( + property->value()->IsConciseMethodDefinition()); builder()->SetExpressionPosition(property->value()); - VisitForEffect(property->value()); + VisitForRegisterValue(property->value(), args[2]); + if (property->emit_store()) { + builder()->CallRuntime(Runtime::kSetKeyedProperty, args); + } } - } else { - RegisterList args = register_allocator()->NewRegisterList(3); - + break; + } + case ObjectLiteral::Property::PROTOTYPE: { + // __proto__:null is handled by CreateObjectLiteral. + if (property->IsNullPrototype()) break; + DCHECK(property->emit_store()); + DCHECK(!property->NeedsSetFunctionName()); + RegisterList args = register_allocator()->NewRegisterList(2); builder()->MoveRegister(literal, args[0]); - builder()->SetExpressionPosition(property->key()); - VisitForRegisterValue(property->key(), args[1]); - - object_literal_context_scope.SetEnteredIf( - property->value()->IsConciseMethodDefinition()); + object_literal_context_scope.SetEnteredIf(false); builder()->SetExpressionPosition(property->value()); - VisitForRegisterValue(property->value(), args[2]); + VisitForRegisterValue(property->value(), args[1]); + builder()->CallRuntime(Runtime::kInternalSetPrototype, args); + break; + } + case ObjectLiteral::Property::GETTER: if (property->emit_store()) { - builder()->CallRuntime(Runtime::kSetKeyedProperty, args); + accessor_table.LookupOrInsert(key)->getter = property; } - } - break; - } - case ObjectLiteral::Property::PROTOTYPE: { - // __proto__:null is handled by CreateObjectLiteral. - if (property->IsNullPrototype()) break; - DCHECK(property->emit_store()); - DCHECK(!property->NeedsSetFunctionName()); - RegisterList args = register_allocator()->NewRegisterList(2); - builder()->MoveRegister(literal, args[0]); - object_literal_context_scope.SetEnteredIf(false); - builder()->SetExpressionPosition(property->value()); - VisitForRegisterValue(property->value(), args[1]); - builder()->CallRuntime(Runtime::kInternalSetPrototype, args); - break; + break; + case ObjectLiteral::Property::SETTER: + if (property->emit_store()) { + accessor_table.LookupOrInsert(key)->setter = property; + } + break; } - case ObjectLiteral::Property::GETTER: - if (property->emit_store()) { - accessor_table.LookupOrInsert(key)->getter = property; - } - break; - case ObjectLiteral::Property::SETTER: - if (property->emit_store()) { - accessor_table.LookupOrInsert(key)->setter = property; - } - break; } - } - // Define accessors, using only a single call to the runtime for each pair of - // corresponding getters and setters. - object_literal_context_scope.SetEnteredIf(true); - for (auto accessors : accessor_table.ordered_accessors()) { - RegisterAllocationScope inner_register_scope(this); - RegisterList args = register_allocator()->NewRegisterList(5); - builder()->MoveRegister(literal, args[0]); - VisitForRegisterValue(accessors.first, args[1]); - VisitLiteralAccessor(accessors.second->getter, args[2]); - VisitLiteralAccessor(accessors.second->setter, args[3]); - builder() - ->LoadLiteral(Smi::FromInt(NONE)) - .StoreAccumulatorInRegister(args[4]) - .CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, args); + // Define accessors, using only a single call to the runtime for each pair + // of corresponding getters and setters. + object_literal_context_scope.SetEnteredIf(true); + for (auto accessors : accessor_table.ordered_accessors()) { + RegisterAllocationScope inner_register_scope(this); + RegisterList args = register_allocator()->NewRegisterList(5); + builder()->MoveRegister(literal, args[0]); + VisitForRegisterValue(accessors.first, args[1]); + VisitLiteralAccessor(accessors.second->getter, args[2]); + VisitLiteralAccessor(accessors.second->setter, args[3]); + builder() + ->LoadLiteral(Smi::FromInt(NONE)) + .StoreAccumulatorInRegister(args[4]) + .CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, args); + } } // Object literals have two parts. The "static" part on the left contains no diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc index e62fef4b1ce0fb..171c963ea034f0 100644 --- a/deps/v8/test/cctest/test-debug.cc +++ b/deps/v8/test/cctest/test-debug.cc @@ -598,10 +598,11 @@ TEST(BreakPointApiIntrinsics) { CHECK_EQ(2, break_point_hit_count); break_point_hit_count = 0; - v8::Local weakmap = - v8::debug::WeakMap::New(env->GetIsolate()); - CHECK(!weakmap->Set(env.local(), weakmap, v8_num(1)).IsEmpty()); - CHECK(!weakmap->Get(env.local(), weakmap).IsEmpty()); + v8::Local weakmap = + v8::debug::EphemeronTable::New(env->GetIsolate()); + v8::Local key = v8::Object::New(env->GetIsolate()); + CHECK(!weakmap->Set(env->GetIsolate(), key, v8_num(1)).IsEmpty()); + CHECK(!weakmap->Get(env->GetIsolate(), key).IsEmpty()); CHECK_EQ(0, break_point_hit_count); } diff --git a/deps/v8/test/cctest/test-inspector.cc b/deps/v8/test/cctest/test-inspector.cc index c1651eaceb917e..49a08bc42e9ac7 100644 --- a/deps/v8/test/cctest/test-inspector.cc +++ b/deps/v8/test/cctest/test-inspector.cc @@ -9,6 +9,7 @@ #include "include/v8-primitive.h" #include "src/inspector/protocol/Runtime.h" #include "src/inspector/string-util.h" +#include "src/inspector/v8-inspector-impl.h" #include "test/cctest/cctest.h" using v8_inspector::StringBuffer; @@ -169,3 +170,38 @@ TEST(BinaryBase64RoundTrip) { CHECK_EQ(values[i], roundtrip_binary.data()[i]); } } + +TEST(NoInterruptOnGetAssociatedData) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope handle_scope(isolate); + + v8_inspector::V8InspectorClient default_client; + std::unique_ptr inspector( + new v8_inspector::V8InspectorImpl(isolate, &default_client)); + + v8::Local context = env->GetIsolate()->GetCurrentContext(); + v8::Local error = v8::Exception::Error(v8_str("custom error")); + v8::Local key = v8_str("key"); + v8::Local value = v8_str("value"); + inspector->associateExceptionData(context, error, key, value); + + struct InterruptRecorder { + static void handler(v8::Isolate* isolate, void* data) { + reinterpret_cast(data)->WasInvoked = true; + } + + bool WasInvoked = false; + } recorder; + + isolate->RequestInterrupt(&InterruptRecorder::handler, &recorder); + + v8::Local data = + inspector->getAssociatedExceptionData(error).ToLocalChecked(); + CHECK(!recorder.WasInvoked); + + CHECK_EQ(data->Get(context, key).ToLocalChecked(), value); + + CompileRun("0"); + CHECK(recorder.WasInvoked); +} diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-1251366.js b/deps/v8/test/mjsunit/regress/regress-crbug-1251366.js new file mode 100644 index 00000000000000..c2e3a74845c200 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-1251366.js @@ -0,0 +1,13 @@ +// Copyright 2021 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. + +Object.defineProperty(Object.prototype, "x", { + set: function (val) {} +}); + +let o = {...{}, x: 3}; +assertEquals(o.x, 3); + +let o2 = {...{x: 1}, x: 3}; +assertEquals(o2.x, 3);