mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-12-27 17:49:12 -05:00
940 lines
28 KiB
Rust
940 lines
28 KiB
Rust
use std::convert::TryFrom;
|
|
use std::marker::PhantomData;
|
|
use std::ptr::null;
|
|
use std::ptr::NonNull;
|
|
|
|
use crate::scope::CallbackScope;
|
|
use crate::script_compiler::CachedData;
|
|
use crate::support::MapFnFrom;
|
|
use crate::support::MapFnTo;
|
|
use crate::support::ToCFn;
|
|
use crate::support::UnitType;
|
|
use crate::support::{int, Opaque};
|
|
use crate::Context;
|
|
use crate::Function;
|
|
use crate::HandleScope;
|
|
use crate::Isolate;
|
|
use crate::Local;
|
|
use crate::Name;
|
|
use crate::Object;
|
|
use crate::PropertyDescriptor;
|
|
use crate::Signature;
|
|
use crate::String;
|
|
use crate::UniqueRef;
|
|
use crate::Value;
|
|
use crate::{undefined, ScriptOrigin};
|
|
|
|
extern "C" {
|
|
fn v8__Function__New(
|
|
context: *const Context,
|
|
callback: FunctionCallback,
|
|
data_or_null: *const Value,
|
|
length: i32,
|
|
constructor_behavior: ConstructorBehavior,
|
|
side_effect_type: SideEffectType,
|
|
) -> *const Function;
|
|
fn v8__Function__Call(
|
|
this: *const Function,
|
|
context: *const Context,
|
|
recv: *const Value,
|
|
argc: int,
|
|
argv: *const *const Value,
|
|
) -> *const Value;
|
|
fn v8__Function__NewInstance(
|
|
this: *const Function,
|
|
context: *const Context,
|
|
argc: int,
|
|
argv: *const *const Value,
|
|
) -> *const Object;
|
|
fn v8__Function__GetName(this: *const Function) -> *const String;
|
|
fn v8__Function__SetName(this: *const Function, name: *const String);
|
|
fn v8__Function__GetScriptColumnNumber(this: *const Function) -> int;
|
|
fn v8__Function__GetScriptLineNumber(this: *const Function) -> int;
|
|
fn v8__Function__ScriptId(this: *const Function) -> int;
|
|
fn v8__Function__GetScriptOrigin(
|
|
this: *const Function,
|
|
) -> *const ScriptOrigin<'static>;
|
|
|
|
fn v8__Function__CreateCodeCache(
|
|
script: *const Function,
|
|
) -> *mut CachedData<'static>;
|
|
|
|
static v8__FunctionCallbackInfo__kArgsLength: int;
|
|
|
|
static v8__PropertyCallbackInfo__kArgsLength: int;
|
|
|
|
fn v8__PropertyCallbackInfo__ShouldThrowOnError(
|
|
this: *const PropertyCallbackInfo,
|
|
) -> bool;
|
|
|
|
fn v8__ReturnValue__Set(this: *mut ReturnValue, value: *const Value);
|
|
fn v8__ReturnValue__Set__Bool(this: *mut ReturnValue, value: bool);
|
|
fn v8__ReturnValue__Set__Int32(this: *mut ReturnValue, value: i32);
|
|
fn v8__ReturnValue__Set__Uint32(this: *mut ReturnValue, value: u32);
|
|
fn v8__ReturnValue__Set__Double(this: *mut ReturnValue, value: f64);
|
|
fn v8__ReturnValue__SetNull(this: *mut ReturnValue);
|
|
fn v8__ReturnValue__SetUndefined(this: *mut ReturnValue);
|
|
fn v8__ReturnValue__SetEmptyString(this: *mut ReturnValue);
|
|
|
|
fn v8__ReturnValue__Get(this: *const ReturnValue) -> *const Value;
|
|
}
|
|
|
|
// Ad-libbed - V8 does not document ConstructorBehavior.
|
|
/// ConstructorBehavior::Allow creates a regular API function.
|
|
///
|
|
/// ConstructorBehavior::Throw creates a "concise" API function, a function
|
|
/// without a ".prototype" property, that is somewhat faster to create and has
|
|
/// a smaller footprint. Functionally equivalent to ConstructorBehavior::Allow
|
|
/// followed by a call to FunctionTemplate::RemovePrototype().
|
|
#[repr(C)]
|
|
pub enum ConstructorBehavior {
|
|
Throw,
|
|
Allow,
|
|
}
|
|
|
|
/// Options for marking whether callbacks may trigger JS-observable side
|
|
/// effects. Side-effect-free callbacks are allowlisted during debug evaluation
|
|
/// with throwOnSideEffect. It applies when calling a Function,
|
|
/// FunctionTemplate, or an Accessor callback. For Interceptors, please see
|
|
/// PropertyHandlerFlags's kHasNoSideEffect.
|
|
/// Callbacks that only cause side effects to the receiver are allowlisted if
|
|
/// invoked on receiver objects that are created within the same debug-evaluate
|
|
/// call, as these objects are temporary and the side effect does not escape.
|
|
#[repr(C)]
|
|
pub enum SideEffectType {
|
|
HasSideEffect,
|
|
HasNoSideEffect,
|
|
HasSideEffectToReceiver,
|
|
}
|
|
|
|
// Note: the 'cb lifetime is required because the ReturnValue object must not
|
|
// outlive the FunctionCallbackInfo/PropertyCallbackInfo object from which it
|
|
// is derived.
|
|
#[repr(C)]
|
|
#[derive(Debug)]
|
|
pub struct ReturnValue<'cb>(NonNull<Value>, PhantomData<&'cb ()>);
|
|
|
|
/// In V8 ReturnValue<> has a type parameter, but
|
|
/// it turns out that in most of the APIs it's ReturnValue<Value>
|
|
/// and for our purposes we currently don't need
|
|
/// other types. So for now it's a simplified version.
|
|
impl<'cb> ReturnValue<'cb> {
|
|
#[inline(always)]
|
|
pub fn from_function_callback_info(info: &'cb FunctionCallbackInfo) -> Self {
|
|
let nn = info.get_return_value_non_null();
|
|
Self(nn, PhantomData)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn from_property_callback_info(info: &'cb PropertyCallbackInfo) -> Self {
|
|
let nn = info.get_return_value_non_null();
|
|
Self(nn, PhantomData)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn set(&mut self, value: Local<Value>) {
|
|
unsafe { v8__ReturnValue__Set(&mut *self, &*value) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn set_bool(&mut self, value: bool) {
|
|
unsafe { v8__ReturnValue__Set__Bool(&mut *self, value) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn set_int32(&mut self, value: i32) {
|
|
unsafe { v8__ReturnValue__Set__Int32(&mut *self, value) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn set_uint32(&mut self, value: u32) {
|
|
unsafe { v8__ReturnValue__Set__Uint32(&mut *self, value) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn set_double(&mut self, value: f64) {
|
|
unsafe { v8__ReturnValue__Set__Double(&mut *self, value) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn set_null(&mut self) {
|
|
unsafe { v8__ReturnValue__SetNull(&mut *self) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn set_undefined(&mut self) {
|
|
unsafe { v8__ReturnValue__SetUndefined(&mut *self) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn set_empty_string(&mut self) {
|
|
unsafe { v8__ReturnValue__SetEmptyString(&mut *self) }
|
|
}
|
|
|
|
/// Getter. Creates a new Local<> so it comes with a certain performance
|
|
/// hit. If the ReturnValue was not yet set, this will return the undefined
|
|
/// value.
|
|
#[inline(always)]
|
|
pub fn get<'s>(&self, scope: &mut HandleScope<'s>) -> Local<'s, Value> {
|
|
unsafe { scope.cast_local(|_| v8__ReturnValue__Get(self)) }.unwrap()
|
|
}
|
|
}
|
|
|
|
/// The argument information given to function call callbacks. This
|
|
/// class provides access to information about the context of the call,
|
|
/// including the receiver, the number and values of arguments, and
|
|
/// the holder of the function.
|
|
#[repr(C)]
|
|
#[derive(Debug)]
|
|
pub struct FunctionCallbackInfo {
|
|
// The layout of this struct must match that of `class FunctionCallbackInfo`
|
|
// as defined in v8.h.
|
|
implicit_args: *mut *const Opaque,
|
|
values: *mut *const Opaque,
|
|
length: int,
|
|
}
|
|
|
|
// These constants must match those defined on `class FunctionCallbackInfo` in
|
|
// v8-function-callback.h.
|
|
#[allow(dead_code, non_upper_case_globals)]
|
|
impl FunctionCallbackInfo {
|
|
const kHolderIndex: i32 = 0;
|
|
const kIsolateIndex: i32 = 1;
|
|
const kReturnValueDefaultValueIndex: i32 = 2;
|
|
const kReturnValueIndex: i32 = 3;
|
|
const kDataIndex: i32 = 4;
|
|
const kNewTargetIndex: i32 = 5;
|
|
const kArgsLength: i32 = 6;
|
|
}
|
|
|
|
impl FunctionCallbackInfo {
|
|
#[inline(always)]
|
|
pub(crate) fn get_isolate_ptr(&self) -> *mut Isolate {
|
|
let arg_nn =
|
|
self.get_implicit_arg_non_null::<*mut Isolate>(Self::kIsolateIndex);
|
|
*unsafe { arg_nn.as_ref() }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn get_return_value_non_null(&self) -> NonNull<Value> {
|
|
self.get_implicit_arg_non_null::<Value>(Self::kReturnValueIndex)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn holder(&self) -> Local<Object> {
|
|
unsafe { self.get_implicit_arg_local(Self::kHolderIndex) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn new_target(&self) -> Local<Value> {
|
|
unsafe { self.get_implicit_arg_local(Self::kNewTargetIndex) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn this(&self) -> Local<Object> {
|
|
unsafe { self.get_arg_local(-1) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn data(&self) -> Local<Value> {
|
|
unsafe { self.get_implicit_arg_local(Self::kDataIndex) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn length(&self) -> i32 {
|
|
self.length
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn get(&self, index: int) -> Local<Value> {
|
|
if index >= 0 && index < self.length {
|
|
unsafe { self.get_arg_local(index) }
|
|
} else {
|
|
let isolate = unsafe { &mut *self.get_isolate_ptr() };
|
|
undefined(isolate).into()
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn get_implicit_arg_non_null<T>(&self, index: i32) -> NonNull<T> {
|
|
// In debug builds, check that `FunctionCallbackInfo::kArgsLength` matches
|
|
// the C++ definition. Unfortunately we can't check the other constants
|
|
// because they are declared protected in the C++ header.
|
|
debug_assert_eq!(
|
|
unsafe { v8__FunctionCallbackInfo__kArgsLength },
|
|
Self::kArgsLength
|
|
);
|
|
// Assert that `index` is in bounds.
|
|
assert!(index >= 0);
|
|
assert!(index < Self::kArgsLength);
|
|
// Compute the address of the implicit argument and cast to `NonNull<T>`.
|
|
let ptr = unsafe { self.implicit_args.offset(index as isize) as *mut T };
|
|
debug_assert!(!ptr.is_null());
|
|
unsafe { NonNull::new_unchecked(ptr) }
|
|
}
|
|
|
|
// SAFETY: caller must guarantee that the implicit argument at `index`
|
|
// contains a valid V8 handle.
|
|
#[inline(always)]
|
|
unsafe fn get_implicit_arg_local<T>(&self, index: i32) -> Local<T> {
|
|
let nn = self.get_implicit_arg_non_null::<T>(index);
|
|
Local::from_non_null(nn)
|
|
}
|
|
|
|
// SAFETY: caller must guarantee that the `index` value lies between -1 and
|
|
// self.length.
|
|
#[inline(always)]
|
|
unsafe fn get_arg_local<T>(&self, index: i32) -> Local<T> {
|
|
let ptr = self.values.offset(index as _) as *mut T;
|
|
debug_assert!(!ptr.is_null());
|
|
let nn = NonNull::new_unchecked(ptr);
|
|
Local::from_non_null(nn)
|
|
}
|
|
}
|
|
|
|
/// The information passed to a property callback about the context
|
|
/// of the property access.
|
|
#[repr(C)]
|
|
#[derive(Debug)]
|
|
pub struct PropertyCallbackInfo {
|
|
// The layout of this struct must match that of `class PropertyCallbackInfo`
|
|
// as defined in v8.h.
|
|
args: *mut *const Opaque,
|
|
}
|
|
|
|
// These constants must match those defined on `class PropertyCallbackInfo` in
|
|
// v8-function-callback.h.
|
|
#[allow(dead_code, non_upper_case_globals)]
|
|
impl PropertyCallbackInfo {
|
|
const kShouldThrowOnErrorIndex: i32 = 0;
|
|
const kHolderIndex: i32 = 1;
|
|
const kIsolateIndex: i32 = 2;
|
|
const kReturnValueDefaultValueIndex: i32 = 3;
|
|
const kReturnValueIndex: i32 = 4;
|
|
const kDataIndex: i32 = 5;
|
|
const kThisIndex: i32 = 6;
|
|
const kArgsLength: i32 = 7;
|
|
}
|
|
|
|
impl PropertyCallbackInfo {
|
|
#[inline(always)]
|
|
pub(crate) fn get_isolate_ptr(&self) -> *mut Isolate {
|
|
let arg_nn = self.get_arg_non_null::<*mut Isolate>(Self::kIsolateIndex);
|
|
*unsafe { arg_nn.as_ref() }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn get_return_value_non_null(&self) -> NonNull<Value> {
|
|
self.get_arg_non_null::<Value>(Self::kReturnValueIndex)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn holder(&self) -> Local<Object> {
|
|
unsafe { self.get_arg_local(Self::kHolderIndex) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn this(&self) -> Local<Object> {
|
|
unsafe { self.get_arg_local(Self::kThisIndex) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn data(&self) -> Local<Value> {
|
|
unsafe { self.get_arg_local(Self::kDataIndex) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(crate) fn should_throw_on_error(&self) -> bool {
|
|
unsafe { v8__PropertyCallbackInfo__ShouldThrowOnError(self) }
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn get_arg_non_null<T>(&self, index: i32) -> NonNull<T> {
|
|
// In debug builds, verify that `PropertyCallbackInfo::kArgsLength` matches
|
|
// the C++ definition. Unfortunately we can't check the other constants
|
|
// because they are declared protected in the C++ header.
|
|
debug_assert_eq!(
|
|
unsafe { v8__PropertyCallbackInfo__kArgsLength },
|
|
Self::kArgsLength
|
|
);
|
|
// Assert that `index` is in bounds.
|
|
assert!(index >= 0);
|
|
assert!(index < Self::kArgsLength);
|
|
// Compute the address of the implicit argument and cast to `NonNull<T>`.
|
|
let ptr = unsafe { self.args.offset(index as isize) as *mut T };
|
|
debug_assert!(!ptr.is_null());
|
|
unsafe { NonNull::new_unchecked(ptr) }
|
|
}
|
|
|
|
// SAFETY: caller must guarantee that the implicit argument at `index`
|
|
// contains a valid V8 handle.
|
|
#[inline(always)]
|
|
unsafe fn get_arg_local<T>(&self, index: i32) -> Local<T> {
|
|
let nn = self.get_arg_non_null::<T>(index);
|
|
Local::from_non_null(nn)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct FunctionCallbackArguments<'s>(&'s FunctionCallbackInfo);
|
|
|
|
impl<'s> FunctionCallbackArguments<'s> {
|
|
#[inline(always)]
|
|
pub fn from_function_callback_info(info: &'s FunctionCallbackInfo) -> Self {
|
|
Self(info)
|
|
}
|
|
|
|
/// SAFETY: caller must guarantee that no other references to the isolate are
|
|
/// accessible. Specifically, if an open CallbackScope or HandleScope exists
|
|
/// in the current function, `FunctionCallbackArguments::get_isolate()` should
|
|
/// not be called.
|
|
#[inline(always)]
|
|
pub unsafe fn get_isolate(&mut self) -> &mut Isolate {
|
|
&mut *self.0.get_isolate_ptr()
|
|
}
|
|
|
|
/// If the callback was created without a Signature, this is the same value as
|
|
/// `this()`. If there is a signature, and the signature didn't match `this()`
|
|
/// but one of its hidden prototypes, this will be the respective hidden
|
|
/// prototype.
|
|
///
|
|
/// Note that this is not the prototype of `this()` on which the accessor
|
|
/// referencing this callback was found (which in V8 internally is often
|
|
/// referred to as holder [sic]).
|
|
#[inline(always)]
|
|
pub fn holder(&self) -> Local<'s, Object> {
|
|
self.0.holder()
|
|
}
|
|
|
|
/// For construct calls, this returns the "new.target" value.
|
|
#[inline(always)]
|
|
pub fn new_target(&self) -> Local<'s, Value> {
|
|
self.0.new_target()
|
|
}
|
|
|
|
/// Returns the receiver. This corresponds to the "this" value.
|
|
#[inline(always)]
|
|
pub fn this(&self) -> Local<'s, Object> {
|
|
self.0.this()
|
|
}
|
|
|
|
/// Returns the data argument specified when creating the callback.
|
|
#[inline(always)]
|
|
pub fn data(&self) -> Local<'s, Value> {
|
|
self.0.data()
|
|
}
|
|
|
|
/// The number of available arguments.
|
|
#[inline(always)]
|
|
pub fn length(&self) -> int {
|
|
self.0.length()
|
|
}
|
|
|
|
/// Accessor for the available arguments. Returns `undefined` if the index is
|
|
/// out of bounds.
|
|
#[inline(always)]
|
|
pub fn get(&self, i: int) -> Local<'s, Value> {
|
|
self.0.get(i)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct PropertyCallbackArguments<'s>(&'s PropertyCallbackInfo);
|
|
|
|
impl<'s> PropertyCallbackArguments<'s> {
|
|
#[inline(always)]
|
|
pub(crate) fn from_property_callback_info(
|
|
info: &'s PropertyCallbackInfo,
|
|
) -> Self {
|
|
Self(info)
|
|
}
|
|
|
|
/// Returns he object in the prototype chain of the receiver that has the
|
|
/// interceptor. Suppose you have `x` and its prototype is `y`, and `y` has an
|
|
/// interceptor. Then `info.this()` is `x` and `info.holder()` is `y`. The
|
|
/// `holder()` could be a hidden object (the global object, rather than the
|
|
/// global proxy).
|
|
///
|
|
/// For security reasons, do not pass the object back into the runtime.
|
|
#[inline(always)]
|
|
pub fn holder(&self) -> Local<'s, Object> {
|
|
self.0.holder()
|
|
}
|
|
|
|
/// Returns the receiver. In many cases, this is the object on which the
|
|
/// property access was intercepted. When using
|
|
/// `Reflect.get`, `Function.prototype.call`, or similar functions, it is the
|
|
/// object passed in as receiver or thisArg.
|
|
///
|
|
/// ```c++
|
|
/// void GetterCallback(Local<Name> name,
|
|
/// const v8::PropertyCallbackInfo<v8::Value>& info) {
|
|
/// auto context = info.GetIsolate()->GetCurrentContext();
|
|
///
|
|
/// v8::Local<v8::Value> a_this =
|
|
/// info.This()
|
|
/// ->GetRealNamedProperty(context, v8_str("a"))
|
|
/// .ToLocalChecked();
|
|
/// v8::Local<v8::Value> a_holder =
|
|
/// info.Holder()
|
|
/// ->GetRealNamedProperty(context, v8_str("a"))
|
|
/// .ToLocalChecked();
|
|
///
|
|
/// CHECK(v8_str("r")->Equals(context, a_this).FromJust());
|
|
/// CHECK(v8_str("obj")->Equals(context, a_holder).FromJust());
|
|
///
|
|
/// info.GetReturnValue().Set(name);
|
|
/// }
|
|
///
|
|
/// v8::Local<v8::FunctionTemplate> templ =
|
|
/// v8::FunctionTemplate::New(isolate);
|
|
/// templ->InstanceTemplate()->SetHandler(
|
|
/// v8::NamedPropertyHandlerConfiguration(GetterCallback));
|
|
/// LocalContext env;
|
|
/// env->Global()
|
|
/// ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
|
|
/// .ToLocalChecked()
|
|
/// ->NewInstance(env.local())
|
|
/// .ToLocalChecked())
|
|
/// .FromJust();
|
|
///
|
|
/// CompileRun("obj.a = 'obj'; var r = {a: 'r'}; Reflect.get(obj, 'x', r)");
|
|
/// ```
|
|
#[inline(always)]
|
|
pub fn this(&self) -> Local<'s, Object> {
|
|
self.0.this()
|
|
}
|
|
|
|
/// Returns the data set in the configuration, i.e., in
|
|
/// `NamedPropertyHandlerConfiguration` or
|
|
/// `IndexedPropertyHandlerConfiguration.`
|
|
#[inline(always)]
|
|
pub fn data(&self) -> Local<'s, Value> {
|
|
self.0.data()
|
|
}
|
|
|
|
/// Returns `true` if the intercepted function should throw if an error
|
|
/// occurs. Usually, `true` corresponds to `'use strict'`.
|
|
///
|
|
/// Always `false` when intercepting `Reflect.set()` independent of the
|
|
/// language mode.
|
|
#[inline(always)]
|
|
pub fn should_throw_on_error(&self) -> bool {
|
|
self.0.should_throw_on_error()
|
|
}
|
|
}
|
|
|
|
pub type FunctionCallback = extern "C" fn(*const FunctionCallbackInfo);
|
|
|
|
impl<F> MapFnFrom<F> for FunctionCallback
|
|
where
|
|
F: UnitType
|
|
+ for<'s> Fn(&mut HandleScope<'s>, FunctionCallbackArguments<'s>, ReturnValue),
|
|
{
|
|
fn mapping() -> Self {
|
|
let f = |info: *const FunctionCallbackInfo| {
|
|
let info = unsafe { &*info };
|
|
let scope = &mut unsafe { CallbackScope::new(info) };
|
|
let args = FunctionCallbackArguments::from_function_callback_info(info);
|
|
let rv = ReturnValue::from_function_callback_info(info);
|
|
(F::get())(scope, args, rv);
|
|
};
|
|
f.to_c_fn()
|
|
}
|
|
}
|
|
|
|
pub(crate) type NamedGetterCallback<'s> =
|
|
extern "C" fn(Local<'s, Name>, *const PropertyCallbackInfo);
|
|
|
|
impl<F> MapFnFrom<F> for NamedGetterCallback<'_>
|
|
where
|
|
F: UnitType
|
|
+ for<'s> Fn(
|
|
&mut HandleScope<'s>,
|
|
Local<'s, Name>,
|
|
PropertyCallbackArguments<'s>,
|
|
ReturnValue,
|
|
),
|
|
{
|
|
fn mapping() -> Self {
|
|
let f = |key: Local<Name>, info: *const PropertyCallbackInfo| {
|
|
let info = unsafe { &*info };
|
|
let scope = &mut unsafe { CallbackScope::new(info) };
|
|
let args = PropertyCallbackArguments::from_property_callback_info(info);
|
|
let rv = ReturnValue::from_property_callback_info(info);
|
|
(F::get())(scope, key, args, rv);
|
|
};
|
|
f.to_c_fn()
|
|
}
|
|
}
|
|
|
|
pub(crate) type NamedSetterCallback<'s> =
|
|
extern "C" fn(Local<'s, Name>, Local<'s, Value>, *const PropertyCallbackInfo);
|
|
|
|
impl<F> MapFnFrom<F> for NamedSetterCallback<'_>
|
|
where
|
|
F: UnitType
|
|
+ for<'s> Fn(
|
|
&mut HandleScope<'s>,
|
|
Local<'s, Name>,
|
|
Local<'s, Value>,
|
|
PropertyCallbackArguments<'s>,
|
|
ReturnValue,
|
|
),
|
|
{
|
|
fn mapping() -> Self {
|
|
let f = |key: Local<Name>,
|
|
value: Local<Value>,
|
|
info: *const PropertyCallbackInfo| {
|
|
let info = unsafe { &*info };
|
|
let scope = &mut unsafe { CallbackScope::new(info) };
|
|
let args = PropertyCallbackArguments::from_property_callback_info(info);
|
|
let rv = ReturnValue::from_property_callback_info(info);
|
|
(F::get())(scope, key, value, args, rv);
|
|
};
|
|
f.to_c_fn()
|
|
}
|
|
}
|
|
|
|
// Should return an Array in Return Value
|
|
pub(crate) type PropertyEnumeratorCallback<'s> =
|
|
extern "C" fn(*const PropertyCallbackInfo);
|
|
|
|
impl<F> MapFnFrom<F> for PropertyEnumeratorCallback<'_>
|
|
where
|
|
F: UnitType
|
|
+ for<'s> Fn(&mut HandleScope<'s>, PropertyCallbackArguments<'s>, ReturnValue),
|
|
{
|
|
fn mapping() -> Self {
|
|
let f = |info: *const PropertyCallbackInfo| {
|
|
let info = unsafe { &*info };
|
|
let scope = &mut unsafe { CallbackScope::new(info) };
|
|
let args = PropertyCallbackArguments::from_property_callback_info(info);
|
|
let rv = ReturnValue::from_property_callback_info(info);
|
|
(F::get())(scope, args, rv);
|
|
};
|
|
f.to_c_fn()
|
|
}
|
|
}
|
|
|
|
pub(crate) type NamedDefinerCallback<'s> = extern "C" fn(
|
|
Local<'s, Name>,
|
|
*const PropertyDescriptor,
|
|
*const PropertyCallbackInfo,
|
|
);
|
|
|
|
impl<F> MapFnFrom<F> for NamedDefinerCallback<'_>
|
|
where
|
|
F: UnitType
|
|
+ for<'s> Fn(
|
|
&mut HandleScope<'s>,
|
|
Local<'s, Name>,
|
|
&PropertyDescriptor,
|
|
PropertyCallbackArguments<'s>,
|
|
ReturnValue,
|
|
),
|
|
{
|
|
fn mapping() -> Self {
|
|
let f = |key: Local<Name>,
|
|
desc: *const PropertyDescriptor,
|
|
info: *const PropertyCallbackInfo| {
|
|
let info = unsafe { &*info };
|
|
let scope = &mut unsafe { CallbackScope::new(info) };
|
|
let args = PropertyCallbackArguments::from_property_callback_info(info);
|
|
let desc = unsafe { &*desc };
|
|
let rv = ReturnValue::from_property_callback_info(info);
|
|
(F::get())(scope, key, desc, args, rv);
|
|
};
|
|
f.to_c_fn()
|
|
}
|
|
}
|
|
|
|
pub(crate) type IndexedGetterCallback<'s> =
|
|
extern "C" fn(u32, *const PropertyCallbackInfo);
|
|
|
|
impl<F> MapFnFrom<F> for IndexedGetterCallback<'_>
|
|
where
|
|
F: UnitType
|
|
+ for<'s> Fn(
|
|
&mut HandleScope<'s>,
|
|
u32,
|
|
PropertyCallbackArguments<'s>,
|
|
ReturnValue,
|
|
),
|
|
{
|
|
fn mapping() -> Self {
|
|
let f = |index: u32, info: *const PropertyCallbackInfo| {
|
|
let info = unsafe { &*info };
|
|
let scope = &mut unsafe { CallbackScope::new(info) };
|
|
let args = PropertyCallbackArguments::from_property_callback_info(info);
|
|
let rv = ReturnValue::from_property_callback_info(info);
|
|
(F::get())(scope, index, args, rv);
|
|
};
|
|
f.to_c_fn()
|
|
}
|
|
}
|
|
|
|
pub(crate) type IndexedSetterCallback<'s> =
|
|
extern "C" fn(u32, Local<'s, Value>, *const PropertyCallbackInfo);
|
|
|
|
impl<F> MapFnFrom<F> for IndexedSetterCallback<'_>
|
|
where
|
|
F: UnitType
|
|
+ for<'s> Fn(
|
|
&mut HandleScope<'s>,
|
|
u32,
|
|
Local<'s, Value>,
|
|
PropertyCallbackArguments<'s>,
|
|
ReturnValue,
|
|
),
|
|
{
|
|
fn mapping() -> Self {
|
|
let f =
|
|
|index: u32, value: Local<Value>, info: *const PropertyCallbackInfo| {
|
|
let info = unsafe { &*info };
|
|
let scope = &mut unsafe { CallbackScope::new(info) };
|
|
let args = PropertyCallbackArguments::from_property_callback_info(info);
|
|
let rv = ReturnValue::from_property_callback_info(info);
|
|
(F::get())(scope, index, value, args, rv);
|
|
};
|
|
f.to_c_fn()
|
|
}
|
|
}
|
|
|
|
pub(crate) type IndexedDefinerCallback<'s> =
|
|
extern "C" fn(u32, *const PropertyDescriptor, *const PropertyCallbackInfo);
|
|
|
|
impl<F> MapFnFrom<F> for IndexedDefinerCallback<'_>
|
|
where
|
|
F: UnitType
|
|
+ for<'s> Fn(
|
|
&mut HandleScope<'s>,
|
|
u32,
|
|
&PropertyDescriptor,
|
|
PropertyCallbackArguments<'s>,
|
|
ReturnValue,
|
|
),
|
|
{
|
|
fn mapping() -> Self {
|
|
let f = |index: u32,
|
|
desc: *const PropertyDescriptor,
|
|
info: *const PropertyCallbackInfo| {
|
|
let info = unsafe { &*info };
|
|
let scope = &mut unsafe { CallbackScope::new(info) };
|
|
let args = PropertyCallbackArguments::from_property_callback_info(info);
|
|
let rv = ReturnValue::from_property_callback_info(info);
|
|
let desc = unsafe { &*desc };
|
|
(F::get())(scope, index, desc, args, rv);
|
|
};
|
|
f.to_c_fn()
|
|
}
|
|
}
|
|
|
|
/// A builder to construct the properties of a Function or FunctionTemplate.
|
|
pub struct FunctionBuilder<'s, T> {
|
|
pub(crate) callback: FunctionCallback,
|
|
pub(crate) data: Option<Local<'s, Value>>,
|
|
pub(crate) signature: Option<Local<'s, Signature>>,
|
|
pub(crate) length: i32,
|
|
pub(crate) constructor_behavior: ConstructorBehavior,
|
|
pub(crate) side_effect_type: SideEffectType,
|
|
phantom: PhantomData<T>,
|
|
}
|
|
|
|
impl<'s, T> FunctionBuilder<'s, T> {
|
|
/// Create a new FunctionBuilder.
|
|
#[inline(always)]
|
|
pub fn new(callback: impl MapFnTo<FunctionCallback>) -> Self {
|
|
Self::new_raw(callback.map_fn_to())
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn new_raw(callback: FunctionCallback) -> Self {
|
|
Self {
|
|
callback,
|
|
data: None,
|
|
signature: None,
|
|
length: 0,
|
|
constructor_behavior: ConstructorBehavior::Allow,
|
|
side_effect_type: SideEffectType::HasSideEffect,
|
|
phantom: PhantomData,
|
|
}
|
|
}
|
|
|
|
/// Set the associated data. The default is no associated data.
|
|
#[inline(always)]
|
|
pub fn data(mut self, data: Local<'s, Value>) -> Self {
|
|
self.data = Some(data);
|
|
self
|
|
}
|
|
|
|
/// Set the function length. The default is 0.
|
|
#[inline(always)]
|
|
pub fn length(mut self, length: i32) -> Self {
|
|
self.length = length;
|
|
self
|
|
}
|
|
|
|
/// Set the constructor behavior. The default is ConstructorBehavior::Allow.
|
|
#[inline(always)]
|
|
pub fn constructor_behavior(
|
|
mut self,
|
|
constructor_behavior: ConstructorBehavior,
|
|
) -> Self {
|
|
self.constructor_behavior = constructor_behavior;
|
|
self
|
|
}
|
|
|
|
/// Set the side effect type. The default is SideEffectType::HasSideEffect.
|
|
#[inline(always)]
|
|
pub fn side_effect_type(mut self, side_effect_type: SideEffectType) -> Self {
|
|
self.side_effect_type = side_effect_type;
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<'s> FunctionBuilder<'s, Function> {
|
|
/// Create the function in the current execution context.
|
|
#[inline(always)]
|
|
pub fn build(
|
|
self,
|
|
scope: &mut HandleScope<'s>,
|
|
) -> Option<Local<'s, Function>> {
|
|
unsafe {
|
|
scope.cast_local(|sd| {
|
|
v8__Function__New(
|
|
sd.get_current_context(),
|
|
self.callback,
|
|
self.data.map_or_else(null, |p| &*p),
|
|
self.length,
|
|
self.constructor_behavior,
|
|
self.side_effect_type,
|
|
)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Function {
|
|
/// Create a FunctionBuilder to configure a Function.
|
|
/// This is the same as FunctionBuilder::<Function>::new().
|
|
#[inline(always)]
|
|
pub fn builder<'s>(
|
|
callback: impl MapFnTo<FunctionCallback>,
|
|
) -> FunctionBuilder<'s, Self> {
|
|
FunctionBuilder::new(callback)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn builder_raw<'s>(
|
|
callback: FunctionCallback,
|
|
) -> FunctionBuilder<'s, Self> {
|
|
FunctionBuilder::new_raw(callback)
|
|
}
|
|
|
|
/// Create a function in the current execution context
|
|
/// for a given FunctionCallback.
|
|
#[inline(always)]
|
|
pub fn new<'s>(
|
|
scope: &mut HandleScope<'s>,
|
|
callback: impl MapFnTo<FunctionCallback>,
|
|
) -> Option<Local<'s, Function>> {
|
|
Self::builder(callback).build(scope)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn new_raw<'s>(
|
|
scope: &mut HandleScope<'s>,
|
|
callback: FunctionCallback,
|
|
) -> Option<Local<'s, Function>> {
|
|
Self::builder_raw(callback).build(scope)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn call<'s>(
|
|
&self,
|
|
scope: &mut HandleScope<'s>,
|
|
recv: Local<Value>,
|
|
args: &[Local<Value>],
|
|
) -> Option<Local<'s, Value>> {
|
|
let args = Local::slice_into_raw(args);
|
|
let argc = int::try_from(args.len()).unwrap();
|
|
let argv = args.as_ptr();
|
|
unsafe {
|
|
scope.cast_local(|sd| {
|
|
v8__Function__Call(self, sd.get_current_context(), &*recv, argc, argv)
|
|
})
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn new_instance<'s>(
|
|
&self,
|
|
scope: &mut HandleScope<'s>,
|
|
args: &[Local<Value>],
|
|
) -> Option<Local<'s, Object>> {
|
|
let args = Local::slice_into_raw(args);
|
|
let argc = int::try_from(args.len()).unwrap();
|
|
let argv = args.as_ptr();
|
|
unsafe {
|
|
scope.cast_local(|sd| {
|
|
v8__Function__NewInstance(self, sd.get_current_context(), argc, argv)
|
|
})
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn get_name<'s>(&self, scope: &mut HandleScope<'s>) -> Local<'s, String> {
|
|
unsafe { scope.cast_local(|_| v8__Function__GetName(self)).unwrap() }
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn set_name(&self, name: Local<String>) {
|
|
unsafe { v8__Function__SetName(self, &*name) }
|
|
}
|
|
|
|
/// Get the (zero-indexed) column number of the function's definition, if available.
|
|
#[inline(always)]
|
|
pub fn get_script_column_number(&self) -> Option<u32> {
|
|
let ret = unsafe { v8__Function__GetScriptColumnNumber(self) };
|
|
(ret >= 0).then_some(ret as u32)
|
|
}
|
|
|
|
/// Get the (zero-indexed) line number of the function's definition, if available.
|
|
#[inline(always)]
|
|
pub fn get_script_line_number(&self) -> Option<u32> {
|
|
let ret = unsafe { v8__Function__GetScriptLineNumber(self) };
|
|
(ret >= 0).then_some(ret as u32)
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn get_script_origin(&self) -> &ScriptOrigin {
|
|
unsafe {
|
|
let ptr = v8__Function__GetScriptOrigin(self);
|
|
&*ptr
|
|
}
|
|
}
|
|
|
|
/// Returns scriptId.
|
|
#[inline(always)]
|
|
pub fn script_id(&self) -> i32 {
|
|
unsafe { v8__Function__ScriptId(self) }
|
|
}
|
|
|
|
/// Creates and returns code cache for the specified unbound_script.
|
|
/// This will return nullptr if the script cannot be serialized. The
|
|
/// CachedData returned by this function should be owned by the caller.
|
|
#[inline(always)]
|
|
pub fn create_code_cache(&self) -> Option<UniqueRef<CachedData<'static>>> {
|
|
let code_cache =
|
|
unsafe { UniqueRef::try_from_raw(v8__Function__CreateCodeCache(self)) };
|
|
#[cfg(debug_assertions)]
|
|
if let Some(code_cache) = &code_cache {
|
|
debug_assert_eq!(
|
|
code_cache.buffer_policy(),
|
|
crate::script_compiler::BufferPolicy::BufferOwned
|
|
);
|
|
}
|
|
code_cache
|
|
}
|
|
}
|