diff --git a/configure b/configure index 9d9bc9bc17d411..69d805c040b534 100755 --- a/configure +++ b/configure @@ -954,6 +954,7 @@ def configure_v8(o): o['variables']['v8_no_strict_aliasing'] = 1 # Work around compiler bugs. o['variables']['v8_optimized_debug'] = 0 # Compile with -O0 in debug builds. o['variables']['v8_random_seed'] = 0 # Use a random seed for hash tables. + o['variables']['v8_promise_internal_field_count'] = 1 # Add internal field to promises for async hooks. o['variables']['v8_use_snapshot'] = 'false' if options.without_snapshot else 'true' o['variables']['node_use_v8_platform'] = b(not options.without_v8_platform) o['variables']['node_use_bundled_v8'] = b(not options.without_bundled_v8) diff --git a/deps/v8/BUILD.gn b/deps/v8/BUILD.gn index 8895103222b4ee..2a77a0ded02199 100644 --- a/deps/v8/BUILD.gn +++ b/deps/v8/BUILD.gn @@ -38,6 +38,9 @@ declare_args() { # Sets -dENABLE_DISASSEMBLER. v8_enable_disassembler = "" + # Sets the number of internal fields on promise objects. + v8_promise_internal_field_count = 0 + # Sets -dENABLE_GDB_JIT_INTERFACE. v8_enable_gdbjit = "" @@ -197,6 +200,10 @@ config("features") { if (v8_enable_disassembler) { defines += [ "ENABLE_DISASSEMBLER" ] } + if (v8_promise_internal_field_count != 0) { + defines += + [ "V8_PROMISE_INTERNAL_FIELD_COUNT=${v8_promise_internal_field_count}" ] + } if (v8_enable_gdbjit) { defines += [ "ENABLE_GDB_JIT_INTERFACE" ] } diff --git a/deps/v8/gypfiles/features.gypi b/deps/v8/gypfiles/features.gypi index 0c4873c3a5f107..bd5cd7cd108f1c 100644 --- a/deps/v8/gypfiles/features.gypi +++ b/deps/v8/gypfiles/features.gypi @@ -31,6 +31,8 @@ 'variables': { 'v8_enable_disassembler%': 0, + 'v8_promise_internal_field_count%': 0, + 'v8_enable_gdbjit%': 0, 'v8_enable_verify_csa%': 0, @@ -77,6 +79,9 @@ ['v8_enable_disassembler==1', { 'defines': ['ENABLE_DISASSEMBLER',], }], + ['v8_promise_internal_field_count!=0', { + 'defines': ['V8_PROMISE_INTERNAL_FIELD_COUNT','v8_promise_internal_field_count'], + }], ['v8_enable_gdbjit==1', { 'defines': ['ENABLE_GDB_JIT_INTERFACE',], }], diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index f0866a2d9b3264..70e1a84d09e949 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 5 #define V8_MINOR_VERSION 8 #define V8_BUILD_NUMBER 283 -#define V8_PATCH_LEVEL 40 +#define V8_PATCH_LEVEL 41 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index e38f657b48fae8..9ae8e1b94874c2 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -3741,6 +3741,10 @@ class V8_EXPORT Function : public Object { static void CheckCast(Value* obj); }; +#ifndef V8_PROMISE_INTERNAL_FIELD_COUNT +// The number of required internal fields can be defined by embedder. +#define V8_PROMISE_INTERNAL_FIELD_COUNT 0 +#endif /** * An instance of the built-in Promise constructor (ES6 draft). @@ -3822,6 +3826,8 @@ class V8_EXPORT Promise : public Object { V8_INLINE static Promise* Cast(Value* obj); + static const int kEmbedderFieldCount = V8_PROMISE_INTERNAL_FIELD_COUNT; + private: Promise(); static void CheckCast(Value* obj); diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 8f9f92a08c66d4..60e989ae17a98d 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -1945,9 +1945,9 @@ void Genesis::InitializeGlobal(Handle global_object, Handle prototype = factory->NewJSObject(isolate->object_function(), TENURED); - Handle promise_fun = - InstallFunction(global, "Promise", JS_PROMISE_TYPE, JSPromise::kSize, - prototype, Builtins::kPromiseConstructor); + Handle promise_fun = InstallFunction( + global, "Promise", JS_PROMISE_TYPE, JSPromise::kSizeWithEmbedderFields, + prototype, Builtins::kPromiseConstructor); InstallWithIntrinsicDefaultProto(isolate, promise_fun, Context::PROMISE_FUNCTION_INDEX); diff --git a/deps/v8/src/builtins/builtins-promise.cc b/deps/v8/src/builtins/builtins-promise.cc index 0d0238d267e48a..6d9fed83a96677 100644 --- a/deps/v8/src/builtins/builtins-promise.cc +++ b/deps/v8/src/builtins/builtins-promise.cc @@ -31,6 +31,10 @@ void PromiseBuiltinsAssembler::PromiseInit(Node* promise) { StoreObjectField(promise, JSPromise::kStatusOffset, SmiConstant(v8::Promise::kPending)); StoreObjectField(promise, JSPromise::kFlagsOffset, SmiConstant(0)); + for (int i = 0; i < v8::Promise::kEmbedderFieldCount; i++) { + int offset = JSPromise::kSize + i * kPointerSize; + StoreObjectFieldNoWriteBarrier(promise, offset, SmiConstant(Smi::kZero)); + } } Node* PromiseBuiltinsAssembler::AllocateAndInitJSPromise(Node* context) { @@ -62,6 +66,10 @@ Node* PromiseBuiltinsAssembler::AllocateAndSetJSPromise(Node* context, StoreObjectFieldNoWriteBarrier(instance, JSPromise::kResultOffset, result); StoreObjectFieldNoWriteBarrier(instance, JSPromise::kFlagsOffset, SmiConstant(0)); + for (int i = 0; i < v8::Promise::kEmbedderFieldCount; i++) { + int offset = JSPromise::kSize + i * kPointerSize; + StoreObjectFieldNoWriteBarrier(instance, offset, SmiConstant(Smi::kZero)); + } Label out(this); GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &out); diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index ca4c3513170e08..3b4ff9bb75157e 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -8443,6 +8443,8 @@ class JSPromise : public JSObject { kFulfillReactionsOffset + kPointerSize; static const int kFlagsOffset = kRejectReactionsOffset + kPointerSize; static const int kSize = kFlagsOffset + kPointerSize; + static const int kSizeWithEmbedderFields = + kSize + v8::Promise::kEmbedderFieldCount * kPointerSize; // Flags layout. static const int kHasHandlerBit = 0; diff --git a/src/async-wrap.cc b/src/async-wrap.cc index d3776c73334b49..4a210741bedc30 100644 --- a/src/async-wrap.cc +++ b/src/async-wrap.cc @@ -281,32 +281,13 @@ static void PromiseHook(PromiseHookType type, Local promise, Local context = promise->CreationContext(); Environment* env = Environment::GetCurrent(context); if (type == PromiseHookType::kInit) { - // Unfortunately, promises don't have internal fields. Need a surrogate that - // async wrap can wrap. - Local obj = - env->async_hooks_promise_object()->NewInstance(context).ToLocalChecked(); - PromiseWrap* wrap = new PromiseWrap(env, obj); - v8::PropertyAttribute hidden = - static_cast(v8::ReadOnly - | v8::DontDelete - | v8::DontEnum); - promise->DefineOwnProperty(context, - env->promise_wrap(), - v8::External::New(env->isolate(), wrap), - hidden).FromJust(); - // The async tag will be destroyed at the same time as the promise as the - // only reference to it is held by the promise. This allows the promise - // wrap instance to be notified when the promise is destroyed. - promise->DefineOwnProperty(context, - env->promise_async_tag(), - obj, hidden).FromJust(); + PromiseWrap* wrap = new PromiseWrap(env, promise); + promise->SetAlignedPointerInInternalField(0, wrap); } else if (type == PromiseHookType::kResolve) { // TODO(matthewloring): need to expose this through the async hooks api. } - Local external_wrap = - promise->Get(context, env->promise_wrap()).ToLocalChecked(); PromiseWrap* wrap = - static_cast(external_wrap.As()->Value()); + static_cast(promise->GetAlignedPointerFromInternalField(0)); CHECK_NE(wrap, nullptr); if (type == PromiseHookType::kBefore) { PreCallbackExecution(wrap, false); @@ -402,11 +383,6 @@ void AsyncWrap::Initialize(Local target, env->SetMethod(target, "clearIdStack", ClearIdStack); env->SetMethod(target, "addIdToDestroyList", QueueDestroyId); - Local promise_object_template = - v8::ObjectTemplate::New(env->isolate()); - promise_object_template->SetInternalFieldCount(1); - env->set_async_hooks_promise_object(promise_object_template); - v8::PropertyAttribute ReadOnlyDontDelete = static_cast(v8::ReadOnly | v8::DontDelete); diff --git a/src/env.h b/src/env.h index 11c957d2be135b..c8c8232cc07fd4 100644 --- a/src/env.h +++ b/src/env.h @@ -195,8 +195,6 @@ namespace node { V(preference_string, "preference") \ V(priority_string, "priority") \ V(produce_cached_data_string, "produceCachedData") \ - V(promise_wrap, "_promise_async_wrap") \ - V(promise_async_tag, "_promise_async_wrap_tag") \ V(raw_string, "raw") \ V(read_host_object_string, "_readHostObject") \ V(readable_string, "readable") \ @@ -258,7 +256,6 @@ namespace node { V(async_hooks_init_function, v8::Function) \ V(async_hooks_before_function, v8::Function) \ V(async_hooks_after_function, v8::Function) \ - V(async_hooks_promise_object, v8::ObjectTemplate) \ V(binding_cache_object, v8::Object) \ V(buffer_constructor_function, v8::Function) \ V(buffer_prototype_object, v8::Object) \