Skip to main content

v8/
function.rs

1use std::convert::TryFrom;
2use std::marker::PhantomData;
3use std::ptr::NonNull;
4use std::ptr::null;
5
6use crate::Array;
7use crate::Boolean;
8use crate::CallbackScope;
9use crate::Context;
10use crate::Function;
11use crate::Integer;
12use crate::Isolate;
13use crate::Local;
14use crate::Name;
15use crate::Object;
16use crate::PropertyDescriptor;
17use crate::SealedLocal;
18use crate::Signature;
19use crate::String;
20use crate::UniqueRef;
21use crate::Value;
22use crate::isolate::RealIsolate;
23use crate::scope::PinScope;
24use crate::scope::callback_scope;
25use crate::script_compiler::CachedData;
26use crate::support::MapFnFrom;
27use crate::support::MapFnTo;
28use crate::support::ToCFn;
29use crate::support::UnitType;
30use crate::support::{Opaque, int};
31use crate::template::Intercepted;
32use crate::{ScriptOrigin, undefined};
33
34unsafe extern "C" {
35  fn v8__Function__New(
36    context: *const Context,
37    callback: FunctionCallback,
38    data_or_null: *const Value,
39    length: i32,
40    constructor_behavior: ConstructorBehavior,
41    side_effect_type: SideEffectType,
42  ) -> *const Function;
43  fn v8__Function__Call(
44    this: *const Function,
45    context: *const Context,
46    recv: *const Value,
47    argc: int,
48    argv: *const *const Value,
49  ) -> *const Value;
50  fn v8__Function__NewInstance(
51    this: *const Function,
52    context: *const Context,
53    argc: int,
54    argv: *const *const Value,
55  ) -> *const Object;
56  fn v8__Function__GetName(this: *const Function) -> *const String;
57  fn v8__Function__SetName(this: *const Function, name: *const String);
58  fn v8__Function__GetScriptColumnNumber(this: *const Function) -> int;
59  fn v8__Function__GetScriptLineNumber(this: *const Function) -> int;
60  fn v8__Function__ScriptId(this: *const Function) -> int;
61  fn v8__Function__GetScriptOrigin(
62    this: *const Function,
63  ) -> *const ScriptOrigin<'static>;
64
65  fn v8__Function__CreateCodeCache(
66    script: *const Function,
67  ) -> *mut CachedData<'static>;
68
69  static v8__FunctionCallbackInfo__kArgsLength: int;
70
71  fn v8__FunctionCallbackInfo__Data(
72    this: *const FunctionCallbackInfo,
73  ) -> *const Value;
74
75  fn v8__PropertyCallbackInfo__GetIsolate(
76    this: *const RawPropertyCallbackInfo,
77  ) -> *mut RealIsolate;
78  fn v8__PropertyCallbackInfo__Data(
79    this: *const RawPropertyCallbackInfo,
80  ) -> *const Value;
81  fn v8__PropertyCallbackInfo__This(
82    this: *const RawPropertyCallbackInfo,
83  ) -> *const Object;
84  fn v8__PropertyCallbackInfo__Holder(
85    this: *const RawPropertyCallbackInfo,
86  ) -> *const Object;
87  fn v8__PropertyCallbackInfo__GetReturnValue(
88    this: *const RawPropertyCallbackInfo,
89  ) -> usize;
90  fn v8__PropertyCallbackInfo__ShouldThrowOnError(
91    this: *const RawPropertyCallbackInfo,
92  ) -> bool;
93
94  fn v8__ReturnValue__Value__Set(
95    this: *mut RawReturnValue,
96    value: *const Value,
97  );
98  fn v8__ReturnValue__Value__Set__Bool(this: *mut RawReturnValue, value: bool);
99  fn v8__ReturnValue__Value__Set__Int32(this: *mut RawReturnValue, value: i32);
100  fn v8__ReturnValue__Value__Set__Uint32(this: *mut RawReturnValue, value: u32);
101  fn v8__ReturnValue__Value__Set__Double(this: *mut RawReturnValue, value: f64);
102  fn v8__ReturnValue__Value__SetNull(this: *mut RawReturnValue);
103  fn v8__ReturnValue__Value__SetUndefined(this: *mut RawReturnValue);
104  fn v8__ReturnValue__Value__SetEmptyString(this: *mut RawReturnValue);
105  fn v8__ReturnValue__Value__Get(this: *const RawReturnValue) -> *const Value;
106}
107
108// Ad-libbed - V8 does not document ConstructorBehavior.
109/// ConstructorBehavior::Allow creates a regular API function.
110///
111/// ConstructorBehavior::Throw creates a "concise" API function, a function
112/// without a ".prototype" property, that is somewhat faster to create and has
113/// a smaller footprint. Functionally equivalent to ConstructorBehavior::Allow
114/// followed by a call to FunctionTemplate::RemovePrototype().
115#[repr(C)]
116pub enum ConstructorBehavior {
117  Throw,
118  Allow,
119}
120
121/// Options for marking whether callbacks may trigger JS-observable side
122/// effects. Side-effect-free callbacks are allowlisted during debug evaluation
123/// with throwOnSideEffect. It applies when calling a Function,
124/// FunctionTemplate, or an Accessor callback. For Interceptors, please see
125/// PropertyHandlerFlags's kHasNoSideEffect.
126/// Callbacks that only cause side effects to the receiver are allowlisted if
127/// invoked on receiver objects that are created within the same debug-evaluate
128/// call, as these objects are temporary and the side effect does not escape.
129#[repr(C)]
130pub enum SideEffectType {
131  HasSideEffect,
132  HasNoSideEffect,
133  HasSideEffectToReceiver,
134}
135
136#[repr(C)]
137#[derive(Debug)]
138struct RawReturnValue(usize);
139
140// Note: the 'cb lifetime is required because the ReturnValue object must not
141// outlive the FunctionCallbackInfo/PropertyCallbackInfo object from which it
142// is derived.
143#[derive(Debug)]
144pub struct ReturnValue<'cb, T = Value>(RawReturnValue, PhantomData<&'cb T>);
145
146impl<'cb, T> ReturnValue<'cb, T> {
147  #[inline(always)]
148  pub fn from_property_callback_info(
149    info: &'cb PropertyCallbackInfo<T>,
150  ) -> Self {
151    Self(
152      unsafe {
153        RawReturnValue(v8__PropertyCallbackInfo__GetReturnValue(&info.0))
154      },
155      PhantomData,
156    )
157  }
158}
159
160impl<'cb> ReturnValue<'cb, Value> {
161  #[inline(always)]
162  pub fn from_function_callback_info(info: &'cb FunctionCallbackInfo) -> Self {
163    let nn = info.get_return_value_non_null();
164    Self(RawReturnValue(nn.as_ptr() as _), PhantomData)
165  }
166}
167
168impl ReturnValue<'_, ()> {
169  #[inline(always)]
170  pub fn set_bool(&mut self, value: bool) {
171    unsafe { v8__ReturnValue__Value__Set__Bool(&mut self.0, value) }
172  }
173}
174
175impl<T> ReturnValue<'_, T>
176where
177  for<'s> Local<'s, T>: Into<Local<'s, Value>>,
178{
179  #[inline(always)]
180  pub fn set(&mut self, value: Local<T>) {
181    unsafe { v8__ReturnValue__Value__Set(&mut self.0, &*value.into()) }
182  }
183
184  #[inline(always)]
185  pub fn set_bool(&mut self, value: bool) {
186    unsafe { v8__ReturnValue__Value__Set__Bool(&mut self.0, value) }
187  }
188
189  #[inline(always)]
190  pub fn set_int32(&mut self, value: i32) {
191    unsafe { v8__ReturnValue__Value__Set__Int32(&mut self.0, value) }
192  }
193
194  #[inline(always)]
195  pub fn set_uint32(&mut self, value: u32) {
196    unsafe { v8__ReturnValue__Value__Set__Uint32(&mut self.0, value) }
197  }
198
199  #[inline(always)]
200  pub fn set_double(&mut self, value: f64) {
201    unsafe { v8__ReturnValue__Value__Set__Double(&mut self.0, value) }
202  }
203
204  #[inline(always)]
205  pub fn set_null(&mut self) {
206    unsafe { v8__ReturnValue__Value__SetNull(&mut self.0) }
207  }
208
209  #[inline(always)]
210  pub fn set_undefined(&mut self) {
211    unsafe { v8__ReturnValue__Value__SetUndefined(&mut self.0) }
212  }
213
214  #[inline(always)]
215  pub fn set_empty_string(&mut self) {
216    unsafe { v8__ReturnValue__Value__SetEmptyString(&mut self.0) }
217  }
218
219  /// Getter. Creates a new Local<> so it comes with a certain performance
220  /// hit. If the ReturnValue was not yet set, this will return the undefined
221  /// value.
222  #[inline(always)]
223  pub fn get<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, Value> {
224    unsafe { scope.cast_local(|_| v8__ReturnValue__Value__Get(&self.0)) }
225      .unwrap()
226  }
227}
228
229/// The argument information given to function call callbacks.  This
230/// class provides access to information about the context of the call,
231/// including the receiver, the number and values of arguments, and
232/// the holder of the function.
233#[repr(C)]
234#[derive(Debug)]
235pub struct FunctionCallbackInfo {
236  // The layout of this struct must match that of `class FunctionCallbackInfo`
237  // as defined in v8.h.
238  implicit_args: *mut *const Opaque,
239  values: *mut *const Opaque,
240  length: int,
241}
242
243// These constants must match those defined on `class FunctionCallbackInfo` in
244// v8-function-callback.h.
245#[allow(dead_code, non_upper_case_globals)]
246impl FunctionCallbackInfo {
247  const kHolderIndex: i32 = 0;
248  const kIsolateIndex: i32 = 1;
249  const kContextIndex: i32 = 2;
250  const kReturnValueIndex: i32 = 3;
251  const kTargetIndex: i32 = 4;
252  const kNewTargetIndex: i32 = 5;
253  const kArgsLength: i32 = 6;
254}
255
256impl FunctionCallbackInfo {
257  #[inline(always)]
258  pub(crate) fn get_isolate_ptr(&self) -> *mut RealIsolate {
259    let arg_nn =
260      self.get_implicit_arg_non_null::<*mut RealIsolate>(Self::kIsolateIndex);
261    *unsafe { arg_nn.as_ref() }
262  }
263
264  #[inline(always)]
265  pub(crate) fn get_return_value_non_null(&self) -> NonNull<Value> {
266    self.get_implicit_arg_non_null::<Value>(Self::kReturnValueIndex)
267  }
268
269  #[inline(always)]
270  pub(crate) fn new_target(&self) -> Local<'_, Value> {
271    unsafe { self.get_implicit_arg_local(Self::kNewTargetIndex) }
272  }
273
274  #[inline(always)]
275  pub(crate) fn this(&self) -> Local<'_, Object> {
276    unsafe { self.get_arg_local(-1) }
277  }
278
279  #[inline]
280  pub fn is_construct_call(&self) -> bool {
281    // The "new.target" value is only set for construct calls.
282    !self.new_target().is_undefined()
283  }
284
285  #[inline(always)]
286  pub(crate) fn data(&self) -> Local<'_, Value> {
287    unsafe {
288      let ptr = v8__FunctionCallbackInfo__Data(self);
289      let nn = NonNull::new_unchecked(ptr as *mut Value);
290      Local::from_non_null(nn)
291    }
292  }
293
294  #[inline(always)]
295  pub(crate) fn length(&self) -> i32 {
296    self.length
297  }
298
299  #[inline(always)]
300  pub(crate) fn get(&self, index: int) -> Local<'_, Value> {
301    if index >= 0 && index < self.length {
302      unsafe { self.get_arg_local(index) }
303    } else {
304      let isolate = unsafe {
305        crate::isolate::Isolate::from_raw_ptr(self.get_isolate_ptr())
306      };
307      undefined(&isolate).into()
308    }
309  }
310
311  #[inline(always)]
312  fn get_implicit_arg_non_null<T>(&self, index: i32) -> NonNull<T> {
313    // In debug builds, check that `FunctionCallbackInfo::kArgsLength` matches
314    // the C++ definition. Unfortunately we can't check the other constants
315    // because they are declared protected in the C++ header.
316    debug_assert_eq!(
317      unsafe { v8__FunctionCallbackInfo__kArgsLength },
318      Self::kArgsLength
319    );
320    // Assert that `index` is in bounds.
321    assert!(index >= 0);
322    assert!(index < Self::kArgsLength);
323    // Compute the address of the implicit argument and cast to `NonNull<T>`.
324    let ptr = unsafe { self.implicit_args.offset(index as isize) as *mut T };
325    debug_assert!(!ptr.is_null());
326    unsafe { NonNull::new_unchecked(ptr) }
327  }
328
329  // SAFETY: caller must guarantee that the implicit argument at `index`
330  // contains a valid V8 handle.
331  #[inline(always)]
332  unsafe fn get_implicit_arg_local<T>(&self, index: i32) -> Local<'_, T> {
333    let nn = self.get_implicit_arg_non_null::<T>(index);
334    unsafe { Local::from_non_null(nn) }
335  }
336
337  // SAFETY: caller must guarantee that the `index` value lies between -1 and
338  // self.length.
339  #[inline(always)]
340  unsafe fn get_arg_local<T>(&self, index: i32) -> Local<'_, T> {
341    let ptr = unsafe { self.values.offset(index as _) } as *mut T;
342    debug_assert!(!ptr.is_null());
343    let nn = unsafe { NonNull::new_unchecked(ptr) };
344    unsafe { Local::from_non_null(nn) }
345  }
346}
347
348#[repr(C)]
349#[derive(Debug)]
350struct RawPropertyCallbackInfo(Opaque);
351
352/// The information passed to a property callback about the context
353/// of the property access.
354#[repr(C)]
355#[derive(Debug)]
356pub struct PropertyCallbackInfo<T>(RawPropertyCallbackInfo, PhantomData<T>);
357
358impl<T> PropertyCallbackInfo<T> {
359  #[inline(always)]
360  pub(crate) fn get_isolate_ptr(&self) -> *mut RealIsolate {
361    unsafe { v8__PropertyCallbackInfo__GetIsolate(&self.0) }
362  }
363}
364
365#[derive(Debug)]
366pub struct FunctionCallbackArguments<'s>(&'s FunctionCallbackInfo);
367
368impl<'s> FunctionCallbackArguments<'s> {
369  #[inline(always)]
370  pub fn from_function_callback_info(info: &'s FunctionCallbackInfo) -> Self {
371    Self(info)
372  }
373
374  /// SAFETY: caller must guarantee that no other references to the isolate are
375  /// accessible. Specifically, if an open CallbackScope or HandleScope exists
376  /// in the current function, `FunctionCallbackArguments::get_isolate()` should
377  /// not be called.
378  #[inline(always)]
379  pub unsafe fn get_isolate(&mut self) -> &mut Isolate {
380    unsafe { &mut *(self.0.get_isolate_ptr() as *mut crate::isolate::Isolate) }
381  }
382
383  /// For construct calls, this returns the "new.target" value.
384  #[inline(always)]
385  pub fn new_target(&self) -> Local<'s, Value> {
386    self.0.new_target()
387  }
388
389  /// Returns true if this is a construct call, i.e., if the function was
390  /// called with the `new` operator.
391  #[inline]
392  pub fn is_construct_call(&self) -> bool {
393    self.0.is_construct_call()
394  }
395
396  /// Returns the receiver. This corresponds to the "this" value.
397  #[inline(always)]
398  pub fn this(&self) -> Local<'s, Object> {
399    self.0.this()
400  }
401
402  /// Returns the data argument specified when creating the callback.
403  #[inline(always)]
404  pub fn data(&self) -> Local<'s, Value> {
405    self.0.data()
406  }
407
408  /// The number of available arguments.
409  #[inline(always)]
410  pub fn length(&self) -> int {
411    self.0.length()
412  }
413
414  /// Accessor for the available arguments. Returns `undefined` if the index is
415  /// out of bounds.
416  #[inline(always)]
417  pub fn get(&self, i: int) -> Local<'s, Value> {
418    self.0.get(i)
419  }
420}
421
422#[derive(Debug)]
423pub struct PropertyCallbackArguments<'s>(&'s RawPropertyCallbackInfo);
424
425impl<'s> PropertyCallbackArguments<'s> {
426  #[inline(always)]
427  pub(crate) fn from_property_callback_info<T>(
428    info: &'s PropertyCallbackInfo<T>,
429  ) -> Self {
430    Self(&info.0)
431  }
432
433  /// Returns the object in the prototype chain of the receiver that has the
434  /// interceptor. Suppose you have `x` and its prototype is `y`, and `y`
435  /// has an interceptor. Then `info.This()` is `x` and `info.Holder()` is `y`.
436  /// In case the property is installed on the global object the Holder()
437  /// would return the global proxy.
438  #[inline(always)]
439  pub fn holder(&self) -> Local<'s, Object> {
440    unsafe {
441      Local::from_raw(v8__PropertyCallbackInfo__Holder(self.0))
442        .unwrap_unchecked()
443    }
444  }
445
446  /// Returns the receiver. In many cases, this is the object on which the
447  /// property access was intercepted. When using
448  /// `Reflect.get`, `Function.prototype.call`, or similar functions, it is the
449  /// object passed in as receiver or thisArg.
450  ///
451  /// ```c++
452  ///   void GetterCallback(Local<Name> name,
453  ///                       const v8::PropertyCallbackInfo<v8::Value>& info) {
454  ///      auto context = info.GetIsolate()->GetCurrentContext();
455  ///
456  ///      v8::Local<v8::Value> a_this =
457  ///          info.This()
458  ///              ->GetRealNamedProperty(context, v8_str("a"))
459  ///              .ToLocalChecked();
460  ///      v8::Local<v8::Value> a_holder =
461  ///          info.Holder()
462  ///              ->GetRealNamedProperty(context, v8_str("a"))
463  ///              .ToLocalChecked();
464  ///
465  ///     CHECK(v8_str("r")->Equals(context, a_this).FromJust());
466  ///     CHECK(v8_str("obj")->Equals(context, a_holder).FromJust());
467  ///
468  ///     info.GetReturnValue().Set(name);
469  ///   }
470  ///
471  ///   v8::Local<v8::FunctionTemplate> templ =
472  ///   v8::FunctionTemplate::New(isolate);
473  ///   templ->InstanceTemplate()->SetHandler(
474  ///       v8::NamedPropertyHandlerConfiguration(GetterCallback));
475  ///   LocalContext env;
476  ///   env->Global()
477  ///       ->Set(env.local(), v8_str("obj"), templ->GetFunction(env.local())
478  ///                                            .ToLocalChecked()
479  ///                                            ->NewInstance(env.local())
480  ///                                            .ToLocalChecked())
481  ///       .FromJust();
482  ///
483  ///   CompileRun("obj.a = 'obj'; var r = {a: 'r'}; Reflect.get(obj, 'x', r)");
484  /// ```
485  #[inline(always)]
486  pub fn this(&self) -> Local<'s, Object> {
487    unsafe {
488      Local::from_raw(v8__PropertyCallbackInfo__This(self.0)).unwrap_unchecked()
489    }
490  }
491
492  /// Returns the data set in the configuration, i.e., in
493  /// `NamedPropertyHandlerConfiguration` or
494  /// `IndexedPropertyHandlerConfiguration.`
495  #[inline(always)]
496  pub fn data(&self) -> Local<'s, Value> {
497    unsafe {
498      Local::from_raw(v8__PropertyCallbackInfo__Data(self.0)).unwrap_unchecked()
499    }
500  }
501
502  /// Returns `true` if the intercepted function should throw if an error
503  /// occurs. Usually, `true` corresponds to `'use strict'`.
504  ///
505  /// Always `false` when intercepting `Reflect.set()` independent of the
506  /// language mode.
507  #[inline(always)]
508  pub fn should_throw_on_error(&self) -> bool {
509    unsafe { v8__PropertyCallbackInfo__ShouldThrowOnError(self.0) }
510  }
511}
512
513pub type FunctionCallback = unsafe extern "C" fn(*const FunctionCallbackInfo);
514
515impl<F> MapFnFrom<F> for FunctionCallback
516where
517  F: UnitType
518    + for<'s, 'i> Fn(
519      &mut PinScope<'s, 'i>,
520      FunctionCallbackArguments<'s>,
521      ReturnValue<'s, Value>,
522    ),
523{
524  fn mapping() -> Self {
525    let f = |info: *const FunctionCallbackInfo| {
526      let info = unsafe { &*info };
527      let scope = std::pin::pin!(unsafe { CallbackScope::new(info) });
528      let mut scope = scope.init();
529      let args = FunctionCallbackArguments::from_function_callback_info(info);
530      let rv = ReturnValue::from_function_callback_info(info);
531      (F::get())(&mut scope, args, rv);
532    };
533    f.to_c_fn()
534  }
535}
536
537pub(crate) type NamedGetterCallbackForAccessor =
538  unsafe extern "C" fn(SealedLocal<Name>, *const PropertyCallbackInfo<Value>);
539
540impl<F> MapFnFrom<F> for NamedGetterCallbackForAccessor
541where
542  F: UnitType
543    + for<'s, 'i> Fn(
544      &mut PinScope<'s, 'i>,
545      Local<'s, Name>,
546      PropertyCallbackArguments<'s>,
547      ReturnValue<Value>,
548    ),
549{
550  fn mapping() -> Self {
551    let f = |key: SealedLocal<Name>,
552             info: *const PropertyCallbackInfo<Value>| {
553      let info = unsafe { &*info };
554      callback_scope!(unsafe scope, info);
555      let key = unsafe { scope.unseal(key) };
556      let args = PropertyCallbackArguments::from_property_callback_info(info);
557      let rv = ReturnValue::from_property_callback_info(info);
558      (F::get())(scope, key, args, rv);
559    };
560    f.to_c_fn()
561  }
562}
563
564pub(crate) type NamedGetterCallback = unsafe extern "C" fn(
565  SealedLocal<Name>,
566  *const PropertyCallbackInfo<Value>,
567) -> Intercepted;
568
569impl<F> MapFnFrom<F> for NamedGetterCallback
570where
571  F: UnitType
572    + for<'s, 'i> Fn(
573      &mut PinScope<'s, 'i>,
574      Local<'s, Name>,
575      PropertyCallbackArguments<'s>,
576      ReturnValue<Value>,
577    ) -> Intercepted,
578{
579  fn mapping() -> Self {
580    let f = |key: SealedLocal<Name>,
581             info: *const PropertyCallbackInfo<Value>| {
582      let info = unsafe { &*info };
583      callback_scope!(unsafe scope, info);
584      let key = unsafe { scope.unseal(key) };
585      let args = PropertyCallbackArguments::from_property_callback_info(info);
586      let rv = ReturnValue::from_property_callback_info(info);
587      (F::get())(scope, key, args, rv)
588    };
589    f.to_c_fn()
590  }
591}
592
593pub(crate) type NamedQueryCallback = unsafe extern "C" fn(
594  SealedLocal<Name>,
595  *const PropertyCallbackInfo<Integer>,
596) -> Intercepted;
597
598impl<F> MapFnFrom<F> for NamedQueryCallback
599where
600  F: UnitType
601    + for<'s, 'i> Fn(
602      &mut PinScope<'s, 'i>,
603      Local<'s, Name>,
604      PropertyCallbackArguments<'s>,
605      ReturnValue<Integer>,
606    ) -> Intercepted,
607{
608  fn mapping() -> Self {
609    let f = |key: SealedLocal<Name>,
610             info: *const PropertyCallbackInfo<Integer>| {
611      let info = unsafe { &*info };
612      callback_scope!(unsafe scope, info);
613      let key = unsafe { scope.unseal(key) };
614      let args = PropertyCallbackArguments::from_property_callback_info(info);
615      let rv = ReturnValue::from_property_callback_info(info);
616      (F::get())(scope, key, args, rv)
617    };
618    f.to_c_fn()
619  }
620}
621
622pub(crate) type NamedSetterCallbackForAccessor = unsafe extern "C" fn(
623  SealedLocal<Name>,
624  SealedLocal<Value>,
625  *const PropertyCallbackInfo<()>,
626);
627
628impl<F> MapFnFrom<F> for NamedSetterCallbackForAccessor
629where
630  F: UnitType
631    + for<'s, 'i> Fn(
632      &mut PinScope<'s, 'i>,
633      Local<'s, Name>,
634      Local<'s, Value>,
635      PropertyCallbackArguments<'s>,
636      ReturnValue<()>,
637    ),
638{
639  fn mapping() -> Self {
640    let f = |key: SealedLocal<Name>,
641             value: SealedLocal<Value>,
642             info: *const PropertyCallbackInfo<()>| {
643      let info = unsafe { &*info };
644      callback_scope!(unsafe scope, info);
645      let key = unsafe { scope.unseal(key) };
646      let value = unsafe { scope.unseal(value) };
647      let args = PropertyCallbackArguments::from_property_callback_info(info);
648      let rv = ReturnValue::from_property_callback_info(info);
649      (F::get())(scope, key, value, args, rv);
650    };
651    f.to_c_fn()
652  }
653}
654
655pub(crate) type NamedSetterCallback = unsafe extern "C" fn(
656  SealedLocal<Name>,
657  SealedLocal<Value>,
658  *const PropertyCallbackInfo<()>,
659) -> Intercepted;
660
661impl<F> MapFnFrom<F> for NamedSetterCallback
662where
663  F: UnitType
664    + for<'s, 'i> Fn(
665      &mut PinScope<'s, 'i>,
666      Local<'s, Name>,
667      Local<'s, Value>,
668      PropertyCallbackArguments<'s>,
669      ReturnValue<()>,
670    ) -> Intercepted,
671{
672  fn mapping() -> Self {
673    let f = |key: SealedLocal<Name>,
674             value: SealedLocal<Value>,
675             info: *const PropertyCallbackInfo<()>| {
676      let info = unsafe { &*info };
677      callback_scope!(unsafe scope, info);
678      let key = unsafe { scope.unseal(key) };
679      let value = unsafe { scope.unseal(value) };
680      let args = PropertyCallbackArguments::from_property_callback_info(info);
681      let rv = ReturnValue::from_property_callback_info(info);
682      (F::get())(scope, key, value, args, rv)
683    };
684    f.to_c_fn()
685  }
686}
687
688// Should return an Array in Return Value
689pub(crate) type PropertyEnumeratorCallback =
690  unsafe extern "C" fn(*const PropertyCallbackInfo<Array>);
691
692impl<F> MapFnFrom<F> for PropertyEnumeratorCallback
693where
694  F: UnitType
695    + for<'s, 'i> Fn(
696      &mut PinScope<'s, 'i>,
697      PropertyCallbackArguments<'s>,
698      ReturnValue<Array>,
699    ),
700{
701  fn mapping() -> Self {
702    let f = |info: *const PropertyCallbackInfo<Array>| {
703      let info = unsafe { &*info };
704      callback_scope!(unsafe scope, info);
705      let args = PropertyCallbackArguments::from_property_callback_info(info);
706      let rv = ReturnValue::from_property_callback_info(info);
707      (F::get())(scope, args, rv);
708    };
709    f.to_c_fn()
710  }
711}
712
713pub(crate) type NamedDefinerCallback = unsafe extern "C" fn(
714  SealedLocal<Name>,
715  *const PropertyDescriptor,
716  *const PropertyCallbackInfo<()>,
717) -> Intercepted;
718
719impl<F> MapFnFrom<F> for NamedDefinerCallback
720where
721  F: UnitType
722    + for<'s, 'i> Fn(
723      &mut PinScope<'s, 'i>,
724      Local<'s, Name>,
725      &PropertyDescriptor,
726      PropertyCallbackArguments<'s>,
727      ReturnValue<()>,
728    ) -> Intercepted,
729{
730  fn mapping() -> Self {
731    let f = |key: SealedLocal<Name>,
732             desc: *const PropertyDescriptor,
733             info: *const PropertyCallbackInfo<()>| {
734      let info = unsafe { &*info };
735      callback_scope!(unsafe scope, info);
736      let key = unsafe { scope.unseal(key) };
737      let args = PropertyCallbackArguments::from_property_callback_info(info);
738      let desc = unsafe { &*desc };
739      let rv = ReturnValue::from_property_callback_info(info);
740      (F::get())(scope, key, desc, args, rv)
741    };
742    f.to_c_fn()
743  }
744}
745
746pub(crate) type NamedDeleterCallback = unsafe extern "C" fn(
747  SealedLocal<Name>,
748  *const PropertyCallbackInfo<Boolean>,
749) -> Intercepted;
750
751impl<F> MapFnFrom<F> for NamedDeleterCallback
752where
753  F: UnitType
754    + for<'s, 'i> Fn(
755      &mut PinScope<'s, 'i>,
756      Local<'s, Name>,
757      PropertyCallbackArguments<'s>,
758      ReturnValue<Boolean>,
759    ) -> Intercepted,
760{
761  fn mapping() -> Self {
762    let f = |key: SealedLocal<Name>,
763             info: *const PropertyCallbackInfo<Boolean>| {
764      let info = unsafe { &*info };
765      callback_scope!(unsafe scope, info);
766      let key = unsafe { scope.unseal(key) };
767      let args = PropertyCallbackArguments::from_property_callback_info(info);
768      let rv = ReturnValue::from_property_callback_info(info);
769      (F::get())(scope, key, args, rv)
770    };
771    f.to_c_fn()
772  }
773}
774
775pub(crate) type IndexedGetterCallback =
776  unsafe extern "C" fn(u32, *const PropertyCallbackInfo<Value>) -> Intercepted;
777
778impl<F> MapFnFrom<F> for IndexedGetterCallback
779where
780  F: UnitType
781    + for<'s, 'i> Fn(
782      &mut PinScope<'s, 'i>,
783      u32,
784      PropertyCallbackArguments<'s>,
785      ReturnValue<Value>,
786    ) -> Intercepted,
787{
788  fn mapping() -> Self {
789    let f = |index: u32, info: *const PropertyCallbackInfo<Value>| {
790      let info = unsafe { &*info };
791      callback_scope!(unsafe scope, info);
792      let args = PropertyCallbackArguments::from_property_callback_info(info);
793      let rv = ReturnValue::from_property_callback_info(info);
794      (F::get())(scope, index, args, rv)
795    };
796    f.to_c_fn()
797  }
798}
799
800pub(crate) type IndexedQueryCallback = unsafe extern "C" fn(
801  u32,
802  *const PropertyCallbackInfo<Integer>,
803) -> Intercepted;
804
805impl<F> MapFnFrom<F> for IndexedQueryCallback
806where
807  F: UnitType
808    + for<'s, 'i> Fn(
809      &mut PinScope<'s, 'i>,
810      u32,
811      PropertyCallbackArguments<'s>,
812      ReturnValue<Integer>,
813    ) -> Intercepted,
814{
815  fn mapping() -> Self {
816    let f = |key: u32, info: *const PropertyCallbackInfo<Integer>| {
817      let info = unsafe { &*info };
818      callback_scope!(unsafe scope, info);
819      let args = PropertyCallbackArguments::from_property_callback_info(info);
820      let rv = ReturnValue::from_property_callback_info(info);
821      (F::get())(scope, key, args, rv)
822    };
823    f.to_c_fn()
824  }
825}
826
827pub(crate) type IndexedSetterCallback = unsafe extern "C" fn(
828  u32,
829  SealedLocal<Value>,
830  *const PropertyCallbackInfo<()>,
831) -> Intercepted;
832
833impl<F> MapFnFrom<F> for IndexedSetterCallback
834where
835  F: UnitType
836    + for<'s, 'i> Fn(
837      &mut PinScope<'s, 'i>,
838      u32,
839      Local<'s, Value>,
840      PropertyCallbackArguments<'s>,
841      ReturnValue<()>,
842    ) -> Intercepted,
843{
844  fn mapping() -> Self {
845    let f = |index: u32,
846             value: SealedLocal<Value>,
847             info: *const PropertyCallbackInfo<()>| {
848      let info = unsafe { &*info };
849      callback_scope!(unsafe scope, info);
850      let value = unsafe { scope.unseal(value) };
851      let args = PropertyCallbackArguments::from_property_callback_info(info);
852      let rv = ReturnValue::from_property_callback_info(info);
853      (F::get())(scope, index, value, args, rv)
854    };
855    f.to_c_fn()
856  }
857}
858
859pub(crate) type IndexedDefinerCallback = unsafe extern "C" fn(
860  u32,
861  *const PropertyDescriptor,
862  *const PropertyCallbackInfo<()>,
863) -> Intercepted;
864
865impl<F> MapFnFrom<F> for IndexedDefinerCallback
866where
867  F: UnitType
868    + for<'s, 'i> Fn(
869      &mut PinScope<'s, 'i>,
870      u32,
871      &PropertyDescriptor,
872      PropertyCallbackArguments<'s>,
873      ReturnValue<()>,
874    ) -> Intercepted,
875{
876  fn mapping() -> Self {
877    let f = |index: u32,
878             desc: *const PropertyDescriptor,
879             info: *const PropertyCallbackInfo<()>| {
880      let info = unsafe { &*info };
881      callback_scope!(unsafe scope, info);
882      let args = PropertyCallbackArguments::from_property_callback_info(info);
883      let rv = ReturnValue::from_property_callback_info(info);
884      let desc = unsafe { &*desc };
885      (F::get())(scope, index, desc, args, rv)
886    };
887    f.to_c_fn()
888  }
889}
890
891pub(crate) type IndexedDeleterCallback = unsafe extern "C" fn(
892  u32,
893  *const PropertyCallbackInfo<Boolean>,
894) -> Intercepted;
895
896impl<F> MapFnFrom<F> for IndexedDeleterCallback
897where
898  F: UnitType
899    + for<'s, 'i> Fn(
900      &mut PinScope<'s, 'i>,
901      u32,
902      PropertyCallbackArguments<'s>,
903      ReturnValue<Boolean>,
904    ) -> Intercepted,
905{
906  fn mapping() -> Self {
907    let f = |index: u32, info: *const PropertyCallbackInfo<Boolean>| {
908      let info = unsafe { &*info };
909      callback_scope!(unsafe scope, info);
910      let args = PropertyCallbackArguments::from_property_callback_info(info);
911      let rv = ReturnValue::from_property_callback_info(info);
912      (F::get())(scope, index, args, rv)
913    };
914    f.to_c_fn()
915  }
916}
917
918/// A builder to construct the properties of a Function or FunctionTemplate.
919pub struct FunctionBuilder<'s, T> {
920  pub(crate) callback: FunctionCallback,
921  pub(crate) data: Option<Local<'s, Value>>,
922  pub(crate) signature: Option<Local<'s, Signature>>,
923  pub(crate) length: i32,
924  pub(crate) constructor_behavior: ConstructorBehavior,
925  pub(crate) side_effect_type: SideEffectType,
926  phantom: PhantomData<T>,
927}
928
929impl<'s, T> FunctionBuilder<'s, T> {
930  /// Create a new FunctionBuilder.
931  #[inline(always)]
932  pub fn new(callback: impl MapFnTo<FunctionCallback>) -> Self {
933    Self::new_raw(callback.map_fn_to())
934  }
935
936  #[inline(always)]
937  pub fn new_raw(callback: FunctionCallback) -> Self {
938    Self {
939      callback,
940      data: None,
941      signature: None,
942      length: 0,
943      constructor_behavior: ConstructorBehavior::Allow,
944      side_effect_type: SideEffectType::HasSideEffect,
945      phantom: PhantomData,
946    }
947  }
948
949  /// Set the associated data. The default is no associated data.
950  #[inline(always)]
951  pub fn data(mut self, data: Local<'s, Value>) -> Self {
952    self.data = Some(data);
953    self
954  }
955
956  /// Set the function length. The default is 0.
957  #[inline(always)]
958  pub fn length(mut self, length: i32) -> Self {
959    self.length = length;
960    self
961  }
962
963  /// Set the constructor behavior. The default is ConstructorBehavior::Allow.
964  #[inline(always)]
965  pub fn constructor_behavior(
966    mut self,
967    constructor_behavior: ConstructorBehavior,
968  ) -> Self {
969    self.constructor_behavior = constructor_behavior;
970    self
971  }
972
973  /// Set the side effect type. The default is SideEffectType::HasSideEffect.
974  #[inline(always)]
975  pub fn side_effect_type(mut self, side_effect_type: SideEffectType) -> Self {
976    self.side_effect_type = side_effect_type;
977    self
978  }
979}
980
981impl<'s> FunctionBuilder<'s, Function> {
982  /// Create the function in the current execution context.
983  #[inline(always)]
984  pub fn build<'i>(
985    self,
986    scope: &PinScope<'s, 'i>,
987  ) -> Option<Local<'s, Function>> {
988    unsafe {
989      scope.cast_local(|sd| {
990        v8__Function__New(
991          sd.get_current_context(),
992          self.callback,
993          self.data.map_or_else(null, |p| &*p),
994          self.length,
995          self.constructor_behavior,
996          self.side_effect_type,
997        )
998      })
999    }
1000  }
1001}
1002
1003impl Function {
1004  /// Create a FunctionBuilder to configure a Function.
1005  /// This is the same as FunctionBuilder::<Function>::new().
1006  #[inline(always)]
1007  pub fn builder<'s>(
1008    callback: impl MapFnTo<FunctionCallback>,
1009  ) -> FunctionBuilder<'s, Self> {
1010    FunctionBuilder::new(callback)
1011  }
1012
1013  #[inline(always)]
1014  pub fn builder_raw<'s>(
1015    callback: FunctionCallback,
1016  ) -> FunctionBuilder<'s, Self> {
1017    FunctionBuilder::new_raw(callback)
1018  }
1019
1020  /// Create a function in the current execution context
1021  /// for a given FunctionCallback.
1022  #[inline(always)]
1023  pub fn new<'s>(
1024    scope: &mut PinScope<'s, '_>,
1025    callback: impl MapFnTo<FunctionCallback>,
1026  ) -> Option<Local<'s, Function>> {
1027    Self::builder(callback).build(scope)
1028  }
1029
1030  #[inline(always)]
1031  pub fn new_raw<'s>(
1032    scope: &mut PinScope<'s, '_>,
1033    callback: FunctionCallback,
1034  ) -> Option<Local<'s, Function>> {
1035    Self::builder_raw(callback).build(scope)
1036  }
1037
1038  /// Call a function in a context scope.
1039  #[inline]
1040  pub fn call<'s>(
1041    &self,
1042    scope: &PinScope<'s, '_>,
1043    recv: Local<Value>,
1044    args: &[Local<Value>],
1045  ) -> Option<Local<'s, Value>> {
1046    let args = Local::slice_into_raw(args);
1047    let argc = int::try_from(args.len()).unwrap();
1048    let argv = args.as_ptr();
1049    unsafe {
1050      scope.cast_local(|sd| {
1051        v8__Function__Call(self, sd.get_current_context(), &*recv, argc, argv)
1052      })
1053    }
1054  }
1055
1056  /// Call a function in a given context.
1057  #[inline]
1058  pub fn call_with_context<'s>(
1059    &self,
1060    scope: &PinScope<'s, '_, ()>,
1061    context: Local<Context>,
1062    recv: Local<Value>,
1063    args: &[Local<Value>],
1064  ) -> Option<Local<'s, Value>> {
1065    let args = Local::slice_into_raw(args);
1066    let argc = int::try_from(args.len()).unwrap();
1067    let argv = args.as_ptr();
1068    unsafe {
1069      let ret = v8__Function__Call(
1070        self,
1071        context.as_non_null().as_ptr(),
1072        &*recv,
1073        argc,
1074        argv,
1075      );
1076      if ret.is_null() {
1077        None
1078      } else {
1079        scope.cast_local(|_| ret)
1080      }
1081    }
1082  }
1083
1084  #[inline(always)]
1085  pub fn new_instance<'s>(
1086    &self,
1087    scope: &PinScope<'s, '_>,
1088    args: &[Local<Value>],
1089  ) -> Option<Local<'s, Object>> {
1090    let args = Local::slice_into_raw(args);
1091    let argc = int::try_from(args.len()).unwrap();
1092    let argv = args.as_ptr();
1093    unsafe {
1094      scope.cast_local(|sd| {
1095        v8__Function__NewInstance(self, sd.get_current_context(), argc, argv)
1096      })
1097    }
1098  }
1099
1100  #[inline(always)]
1101  pub fn get_name<'s>(&self, scope: &PinScope<'s, '_>) -> Local<'s, String> {
1102    unsafe { scope.cast_local(|_| v8__Function__GetName(self)).unwrap() }
1103  }
1104
1105  #[inline(always)]
1106  pub fn set_name(&self, name: Local<String>) {
1107    unsafe { v8__Function__SetName(self, &*name) }
1108  }
1109
1110  /// Get the (zero-indexed) column number of the function's definition, if available.
1111  #[inline(always)]
1112  pub fn get_script_column_number(&self) -> Option<u32> {
1113    let ret = unsafe { v8__Function__GetScriptColumnNumber(self) };
1114    (ret >= 0).then_some(ret as u32)
1115  }
1116
1117  /// Get the (zero-indexed) line number of the function's definition, if available.
1118  #[inline(always)]
1119  pub fn get_script_line_number(&self) -> Option<u32> {
1120    let ret = unsafe { v8__Function__GetScriptLineNumber(self) };
1121    (ret >= 0).then_some(ret as u32)
1122  }
1123
1124  #[inline(always)]
1125  pub fn get_script_origin(&self) -> &ScriptOrigin<'_> {
1126    unsafe {
1127      let ptr = v8__Function__GetScriptOrigin(self);
1128      &*ptr
1129    }
1130  }
1131
1132  /// Returns scriptId.
1133  #[inline(always)]
1134  pub fn script_id(&self) -> i32 {
1135    unsafe { v8__Function__ScriptId(self) }
1136  }
1137
1138  /// Creates and returns code cache for the specified unbound_script.
1139  /// This will return nullptr if the script cannot be serialized. The
1140  /// CachedData returned by this function should be owned by the caller.
1141  #[inline(always)]
1142  pub fn create_code_cache(&self) -> Option<UniqueRef<CachedData<'static>>> {
1143    let code_cache =
1144      unsafe { UniqueRef::try_from_raw(v8__Function__CreateCodeCache(self)) };
1145    if let Some(code_cache) = &code_cache {
1146      debug_assert_eq!(
1147        code_cache.buffer_policy(),
1148        crate::script_compiler::BufferPolicy::BufferOwned
1149      );
1150    }
1151    code_cache
1152  }
1153}