feat: add binding for Context::SetPromiseHooks (#938)

This commit is contained in:
legendecas 2022-05-06 00:31:29 +08:00 committed by GitHub
parent 64ce32392a
commit 196145abf1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 140 additions and 0 deletions

1
.gn
View File

@ -36,6 +36,7 @@ default_args = {
clang_use_chrome_plugins = false
v8_monolithic = false
v8_enable_snapshot_compression = false
v8_enable_javascript_promise_hooks = true
v8_use_external_startup_data = false
v8_use_snapshot = true
is_component_build = false

View File

@ -1560,6 +1560,18 @@ const v8::Data* v8__Context__GetDataFromSnapshotOnce(v8::Context& self,
ptr_to_local(&self)->GetDataFromSnapshotOnce<v8::Data>(index));
}
void v8__Context__SetPromiseHooks(v8::Context& self,
v8::Function& init_hook,
v8::Function& before_hook,
v8::Function& after_hook,
v8::Function& resolve_hook) {
ptr_to_local(&self)->SetPromiseHooks(
ptr_to_local(&init_hook),
ptr_to_local(&before_hook),
ptr_to_local(&after_hook),
ptr_to_local(&resolve_hook));
}
const v8::String* v8__Message__Get(const v8::Message& self) {
return local_to_ptr(self.Get());
}

View File

@ -1,6 +1,7 @@
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
use crate::isolate::Isolate;
use crate::Context;
use crate::Function;
use crate::HandleScope;
use crate::Local;
use crate::Object;
@ -15,6 +16,13 @@ extern "C" {
global_object: *const Value,
) -> *const Context;
fn v8__Context__Global(this: *const Context) -> *const Object;
fn v8__Context__SetPromiseHooks(
this: *const Context,
init_hook: *const Function,
before_hook: *const Function,
after_hook: *const Function,
resolve_hook: *const Function,
);
}
impl Context {
@ -58,4 +66,22 @@ impl Context {
) -> Local<'s, Object> {
unsafe { scope.cast_local(|_| v8__Context__Global(self)) }.unwrap()
}
pub fn set_promise_hooks(
&self,
init_hook: Local<Function>,
before_hook: Local<Function>,
after_hook: Local<Function>,
resolve_hook: Local<Function>,
) {
unsafe {
v8__Context__SetPromiseHooks(
self,
&*init_hook,
&*before_hook,
&*after_hook,
&*resolve_hook,
)
}
}
}

View File

@ -2483,6 +2483,107 @@ fn promise_hook() {
}
}
#[test]
fn context_promise_hooks() {
let _setup_guard = setup();
let isolate = &mut v8::Isolate::new(Default::default());
{
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let scope = &mut v8::ContextScope::new(scope, context);
let init_hook = v8::Local::<v8::Function>::try_from(
eval(
scope,
r#"
globalThis.promises = new Set();
function initHook(promise) {
promises.add(promise);
}
initHook;
"#,
)
.unwrap(),
)
.unwrap();
let before_hook = v8::Local::<v8::Function>::try_from(
eval(
scope,
r#"
globalThis.promiseStack = [];
function beforeHook(promise) {
promiseStack.push(promise);
}
beforeHook;
"#,
)
.unwrap(),
)
.unwrap();
let after_hook = v8::Local::<v8::Function>::try_from(
eval(
scope,
r#"
function afterHook(promise) {
const it = promiseStack.pop();
if (it !== promise) throw new Error("unexpected promise");
}
afterHook;
"#,
)
.unwrap(),
)
.unwrap();
let resolve_hook = v8::Local::<v8::Function>::try_from(
eval(
scope,
r#"
function resolveHook(promise) {
promises.delete(promise);
}
resolveHook;
"#,
)
.unwrap(),
)
.unwrap();
context.set_promise_hooks(init_hook, before_hook, after_hook, resolve_hook);
let source = r#"
function expect(expected, actual = promises.size) {
if (actual !== expected) throw `expected ${expected}, actual ${actual}`;
}
expect(0);
var p = new Promise(resolve => {
expect(1);
resolve();
expect(0);
});
expect(0);
new Promise(() => {});
expect(1);
expect(0, promiseStack.length);
p.then(() => {
expect(1, promiseStack.length);
});
promises.values().next().value
"#;
let promise = eval(scope, source).unwrap();
let promise = v8::Local::<v8::Promise>::try_from(promise).unwrap();
assert!(!promise.has_handler());
assert_eq!(promise.state(), v8::PromiseState::Pending);
scope.perform_microtask_checkpoint();
let _ = eval(
scope,
r#"
expect(0, promiseStack.length);
"#,
)
.unwrap();
}
}
#[test]
fn allow_atomics_wait() {
let _setup_guard = setup();