mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
bindings: Support non-object this values for callbacks. (#35427)
Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
cf3ad2de77
commit
cb3ecd4417
3 changed files with 24 additions and 22 deletions
|
@ -7,7 +7,6 @@
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::mem::drop;
|
use std::mem::drop;
|
||||||
use std::ptr;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use js::jsapi::{
|
use js::jsapi::{
|
||||||
|
@ -15,7 +14,7 @@ use js::jsapi::{
|
||||||
};
|
};
|
||||||
use js::jsval::{JSVal, ObjectValue, UndefinedValue};
|
use js::jsval::{JSVal, ObjectValue, UndefinedValue};
|
||||||
use js::rust::wrappers::{JS_GetProperty, JS_WrapObject};
|
use js::rust::wrappers::{JS_GetProperty, JS_WrapObject};
|
||||||
use js::rust::{MutableHandleObject, Runtime};
|
use js::rust::{MutableHandleValue, Runtime};
|
||||||
|
|
||||||
use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods;
|
use crate::dom::bindings::codegen::Bindings::WindowBinding::Window_Binding::WindowMethods;
|
||||||
use crate::dom::bindings::error::{report_pending_exception, Error, Fallible};
|
use crate::dom::bindings::error::{report_pending_exception, Error, Fallible};
|
||||||
|
@ -208,19 +207,22 @@ impl CallbackInterface {
|
||||||
pub(crate) use script_bindings::callback::ThisReflector;
|
pub(crate) use script_bindings::callback::ThisReflector;
|
||||||
|
|
||||||
/// Wraps the reflector for `p` into the realm of `cx`.
|
/// Wraps the reflector for `p` into the realm of `cx`.
|
||||||
pub(crate) fn wrap_call_this_object<T: ThisReflector>(
|
pub(crate) fn wrap_call_this_value<T: ThisReflector>(
|
||||||
cx: JSContext,
|
cx: JSContext,
|
||||||
p: &T,
|
p: &T,
|
||||||
mut rval: MutableHandleObject,
|
mut rval: MutableHandleValue,
|
||||||
) {
|
) -> bool {
|
||||||
rval.set(p.jsobject());
|
rooted!(in(*cx) let mut obj = p.jsobject());
|
||||||
assert!(!rval.get().is_null());
|
assert!(!obj.is_null());
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if !JS_WrapObject(*cx, rval) {
|
if !JS_WrapObject(*cx, obj.handle_mut()) {
|
||||||
rval.set(ptr::null_mut());
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rval.set(ObjectValue(*obj));
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A class that performs whatever setup we need to safely make a call while
|
/// A class that performs whatever setup we need to safely make a call while
|
||||||
|
|
|
@ -14,11 +14,11 @@ pub(crate) mod base {
|
||||||
};
|
};
|
||||||
pub(crate) use js::jsval::{JSVal, NullValue, ObjectOrNullValue, ObjectValue, UndefinedValue};
|
pub(crate) use js::jsval::{JSVal, NullValue, ObjectOrNullValue, ObjectValue, UndefinedValue};
|
||||||
pub(crate) use js::panic::maybe_resume_unwind;
|
pub(crate) use js::panic::maybe_resume_unwind;
|
||||||
pub(crate) use js::rust::wrappers::{JS_CallFunctionValue, JS_WrapValue};
|
pub(crate) use js::rust::wrappers::{Call, JS_WrapValue};
|
||||||
pub(crate) use js::rust::{HandleObject, HandleValue, MutableHandleObject, MutableHandleValue};
|
pub(crate) use js::rust::{HandleObject, HandleValue, MutableHandleObject, MutableHandleValue};
|
||||||
|
|
||||||
pub(crate) use crate::dom::bindings::callback::{
|
pub(crate) use crate::dom::bindings::callback::{
|
||||||
wrap_call_this_object, CallSetup, CallbackContainer, CallbackFunction, CallbackInterface,
|
wrap_call_this_value, CallSetup, CallbackContainer, CallbackFunction, CallbackInterface,
|
||||||
CallbackObject, ExceptionHandling, ThisReflector,
|
CallbackObject, ExceptionHandling, ThisReflector,
|
||||||
};
|
};
|
||||||
pub(crate) use crate::dom::bindings::codegen::Bindings::AudioNodeBinding::{
|
pub(crate) use crate::dom::bindings::codegen::Bindings::AudioNodeBinding::{
|
||||||
|
|
|
@ -7658,13 +7658,13 @@ class CGCallback(CGClass):
|
||||||
# Strip out the JSContext*/JSObject* args
|
# Strip out the JSContext*/JSObject* args
|
||||||
# that got added.
|
# that got added.
|
||||||
assert args[0].name == "cx" and args[0].argType == "SafeJSContext"
|
assert args[0].name == "cx" and args[0].argType == "SafeJSContext"
|
||||||
assert args[1].name == "aThisObj" and args[1].argType == "HandleObject"
|
assert args[1].name == "aThisObj" and args[1].argType == "HandleValue"
|
||||||
args = args[2:]
|
args = args[2:]
|
||||||
# Record the names of all the arguments, so we can use them when we call
|
# Record the names of all the arguments, so we can use them when we call
|
||||||
# the private method.
|
# the private method.
|
||||||
argnames = [arg.name for arg in args]
|
argnames = [arg.name for arg in args]
|
||||||
argnamesWithThis = ["s.get_context()", "thisObjJS.handle()"] + argnames
|
argnamesWithThis = ["s.get_context()", "thisValue.handle()"] + argnames
|
||||||
argnamesWithoutThis = ["s.get_context()", "thisObjJS.handle()"] + argnames
|
argnamesWithoutThis = ["s.get_context()", "HandleValue::undefined()"] + argnames
|
||||||
# Now that we've recorded the argnames for our call to our private
|
# Now that we've recorded the argnames for our call to our private
|
||||||
# method, insert our optional argument for deciding whether the
|
# method, insert our optional argument for deciding whether the
|
||||||
# CallSetup should re-throw exceptions on aRv.
|
# CallSetup should re-throw exceptions on aRv.
|
||||||
|
@ -7683,14 +7683,14 @@ class CGCallback(CGClass):
|
||||||
setupCall = "let s = CallSetup::new(self, aExceptionHandling);\n"
|
setupCall = "let s = CallSetup::new(self, aExceptionHandling);\n"
|
||||||
|
|
||||||
bodyWithThis = (
|
bodyWithThis = (
|
||||||
f"{setupCall}rooted!(in(*s.get_context()) let mut thisObjJS = ptr::null_mut::<JSObject>());\n"
|
f"{setupCall}rooted!(in(*s.get_context()) let mut thisValue: JSVal);\n"
|
||||||
"wrap_call_this_object(s.get_context(), thisObj, thisObjJS.handle_mut());\n"
|
"let wrap_result = wrap_call_this_value(s.get_context(), thisObj, thisValue.handle_mut());\n"
|
||||||
"if thisObjJS.is_null() {\n"
|
"if !wrap_result {\n"
|
||||||
" return Err(JSFailed);\n"
|
" return Err(JSFailed);\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
f"unsafe {{ self.{method.name}({', '.join(argnamesWithThis)}) }}")
|
f"unsafe {{ self.{method.name}({', '.join(argnamesWithThis)}) }}")
|
||||||
bodyWithoutThis = (
|
bodyWithoutThis = (
|
||||||
f"{setupCall}rooted!(in(*s.get_context()) let thisObjJS = ptr::null_mut::<JSObject>());\n"
|
f"{setupCall}\n"
|
||||||
f"unsafe {{ self.{method.name}({', '.join(argnamesWithoutThis)}) }}")
|
f"unsafe {{ self.{method.name}({', '.join(argnamesWithoutThis)}) }}")
|
||||||
return [ClassMethod(f'{method.name}_', method.returnType, args,
|
return [ClassMethod(f'{method.name}_', method.returnType, args,
|
||||||
bodyInHeader=True,
|
bodyInHeader=True,
|
||||||
|
@ -7931,7 +7931,7 @@ class CallbackMember(CGNativeMember):
|
||||||
# We want to allow the caller to pass in a "this" object, as
|
# We want to allow the caller to pass in a "this" object, as
|
||||||
# well as a JSContext.
|
# well as a JSContext.
|
||||||
return [Argument("SafeJSContext", "cx"),
|
return [Argument("SafeJSContext", "cx"),
|
||||||
Argument("HandleObject", "aThisObj")] + args
|
Argument("HandleValue", "aThisObj")] + args
|
||||||
|
|
||||||
def getCallSetup(self):
|
def getCallSetup(self):
|
||||||
if self.needThisHandling:
|
if self.needThisHandling:
|
||||||
|
@ -7982,7 +7982,7 @@ class CallbackMethod(CallbackMember):
|
||||||
suffix = "" if self.usingOutparam else ".handle_mut()"
|
suffix = "" if self.usingOutparam else ".handle_mut()"
|
||||||
return (f"{self.getCallableDecl()}"
|
return (f"{self.getCallableDecl()}"
|
||||||
f"rooted!(in(*cx) let rootedThis = {self.getThisObj()});\n"
|
f"rooted!(in(*cx) let rootedThis = {self.getThisObj()});\n"
|
||||||
f"let ok = {self.getCallGuard()}JS_CallFunctionValue(\n"
|
f"let ok = {self.getCallGuard()}Call(\n"
|
||||||
" *cx, rootedThis.handle(), callable.handle(),\n"
|
" *cx, rootedThis.handle(), callable.handle(),\n"
|
||||||
" &HandleValueArray {\n"
|
" &HandleValueArray {\n"
|
||||||
f" length_: {argc} as ::libc::size_t,\n"
|
f" length_: {argc} as ::libc::size_t,\n"
|
||||||
|
@ -8023,11 +8023,11 @@ class CallbackOperationBase(CallbackMethod):
|
||||||
|
|
||||||
def getThisObj(self):
|
def getThisObj(self):
|
||||||
if not self.singleOperation:
|
if not self.singleOperation:
|
||||||
return "self.callback()"
|
return "ObjectValue(self.callback())"
|
||||||
# This relies on getCallableDecl declaring a boolean
|
# This relies on getCallableDecl declaring a boolean
|
||||||
# isCallable in the case when we're a single-operation
|
# isCallable in the case when we're a single-operation
|
||||||
# interface.
|
# interface.
|
||||||
return "if isCallable { aThisObj.get() } else { self.callback() }"
|
return "if isCallable { aThisObj.get() } else { ObjectValue(self.callback()) }"
|
||||||
|
|
||||||
def getCallableDecl(self):
|
def getCallableDecl(self):
|
||||||
getCallableFromProp = f'self.parent.get_callable_property(cx, "{self.methodName}")?'
|
getCallableFromProp = f'self.parent.get_callable_property(cx, "{self.methodName}")?'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue