Provide a way to propagate contextual script information through promise resolution
This state can be set on the NativeContext by the embedder. When a PromiseReaction/PromiseReactionJobTask is constructed, store this contextual state if present, and restore it while the reaction job is running. Change-Id: I141cdbd9e36ea83ce4a6bf08440ae7eaa54523df Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2005849 Reviewed-by: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Cr-Commit-Position: refs/heads/master@{#66617}
This commit is contained in:
parent
1333214417
commit
9423ede124
12
include/v8.h
12
include/v8.h
@ -10371,6 +10371,18 @@ class V8_EXPORT Context {
|
||||
Local<Context> context);
|
||||
void SetAbortScriptExecution(AbortScriptExecutionCallback callback);
|
||||
|
||||
/**
|
||||
* Returns the value that was set or restored by
|
||||
* SetContinuationPreservedEmbedderData(), if any.
|
||||
*/
|
||||
Local<Value> GetContinuationPreservedEmbedderData() const;
|
||||
|
||||
/**
|
||||
* Sets a value that will be stored on continuations and reset while the
|
||||
* continuation runs.
|
||||
*/
|
||||
void SetContinuationPreservedEmbedderData(Local<Value> context);
|
||||
|
||||
/**
|
||||
* Stack-allocated class which sets the execution context for all
|
||||
* operations executed within a local scope.
|
||||
|
@ -6148,6 +6148,24 @@ void Context::SetAbortScriptExecution(
|
||||
}
|
||||
}
|
||||
|
||||
Local<Value> Context::GetContinuationPreservedEmbedderData() const {
|
||||
i::Handle<i::Context> context = Utils::OpenHandle(this);
|
||||
i::Isolate* isolate = context->GetIsolate();
|
||||
i::Handle<i::Object> data(
|
||||
context->native_context().continuation_preserved_embedder_data(),
|
||||
isolate);
|
||||
return ToApiHandle<Object>(data);
|
||||
}
|
||||
|
||||
void Context::SetContinuationPreservedEmbedderData(Local<Value> data) {
|
||||
i::Handle<i::Context> context = Utils::OpenHandle(this);
|
||||
i::Isolate* isolate = context->GetIsolate();
|
||||
if (data.IsEmpty())
|
||||
data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate));
|
||||
context->native_context().set_continuation_preserved_embedder_data(
|
||||
*i::Handle<i::HeapObject>::cast(Utils::OpenHandle(*data)));
|
||||
}
|
||||
|
||||
namespace {
|
||||
i::Address* GetSerializedDataFromFixedArray(i::Isolate* isolate,
|
||||
i::FixedArray list, size_t index) {
|
||||
|
@ -223,6 +223,13 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
|
||||
const TNode<HeapObject> promise_or_capability = CAST(LoadObjectField(
|
||||
microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset));
|
||||
|
||||
TNode<Object> preserved_embedder_data = LoadObjectField(
|
||||
microtask,
|
||||
PromiseReactionJobTask::kContinuationPreservedEmbedderDataOffset);
|
||||
StoreContextElement(native_context,
|
||||
Context::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX,
|
||||
preserved_embedder_data);
|
||||
|
||||
// Run the promise before/debug hook if enabled.
|
||||
RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
|
||||
promise_or_capability);
|
||||
@ -237,6 +244,10 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
|
||||
RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context,
|
||||
promise_or_capability);
|
||||
|
||||
StoreContextElement(native_context,
|
||||
Context::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX,
|
||||
UndefinedConstant());
|
||||
|
||||
RewindEnteredContext(saved_entered_context_count);
|
||||
SetCurrentContext(current_context);
|
||||
Goto(&done);
|
||||
@ -257,6 +268,13 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
|
||||
const TNode<HeapObject> promise_or_capability = CAST(LoadObjectField(
|
||||
microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset));
|
||||
|
||||
TNode<Object> preserved_embedder_data = LoadObjectField(
|
||||
microtask,
|
||||
PromiseReactionJobTask::kContinuationPreservedEmbedderDataOffset);
|
||||
StoreContextElement(native_context,
|
||||
Context::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX,
|
||||
preserved_embedder_data);
|
||||
|
||||
// Run the promise before/debug hook if enabled.
|
||||
RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
|
||||
promise_or_capability);
|
||||
@ -271,6 +289,10 @@ void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
|
||||
RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context,
|
||||
promise_or_capability);
|
||||
|
||||
StoreContextElement(native_context,
|
||||
Context::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX,
|
||||
UndefinedConstant());
|
||||
|
||||
RewindEnteredContext(saved_entered_context_count);
|
||||
SetCurrentContext(current_context);
|
||||
Goto(&done);
|
||||
|
@ -429,10 +429,12 @@ namespace promise {
|
||||
// PromiseReaction holding both the onFulfilled and onRejected callbacks.
|
||||
// Once the {promise} is resolved we decide on the concrete handler to
|
||||
// push onto the microtask queue.
|
||||
const handlerContext = ExtractHandlerContext(onFulfilled, onRejected);
|
||||
const promiseReactions =
|
||||
UnsafeCast<(Zero | PromiseReaction)>(promise.reactions_or_result);
|
||||
const reaction = NewPromiseReaction(
|
||||
promiseReactions, resultPromiseOrCapability, onFulfilled, onRejected);
|
||||
handlerContext, promiseReactions, resultPromiseOrCapability,
|
||||
onFulfilled, onRejected);
|
||||
promise.reactions_or_result = reaction;
|
||||
} else {
|
||||
let map: Map;
|
||||
|
@ -59,6 +59,7 @@ namespace promise {
|
||||
handler: Callable|Undefined,
|
||||
promiseOrCapability: JSPromise|PromiseCapability|
|
||||
Undefined): PromiseReactionJobTask {
|
||||
const nativeContext = LoadNativeContext(handlerContext);
|
||||
const taskHeapObject =
|
||||
promise_internal::AllocatePromiseReactionJobTask(context);
|
||||
taskHeapObject.map = map;
|
||||
@ -67,6 +68,9 @@ namespace promise {
|
||||
jobTask.context = handlerContext;
|
||||
jobTask.handler = handler;
|
||||
jobTask.promise_or_capability = promiseOrCapability;
|
||||
jobTask.continuation_preserved_embedder_data =
|
||||
nativeContext[NativeContextSlot::
|
||||
CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX];
|
||||
return jobTask;
|
||||
}
|
||||
|
||||
@ -113,16 +117,19 @@ namespace promise {
|
||||
}
|
||||
|
||||
macro NewPromiseReaction(implicit context: Context)(
|
||||
next: Zero|PromiseReaction,
|
||||
handlerContext: Context, next: Zero|PromiseReaction,
|
||||
promiseOrCapability: JSPromise|PromiseCapability|Undefined,
|
||||
fulfillHandler: Callable|Undefined,
|
||||
rejectHandler: Callable|Undefined): PromiseReaction {
|
||||
const nativeContext = LoadNativeContext(handlerContext);
|
||||
return new PromiseReaction{
|
||||
map: PromiseReactionMapConstant(),
|
||||
next: next,
|
||||
reject_handler: rejectHandler,
|
||||
fulfill_handler: fulfillHandler,
|
||||
promise_or_capability: promiseOrCapability
|
||||
promise_or_capability: promiseOrCapability,
|
||||
continuation_preserved_embedder_data: nativeContext
|
||||
[NativeContextSlot::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX]
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,8 @@ enum ContextLookupFlags {
|
||||
/* it's already UBSan-fiendly and doesn't require a star... So declare */ \
|
||||
/* it as a HeapObject for now. */ \
|
||||
V(EMBEDDER_DATA_INDEX, HeapObject, embedder_data) \
|
||||
V(CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX, HeapObject, \
|
||||
continuation_preserved_embedder_data) \
|
||||
/* Below is alpha-sorted */ \
|
||||
V(ACCESSOR_PROPERTY_DESCRIPTOR_MAP_INDEX, Map, \
|
||||
accessor_property_descriptor_map) \
|
||||
|
@ -59,6 +59,8 @@ extern enum NativeContextSlot extends intptr constexpr 'Context::Field' {
|
||||
PROMISE_THEN_FINALLY_SHARED_FUN,
|
||||
PROMISE_VALUE_THUNK_FINALLY_SHARED_FUN,
|
||||
STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
|
||||
|
||||
CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX,
|
||||
...
|
||||
}
|
||||
|
||||
|
@ -6135,6 +6135,11 @@ Handle<Object> JSPromise::TriggerPromiseReactions(Isolate* isolate,
|
||||
static_cast<int>(PromiseReaction::kPromiseOrCapabilityOffset) ==
|
||||
static_cast<int>(
|
||||
PromiseFulfillReactionJobTask::kPromiseOrCapabilityOffset));
|
||||
STATIC_ASSERT(
|
||||
static_cast<int>(
|
||||
PromiseReaction::kContinuationPreservedEmbedderDataOffset) ==
|
||||
static_cast<int>(PromiseFulfillReactionJobTask::
|
||||
kContinuationPreservedEmbedderDataOffset));
|
||||
} else {
|
||||
DisallowHeapAllocation no_gc;
|
||||
task->synchronized_set_map(
|
||||
@ -6148,6 +6153,11 @@ Handle<Object> JSPromise::TriggerPromiseReactions(Isolate* isolate,
|
||||
static_cast<int>(PromiseReaction::kPromiseOrCapabilityOffset) ==
|
||||
static_cast<int>(
|
||||
PromiseRejectReactionJobTask::kPromiseOrCapabilityOffset));
|
||||
STATIC_ASSERT(
|
||||
static_cast<int>(
|
||||
PromiseReaction::kContinuationPreservedEmbedderDataOffset) ==
|
||||
static_cast<int>(PromiseRejectReactionJobTask::
|
||||
kContinuationPreservedEmbedderDataOffset));
|
||||
}
|
||||
|
||||
MicrotaskQueue* microtask_queue = handler_context->microtask_queue();
|
||||
|
@ -22,6 +22,8 @@ const kPromiseReactionFulfillHandlerOffset: constexpr int31
|
||||
generates 'PromiseReaction::kFulfillHandlerOffset';
|
||||
const kPromiseReactionPromiseOrCapabilityOffset: constexpr int31
|
||||
generates 'PromiseReaction::kPromiseOrCapabilityOffset';
|
||||
const kPromiseReactionContinuationPreservedEmbedderDataOffset: constexpr int31
|
||||
generates 'PromiseReaction::kContinuationPreservedEmbedderDataOffset';
|
||||
|
||||
@generateCppClass
|
||||
extern class PromiseReaction extends Struct {
|
||||
@ -31,6 +33,7 @@ extern class PromiseReaction extends Struct {
|
||||
// Either a JSPromise (in case of native promises), a PromiseCapability
|
||||
// (general case), or undefined (in case of await).
|
||||
promise_or_capability: JSPromise|PromiseCapability|Undefined;
|
||||
continuation_preserved_embedder_data: Object|Undefined;
|
||||
}
|
||||
|
||||
// PromiseReactionJobTask constants
|
||||
@ -40,6 +43,10 @@ const kPromiseReactionJobTaskHandlerOffset: constexpr int31
|
||||
generates 'PromiseReactionJobTask::kHandlerOffset';
|
||||
const kPromiseReactionJobTaskPromiseOrCapabilityOffset: constexpr int31
|
||||
generates 'PromiseReactionJobTask::kPromiseOrCapabilityOffset';
|
||||
const kPromiseReactionJobTaskContinuationPreservedEmbedderDataOffset:
|
||||
constexpr int31
|
||||
generates 'PromiseReactionJobTask::kContinuationPreservedEmbedderDataOffset'
|
||||
;
|
||||
|
||||
@abstract
|
||||
@generateCppClass
|
||||
@ -50,6 +57,7 @@ extern class PromiseReactionJobTask extends Microtask {
|
||||
// Either a JSPromise (in case of native promises), a PromiseCapability
|
||||
// (general case), or undefined (in case of await).
|
||||
promise_or_capability: JSPromise|PromiseCapability|Undefined;
|
||||
continuation_preserved_embedder_data: Object|Undefined;
|
||||
}
|
||||
|
||||
@generateCppClass
|
||||
|
Loading…
Reference in New Issue
Block a user