mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
Refactor prototype initialisation
The function do_create_interface_objects is removed in favour of 4 functions: create_callback_interface_object, create_interface_prototype_object, create_noncallback_interface_object and create_named_constructors. While this increases the amount of codegen'd code, this greatly improves the readability of the code involved in this part of DOM, instead of having one function doing 4 different things. We can always find a more adequate abstraction later. NativeProperties and everything related to the interface objects have been removed from the utils module.
This commit is contained in:
parent
967948be06
commit
833e0d2fac
4 changed files with 256 additions and 295 deletions
|
@ -2355,30 +2355,6 @@ class PropertyArrays():
|
||||||
return define
|
return define
|
||||||
|
|
||||||
|
|
||||||
class CGNativeProperties(CGThing):
|
|
||||||
def __init__(self, descriptor, properties):
|
|
||||||
CGThing.__init__(self)
|
|
||||||
self.properties = properties
|
|
||||||
|
|
||||||
def define(self):
|
|
||||||
def getField(array):
|
|
||||||
propertyArray = getattr(self.properties, array)
|
|
||||||
if propertyArray.length() > 0:
|
|
||||||
value = "Some(%s)" % propertyArray.variableName()
|
|
||||||
else:
|
|
||||||
value = "None"
|
|
||||||
|
|
||||||
return CGGeneric(string.Template('${name}: ${value},').substitute({
|
|
||||||
'name': array,
|
|
||||||
'value': value,
|
|
||||||
}))
|
|
||||||
|
|
||||||
nativeProps = CGList([getField(array) for array in self.properties.arrayNames()], '\n')
|
|
||||||
return CGWrapper(CGIndenter(nativeProps),
|
|
||||||
pre="static sNativeProperties: NativeProperties = NativeProperties {\n",
|
|
||||||
post="\n};\n").define()
|
|
||||||
|
|
||||||
|
|
||||||
class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||||
"""
|
"""
|
||||||
Generate the CreateInterfaceObjects method for an interface descriptor.
|
Generate the CreateInterfaceObjects method for an interface descriptor.
|
||||||
|
@ -2389,59 +2365,85 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||||
args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'),
|
args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'),
|
||||||
Argument('HandleObject', 'receiver'),
|
Argument('HandleObject', 'receiver'),
|
||||||
Argument('MutableHandleObject', 'rval')]
|
Argument('MutableHandleObject', 'rval')]
|
||||||
CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args)
|
CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args,
|
||||||
|
unsafe=True)
|
||||||
self.properties = properties
|
self.properties = properties
|
||||||
|
|
||||||
def definition_body(self):
|
def definition_body(self):
|
||||||
|
name = self.descriptor.interface.identifier.name
|
||||||
|
if self.descriptor.interface.isCallback():
|
||||||
|
assert not self.descriptor.interface.ctor() and self.descriptor.interface.hasConstants()
|
||||||
|
return CGGeneric("""\
|
||||||
|
create_callback_interface_object(cx, receiver, throwing_constructor, 0, sConstants, %s);""" % str_to_const_array(name))
|
||||||
|
|
||||||
protoChain = self.descriptor.prototypeChain
|
protoChain = self.descriptor.prototypeChain
|
||||||
if len(protoChain) == 1:
|
if len(protoChain) == 1:
|
||||||
self.unsafe = True
|
getPrototypeProto = "prototype_proto.ptr = JS_GetObjectPrototype(cx, global)"
|
||||||
getParentProto = "parent_proto.ptr = JS_GetObjectPrototype(cx, global)"
|
|
||||||
else:
|
else:
|
||||||
parentProtoName = self.descriptor.prototypeChain[-2]
|
getPrototypeProto = ("%s::GetProtoObject(cx, global, receiver, prototype_proto.handle_mut())" %
|
||||||
getParentProto = ("%s::GetProtoObject(cx, global, receiver, parent_proto.handle_mut())" %
|
toBindingNamespace(self.descriptor.prototypeChain[-2]))
|
||||||
toBindingNamespace(parentProtoName))
|
|
||||||
|
|
||||||
getParentProto = ("let mut parent_proto = RootedObject::new(cx, ptr::null_mut());\n"
|
code = [CGGeneric("""\
|
||||||
"%s;\n"
|
let mut prototype_proto = RootedObject::new(cx, ptr::null_mut());
|
||||||
"assert!(!parent_proto.ptr.is_null());\n") % getParentProto
|
%s;
|
||||||
|
assert!(!prototype_proto.ptr.is_null());""" % getPrototypeProto)]
|
||||||
|
|
||||||
if self.descriptor.interface.isCallback():
|
properties = {"id": name}
|
||||||
protoClass = "None"
|
for arrayName in self.properties.arrayNames():
|
||||||
else:
|
array = getattr(self.properties, arrayName)
|
||||||
protoClass = "Some(&PrototypeClass)"
|
if arrayName == "consts":
|
||||||
|
if array.length():
|
||||||
|
properties[arrayName] = array.variableName()
|
||||||
|
else:
|
||||||
|
properties[arrayName] = "&[]"
|
||||||
|
elif array.length():
|
||||||
|
properties[arrayName] = "Some(%s)" % array.variableName()
|
||||||
|
else:
|
||||||
|
properties[arrayName] = "None"
|
||||||
|
|
||||||
|
code.append(CGGeneric("""
|
||||||
|
create_interface_prototype_object(cx,
|
||||||
|
prototype_proto.handle(),
|
||||||
|
&PrototypeClass,
|
||||||
|
%(methods)s,
|
||||||
|
%(attrs)s,
|
||||||
|
%(consts)s,
|
||||||
|
rval);
|
||||||
|
assert!(!rval.ptr.is_null());""" % properties))
|
||||||
|
|
||||||
if self.descriptor.interface.hasInterfaceObject():
|
if self.descriptor.interface.hasInterfaceObject():
|
||||||
|
properties["name"] = str_to_const_array(name)
|
||||||
if self.descriptor.interface.ctor():
|
if self.descriptor.interface.ctor():
|
||||||
constructHook = CONSTRUCT_HOOK_NAME
|
properties["constructor"] = CONSTRUCT_HOOK_NAME
|
||||||
constructArgs = methodLength(self.descriptor.interface.ctor())
|
properties["length"] = methodLength(self.descriptor.interface.ctor())
|
||||||
else:
|
else:
|
||||||
constructHook = "throwing_constructor"
|
properties["constructor"] = "throwing_constructor"
|
||||||
constructArgs = 0
|
properties["length"] = 0
|
||||||
|
|
||||||
constructor = 'Some((%s as NonNullJSNative, "%s", %d))' % (
|
code.append(CGGeneric("""\
|
||||||
constructHook, self.descriptor.interface.identifier.name,
|
|
||||||
constructArgs)
|
|
||||||
else:
|
|
||||||
constructor = 'None'
|
|
||||||
|
|
||||||
call = """\
|
create_noncallback_interface_object(cx,
|
||||||
do_create_interface_objects(cx, receiver, parent_proto.handle(),
|
receiver,
|
||||||
%s, %s,
|
%(constructor)s,
|
||||||
&named_constructors,
|
%(static_methods)s,
|
||||||
&sNativeProperties, rval);""" % (protoClass, constructor)
|
%(static_attrs)s,
|
||||||
|
%(consts)s,
|
||||||
|
rval.handle(),
|
||||||
|
%(name)s,
|
||||||
|
%(length)s);""" % properties))
|
||||||
|
|
||||||
createArray = """\
|
constructors = self.descriptor.interface.namedConstructors
|
||||||
let named_constructors: [(NonNullJSNative, &'static str, u32); %d] = [
|
if constructors:
|
||||||
""" % len(self.descriptor.interface.namedConstructors)
|
decl = "let named_constructors: [(NonNullJSNative, &'static [u8], u32); %d]" % len(constructors)
|
||||||
for ctor in self.descriptor.interface.namedConstructors:
|
specs = []
|
||||||
constructHook = CONSTRUCT_HOOK_NAME + "_" + ctor.identifier.name
|
for constructor in constructors:
|
||||||
constructArgs = methodLength(ctor)
|
hook = CONSTRUCT_HOOK_NAME + "_" + constructor.identifier.name
|
||||||
constructor = '(%s as NonNullJSNative, "%s", %d)' % (
|
name = str_to_const_array(constructor.identifier.name)
|
||||||
constructHook, ctor.identifier.name, constructArgs)
|
length = methodLength(constructor)
|
||||||
createArray += constructor
|
specs.append(CGGeneric("(%s as NonNullJSNative, %s, %d)" % (hook, name, length)))
|
||||||
createArray += ","
|
values = CGIndenter(CGList(specs, "\n"), 4)
|
||||||
createArray += "];"
|
code.append(CGWrapper(values, pre="%s = [\n" % decl, post="\n];"))
|
||||||
|
code.append(CGGeneric("create_named_constructors(cx, receiver, &named_constructors, rval.handle());"))
|
||||||
|
|
||||||
if self.descriptor.hasUnforgeableMembers:
|
if self.descriptor.hasUnforgeableMembers:
|
||||||
# We want to use the same JSClass and prototype as the object we'll
|
# We want to use the same JSClass and prototype as the object we'll
|
||||||
|
@ -2457,41 +2459,22 @@ let named_constructors: [(NonNullJSNative, &'static str, u32); %d] = [
|
||||||
# the prototype.
|
# the prototype.
|
||||||
if self.descriptor.proxy or self.descriptor.isGlobal():
|
if self.descriptor.proxy or self.descriptor.isGlobal():
|
||||||
holderClass = "ptr::null()"
|
holderClass = "ptr::null()"
|
||||||
holderProto = "ptr::null_mut()"
|
holderProto = "HandleObject::null()"
|
||||||
else:
|
else:
|
||||||
holderClass = "&Class.base as *const js::jsapi::Class as *const JSClass"
|
holderClass = "&Class.base as *const js::jsapi::Class as *const JSClass"
|
||||||
holderProto = "rval.get()"
|
holderProto = "rval.handle()"
|
||||||
# JS_NewObjectWithoutMetadata() is unsafe.
|
code.append(CGGeneric("""
|
||||||
self.unsafe = True
|
|
||||||
createUnforgeableHolder = CGGeneric("""
|
|
||||||
let mut unforgeable_holder = RootedObject::new(cx, ptr::null_mut());
|
let mut unforgeable_holder = RootedObject::new(cx, ptr::null_mut());
|
||||||
{
|
unforgeable_holder.handle_mut().set(
|
||||||
let holder_class = %(holderClass)s;
|
JS_NewObjectWithoutMetadata(cx, %(holderClass)s, %(holderProto)s));
|
||||||
let holder_proto = RootedObject::new(cx, %(holderProto)s);
|
assert!(!unforgeable_holder.ptr.is_null());
|
||||||
unforgeable_holder.handle_mut().set(
|
""" % {'holderClass': holderClass, 'holderProto': holderProto}))
|
||||||
JS_NewObjectWithoutMetadata(cx, holder_class, holder_proto.handle()));
|
code.append(InitUnforgeablePropertiesOnHolder(self.descriptor, self.properties))
|
||||||
assert!(!unforgeable_holder.ptr.is_null());
|
code.append(CGGeneric("""\
|
||||||
}""" % {'holderClass': holderClass, 'holderProto': holderProto})
|
|
||||||
defineUnforgeables = InitUnforgeablePropertiesOnHolder(self.descriptor,
|
|
||||||
self.properties)
|
|
||||||
createUnforgeableHolder = CGList(
|
|
||||||
[createUnforgeableHolder, defineUnforgeables], "\n")
|
|
||||||
|
|
||||||
installUnforgeableHolder = CGGeneric("""\
|
|
||||||
JS_SetReservedSlot(rval.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT,
|
JS_SetReservedSlot(rval.get(), DOM_PROTO_UNFORGEABLE_HOLDER_SLOT,
|
||||||
ObjectValue(&*unforgeable_holder.ptr))""")
|
ObjectValue(&*unforgeable_holder.ptr))"""))
|
||||||
|
|
||||||
unforgeableHolderSetup = CGList(
|
return CGList(code, "\n")
|
||||||
[createUnforgeableHolder, installUnforgeableHolder], "\n")
|
|
||||||
else:
|
|
||||||
unforgeableHolderSetup = None
|
|
||||||
|
|
||||||
return CGList([
|
|
||||||
CGGeneric(getParentProto),
|
|
||||||
CGGeneric(createArray),
|
|
||||||
CGGeneric(call % self.properties.variableNames()),
|
|
||||||
unforgeableHolderSetup,
|
|
||||||
], "\n")
|
|
||||||
|
|
||||||
|
|
||||||
class CGGetPerInterfaceObject(CGAbstractMethod):
|
class CGGetPerInterfaceObject(CGAbstractMethod):
|
||||||
|
@ -4883,7 +4866,6 @@ class CGDescriptor(CGThing):
|
||||||
|
|
||||||
properties = PropertyArrays(descriptor)
|
properties = PropertyArrays(descriptor)
|
||||||
cgThings.append(CGGeneric(str(properties)))
|
cgThings.append(CGGeneric(str(properties)))
|
||||||
cgThings.append(CGNativeProperties(descriptor, properties))
|
|
||||||
cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
|
cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
|
||||||
|
|
||||||
cgThings.append(CGNamespace.build([descriptor.name + "Constants"],
|
cgThings.append(CGNamespace.build([descriptor.name + "Constants"],
|
||||||
|
@ -5271,16 +5253,16 @@ class CGBindingRoot(CGThing):
|
||||||
'js::jsapi::{HandleId, HandleObject, HandleValue, HandleValueArray}',
|
'js::jsapi::{HandleId, HandleObject, HandleValue, HandleValueArray}',
|
||||||
'js::jsapi::{INTERNED_STRING_TO_JSID, IsCallable, JS_CallFunctionValue}',
|
'js::jsapi::{INTERNED_STRING_TO_JSID, IsCallable, JS_CallFunctionValue}',
|
||||||
'js::jsapi::{JS_ComputeThis, JS_CopyPropertiesFrom, JS_ForwardGetPropertyTo}',
|
'js::jsapi::{JS_ComputeThis, JS_CopyPropertiesFrom, JS_ForwardGetPropertyTo}',
|
||||||
'js::jsapi::{JS_GetClass, JS_GetGlobalForObject, JS_GetObjectPrototype}',
|
'js::jsapi::{JS_GetClass, JS_GetFunctionPrototype, JS_GetGlobalForObject}',
|
||||||
'js::jsapi::{JS_GetProperty, JS_GetPropertyById, JS_GetPropertyDescriptorById}',
|
'js::jsapi::{JS_GetObjectPrototype, JS_GetProperty, JS_GetPropertyById}',
|
||||||
'js::jsapi::{JS_GetReservedSlot, JS_HasProperty, JS_HasPropertyById}',
|
'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot, JS_HasProperty}',
|
||||||
'js::jsapi::{JS_InitializePropertiesFromCompatibleNativeObject, JS_InternString}',
|
'js::jsapi::{JS_HasPropertyById, JS_InitializePropertiesFromCompatibleNativeObject}',
|
||||||
'js::jsapi::{JS_IsExceptionPending, JS_NewObject, JS_NewObjectWithGivenProto}',
|
'js::jsapi::{JS_InternString, JS_IsExceptionPending, JS_NewObject}',
|
||||||
'js::jsapi::{JS_NewObjectWithoutMetadata, JS_SetProperty, JS_SetPrototype}',
|
'js::jsapi::{JS_NewObjectWithGivenProto, JS_NewObjectWithoutMetadata, JS_SetProperty}',
|
||||||
'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSAutoCompartment, JSAutoRequest}',
|
'js::jsapi::{JS_SetPrototype, JS_SetReservedSlot, JS_WrapValue, JSAutoCompartment}',
|
||||||
'js::jsapi::{JSContext, JSClass, JSFreeOp, JSFunctionSpec, JSJitGetterCallArgs}',
|
'js::jsapi::{JSAutoRequest, JSContext, JSClass, JSFreeOp, JSFunctionSpec}',
|
||||||
'js::jsapi::{JSJitInfo, JSJitMethodCallArgs, JSJitSetterCallArgs, JSNative}',
|
'js::jsapi::{JSJitGetterCallArgs, JSJitInfo, JSJitMethodCallArgs, JSJitSetterCallArgs}',
|
||||||
'js::jsapi::{JSObject, JSNativeWrapper, JSPropertyDescriptor, JSPropertySpec}',
|
'js::jsapi::{JSNative, JSObject, JSNativeWrapper, JSPropertyDescriptor, JSPropertySpec}',
|
||||||
'js::jsapi::{JSString, JSTracer, JSType, JSTypedMethodJitInfo, JSValueType}',
|
'js::jsapi::{JSString, JSTracer, JSType, JSTypedMethodJitInfo, JSValueType}',
|
||||||
'js::jsapi::{ObjectOpResult, OpType, MutableHandle, MutableHandleObject}',
|
'js::jsapi::{ObjectOpResult, OpType, MutableHandle, MutableHandleObject}',
|
||||||
'js::jsapi::{MutableHandleValue, RootedId, RootedObject, RootedString}',
|
'js::jsapi::{MutableHandleValue, RootedId, RootedObject, RootedString}',
|
||||||
|
@ -5296,13 +5278,14 @@ class CGBindingRoot(CGThing):
|
||||||
'js::rust::{GCMethods, define_methods, define_properties}',
|
'js::rust::{GCMethods, define_methods, define_properties}',
|
||||||
'dom::bindings',
|
'dom::bindings',
|
||||||
'dom::bindings::global::{GlobalRef, global_root_from_object, global_root_from_reflector}',
|
'dom::bindings::global::{GlobalRef, global_root_from_object, global_root_from_reflector}',
|
||||||
|
'dom::bindings::interface::{create_callback_interface_object, create_interface_prototype_object}',
|
||||||
|
'dom::bindings::interface::{create_named_constructors, create_noncallback_interface_object}',
|
||||||
'dom::bindings::js::{JS, Root, RootedReference}',
|
'dom::bindings::js::{JS, Root, RootedReference}',
|
||||||
'dom::bindings::js::{OptionalRootedReference}',
|
'dom::bindings::js::{OptionalRootedReference}',
|
||||||
'dom::bindings::reflector::{Reflectable}',
|
'dom::bindings::reflector::{Reflectable}',
|
||||||
'dom::bindings::utils::{ConstantSpec, DOMClass, DOMJSClass}',
|
'dom::bindings::utils::{ConstantSpec, DOMClass, DOMJSClass}',
|
||||||
'dom::bindings::utils::{DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, JSCLASS_DOM_GLOBAL}',
|
'dom::bindings::utils::{DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, JSCLASS_DOM_GLOBAL}',
|
||||||
'dom::bindings::utils::{NativeProperties, NonNullJSNative, create_dom_global}',
|
'dom::bindings::utils::{NonNullJSNative, create_dom_global, finalize_global}',
|
||||||
'dom::bindings::utils::{do_create_interface_objects, finalize_global}',
|
|
||||||
'dom::bindings::utils::{find_enum_string_index, generic_getter}',
|
'dom::bindings::utils::{find_enum_string_index, generic_getter}',
|
||||||
'dom::bindings::utils::{generic_lenient_getter, generic_lenient_setter}',
|
'dom::bindings::utils::{generic_lenient_getter, generic_lenient_setter}',
|
||||||
'dom::bindings::utils::{generic_method, generic_setter, get_array_index_from_id}',
|
'dom::bindings::utils::{generic_method, generic_setter, get_array_index_from_id}',
|
||||||
|
|
155
components/script/dom/bindings/interface.rs
Normal file
155
components/script/dom/bindings/interface.rs
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! Machinery to initialise interface prototype objects and interface objects.
|
||||||
|
|
||||||
|
use dom::bindings::utils::{ConstantSpec, NonNullJSNative, define_constants};
|
||||||
|
use js::jsapi::{HandleObject, JSClass, JSContext, JSFunctionSpec, JSObject};
|
||||||
|
use js::jsapi::{JSPropertySpec, JS_DefineProperty1, JS_GetFunctionObject};
|
||||||
|
use js::jsapi::{JS_LinkConstructorAndPrototype, JS_NewFunction};
|
||||||
|
use js::jsapi::{JS_NewObjectWithUniqueType, MutableHandleObject, RootedObject};
|
||||||
|
use js::rust::{define_methods, define_properties};
|
||||||
|
use js::{JSFUN_CONSTRUCTOR, JSPROP_PERMANENT, JSPROP_READONLY};
|
||||||
|
use libc;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
/// Create and define the interface object of a callback interface.
|
||||||
|
pub unsafe fn create_callback_interface_object(
|
||||||
|
cx: *mut JSContext,
|
||||||
|
receiver: HandleObject,
|
||||||
|
constructor_native: NonNullJSNative,
|
||||||
|
length: u32,
|
||||||
|
constants: &'static [ConstantSpec],
|
||||||
|
name: &'static [u8]) {
|
||||||
|
assert!(!constants.is_empty());
|
||||||
|
let interface_object =
|
||||||
|
RootedObject::new(cx, create_constructor(cx, constructor_native, length, name));
|
||||||
|
assert!(!interface_object.ptr.is_null());
|
||||||
|
define_constants(cx, interface_object.handle(), constants);
|
||||||
|
define_on_global_object(cx, receiver, name, interface_object.handle());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create the interface prototype object of a non-callback interface.
|
||||||
|
pub unsafe fn create_interface_prototype_object(
|
||||||
|
cx: *mut JSContext,
|
||||||
|
proto: HandleObject,
|
||||||
|
class: &'static JSClass,
|
||||||
|
regular_methods: Option<&'static [JSFunctionSpec]>,
|
||||||
|
regular_properties: Option<&'static [JSPropertySpec]>,
|
||||||
|
constants: &'static [ConstantSpec],
|
||||||
|
rval: MutableHandleObject) {
|
||||||
|
create_object(cx, proto, class, regular_methods, regular_properties, constants, rval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create and define the interface object of a non-callback interface.
|
||||||
|
pub unsafe fn create_noncallback_interface_object(
|
||||||
|
cx: *mut JSContext,
|
||||||
|
receiver: HandleObject,
|
||||||
|
constructor_native: NonNullJSNative,
|
||||||
|
static_methods: Option<&'static [JSFunctionSpec]>,
|
||||||
|
static_properties: Option<&'static [JSPropertySpec]>,
|
||||||
|
constants: &'static [ConstantSpec],
|
||||||
|
interface_prototype_object: HandleObject,
|
||||||
|
name: &'static [u8],
|
||||||
|
length: u32) {
|
||||||
|
assert!(!interface_prototype_object.ptr.is_null());
|
||||||
|
|
||||||
|
let interface_object =
|
||||||
|
RootedObject::new(cx, create_constructor(cx, constructor_native, length, name));
|
||||||
|
assert!(!interface_object.ptr.is_null());
|
||||||
|
|
||||||
|
if let Some(static_methods) = static_methods {
|
||||||
|
define_methods(cx, interface_object.handle(), static_methods).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(static_properties) = static_properties {
|
||||||
|
define_properties(cx, interface_object.handle(), static_properties).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
define_constants(cx, interface_object.handle(), constants);
|
||||||
|
|
||||||
|
assert!(JS_LinkConstructorAndPrototype(cx, interface_object.handle(),
|
||||||
|
interface_prototype_object));
|
||||||
|
define_on_global_object(cx, receiver, name, interface_object.handle());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create and define the named constructors of a non-callback interface.
|
||||||
|
pub unsafe fn create_named_constructors(
|
||||||
|
cx: *mut JSContext,
|
||||||
|
receiver: HandleObject,
|
||||||
|
named_constructors: &[(NonNullJSNative, &'static [u8], u32)],
|
||||||
|
interface_prototype_object: HandleObject) {
|
||||||
|
let mut constructor = RootedObject::new(cx, ptr::null_mut());
|
||||||
|
|
||||||
|
for &(native, name, arity) in named_constructors {
|
||||||
|
assert!(*name.last().unwrap() == b'\0');
|
||||||
|
|
||||||
|
constructor.ptr = create_constructor(cx, native, arity, name);
|
||||||
|
assert!(!constructor.ptr.is_null());
|
||||||
|
|
||||||
|
assert!(JS_DefineProperty1(cx,
|
||||||
|
constructor.handle(),
|
||||||
|
b"prototype\0".as_ptr() as *const libc::c_char,
|
||||||
|
interface_prototype_object,
|
||||||
|
JSPROP_PERMANENT | JSPROP_READONLY,
|
||||||
|
None,
|
||||||
|
None));
|
||||||
|
|
||||||
|
define_on_global_object(cx, receiver, name, constructor.handle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn create_constructor(
|
||||||
|
cx: *mut JSContext,
|
||||||
|
constructor_native: NonNullJSNative,
|
||||||
|
ctor_nargs: u32,
|
||||||
|
name: &'static [u8])
|
||||||
|
-> *mut JSObject {
|
||||||
|
assert!(*name.last().unwrap() == b'\0');
|
||||||
|
|
||||||
|
let fun = JS_NewFunction(cx,
|
||||||
|
Some(constructor_native),
|
||||||
|
ctor_nargs,
|
||||||
|
JSFUN_CONSTRUCTOR,
|
||||||
|
name.as_ptr() as *const _);
|
||||||
|
assert!(!fun.is_null());
|
||||||
|
|
||||||
|
let constructor = JS_GetFunctionObject(fun);
|
||||||
|
assert!(!constructor.is_null());
|
||||||
|
|
||||||
|
constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn create_object(
|
||||||
|
cx: *mut JSContext,
|
||||||
|
proto: HandleObject,
|
||||||
|
class: &'static JSClass,
|
||||||
|
methods: Option<&'static [JSFunctionSpec]>,
|
||||||
|
properties: Option<&'static [JSPropertySpec]>,
|
||||||
|
constants: &'static [ConstantSpec],
|
||||||
|
rval: MutableHandleObject) {
|
||||||
|
rval.set(JS_NewObjectWithUniqueType(cx, class, proto));
|
||||||
|
assert!(!rval.ptr.is_null());
|
||||||
|
if let Some(methods) = methods {
|
||||||
|
define_methods(cx, rval.handle(), methods).unwrap();
|
||||||
|
}
|
||||||
|
if let Some(properties) = properties {
|
||||||
|
define_properties(cx, rval.handle(), properties).unwrap();
|
||||||
|
}
|
||||||
|
define_constants(cx, rval.handle(), constants);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn define_on_global_object(
|
||||||
|
cx: *mut JSContext,
|
||||||
|
receiver: HandleObject,
|
||||||
|
name: &'static [u8],
|
||||||
|
obj: HandleObject) {
|
||||||
|
assert!(*name.last().unwrap() == b'\0');
|
||||||
|
assert!(JS_DefineProperty1(cx,
|
||||||
|
receiver,
|
||||||
|
name.as_ptr() as *const libc::c_char,
|
||||||
|
obj,
|
||||||
|
0,
|
||||||
|
None, None));
|
||||||
|
}
|
|
@ -138,6 +138,7 @@ pub mod conversions;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod global;
|
pub mod global;
|
||||||
pub mod inheritance;
|
pub mod inheritance;
|
||||||
|
pub mod interface;
|
||||||
pub mod js;
|
pub mod js;
|
||||||
pub mod num;
|
pub mod num;
|
||||||
pub mod proxyhandler;
|
pub mod proxyhandler;
|
||||||
|
|
|
@ -19,32 +19,19 @@ use js::glue::{CallJitGetterOp, CallJitMethodOp, CallJitSetterOp, IsWrapper};
|
||||||
use js::glue::{GetCrossCompartmentWrapper, WrapperNew};
|
use js::glue::{GetCrossCompartmentWrapper, WrapperNew};
|
||||||
use js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO, RUST_JSID_IS_INT};
|
use js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO, RUST_JSID_IS_INT};
|
||||||
use js::glue::{RUST_JSID_TO_INT, UnwrapObject};
|
use js::glue::{RUST_JSID_TO_INT, UnwrapObject};
|
||||||
use js::jsapi::JSAutoCompartment;
|
use js::jsapi::{CallArgs, CompartmentOptions, DOMCallbacks, GetGlobalForObjectCrossCompartment};
|
||||||
use js::jsapi::JS_DeletePropertyById1;
|
use js::jsapi::{HandleId, HandleObject, HandleValue, Heap, JSAutoCompartment, JSClass, JSContext};
|
||||||
use js::jsapi::JS_GetFunctionObject;
|
use js::jsapi::{JSJitInfo, JSObject, JSTraceOp, JSTracer, JSVersion, JSWrapObjectCallbacks};
|
||||||
use js::jsapi::JS_IsExceptionPending;
|
use js::jsapi::{JS_DefineProperty, JS_DeletePropertyById1, JS_FireOnNewGlobalObject};
|
||||||
use js::jsapi::JS_NewObjectWithUniqueType;
|
use js::jsapi::{JS_ForwardGetPropertyTo, JS_GetClass, JS_GetProperty, JS_GetPrototype};
|
||||||
use js::jsapi::JS_ObjectToOuterObject;
|
use js::jsapi::{JS_GetReservedSlot, JS_HasProperty, JS_HasPropertyById, JS_InitStandardClasses};
|
||||||
use js::jsapi::{CallArgs, GetGlobalForObjectCrossCompartment, JSJitInfo};
|
use js::jsapi::{JS_IsExceptionPending, JS_NewGlobalObject, JS_ObjectToOuterObject, JS_SetProperty};
|
||||||
use js::jsapi::{CompartmentOptions, OnNewGlobalHookOption};
|
use js::jsapi::{JS_SetReservedSlot, MutableHandleValue, ObjectOpResult, OnNewGlobalHookOption};
|
||||||
use js::jsapi::{DOMCallbacks, JSWrapObjectCallbacks};
|
use js::jsapi::{RootedObject, RootedValue};
|
||||||
use js::jsapi::{HandleId, HandleObject, HandleValue, MutableHandleValue};
|
|
||||||
use js::jsapi::{Heap, MutableHandleObject, ObjectOpResult, RootedObject, RootedValue};
|
|
||||||
use js::jsapi::{JSClass, JSContext, JSObject, JSTracer};
|
|
||||||
use js::jsapi::{JSFunctionSpec, JSPropertySpec};
|
|
||||||
use js::jsapi::{JSTraceOp, JS_AlreadyHasOwnProperty, JS_NewFunction};
|
|
||||||
use js::jsapi::{JSVersion, JS_FireOnNewGlobalObject};
|
|
||||||
use js::jsapi::{JS_DefineProperty, JS_DefineProperty1, JS_ForwardGetPropertyTo};
|
|
||||||
use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype};
|
|
||||||
use js::jsapi::{JS_GetProperty, JS_HasProperty, JS_SetProperty};
|
|
||||||
use js::jsapi::{JS_GetPrototype, JS_HasPropertyById};
|
|
||||||
use js::jsapi::{JS_GetReservedSlot, JS_SetReservedSlot};
|
|
||||||
use js::jsapi::{JS_InitStandardClasses, JS_NewGlobalObject};
|
|
||||||
use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue};
|
use js::jsval::{BooleanValue, DoubleValue, Int32Value, JSVal, NullValue};
|
||||||
use js::jsval::{PrivateValue, UInt32Value, UndefinedValue};
|
use js::jsval::{PrivateValue, UInt32Value, UndefinedValue};
|
||||||
use js::rust::{GCMethods, ToString, define_methods, define_properties};
|
use js::rust::{GCMethods, ToString};
|
||||||
use js::{JSFUN_CONSTRUCTOR, JSPROP_ENUMERATE, JS_CALLEE};
|
use js::{JS_CALLEE, JSPROP_ENUMERATE, JSPROP_PERMANENT, JSPROP_READONLY};
|
||||||
use js::{JSPROP_PERMANENT, JSPROP_READONLY};
|
|
||||||
use libc::{self, c_uint};
|
use libc::{self, c_uint};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
@ -168,153 +155,13 @@ pub fn get_proto_or_iface_array(global: *mut JSObject) -> *mut ProtoOrIfaceArray
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains references to lists of methods, attributes, and constants for a
|
|
||||||
/// given interface.
|
|
||||||
pub struct NativeProperties {
|
|
||||||
/// Instance methods for the interface.
|
|
||||||
pub methods: Option<&'static [JSFunctionSpec]>,
|
|
||||||
/// Unforgeable instance methods for the interface.
|
|
||||||
pub unforgeable_methods: Option<&'static [JSFunctionSpec]>,
|
|
||||||
/// Instance attributes for the interface.
|
|
||||||
pub attrs: Option<&'static [JSPropertySpec]>,
|
|
||||||
/// Unforgeable instance attributes for the interface.
|
|
||||||
pub unforgeable_attrs: Option<&'static [JSPropertySpec]>,
|
|
||||||
/// Constants for the interface.
|
|
||||||
pub consts: Option<&'static [ConstantSpec]>,
|
|
||||||
/// Static methods for the interface.
|
|
||||||
pub static_methods: Option<&'static [JSFunctionSpec]>,
|
|
||||||
/// Static attributes for the interface.
|
|
||||||
pub static_attrs: Option<&'static [JSPropertySpec]>,
|
|
||||||
}
|
|
||||||
unsafe impl Sync for NativeProperties {}
|
|
||||||
|
|
||||||
/// A JSNative that cannot be null.
|
/// A JSNative that cannot be null.
|
||||||
pub type NonNullJSNative =
|
pub type NonNullJSNative =
|
||||||
unsafe extern "C" fn (arg1: *mut JSContext, arg2: c_uint, arg3: *mut JSVal) -> bool;
|
unsafe extern "C" fn (arg1: *mut JSContext, arg2: c_uint, arg3: *mut JSVal) -> bool;
|
||||||
|
|
||||||
/// Creates the *interface prototype object* (if a `proto_class` is given)
|
|
||||||
/// and the *interface object* (if a `constructor` is given).
|
|
||||||
/// Fails on JSAPI failure.
|
|
||||||
pub fn do_create_interface_objects(cx: *mut JSContext,
|
|
||||||
receiver: HandleObject,
|
|
||||||
proto_proto: HandleObject,
|
|
||||||
proto_class: Option<&'static JSClass>,
|
|
||||||
constructor: Option<(NonNullJSNative, &'static str, u32)>,
|
|
||||||
named_constructors: &[(NonNullJSNative, &'static str, u32)],
|
|
||||||
members: &'static NativeProperties,
|
|
||||||
rval: MutableHandleObject) {
|
|
||||||
assert!(rval.get().is_null());
|
|
||||||
if let Some(proto_class) = proto_class {
|
|
||||||
create_interface_prototype_object(cx, proto_proto, proto_class, members, rval);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((native, name, nargs)) = constructor {
|
|
||||||
let s = CString::new(name).unwrap();
|
|
||||||
create_interface_object(cx,
|
|
||||||
receiver,
|
|
||||||
native,
|
|
||||||
nargs,
|
|
||||||
rval.handle(),
|
|
||||||
members,
|
|
||||||
s.as_ptr())
|
|
||||||
}
|
|
||||||
|
|
||||||
for ctor in named_constructors {
|
|
||||||
let (cnative, cname, cnargs) = *ctor;
|
|
||||||
|
|
||||||
let cs = CString::new(cname).unwrap();
|
|
||||||
let constructor = RootedObject::new(cx,
|
|
||||||
create_constructor(cx, cnative, cnargs, cs.as_ptr()));
|
|
||||||
assert!(!constructor.ptr.is_null());
|
|
||||||
unsafe {
|
|
||||||
assert!(JS_DefineProperty1(cx,
|
|
||||||
constructor.handle(),
|
|
||||||
b"prototype\0".as_ptr() as *const libc::c_char,
|
|
||||||
rval.handle(),
|
|
||||||
JSPROP_PERMANENT | JSPROP_READONLY,
|
|
||||||
None,
|
|
||||||
None));
|
|
||||||
}
|
|
||||||
define_constructor(cx, receiver, cs.as_ptr(), constructor.handle());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_constructor(cx: *mut JSContext,
|
|
||||||
constructor_native: NonNullJSNative,
|
|
||||||
ctor_nargs: u32,
|
|
||||||
name: *const libc::c_char)
|
|
||||||
-> *mut JSObject {
|
|
||||||
unsafe {
|
|
||||||
let fun = JS_NewFunction(cx,
|
|
||||||
Some(constructor_native),
|
|
||||||
ctor_nargs,
|
|
||||||
JSFUN_CONSTRUCTOR,
|
|
||||||
name);
|
|
||||||
assert!(!fun.is_null());
|
|
||||||
|
|
||||||
let constructor = JS_GetFunctionObject(fun);
|
|
||||||
assert!(!constructor.is_null());
|
|
||||||
|
|
||||||
constructor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn define_constructor(cx: *mut JSContext,
|
|
||||||
receiver: HandleObject,
|
|
||||||
name: *const libc::c_char,
|
|
||||||
constructor: HandleObject) {
|
|
||||||
unsafe {
|
|
||||||
let mut already_defined = false;
|
|
||||||
assert!(JS_AlreadyHasOwnProperty(cx, receiver, name, &mut already_defined));
|
|
||||||
|
|
||||||
if !already_defined {
|
|
||||||
assert!(JS_DefineProperty1(cx, receiver, name, constructor, 0, None, None));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates the *interface object*.
|
|
||||||
/// Fails on JSAPI failure.
|
|
||||||
fn create_interface_object(cx: *mut JSContext,
|
|
||||||
receiver: HandleObject,
|
|
||||||
constructor_native: NonNullJSNative,
|
|
||||||
ctor_nargs: u32,
|
|
||||||
proto: HandleObject,
|
|
||||||
members: &'static NativeProperties,
|
|
||||||
name: *const libc::c_char) {
|
|
||||||
unsafe {
|
|
||||||
let constructor = RootedObject::new(cx,
|
|
||||||
create_constructor(cx,
|
|
||||||
constructor_native,
|
|
||||||
ctor_nargs,
|
|
||||||
name));
|
|
||||||
assert!(!constructor.ptr.is_null());
|
|
||||||
|
|
||||||
if let Some(static_methods) = members.static_methods {
|
|
||||||
define_methods(cx, constructor.handle(), static_methods).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(static_properties) = members.static_attrs {
|
|
||||||
define_properties(cx, constructor.handle(), static_properties).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(constants) = members.consts {
|
|
||||||
define_constants(cx, constructor.handle(), constants);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !proto.get().is_null() {
|
|
||||||
assert!(JS_LinkConstructorAndPrototype(cx, constructor.handle(), proto));
|
|
||||||
}
|
|
||||||
|
|
||||||
define_constructor(cx, receiver, name, constructor.handle());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Defines constants on `obj`.
|
/// Defines constants on `obj`.
|
||||||
/// Fails on JSAPI failure.
|
/// Fails on JSAPI failure.
|
||||||
fn define_constants(cx: *mut JSContext, obj: HandleObject, constants: &'static [ConstantSpec]) {
|
pub fn define_constants(cx: *mut JSContext, obj: HandleObject, constants: &'static [ConstantSpec]) {
|
||||||
for spec in constants {
|
for spec in constants {
|
||||||
let value = RootedValue::new(cx, spec.get_value());
|
let value = RootedValue::new(cx, spec.get_value());
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -329,31 +176,6 @@ fn define_constants(cx: *mut JSContext, obj: HandleObject, constants: &'static [
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the *interface prototype object*.
|
|
||||||
/// Fails on JSAPI failure.
|
|
||||||
fn create_interface_prototype_object(cx: *mut JSContext,
|
|
||||||
parent_proto: HandleObject,
|
|
||||||
proto_class: &'static JSClass,
|
|
||||||
members: &'static NativeProperties,
|
|
||||||
rval: MutableHandleObject) {
|
|
||||||
unsafe {
|
|
||||||
rval.set(JS_NewObjectWithUniqueType(cx, proto_class, parent_proto));
|
|
||||||
assert!(!rval.get().is_null());
|
|
||||||
|
|
||||||
if let Some(methods) = members.methods {
|
|
||||||
define_methods(cx, rval.handle(), methods).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(properties) = members.attrs {
|
|
||||||
define_properties(cx, rval.handle(), properties).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(constants) = members.consts {
|
|
||||||
define_constants(cx, rval.handle(), constants);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A throwing constructor, for those interfaces that have neither
|
/// A throwing constructor, for those interfaces that have neither
|
||||||
/// `NoInterfaceObject` nor `Constructor`.
|
/// `NoInterfaceObject` nor `Constructor`.
|
||||||
pub unsafe extern "C" fn throwing_constructor(cx: *mut JSContext,
|
pub unsafe extern "C" fn throwing_constructor(cx: *mut JSContext,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue