Commit 916e35d7 authored by Maya Lekova's avatar Maya Lekova Committed by Commit Bot

Reland ^3 "[async] Expose async hooks to d8"

This is a reland of ade7f55b

Previously landed as: ade7f55b / 1125679
Previously landed as: 3c4d0316 / 1065818
Previously landed as: 8e0f67be / 1088890

Original change's description:
> Reland ^2 "[async] Expose async hooks to d8"
>
> This is a reland of 8e0f67be
>

Bug: chromium:850530
Change-Id: I536cfb9443d80d62937d9c3dc6a53b52b209d5c7
Reviewed-on: https://chromium-review.googlesource.com/1125683
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54218}
parent 9b2358d6
......@@ -3330,6 +3330,8 @@ if (is_component_build) {
v8_executable("d8") {
sources = [
"$target_gen_dir/d8-js.cc",
"src/async-hooks-wrapper.cc",
"src/async-hooks-wrapper.h",
"src/d8-console.cc",
"src/d8-console.h",
"src/d8.cc",
......
// Copyright 2018 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.
#include "src/async-hooks-wrapper.h"
#include "src/d8.h"
namespace v8 {
void AsyncHooksWrap::Enable() { enabled_ = true; }
void AsyncHooksWrap::Disable() { enabled_ = false; }
v8::Local<v8::Function> AsyncHooksWrap::init_function() const {
return init_function_.Get(isolate_);
}
void AsyncHooksWrap::set_init_function(v8::Local<v8::Function> value) {
init_function_.Reset(isolate_, value);
}
v8::Local<v8::Function> AsyncHooksWrap::before_function() const {
return before_function_.Get(isolate_);
}
void AsyncHooksWrap::set_before_function(v8::Local<v8::Function> value) {
before_function_.Reset(isolate_, value);
}
v8::Local<v8::Function> AsyncHooksWrap::after_function() const {
return after_function_.Get(isolate_);
}
void AsyncHooksWrap::set_after_function(v8::Local<v8::Function> value) {
after_function_.Reset(isolate_, value);
}
v8::Local<v8::Function> AsyncHooksWrap::promiseResolve_function() const {
return promiseResolve_function_.Get(isolate_);
}
void AsyncHooksWrap::set_promiseResolve_function(
v8::Local<v8::Function> value) {
promiseResolve_function_.Reset(isolate_, value);
}
static AsyncHooksWrap* UnwrapHook(
const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate();
HandleScope scope(isolate);
Local<Object> hook = args.This();
Local<External> wrap = Local<External>::Cast(hook->GetInternalField(0));
void* ptr = wrap->Value();
return static_cast<AsyncHooksWrap*>(ptr);
}
static void EnableHook(const v8::FunctionCallbackInfo<v8::Value>& args) {
AsyncHooksWrap* wrap = UnwrapHook(args);
wrap->Enable();
}
static void DisableHook(const v8::FunctionCallbackInfo<v8::Value>& args) {
AsyncHooksWrap* wrap = UnwrapHook(args);
wrap->Disable();
}
async_id_t AsyncHooks::GetExecutionAsyncId() const {
return asyncContexts.top().execution_async_id;
}
async_id_t AsyncHooks::GetTriggerAsyncId() const {
return asyncContexts.top().trigger_async_id;
}
Local<Object> AsyncHooks::CreateHook(
const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate();
EscapableHandleScope handle_scope(isolate);
Local<Context> currentContext = isolate->GetCurrentContext();
AsyncHooksWrap* wrap = new AsyncHooksWrap(isolate);
CHECK(args[0]->IsObject());
Local<Object> fn_obj = args[0].As<Object>();
#define SET_HOOK_FN(name) \
Local<Value> name##_v = \
fn_obj \
->Get(currentContext, \
String::NewFromUtf8(isolate, #name, NewStringType::kNormal) \
.ToLocalChecked()) \
.ToLocalChecked(); \
if (name##_v->IsFunction()) { \
wrap->set_##name##_function(name##_v.As<Function>()); \
}
SET_HOOK_FN(init);
SET_HOOK_FN(before);
SET_HOOK_FN(after);
SET_HOOK_FN(promiseResolve);
#undef SET_HOOK_FN
async_wraps_.push_back(wrap);
Local<Object> obj = async_hooks_templ.Get(isolate)
->NewInstance(currentContext)
.ToLocalChecked();
obj->SetInternalField(0, External::New(isolate, wrap));
return handle_scope.Escape(obj);
}
void AsyncHooks::ShellPromiseHook(PromiseHookType type, Local<Promise> promise,
Local<Value> parent) {
AsyncHooks* hooks =
PerIsolateData::Get(promise->GetIsolate())->GetAsyncHooks();
HandleScope handle_scope(hooks->isolate_);
Local<Context> currentContext = hooks->isolate_->GetCurrentContext();
if (type == PromiseHookType::kInit) {
++hooks->current_async_id;
Local<Integer> async_id =
Integer::New(hooks->isolate_, hooks->current_async_id);
promise->SetPrivate(currentContext,
hooks->async_id_smb.Get(hooks->isolate_), async_id);
if (parent->IsPromise()) {
Local<Promise> parent_promise = parent.As<Promise>();
Local<Value> parent_async_id =
parent_promise
->GetPrivate(hooks->isolate_->GetCurrentContext(),
hooks->async_id_smb.Get(hooks->isolate_))
.ToLocalChecked();
promise->SetPrivate(currentContext,
hooks->trigger_id_smb.Get(hooks->isolate_),
parent_async_id);
} else {
CHECK(parent->IsUndefined());
Local<Integer> trigger_id = Integer::New(hooks->isolate_, 0);
promise->SetPrivate(currentContext,
hooks->trigger_id_smb.Get(hooks->isolate_),
trigger_id);
}
} else if (type == PromiseHookType::kBefore) {
AsyncContext ctx;
ctx.execution_async_id =
promise
->GetPrivate(hooks->isolate_->GetCurrentContext(),
hooks->async_id_smb.Get(hooks->isolate_))
.ToLocalChecked()
.As<Integer>()
->Value();
ctx.trigger_async_id =
promise
->GetPrivate(hooks->isolate_->GetCurrentContext(),
hooks->trigger_id_smb.Get(hooks->isolate_))
.ToLocalChecked()
.As<Integer>()
->Value();
hooks->asyncContexts.push(ctx);
} else if (type == PromiseHookType::kAfter) {
hooks->asyncContexts.pop();
}
for (AsyncHooksWrap* wrap : hooks->async_wraps_) {
PromiseHookDispatch(type, promise, parent, wrap, hooks);
}
}
void AsyncHooks::Initialize() {
HandleScope handle_scope(isolate_);
async_hook_ctor.Reset(isolate_, FunctionTemplate::New(isolate_));
async_hook_ctor.Get(isolate_)->SetClassName(
String::NewFromUtf8(isolate_, "AsyncHook", NewStringType::kNormal)
.ToLocalChecked());
async_hooks_templ.Reset(isolate_,
async_hook_ctor.Get(isolate_)->InstanceTemplate());
async_hooks_templ.Get(isolate_)->SetInternalFieldCount(1);
async_hooks_templ.Get(isolate_)->Set(
String::NewFromUtf8(isolate_, "enable"),
FunctionTemplate::New(isolate_, EnableHook));
async_hooks_templ.Get(isolate_)->Set(
String::NewFromUtf8(isolate_, "disable"),
FunctionTemplate::New(isolate_, DisableHook));
async_id_smb.Reset(isolate_, Private::New(isolate_));
trigger_id_smb.Reset(isolate_, Private::New(isolate_));
isolate_->SetPromiseHook(ShellPromiseHook);
}
void AsyncHooks::Deinitialize() {
isolate_->SetPromiseHook(nullptr);
for (AsyncHooksWrap* wrap : async_wraps_) {
delete wrap;
}
}
void AsyncHooks::PromiseHookDispatch(PromiseHookType type,
Local<Promise> promise,
Local<Value> parent, AsyncHooksWrap* wrap,
AsyncHooks* hooks) {
if (!wrap->IsEnabled()) {
return;
}
HandleScope handle_scope(hooks->isolate_);
Local<Value> rcv = Undefined(hooks->isolate_);
Local<Value> async_id =
promise
->GetPrivate(hooks->isolate_->GetCurrentContext(),
hooks->async_id_smb.Get(hooks->isolate_))
.ToLocalChecked();
Local<Value> args[1] = {async_id};
// Sacrifice the brevity for readability and debugfulness
if (type == PromiseHookType::kInit) {
if (!wrap->init_function().IsEmpty()) {
Local<Value> initArgs[4] = {
async_id,
String::NewFromUtf8(hooks->isolate_, "PROMISE",
NewStringType::kNormal)
.ToLocalChecked(),
promise
->GetPrivate(hooks->isolate_->GetCurrentContext(),
hooks->trigger_id_smb.Get(hooks->isolate_))
.ToLocalChecked(),
promise};
wrap->init_function()->Call(rcv, 4, initArgs);
}
} else if (type == PromiseHookType::kBefore) {
if (!wrap->before_function().IsEmpty()) {
wrap->before_function()->Call(rcv, 1, args);
}
} else if (type == PromiseHookType::kAfter) {
if (!wrap->after_function().IsEmpty()) {
wrap->after_function()->Call(rcv, 1, args);
}
} else if (type == PromiseHookType::kResolve) {
if (!wrap->promiseResolve_function().IsEmpty()) {
wrap->promiseResolve_function()->Call(rcv, 1, args);
}
}
}
} // namespace v8
// Copyright 2018 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.
#ifndef V8_ASYNC_HOOKS_WRAPPER_H_
#define V8_ASYNC_HOOKS_WRAPPER_H_
#include <stack>
#include "include/v8.h"
#include "src/objects.h"
namespace v8 {
typedef double async_id_t;
struct AsyncContext {
async_id_t execution_async_id;
async_id_t trigger_async_id;
};
class AsyncHooksWrap {
public:
explicit AsyncHooksWrap(Isolate* isolate) {
enabled_ = false;
isolate_ = isolate;
}
void Enable();
void Disable();
bool IsEnabled() const { return enabled_; }
inline v8::Local<v8::Function> init_function() const;
inline void set_init_function(v8::Local<v8::Function> value);
inline v8::Local<v8::Function> before_function() const;
inline void set_before_function(v8::Local<v8::Function> value);
inline v8::Local<v8::Function> after_function() const;
inline void set_after_function(v8::Local<v8::Function> value);
inline v8::Local<v8::Function> promiseResolve_function() const;
inline void set_promiseResolve_function(v8::Local<v8::Function> value);
private:
Isolate* isolate_;
Persistent<v8::Function> init_function_;
Persistent<v8::Function> before_function_;
Persistent<v8::Function> after_function_;
Persistent<v8::Function> promiseResolve_function_;
bool enabled_;
};
class AsyncHooks {
public:
explicit AsyncHooks(Isolate* isolate) {
isolate_ = isolate;
AsyncContext ctx;
ctx.execution_async_id = 1;
ctx.trigger_async_id = 0;
asyncContexts.push(ctx);
current_async_id = 1;
Initialize();
}
~AsyncHooks() { Deinitialize(); }
async_id_t GetExecutionAsyncId() const;
async_id_t GetTriggerAsyncId() const;
Local<Object> CreateHook(const v8::FunctionCallbackInfo<v8::Value>& args);
private:
std::vector<AsyncHooksWrap*> async_wraps_;
Isolate* isolate_;
Persistent<FunctionTemplate> async_hook_ctor;
Persistent<ObjectTemplate> async_hooks_templ;
Persistent<Private> async_id_smb;
Persistent<Private> trigger_id_smb;
void Initialize();
void Deinitialize();
static void ShellPromiseHook(PromiseHookType type, Local<Promise> promise,
Local<Value> parent);
static void PromiseHookDispatch(PromiseHookType type, Local<Promise> promise,
Local<Value> parent, AsyncHooksWrap* wrap,
AsyncHooks* hooks);
std::stack<AsyncContext> asyncContexts;
async_id_t current_async_id;
};
} // namespace v8
#endif // V8_ASYNC_HOOKS_WRAPPER_H_
......@@ -383,64 +383,6 @@ static platform::tracing::TraceConfig* CreateTraceConfigFromJSON(
} // namespace tracing
class PerIsolateData {
public:
explicit PerIsolateData(Isolate* isolate)
: isolate_(isolate), realms_(nullptr) {
isolate->SetData(0, this);
}
~PerIsolateData() {
isolate_->SetData(0, nullptr); // Not really needed, just to be sure...
}
inline static PerIsolateData* Get(Isolate* isolate) {
return reinterpret_cast<PerIsolateData*>(isolate->GetData(0));
}
class RealmScope {
public:
explicit RealmScope(PerIsolateData* data);
~RealmScope();
private:
PerIsolateData* data_;
};
inline void SetTimeout(Local<Function> callback, Local<Context> context) {
set_timeout_callbacks_.emplace(isolate_, callback);
set_timeout_contexts_.emplace(isolate_, context);
}
inline MaybeLocal<Function> GetTimeoutCallback() {
if (set_timeout_callbacks_.empty()) return MaybeLocal<Function>();
Local<Function> result = set_timeout_callbacks_.front().Get(isolate_);
set_timeout_callbacks_.pop();
return result;
}
inline MaybeLocal<Context> GetTimeoutContext() {
if (set_timeout_contexts_.empty()) return MaybeLocal<Context>();
Local<Context> result = set_timeout_contexts_.front().Get(isolate_);
set_timeout_contexts_.pop();
return result;
}
private:
friend class Shell;
friend class RealmScope;
Isolate* isolate_;
int realm_count_;
int realm_current_;
int realm_switch_;
Global<Context>* realms_;
Global<Value> realm_shared_;
std::queue<Global<Function>> set_timeout_callbacks_;
std::queue<Global<Context>> set_timeout_contexts_;
int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
int arg_offset);
int RealmFind(Local<Context> context);
};
class ExternalOwningOneByteStringResource
: public String::ExternalOneByteStringResource {
......@@ -990,6 +932,41 @@ bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) {
return true;
}
PerIsolateData::PerIsolateData(Isolate* isolate)
: isolate_(isolate), realms_(nullptr) {
isolate->SetData(0, this);
if (i::FLAG_expose_async_hooks) {
async_hooks_wrapper_ = new AsyncHooks(isolate);
}
}
PerIsolateData::~PerIsolateData() {
isolate_->SetData(0, nullptr); // Not really needed, just to be sure...
if (i::FLAG_expose_async_hooks) {
delete async_hooks_wrapper_; // This uses the isolate
}
}
void PerIsolateData::SetTimeout(Local<Function> callback,
Local<Context> context) {
set_timeout_callbacks_.emplace(isolate_, callback);
set_timeout_contexts_.emplace(isolate_, context);
}
MaybeLocal<Function> PerIsolateData::GetTimeoutCallback() {
if (set_timeout_callbacks_.empty()) return MaybeLocal<Function>();
Local<Function> result = set_timeout_callbacks_.front().Get(isolate_);
set_timeout_callbacks_.pop();
return result;
}
MaybeLocal<Context> PerIsolateData::GetTimeoutContext() {
if (set_timeout_contexts_.empty()) return MaybeLocal<Context>();
Local<Context> result = set_timeout_contexts_.front().Get(isolate_);
set_timeout_contexts_.pop();
return result;
}
PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
data_->realm_count_ = 1;
data_->realm_current_ = 0;
......@@ -1244,6 +1221,35 @@ void Shell::RealmSharedSet(Local<String> property,
data->realm_shared_.Reset(isolate, value);
}
// async_hooks.createHook() registers functions to be called for different
// lifetime events of each async operation.
void Shell::AsyncHooksCreateHook(
const v8::FunctionCallbackInfo<v8::Value>& args) {
Local<Object> wrap =
PerIsolateData::Get(args.GetIsolate())->GetAsyncHooks()->CreateHook(args);
args.GetReturnValue().Set(wrap);
}
// async_hooks.executionAsyncId() returns the asyncId of the current execution
// context.
void Shell::AsyncHooksExecutionAsyncId(
const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate();
HandleScope handle_scope(isolate);
args.GetReturnValue().Set(v8::Number::New(
isolate,
PerIsolateData::Get(isolate)->GetAsyncHooks()->GetExecutionAsyncId()));
}
void Shell::AsyncHooksTriggerAsyncId(
const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate();
HandleScope handle_scope(isolate);
args.GetReturnValue().Set(v8::Number::New(
isolate,
PerIsolateData::Get(isolate)->GetAsyncHooks()->GetTriggerAsyncId()));
}
void WriteToFile(FILE* file, const v8::FunctionCallbackInfo<v8::Value>& args) {
for (int i = 0; i < args.Length(); i++) {
HandleScope handle_scope(args.GetIsolate());
......@@ -1857,6 +1863,26 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
.ToLocalChecked(),
os_templ);
if (i::FLAG_expose_async_hooks) {
Local<ObjectTemplate> async_hooks_templ = ObjectTemplate::New(isolate);
async_hooks_templ->Set(
String::NewFromUtf8(isolate, "createHook", NewStringType::kNormal)
.ToLocalChecked(),
FunctionTemplate::New(isolate, AsyncHooksCreateHook));
async_hooks_templ->Set(
String::NewFromUtf8(isolate, "executionAsyncId", NewStringType::kNormal)
.ToLocalChecked(),
FunctionTemplate::New(isolate, AsyncHooksExecutionAsyncId));
async_hooks_templ->Set(
String::NewFromUtf8(isolate, "triggerAsyncId", NewStringType::kNormal)
.ToLocalChecked(),
FunctionTemplate::New(isolate, AsyncHooksTriggerAsyncId));
global_template->Set(
String::NewFromUtf8(isolate, "async_hooks", NewStringType::kNormal)
.ToLocalChecked(),
async_hooks_templ);
}
return global_template;
}
......
......@@ -8,11 +8,13 @@
#include <iterator>
#include <map>
#include <memory>
#include <queue>
#include <string>
#include <unordered_map>
#include <vector>
#include "src/allocation.h"
#include "src/async-hooks-wrapper.h"
#include "src/base/platform/time.h"
#include "src/string-hasher.h"
#include "src/utils.h"
......@@ -264,6 +266,49 @@ class Worker {
base::Atomic32 running_;
};
class PerIsolateData {
public:
explicit PerIsolateData(Isolate* isolate);
~PerIsolateData();
inline static PerIsolateData* Get(Isolate* isolate) {
return reinterpret_cast<PerIsolateData*>(isolate->GetData(0));
}
class RealmScope {
public:
explicit RealmScope(PerIsolateData* data);
~RealmScope();
private:
PerIsolateData* data_;
};
inline void SetTimeout(Local<Function> callback, Local<Context> context);
inline MaybeLocal<Function> GetTimeoutCallback();
inline MaybeLocal<Context> GetTimeoutContext();
AsyncHooks* GetAsyncHooks() { return async_hooks_wrapper_; }
private:
friend class Shell;
friend class RealmScope;
Isolate* isolate_;
int realm_count_;
int realm_current_;
int realm_switch_;
Global<Context>* realms_;
Global<Value> realm_shared_;
std::queue<Global<Function>> set_timeout_callbacks_;
std::queue<Global<Context>> set_timeout_contexts_;
AsyncHooks* async_hooks_wrapper_;
int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
int arg_offset);
int RealmFind(Local<Context> context);
};
class ShellOptions {
public:
enum CodeCacheOptions {
......@@ -400,6 +445,13 @@ class Shell : public i::AllStatic {
Local<Value> value,
const PropertyCallbackInfo<void>& info);
static void AsyncHooksCreateHook(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void AsyncHooksExecutionAsyncId(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void AsyncHooksTriggerAsyncId(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void Print(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PrintErr(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Write(const v8::FunctionCallbackInfo<v8::Value>& args);
......
......@@ -863,6 +863,7 @@ DEFINE_BOOL(enable_experimental_builtins, false,
"enable new csa-based experimental builtins")
DEFINE_BOOL(disallow_code_generation_from_strings, false,
"disallow eval and friends")
DEFINE_BOOL(expose_async_hooks, false, "expose async_hooks object")
// builtins.cc
DEFINE_BOOL(allow_unsafe_function_constructor, false,
......
......@@ -258,6 +258,12 @@ assertKind(elements_kind.fast, obj);
obj = newarraycase_list_smiobj(2);
assertKind(elements_kind.fast, obj);
// Perform a gc because without it the test below can experience an
// allocation failure at an inconvenient point. Allocation mementos get
// cleared on gc, and they can't deliver elements kind feedback when that
// happens.
gc();
// Case: array constructor calls with out of date feedback.
// The boilerplate should incorporate all feedback, but the input array
// should be minimally transitioned based on immediate need.
......
// Copyright 2018 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-async-hooks
// Check for correct API methods
(function() {
assertTrue(async_hooks.hasOwnProperty('createHook'),
'Async hooks missing createHook method');
assertTrue(async_hooks.hasOwnProperty('executionAsyncId'),
'Async hooks missing executionAsyncId method');
assertTrue(async_hooks.hasOwnProperty('triggerAsyncId'),
'Async hooks missing triggerAsyncId method');
let ah = async_hooks.createHook({});
assertTrue(ah.hasOwnProperty('enable'), 'Async hooks missing enable method');
assertTrue(ah.hasOwnProperty('disable'),
'Async hooks missing disable method');
})();
// Check for correct enabling/disabling of async hooks
(function() {
let storedPromise;
let ah = async_hooks.createHook({
init(asyncId, type, triggerAsyncId, resource) {
storedPromise = resource.promise || resource;
}
});
ah.enable();
let createdPromise = new Promise(function(resolve) {
resolve(42);
});
assertSame(storedPromise, createdPromise,
"Async hooks weren't enabled correctly");
ah.disable();
createdPromise = Promise.resolve(52);
assertNotSame(storedPromise, createdPromise,
"Async hooks weren't disabled correctly");
ah.enable();
createdPromise = Promise.resolve(62);
assertSame(storedPromise, createdPromise,
"Async hooks weren't enabled correctly");
})();
// Copyright 2018 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-async-hooks
// Check for async/await asyncIds relation
(function() {
let asyncIds = [], triggerIds = [];
let ah = async_hooks.createHook({
init(asyncId, type, triggerAsyncId, resource) {
if (type !== 'PROMISE') {
return;
}
asyncIds.push(asyncId);
triggerIds.push(triggerAsyncId);
},
});
ah.enable();
// Simplified version of Node.js util.promisify(setTimeout)
function sleep(callback, timeout) {
const promise = new Promise(function(resolve, reject) {
try {
setTimeout((err, ...values) => {
if (err) {
reject(err);
} else {
resolve(values[0]);
}
}, timeout);
} catch (err) {
reject(err);
}
});
return promise;
}
async function foo() {
await sleep(10);
}
foo().then(function() {
assertEquals(asyncIds.length, 6);
assertEquals(triggerIds.length, 6);
assertEquals(triggerIds[2], asyncIds[0]);
assertEquals(triggerIds[3], asyncIds[2]);
assertEquals(triggerIds[4], asyncIds[0]);
assertEquals(triggerIds[5], asyncIds[1]);
});
})();
// Copyright 2018 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-async-hooks
// Check for chained promises asyncIds relation
(function() {
let asyncIds = [], triggerIds = [];
let ah = async_hooks.createHook({
init(asyncId, type, triggerAsyncId, resource) {
asyncIds.push(asyncId);
triggerIds.push(triggerAsyncId);
},
});
ah.enable();
let createdPromise = new Promise(function(resolve) {
resolve(42);
}).then(function() {
assertEquals(asyncIds.length, 2, 'Exactly 2 promises should be inited');
assertEquals(triggerIds.length, 2, 'Exactly 2 promises should be inited');
assertEquals(triggerIds[1], asyncIds[0],
"Parent promise asyncId doesn't correspond to child triggerAsyncId");
});
})();
// Copyright 2018 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-async-hooks
// Check for correct execution of available hooks and asyncIds
(function() {
let inited = false, resolved = false, before = false, after = false;
let storedAsyncId;
let ah = async_hooks.createHook({
init(asyncId, type, triggerAsyncId, resource) {
if (type !== 'PROMISE') {
return;
}
inited = true;
storedAsyncId = asyncId;
},
promiseResolve(asyncId) {
assertEquals(asyncId, storedAsyncId, 'AsyncId mismatch in resolve hook');
resolved = true;
},
before(asyncId) {
assertEquals(asyncId, storedAsyncId, 'AsyncId mismatch in before hook');
before = true;
},
after(asyncId) {
assertEquals(asyncId, storedAsyncId, 'AsyncId mismatch in after hook');
after = true;
},
});
ah.enable();
new Promise(function(resolve) {
resolve(42);
}).then(function() {
assertTrue(inited, "Didn't call init hook");
assertTrue(resolved, "Didn't call resolve hook");
assertTrue(before, "Didn't call before hook before the callback");
assertFalse(after, "Called after hook before the callback");
});
})();
// Copyright 2018 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --expose-async-hooks
// Check for executionAsyncId/triggerAsyncId when chained promises and
// async/await are combined
(function() {
let p;
let outerExecutionAsyncId = -1, outerTriggerAsyncId = -1;
function inIrrelevantContext(resolve) {
resolve(42);
}
function inContext1(foo) {
foo();
}
function inContext2(foo) {
foo();
}
outerExecutionAsyncId = async_hooks.executionAsyncId();
outerTriggerAsyncId = async_hooks.triggerAsyncId();
inContext1(() => {
p = new Promise(resolve => {
assertEquals(outerExecutionAsyncId, async_hooks.executionAsyncId());
assertEquals(outerTriggerAsyncId, async_hooks.triggerAsyncId());
inIrrelevantContext(resolve);
}).then(() => {
assertNotEquals(outerExecutionAsyncId, async_hooks.executionAsyncId());
assertNotEquals(outerTriggerAsyncId, async_hooks.triggerAsyncId());
});
});
inContext2(async () => {
assertEquals(outerExecutionAsyncId, async_hooks.executionAsyncId());
assertEquals(outerTriggerAsyncId, async_hooks.triggerAsyncId());
await p;
assertNotEquals(outerExecutionAsyncId, async_hooks.executionAsyncId());
assertNotEquals(outerTriggerAsyncId, async_hooks.triggerAsyncId());
});
})();
// Copyright 2018 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Check for correct interleaving of Promises and async/await
(function () {
const iterations = 10;
let promiseCounter = iterations;
let awaitCounter = 0;
async function check(v) {
awaitCounter = v;
// The following checks ensure that "await" takes 3 ticks on the
// microtask queue. Note: this will change in the future
if (awaitCounter === 0) {
assertEquals(iterations, promiseCounter);
} else if (awaitCounter <= Math.floor(iterations / 3)) {
assertEquals(iterations - awaitCounter * 3, promiseCounter);
} else {
assertEquals(0, promiseCounter);
}
}
async function f() {
for (let i = 0; i < iterations; i++) {
await check(i);
}
return 0;
}
function countdown(v) {
promiseCounter = v;
if (v > 0) Promise.resolve(v - 1).then(countdown);
}
countdown(iterations);
f();
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment