Skip to content

Commit

Permalink
Convert execution async resource to use a stack
Browse files Browse the repository at this point in the history
  • Loading branch information
Qard committed Dec 19, 2019
1 parent d0d7522 commit 4788019
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 27 deletions.
2 changes: 1 addition & 1 deletion lib/async_hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ class AsyncResource {

runInAsyncScope(fn, thisArg, ...args) {
const asyncId = this[async_id_symbol];
emitBefore(asyncId, this[trigger_async_id_symbol]);
emitBefore(asyncId, this[trigger_async_id_symbol], this);

const ret = thisArg === undefined ?
fn(...args) :
Expand Down
11 changes: 6 additions & 5 deletions lib/internal/async_hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ const active_hooks = {
const { registerDestroyHook } = async_wrap;
const { enqueueMicrotask } = internalBinding('task_queue');

const { executionAsyncResource, setExecutionAsyncResource } = async_wrap;
const { executionAsyncResource, pushExecutionAsyncResource,
popExecutionAsyncResource } = async_wrap;

// Each constant tracks how many callbacks there are for any given step of
// async execution. These are tracked so if the user didn't include callbacks
Expand Down Expand Up @@ -360,7 +361,7 @@ function emitBeforeScript(asyncId, triggerAsyncId, resource) {
validateAsyncId(asyncId, 'asyncId');
validateAsyncId(triggerAsyncId, 'triggerAsyncId');

setExecutionAsyncResource(resource);
pushExecutionAsyncResource(resource);
pushAsyncIds(asyncId, triggerAsyncId);

if (async_hook_fields[kBefore] > 0)
Expand All @@ -374,8 +375,7 @@ function emitAfterScript(asyncId) {
if (async_hook_fields[kAfter] > 0)
emitAfterNative(asyncId);

setExecutionAsyncResource(null);

popExecutionAsyncResource();
popAsyncIds(asyncId);
}

Expand Down Expand Up @@ -477,7 +477,8 @@ module.exports = {
emitAfter: emitAfterScript,
emitDestroy: emitDestroyScript,
registerDestroyHook,
setExecutionAsyncResource,
pushExecutionAsyncResource,
popExecutionAsyncResource,
nativeHooks: {
init: emitInitNative,
before: emitBeforeNative,
Expand Down
6 changes: 4 additions & 2 deletions lib/internal/timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ const {
emitBefore,
emitAfter,
emitDestroy,
setExecutionAsyncResource
popExecutionAsyncResource,
pushExecutionAsyncResource,
} = require('internal/async_hooks');

// Symbols for storing async id state.
Expand Down Expand Up @@ -539,7 +540,7 @@ function getTimerCallbacks(runNextTicks) {
else
timer._onTimeout(...args);
} finally {
setExecutionAsyncResource(null);
popExecutionAsyncResource();
if (timer._repeat && timer._idleTimeout !== -1) {
timer._idleTimeout = timer._repeat;
if (start === undefined)
Expand All @@ -555,6 +556,7 @@ function getTimerCallbacks(runNextTicks) {
}
timer._destroyed = true;
}
pushExecutionAsyncResource(timer);
}

emitAfter(asyncId);
Expand Down
30 changes: 22 additions & 8 deletions src/async_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ void AsyncWrap::EmitTraceEventBefore() {
void AsyncWrap::EmitBefore(Environment* env, double async_id,
v8::Local<v8::Object> resource) {
v8::Local<v8::Context> context = env->isolate()->GetCurrentContext();
env->async_hooks()->set_execution_async_resource(resource);
env->async_hooks()->push_execution_async_resource(resource);

Emit(env, async_id, AsyncHooks::kBefore,
env->async_hooks_before_function());
Expand Down Expand Up @@ -180,7 +180,7 @@ void AsyncWrap::EmitAfter(Environment* env, double async_id) {
Emit(env, async_id, AsyncHooks::kAfter,
env->async_hooks_after_function());

env->async_hooks()->clear_execution_async_resource();
env->async_hooks()->pop_execution_async_resource();
}

class PromiseWrap : public AsyncWrap {
Expand Down Expand Up @@ -266,10 +266,14 @@ static void PromiseHook(PromiseHookType type, Local<Promise> promise,

// needed for async functions :/
// the top level will not emit before and after
env->async_hooks()->set_execution_async_resource(wrap->object());
env->async_hooks()->push_execution_async_resource(wrap->object());
}
}

if (type == PromiseHookType::kResolve && !parent->IsPromise()) {
env->async_hooks()->pop_execution_async_resource();
}

if (wrap == nullptr) return;

if (type == PromiseHookType::kBefore) {
Expand Down Expand Up @@ -402,11 +406,19 @@ static void GetExecutionAsyncResource(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(env->async_hooks()->get_execution_async_resource());
}

static void SetExecutionAsyncResource(const FunctionCallbackInfo<Value>& args) {
static void PushExecutionAsyncResource(
const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Environment* env = Environment::GetCurrent(args);
v8::Local<v8::Context> context = isolate->GetCurrentContext();
env->async_hooks()->push_execution_async_resource(args[0]);
}

static void PopExecutionAsyncResource(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Environment* env = Environment::GetCurrent(args);
v8::Local<v8::Context> context = isolate->GetCurrentContext();
env->async_hooks()->set_execution_async_resource(args[0]);
env->async_hooks()->pop_execution_async_resource();
}

void AsyncWrap::GetAsyncId(const FunctionCallbackInfo<Value>& args) {
Expand Down Expand Up @@ -497,10 +509,12 @@ void AsyncWrap::Initialize(Local<Object> target,
env->SetMethod(target, "disablePromiseHook", DisablePromiseHook);
env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook);
env->SetMethod(target, "executionAsyncResource", GetExecutionAsyncResource);
env->SetMethod(target, "setExecutionAsyncResource",
SetExecutionAsyncResource);
env->SetMethod(target, "pushExecutionAsyncResource",
PushExecutionAsyncResource);
env->SetMethod(target, "popExecutionAsyncResource",
PopExecutionAsyncResource);

env->async_hooks()->clear_execution_async_resource();
env->async_hooks()->push_execution_async_resource(v8::Object::New(isolate));

PropertyAttribute ReadOnlyDontDelete =
static_cast<PropertyAttribute>(ReadOnly | DontDelete);
Expand Down
21 changes: 13 additions & 8 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ inline MultiIsolatePlatform* IsolateData::platform() const {
inline AsyncHooks::AsyncHooks()
: async_ids_stack_(env()->isolate(), 16 * 2),
fields_(env()->isolate(), kFieldsCount),
async_id_fields_(env()->isolate(), kUidFieldsCount),
execution_async_resource_(env()->isolate(), v8::Null(env()->isolate())) {
async_id_fields_(env()->isolate(), kUidFieldsCount) {
v8::HandleScope handle_scope(env()->isolate());

// Always perform async_hooks checks, not just when async_hooks is enabled.
Expand Down Expand Up @@ -207,17 +206,23 @@ inline AsyncHooks::DefaultTriggerAsyncIdScope ::~DefaultTriggerAsyncIdScope() {
old_default_trigger_async_id_;
}

inline void AsyncHooks::set_execution_async_resource(
inline void AsyncHooks::push_execution_async_resource(
v8::Local<v8::Value> execution_async_resource) {
execution_async_resource_.Reset(env()->isolate(), execution_async_resource);
execution_async_resources_.push(v8::Global<v8::Value>(
env()->isolate(), execution_async_resource));
}

inline v8::Local<v8::Value> AsyncHooks::get_execution_async_resource() {
return execution_async_resource_.Get(env()->isolate());
inline void AsyncHooks::pop_execution_async_resource() {
if (execution_async_resources_.size()) {
execution_async_resources_.pop();
}
}

inline void AsyncHooks::clear_execution_async_resource() {
execution_async_resource_.Reset();
inline v8::Local<v8::Value> AsyncHooks::get_execution_async_resource() {
if (!execution_async_resources_.size()) {
return v8::Null(env()->isolate());
}
return execution_async_resources_.top().Get(env()->isolate());
}

Environment* Environment::ForAsyncHooks(AsyncHooks* hooks) {
Expand Down
7 changes: 4 additions & 3 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include <cstdint>
#include <functional>
#include <list>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>
Expand Down Expand Up @@ -684,10 +685,10 @@ class AsyncHooks : public MemoryRetainer {
inline bool pop_async_id(double async_id);
inline void clear_async_id_stack(); // Used in fatal exceptions.

inline void set_execution_async_resource(
inline void push_execution_async_resource(
v8::Local<v8::Value> execution_async_resource_);
inline void pop_execution_async_resource();
inline v8::Local<v8::Value> get_execution_async_resource();
inline void clear_execution_async_resource();

AsyncHooks(const AsyncHooks&) = delete;
AsyncHooks& operator=(const AsyncHooks&) = delete;
Expand Down Expand Up @@ -732,7 +733,7 @@ class AsyncHooks : public MemoryRetainer {

void grow_async_ids_stack();

v8::Persistent<v8::Value> execution_async_resource_;
std::stack<v8::Global<v8::Value>> execution_async_resources_;
};

class ImmediateInfo : public MemoryRetainer {
Expand Down

0 comments on commit 4788019

Please sign in to comment.