0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2024-12-24 08:09:16 -05:00

Move get_*_context() methods to scope::Entered, remove InContext trait (#279)

The `get_current_context()` and `get_entered_or_microtask_context()`
methods now return `Option<Local<Context>>` to reflect that an isolate
may not have entered any context.

They're also moved from `Isolate` to `struct Entered` because it turns
out that the underlying V8 API calls actually create new local handles,
hence they should only be used inside an active HandleScope.

The `InContext` trait has been removed.

A test exercising `ContextScope` and the `get_*_context()` methods
mentioned above was added.

Closes: #248.
This commit is contained in:
Bert Belder 2020-02-12 21:23:19 -08:00
parent ffdf69bd00
commit ddc8062644
No known key found for this signature in database
GPG key ID: 7A77887B2E2ED461
8 changed files with 173 additions and 125 deletions

View file

@ -478,57 +478,68 @@ bool v8__Value__SameValue(const v8::Value& self, v8::Value* that) {
return self.SameValue(ptr_to_local(that));
}
v8::Uint32* v8__Value__ToUint32(const v8::Value& self, v8::Context* context) {
return maybe_local_to_ptr(self.ToUint32(ptr_to_local(context)));
v8::Uint32* v8__Value__ToUint32(const v8::Value& self,
v8::Local<v8::Context> context) {
return maybe_local_to_ptr(self.ToUint32(context));
}
v8::Int32* v8__Value__ToInt32(const v8::Value& self, v8::Context* context) {
return maybe_local_to_ptr(self.ToInt32(ptr_to_local(context)));
v8::Int32* v8__Value__ToInt32(const v8::Value& self,
v8::Local<v8::Context> context) {
return maybe_local_to_ptr(self.ToInt32(context));
}
v8::Integer* v8__Value__ToInteger(const v8::Value& self, v8::Context* context) {
return maybe_local_to_ptr(self.ToInteger(ptr_to_local(context)));
v8::Integer* v8__Value__ToInteger(const v8::Value& self,
v8::Local<v8::Context> context) {
return maybe_local_to_ptr(self.ToInteger(context));
}
v8::BigInt* v8__Value__ToBigInt(const v8::Value& self, v8::Context* context) {
return maybe_local_to_ptr(self.ToBigInt(ptr_to_local(context)));
v8::BigInt* v8__Value__ToBigInt(const v8::Value& self,
v8::Local<v8::Context> context) {
return maybe_local_to_ptr(self.ToBigInt(context));
}
v8::String* v8__Value__ToString(const v8::Value& self, v8::Context* context) {
return maybe_local_to_ptr(self.ToString(ptr_to_local(context)));
v8::String* v8__Value__ToString(const v8::Value& self,
v8::Local<v8::Context> context) {
return maybe_local_to_ptr(self.ToString(context));
}
v8::String* v8__Value__ToDetailString(const v8::Value& self,
v8::Context* context) {
return maybe_local_to_ptr(self.ToDetailString(ptr_to_local(context)));
v8::Local<v8::Context> context) {
return maybe_local_to_ptr(self.ToDetailString(context));
}
v8::Number* v8__Value__ToNumber(const v8::Value& self, v8::Context* context) {
return maybe_local_to_ptr(self.ToNumber(ptr_to_local(context)));
v8::Number* v8__Value__ToNumber(const v8::Value& self,
v8::Local<v8::Context> context) {
return maybe_local_to_ptr(self.ToNumber(context));
}
v8::Object* v8__Value__ToObject(const v8::Value& self, v8::Context* context) {
return maybe_local_to_ptr(self.ToObject(ptr_to_local(context)));
v8::Object* v8__Value__ToObject(const v8::Value& self,
v8::Local<v8::Context> context) {
return maybe_local_to_ptr(self.ToObject(context));
}
void v8__Value__NumberValue(const v8::Value& self, v8::Context* context,
void v8__Value__NumberValue(const v8::Value& self,
v8::Local<v8::Context> context,
v8::Maybe<double>* out) {
*out = self.NumberValue(ptr_to_local(context));
*out = self.NumberValue(context);
}
void v8__Value__IntegerValue(const v8::Value& self, v8::Context* context,
void v8__Value__IntegerValue(const v8::Value& self,
v8::Local<v8::Context> context,
v8::Maybe<int64_t>* out) {
*out = self.IntegerValue(ptr_to_local(context));
*out = self.IntegerValue(context);
}
void v8__Value__Uint32Value(const v8::Value& self, v8::Context* context,
void v8__Value__Uint32Value(const v8::Value& self,
v8::Local<v8::Context> context,
v8::Maybe<uint32_t>* out) {
*out = self.Uint32Value(ptr_to_local(context));
*out = self.Uint32Value(context);
}
void v8__Value__Int32Value(const v8::Value& self, v8::Context* context,
void v8__Value__Int32Value(const v8::Value& self,
v8::Local<v8::Context> context,
v8::Maybe<int32_t>* out) {
*out = self.Int32Value(ptr_to_local(context));
*out = self.Int32Value(context);
}
v8::Primitive* v8__Null(v8::Isolate* isolate) {

View file

@ -78,10 +78,6 @@ extern "C" {
fn v8__Isolate__GetNumberOfDataSlots(this: *const Isolate) -> u32;
fn v8__Isolate__Enter(this: *mut Isolate);
fn v8__Isolate__Exit(this: *mut Isolate);
fn v8__Isolate__GetCurrentContext(this: *mut Isolate) -> *mut Context;
fn v8__Isolate__GetEnteredOrMicrotaskContext(
this: *mut Isolate,
) -> *mut Context;
fn v8__Isolate__SetCaptureStackTraceForUncaughtExceptions(
this: *mut Isolate,
caputre: bool,
@ -204,24 +200,6 @@ impl Isolate {
unsafe { v8__Isolate__Exit(self) }
}
/// Returns the context of the currently running JavaScript, or the context
/// on the top of the stack if no JavaScript is running.
pub fn get_current_context<'sc>(&mut self) -> Local<'sc, Context> {
unsafe { Local::from_raw(v8__Isolate__GetCurrentContext(self)).unwrap() }
}
/// Returns either the last context entered through V8's C++ API, or the
/// context of the currently running microtask while processing microtasks.
/// If a context is entered while executing a microtask, that context is
/// returned.
pub fn get_entered_or_microtask_context<'sc>(
&mut self,
) -> Local<'sc, Context> {
unsafe {
Local::from_raw(v8__Isolate__GetEnteredOrMicrotaskContext(self)).unwrap()
}
}
/// Tells V8 to capture current stack trace when uncaught exception occurs
/// and report it to the message listeners. The option is off by default.
pub fn set_capture_stack_trace_for_uncaught_exceptions(

View file

@ -47,17 +47,14 @@
//! InIsolate which gives access to &mut Isolate is implemented for all scopes,
//! ToLocal (I might rename that) is implemented for all Scopes in which new
//! Local handles can be created and it sets the appropriate lifetime on them.
//! InContext means that a context has been entered (I'll make sure they have a
//! get_context() method), etc.
//!
//! Furthermore, many callbacks will receive receive an appropriate Scope object
//! as their first argument, which 'encodes' the the state the isolate is in
//! when the callback is called. E.g. a FunctionCallbackScope implements
//! InIsolate + InContext + (there is an active context) and ToLocal (it acts as
//! a handlescope). HostImportModuleDynamicallyScope would also implement
//! InIsolate + InContext plus EscapeLocal (it doesn't act like a HandleScope,
//! but it lets you safely escape one MaybeLocal which is returned to the
//! caller.
//! InIsolate + and ToLocal (it acts as a HandleScope).
//! HostImportModuleDynamicallyScope would also implement InIsolate plus
//! EscapeLocal (it doesn't act like a HandleScope, but it lets you safely
//! escape one MaybeLocal which is returned to the caller).
//!
//! In a nutshell, that's it.
//!

View file

@ -141,20 +141,28 @@ where
}
}
pub trait InContext: InIsolate {}
impl<'s> InContext for Entered<'s, FunctionCallbackInfo, ()> {}
impl<'s> InContext for Entered<'s, PropertyCallbackInfo, ()> {}
impl<'s, X> InContext for Entered<'s, CallbackScope<X>> {}
impl<'s, P> InContext for Entered<'s, ContextScope, P> {}
impl<'s, P> InContext for Entered<'s, HandleScope, P> where P: InContext {}
impl<'s, P> InContext for Entered<'s, EscapableHandleScope, P> where P: InContext
{}
extern "C" {
fn v8__Isolate__GetCurrentContext(this: *mut Isolate) -> *mut Context;
fn v8__Isolate__GetEnteredOrMicrotaskContext(
this: *mut Isolate,
) -> *mut Context;
}
/// When scope implements this trait, this means that Local handles can be
/// created inside it.
pub trait ToLocal<'s>: InIsolate {
unsafe fn to_local<T>(&mut self, ptr: *mut T) -> Option<Local<'s, T>> {
crate::Local::<'s, T>::from_raw(ptr)
Local::from_raw(ptr)
}
fn get_current_context(&mut self) -> Option<Local<'s, Context>> {
unsafe { Local::from_raw(v8__Isolate__GetCurrentContext(self.isolate())) }
}
fn get_entered_or_microtask_context(&mut self) -> Option<Local<'s, Context>> {
unsafe {
Local::from_raw(v8__Isolate__GetEnteredOrMicrotaskContext(self.isolate()))
}
}
}
@ -162,7 +170,10 @@ impl<'s> ToLocal<'s> for Entered<'s, FunctionCallbackInfo> {}
impl<'s> ToLocal<'s> for Entered<'s, PropertyCallbackInfo> {}
impl<'s, P> ToLocal<'s> for Entered<'s, HandleScope, P> {}
impl<'s, P> ToLocal<'s> for Entered<'s, EscapableHandleScope, P> {}
impl<'s, P> ToLocal<'s> for Entered<'s, ContextScope, P> where P: ToLocal<'s> {}
impl<'s, 'p: 's, P> ToLocal<'p> for Entered<'s, ContextScope, P> where
P: ToLocal<'p>
{
}
pub trait ToLocalOrReturnsLocal<'s>: InIsolate {}
impl<'s, E> ToLocalOrReturnsLocal<'s> for E where E: ToLocal<'s> {}
@ -213,10 +224,33 @@ where
}
}
impl<'s, 'p: 's, S, P> Entered<'s, S, P>
where
Self: ToLocal<'p>,
{
/// Returns the context of the currently running JavaScript, or the context
/// on the top of the stack if no JavaScript is running.
pub fn get_current_context(&mut self) -> Option<Local<'p, Context>> {
<Self as ToLocal<'p>>::get_current_context(self)
}
/// Returns either the last context entered through V8's C++ API, or the
/// context of the currently running microtask while processing microtasks.
/// If a context is entered while executing a microtask, that context is
/// returned.
pub fn get_entered_or_microtask_context(
&mut self,
) -> Option<Local<'p, Context>> {
<Self as ToLocal<'p>>::get_entered_or_microtask_context(self)
}
}
impl<'s, 'p: 's, S, P> Entered<'s, S, P>
where
Self: EscapeLocal<'s, 'p>,
{
/// Pushes the value into the previous scope and returns a handle to it.
/// Cannot be called twice.
pub fn escape<T>(&mut self, local: Local<T>) -> Local<'p, T> {
<Self as EscapeLocal<'s, 'p>>::escape(self, local)
}

View file

@ -5,7 +5,6 @@ use std::ptr::null;
use crate::support::Opaque;
use crate::Boolean;
use crate::Context;
use crate::InContext;
use crate::Integer;
use crate::Local;
use crate::String;
@ -46,7 +45,7 @@ pub struct Script(Opaque);
impl Script {
/// A shorthand for ScriptCompiler::Compile().
pub fn compile<'sc>(
scope: &mut (impl ToLocal<'sc> + InContext),
scope: &mut impl ToLocal<'sc>,
mut context: Local<Context>,
mut source: Local<String>,
origin: Option<&ScriptOrigin>,

View file

@ -69,36 +69,39 @@ extern "C" {
fn v8__Value__StrictEquals(this: &Value, that: &Value) -> bool;
fn v8__Value__SameValue(this: &Value, that: &Value) -> bool;
fn v8__Value__ToBigInt(this: &Value, context: *mut Context) -> *mut BigInt;
fn v8__Value__ToNumber(this: &Value, context: *mut Context) -> *mut Number;
fn v8__Value__ToString(this: &Value, context: *mut Context) -> *mut String;
fn v8__Value__ToBigInt(this: &Value, context: Local<Context>) -> *mut BigInt;
fn v8__Value__ToNumber(this: &Value, context: Local<Context>) -> *mut Number;
fn v8__Value__ToString(this: &Value, context: Local<Context>) -> *mut String;
fn v8__Value__ToDetailString(
this: &Value,
context: *mut Context,
context: Local<Context>,
) -> *mut String;
fn v8__Value__ToObject(this: &Value, context: *mut Context) -> *mut Object;
fn v8__Value__ToInteger(this: &Value, context: *mut Context) -> *mut Integer;
fn v8__Value__ToUint32(this: &Value, context: *mut Context) -> *mut Uint32;
fn v8__Value__ToInt32(this: &Value, context: *mut Context) -> *mut Int32;
fn v8__Value__ToObject(this: &Value, context: Local<Context>) -> *mut Object;
fn v8__Value__ToInteger(
this: &Value,
context: Local<Context>,
) -> *mut Integer;
fn v8__Value__ToUint32(this: &Value, context: Local<Context>) -> *mut Uint32;
fn v8__Value__ToInt32(this: &Value, context: Local<Context>) -> *mut Int32;
fn v8__Value__NumberValue(
this: &Value,
context: *mut Context,
context: Local<Context>,
out: *mut Maybe<f64>,
);
fn v8__Value__IntegerValue(
this: &Value,
context: *mut Context,
context: Local<Context>,
out: *mut Maybe<i64>,
);
fn v8__Value__Uint32Value(
this: &Value,
context: *mut Context,
context: Local<Context>,
out: *mut Maybe<u32>,
);
fn v8__Value__Int32Value(
this: &Value,
context: *mut Context,
context: Local<Context>,
out: *mut Maybe<i32>,
);
}
@ -396,112 +399,112 @@ impl Value {
&self,
scope: &mut impl ToLocal<'sc>,
) -> Option<Local<'sc, BigInt>> {
let isolate = scope.isolate();
let mut context = isolate.get_current_context();
unsafe { Local::from_raw(v8__Value__ToBigInt(self, &mut *context)) }
scope.get_current_context().and_then(|context| unsafe {
Local::from_raw(v8__Value__ToBigInt(self, context))
})
}
pub fn to_number<'sc>(
&self,
scope: &mut impl ToLocal<'sc>,
) -> Option<Local<'sc, Number>> {
let isolate = scope.isolate();
let mut context = isolate.get_current_context();
unsafe { Local::from_raw(v8__Value__ToNumber(self, &mut *context)) }
scope.get_current_context().and_then(|context| unsafe {
Local::from_raw(v8__Value__ToNumber(self, context))
})
}
pub fn to_string<'sc>(
&self,
scope: &mut impl ToLocal<'sc>,
) -> Option<Local<'sc, String>> {
let isolate = scope.isolate();
let mut context = isolate.get_current_context();
unsafe { Local::from_raw(v8__Value__ToString(self, &mut *context)) }
scope.get_current_context().and_then(|context| unsafe {
Local::from_raw(v8__Value__ToString(self, context))
})
}
pub fn to_detail_string<'sc>(
&self,
scope: &mut impl ToLocal<'sc>,
) -> Option<Local<'sc, String>> {
let isolate = scope.isolate();
let mut context = isolate.get_current_context();
unsafe { Local::from_raw(v8__Value__ToDetailString(self, &mut *context)) }
scope.get_current_context().and_then(|context| unsafe {
Local::from_raw(v8__Value__ToDetailString(self, context))
})
}
pub fn to_object<'sc>(
&self,
scope: &mut impl ToLocal<'sc>,
) -> Option<Local<'sc, Object>> {
let isolate = scope.isolate();
let mut context = isolate.get_current_context();
unsafe { Local::from_raw(v8__Value__ToObject(self, &mut *context)) }
scope.get_current_context().and_then(|context| unsafe {
Local::from_raw(v8__Value__ToObject(self, context))
})
}
pub fn to_integer<'sc>(
&self,
scope: &mut impl ToLocal<'sc>,
) -> Option<Local<'sc, Integer>> {
let isolate = scope.isolate();
let mut context = isolate.get_current_context();
unsafe { Local::from_raw(v8__Value__ToInteger(self, &mut *context)) }
scope.get_current_context().and_then(|context| unsafe {
Local::from_raw(v8__Value__ToInteger(self, context))
})
}
pub fn to_uint32<'sc>(
&self,
scope: &mut impl ToLocal<'sc>,
) -> Option<Local<'sc, Uint32>> {
let isolate = scope.isolate();
let mut context = isolate.get_current_context();
unsafe { Local::from_raw(v8__Value__ToUint32(self, &mut *context)) }
scope.get_current_context().and_then(|context| unsafe {
Local::from_raw(v8__Value__ToUint32(self, context))
})
}
pub fn to_int32<'sc>(
&self,
scope: &mut impl ToLocal<'sc>,
) -> Option<Local<'sc, Int32>> {
let isolate = scope.isolate();
let mut context = isolate.get_current_context();
unsafe { Local::from_raw(v8__Value__ToInt32(self, &mut *context)) }
scope.get_current_context().and_then(|context| unsafe {
Local::from_raw(v8__Value__ToInt32(self, context))
})
}
pub fn number_value<'sc>(
&self,
scope: &mut impl ToLocal<'sc>,
) -> Option<f64> {
let isolate = scope.isolate();
let mut context = isolate.get_current_context();
let mut out = Maybe::<f64>::default();
unsafe { v8__Value__NumberValue(self, &mut *context, &mut out) };
out.into()
scope.get_current_context().and_then(|context| unsafe {
let mut out = Maybe::<f64>::default();
v8__Value__NumberValue(self, context, &mut out);
out.into()
})
}
pub fn integer_value<'sc>(
&self,
scope: &mut impl ToLocal<'sc>,
) -> Option<i64> {
let isolate = scope.isolate();
let mut context = isolate.get_current_context();
let mut out = Maybe::<i64>::default();
unsafe { v8__Value__IntegerValue(self, &mut *context, &mut out) };
out.into()
scope.get_current_context().and_then(|context| unsafe {
let mut out = Maybe::<i64>::default();
v8__Value__IntegerValue(self, context, &mut out);
out.into()
})
}
pub fn uint32_value<'sc>(
&self,
scope: &mut impl ToLocal<'sc>,
) -> Option<u32> {
let isolate = scope.isolate();
let mut context = isolate.get_current_context();
let mut out = Maybe::<u32>::default();
unsafe { v8__Value__Uint32Value(self, &mut *context, &mut out) };
out.into()
scope.get_current_context().and_then(|context| unsafe {
let mut out = Maybe::<u32>::default();
v8__Value__Uint32Value(self, context, &mut out);
out.into()
})
}
pub fn int32_value<'sc>(&self, scope: &mut impl ToLocal<'sc>) -> Option<i32> {
let isolate = scope.isolate();
let mut context = isolate.get_current_context();
let mut out = Maybe::<i32>::default();
unsafe { v8__Value__Int32Value(self, &mut *context, &mut out) };
out.into()
scope.get_current_context().and_then(|context| unsafe {
let mut out = Maybe::<i32>::default();
v8__Value__Int32Value(self, context, &mut out);
out.into()
})
}
}

View file

@ -14,5 +14,5 @@ error[E0277]: the trait bound `rusty_v8::scope::Entered<'_, rusty_v8::scope::Cal
<rusty_v8::scope::Entered<'s, rusty_v8::function::PropertyCallbackInfo> as rusty_v8::scope_traits::ToLocal<'s>>
<rusty_v8::scope::Entered<'s, rusty_v8::handle_scope::EscapableHandleScope, P> as rusty_v8::scope_traits::ToLocal<'s>>
<rusty_v8::scope::Entered<'s, rusty_v8::handle_scope::HandleScope, P> as rusty_v8::scope_traits::ToLocal<'s>>
<rusty_v8::scope::Entered<'s, rusty_v8::scope::ContextScope, P> as rusty_v8::scope_traits::ToLocal<'s>>
<rusty_v8::scope::Entered<'s, rusty_v8::scope::ContextScope, P> as rusty_v8::scope_traits::ToLocal<'p>>
= note: required because of the requirements on the impl of `rusty_v8::scope_traits::ToLocalOrReturnsLocal<'_>` for `rusty_v8::scope::Entered<'_, rusty_v8::scope::CallbackScope>`

View file

@ -226,6 +226,32 @@ fn escapable_handle_scope() {
}
}
#[test]
fn context_scope() {
let _setup_guard = setup();
let mut params = v8::Isolate::create_params();
params.set_array_buffer_allocator(v8::new_default_allocator());
let mut isolate = v8::Isolate::new(params);
let mut hs = v8::HandleScope::new(&mut isolate);
let scope = hs.enter();
assert!(scope.get_current_context().is_none());
assert!(scope.get_entered_or_microtask_context().is_none());
{
let context = v8::Context::new(scope);
let mut cs = v8::ContextScope::new(scope, context);
let scope = cs.enter();
scope.get_current_context().unwrap();
scope.get_entered_or_microtask_context().unwrap();
}
assert!(scope.get_current_context().is_none());
assert!(scope.get_entered_or_microtask_context().is_none());
}
#[test]
fn microtasks() {
let _setup_guard = setup();
@ -378,7 +404,7 @@ fn v8_str<'sc>(
}
fn eval<'sc>(
scope: &mut (impl v8::ToLocal<'sc> + v8::InContext),
scope: &mut impl v8::ToLocal<'sc>,
context: v8::Local<v8::Context>,
code: &'static str,
) -> Option<v8::Local<'sc, v8::Value>> {
@ -601,7 +627,7 @@ fn add_message_listener() {
let mut sc = v8::CallbackScope::new(message);
let mut sc = v8::HandleScope::new(sc.enter());
let scope = sc.enter();
let context = scope.isolate().get_current_context();
let context = scope.get_current_context().unwrap();
let message_str = message.get(scope);
assert_eq!(message_str.to_rust_string_lossy(scope), "Uncaught foo");
assert_eq!(Some(1), message.get_line_number(context));
@ -1135,7 +1161,7 @@ fn object_set_accessor() {
key: v8::Local<v8::Name>,
args: v8::PropertyCallbackArguments,
mut rv: v8::ReturnValue| {
let context = scope.isolate().get_current_context();
let context = scope.get_current_context().unwrap();
let this = args.this();
let expected_key = v8::String::new(scope, "getter_key").unwrap();