servo: Merge #2599 - Improve types around CreateInterfaceObjects2 (from Ms2ger:constantspec); r=jdm
authorMs2ger <ms2ger@gmail.com>
Fri, 06 Jun 2014 14:04:29 -0400
changeset 334489 3306c07d48d2d2ed486d7f1d509a219a40188338
parent 334488 90ea05cfd2fd6e01fd22b32b1a1cfe4cbd493543
child 334490 2f65d85ad234c8604b0227aa56dcd0ba20a83b12
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdm
servo: Merge #2599 - Improve types around CreateInterfaceObjects2 (from Ms2ger:constantspec); r=jdm Source-Repo: https://github.com/servo/servo Source-Revision: eae9b943991cef4495bdc0b2bb5f8deae57cb835
servo/src/components/script/dom/bindings/codegen/CodegenRust.py
servo/src/components/script/dom/bindings/utils.rs
--- a/servo/src/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/servo/src/components/script/dom/bindings/codegen/CodegenRust.py
@@ -1057,78 +1057,42 @@ class PropertyDefiner:
         if prefName is None:
             return None
         # It's a list of strings
         assert(len(prefName) is 1)
         assert(prefName[0] is not None)
         return prefName[0]
 
     def generatePrefableArray(self, array, name, specTemplate, specTerminator,
-                              specType, getPref, getDataTuple):
+                              specType, getDataTuple):
         """
         This method generates our various arrays.
 
         array is an array of interface members as passed to generateArray
 
         name is the name as passed to generateArray
 
         specTemplate is a template for each entry of the spec array
 
-        specTerminator is a terminator for the spec array (inserted every time
-          our controlling pref changes and at the end of the array)
+        specTerminator is a terminator for the spec array (inserted at the end
+          of the array), or None
 
         specType is the actual typename of our spec
 
-        getPref is a callback function that takes an array entry and returns
-          the corresponding pref value.
-
         getDataTuple is a callback function that takes an array entry and
           returns a tuple suitable for substitution into specTemplate.
         """
 
-        # We want to generate a single list of specs, but with specTerminator
-        # inserted at every point where the pref name controlling the member
-        # changes.  That will make sure the order of the properties as exposed
-        # on the interface and interface prototype objects does not change when
-        # pref control is added to members while still allowing us to define all
-        # the members in the smallest number of JSAPI calls.
         assert(len(array) is not 0)
-        lastPref = getPref(array[0]) # So we won't put a specTerminator
-                                     # at the very front of the list.
         specs = []
-        prefableSpecs = []
-
-        prefableTemplate = '  { true, &%s[%d] }'
-        prefCacheTemplate = '&%s[%d].enabled'
-        def switchToPref(props, pref):
-            # Remember the info about where our pref-controlled
-            # booleans live.
-            if pref is not None:
-                props.prefCacheData.append(
-                    (pref, prefCacheTemplate % (name, len(prefableSpecs)))
-                    )
-            # Set up pointers to the new sets of specs and ids
-            # inside prefableSpecs and prefableIds
-            prefableSpecs.append(prefableTemplate %
-                                 (name + "_specs", len(specs)))
-
-        switchToPref(self, lastPref)
 
         for member in array:
-            curPref = getPref(member)
-            if lastPref != curPref:
-                # Terminate previous list
-                specs.append(specTerminator)
-                # And switch to our new pref
-                switchToPref(self, curPref)
-                lastPref = curPref
-            # And the actual spec
             specs.append(specTemplate % getDataTuple(member))
-        specs.append(specTerminator)
-        prefableSpecs.append("  { false, NULL }");
+        if specTerminator:
+            specs.append(specTerminator)
 
         return (("static %s: [%s, ..%i] = [\n" +
                  ",\n".join(specs) + "\n" +
                  "];\n\n") % (name, specType, len(specs)))
 
 # The length of a method is the maximum of the lengths of the
 # argument lists of all its overloads.
 def methodLength(method):
@@ -1189,19 +1153,16 @@ class MethodDefiner(PropertyDefiner):
             if not descriptor.interface.hasInterfacePrototypeObject():
                 # non-static methods go on the interface prototype object
                 assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
 
     def generateArray(self, array, name):
         if len(array) == 0:
             return ""
 
-        def pref(m):
-            return m["pref"]
-
         def specData(m):
             if m.get("methodInfo", True):
                 jitinfo = ("&%s_methodinfo" % m["name"])
                 accessor = "genericMethod"
             else:
                 jitinfo = "0 as *JSJitInfo"
                 accessor = m.get("nativeName", m["name"])
             return (m["name"], accessor, jitinfo, m["length"], m["flags"])
@@ -1211,17 +1172,17 @@ class MethodDefiner(PropertyDefiner):
                                                          str_to_const_array(m["name"]))
         
         decls = ''.join([stringDecl(m) for m in array])
         return decls + self.generatePrefableArray(
             array, name,
             '  JSFunctionSpec {name: &%s_name as *u8 as *libc::c_char, call: JSNativeWrapper {op: Some(%s), info: %s}, nargs: %s, flags: %s as u16, selfHostedName: 0 as *libc::c_char }',
             '  JSFunctionSpec {name: 0 as *libc::c_char, call: JSNativeWrapper {op: None, info: 0 as *JSJitInfo}, nargs: 0, flags: 0, selfHostedName: 0 as *libc::c_char }',
             'JSFunctionSpec',
-            pref, specData)
+            specData)
 
 class AttrDefiner(PropertyDefiner):
     def __init__(self, descriptor, name):
         PropertyDefiner.__init__(self, descriptor, name)
         self.name = name
         self.chrome = [m for m in descriptor.interface.members if m.isAttr()]
         self.regular = [m for m in self.chrome if not isChromeOnly(m)]
 
@@ -1259,17 +1220,17 @@ class AttrDefiner(PropertyDefiner):
         
         decls = ''.join([stringDecl(m) for m in array])
 
         return decls + self.generatePrefableArray(
             array, name,
             '  JSPropertySpec { name: &%s_name as *u8 as *libc::c_char, tinyid: 0, flags: ((%s) & 0xFF) as u8, getter: %s, setter: %s }',
             '  JSPropertySpec { name: 0 as *libc::c_char, tinyid: 0, flags: 0, getter: JSPropertyOpWrapper {op: None, info: 0 as *JSJitInfo}, setter: JSStrictPropertyOpWrapper {op: None, info: 0 as *JSJitInfo} }',
             'JSPropertySpec',
-            PropertyDefiner.getControllingPref, specData)
+            specData)
 
 class ConstDefiner(PropertyDefiner):
     """
     A class for definining constants on the interface object
     """
     def __init__(self, descriptor, name):
         PropertyDefiner.__init__(self, descriptor, name)
         self.name = name
@@ -1281,27 +1242,26 @@ class ConstDefiner(PropertyDefiner):
             return ""
 
         def specData(const):
             return (const.identifier.name,
                     convertConstIDLValueToJSVal(const.value))
 
         def stringDecl(const):
             name = const.identifier.name
-            return "static %s_name: [u8, ..%i] = %s;\n" % (name, len(name) + 1,
-                                                         str_to_const_array(name))
+            return "static %s_name: &'static [u8] = &%s;\n" % (name, str_to_const_array(name))
         
         decls = ''.join([stringDecl(m) for m in array])
 
         return decls + self.generatePrefableArray(
             array, name,
-            '  ConstantSpec { name: &%s_name as *u8 as *libc::c_char, value: %s }',
-            '  ConstantSpec { name: 0 as *libc::c_char, value: VoidVal }',
+            '  ConstantSpec { name: %s_name, value: %s }',
+            None,
             'ConstantSpec',
-            PropertyDefiner.getControllingPref, specData)
+            specData)
 
 # We'll want to insert the indent at the beginnings of lines, but we
 # don't want to indent empty lines.  So only indent lines that have a
 # non-newline character on them.
 lineStartDetector = re.compile("^(?=[^\n])", re.MULTILINE)
 class CGIndenter(CGThing):
     """
     A class that takes another CGThing and generates code that indents that
@@ -1977,18 +1937,18 @@ class CGCreateInterfaceObjectsMethod(CGA
             else:
                 domClass = "&Class.dom_class"
         else:
             domClass = "ptr::null()"
 
         def arrayPtr(name):
             val = ('%(' + name + ')s') % self.properties.variableNames(False)
             if val == "ptr::null()":
-                return val
-            return "&%s[0]" % val
+                return "None"
+            return "Some(%s.as_slice())" % val
 
         call = """return CreateInterfaceObjects2(aCx, aGlobal, aReceiver, parentProto,
                                %s, %s, %d,
                                %s,
                                %s,
                                %s,
                                %s,
                                %s,
--- a/servo/src/components/script/dom/bindings/utils.rs
+++ b/servo/src/components/script/dom/bindings/utils.rs
@@ -187,17 +187,17 @@ pub enum ConstantVal {
     DoubleVal(f64),
     BoolVal(bool),
     NullVal,
     VoidVal
 }
 
 #[deriving(Clone)]
 pub struct ConstantSpec {
-    pub name: *libc::c_char,
+    pub name: &'static [u8],
     pub value: ConstantVal
 }
 
 pub struct DOMClass {
     // A list of interfaces that this object implements, in order of decreasing
     // derivedness.
     pub interface_chain: [PrototypeList::id::ID, ..MAX_PROTO_CHAIN_LENGTH]
 }
@@ -214,20 +214,20 @@ pub fn GetProtoOrIfaceArray(global: *mut
     }
 }
 
 pub fn CreateInterfaceObjects2(cx: *mut JSContext, global: *mut JSObject, receiver: *mut JSObject,
                                protoProto: *mut JSObject, protoClass: *JSClass,
                                constructor: JSNative,
                                ctorNargs: u32,
                                domClass: *DOMClass,
-                               methods: *JSFunctionSpec,
-                               properties: *JSPropertySpec,
-                               constants: *ConstantSpec,
-                               staticMethods: *JSFunctionSpec,
+                               methods: Option<&'static [JSFunctionSpec]>,
+                               properties: Option<&'static [JSPropertySpec]>,
+                               constants: Option<&'static [ConstantSpec]>,
+                               staticMethods: Option<&'static [JSFunctionSpec]>,
                                name: &str) -> *mut JSObject {
     let mut proto = ptr::mut_null();
     if protoClass.is_not_null() {
         proto = CreateInterfacePrototypeObject(cx, global, protoProto,
                                                protoClass, methods,
                                                properties, constants);
         if proto.is_null() {
             return ptr::mut_null();
@@ -256,37 +256,45 @@ pub fn CreateInterfaceObjects2(cx: *mut 
     } else {
         interface
     }
 }
 
 fn CreateInterfaceObject(cx: *mut JSContext, global: *mut JSObject, receiver: *mut JSObject,
                          constructorNative: JSNative,
                          ctorNargs: u32, proto: *mut JSObject,
-                         staticMethods: *JSFunctionSpec,
-                         constants: *ConstantSpec,
+                         staticMethods: Option<&'static [JSFunctionSpec]>,
+                         constants: Option<&'static [ConstantSpec]>,
                          name: *libc::c_char) -> *mut JSObject {
     unsafe {
         let fun = JS_NewFunction(cx, constructorNative, ctorNargs,
                                  JSFUN_CONSTRUCTOR, global, name);
         if fun.is_null() {
             return ptr::mut_null();
         }
 
         let constructor = JS_GetFunctionObject(fun);
         assert!(constructor.is_not_null());
 
-        if staticMethods.is_not_null() &&
-            !DefineMethods(cx, constructor, staticMethods) {
-            return ptr::mut_null();
+        match staticMethods {
+            Some(staticMethods) => {
+                if !DefineMethods(cx, constructor, staticMethods) {
+                    return ptr::mut_null();
+                }
+            },
+            _ => (),
         }
 
-        if constants.is_not_null() &&
-            !DefineConstants(cx, constructor, constants) {
-            return ptr::mut_null();
+        match constants {
+            Some(constants) => {
+                if !DefineConstants(cx, constructor, constants) {
+                    return ptr::mut_null();
+                }
+            },
+            _ => (),
         }
 
         if proto.is_not_null() && JS_LinkConstructorAndPrototype(cx, constructor, proto) == 0 {
             return ptr::mut_null();
         }
 
         let mut alreadyDefined = 0;
         if JS_AlreadyHasOwnProperty(cx, receiver, name, &mut alreadyDefined) == 0 {
@@ -298,77 +306,83 @@ fn CreateInterfaceObject(cx: *mut JSCont
                               None, None, 0) == 0 {
             return ptr::mut_null();
         }
 
         return constructor;
     }
 }
 
-fn DefineConstants(cx: *mut JSContext, obj: *mut JSObject, constants: *ConstantSpec) -> bool {
-    let mut i = 0;
-    loop {
+fn DefineConstants(cx: *mut JSContext, obj: *mut JSObject, constants: &'static [ConstantSpec]) -> bool {
+    constants.iter().all(|spec| {
+        let jsval = match spec.value {
+            NullVal => NullValue(),
+            IntVal(i) => Int32Value(i),
+            UintVal(u) => UInt32Value(u),
+            DoubleVal(d) => DoubleValue(d),
+            BoolVal(b) => BooleanValue(b),
+            VoidVal => UndefinedValue(),
+        };
         unsafe {
-            let spec = *constants.offset(i);
-            if spec.name.is_null() {
-                return true;
-            }
-            let jsval = match spec.value {
-                NullVal => NullValue(),
-                IntVal(i) => Int32Value(i),
-                UintVal(u) => UInt32Value(u),
-                DoubleVal(d) => DoubleValue(d),
-                BoolVal(b) => BooleanValue(b),
-                VoidVal => UndefinedValue(),
-            };
-            if JS_DefineProperty(cx, obj, spec.name,
-                                 jsval, None,
-                                 None,
-                                 JSPROP_ENUMERATE | JSPROP_READONLY |
-                                 JSPROP_PERMANENT) == 0 {
-                return false;
-            }
+            JS_DefineProperty(cx, obj, spec.name.as_ptr() as *libc::c_char,
+                              jsval, None, None,
+                              JSPROP_ENUMERATE | JSPROP_READONLY |
+                              JSPROP_PERMANENT) != 0
         }
-        i += 1;
+    })
+}
+
+fn DefineMethods(cx: *mut JSContext, obj: *mut JSObject, methods: &'static [JSFunctionSpec]) -> bool {
+    unsafe {
+        JS_DefineFunctions(cx, obj, methods.as_ptr()) != 0
     }
 }
 
-fn DefineMethods(cx: *mut JSContext, obj: *mut JSObject, methods: *JSFunctionSpec) -> bool {
+fn DefineProperties(cx: *mut JSContext, obj: *mut JSObject, properties: &'static [JSPropertySpec]) -> bool {
     unsafe {
-        JS_DefineFunctions(cx, obj, methods) != 0
-    }
-}
-
-fn DefineProperties(cx: *mut JSContext, obj: *mut JSObject, properties: *JSPropertySpec) -> bool {
-    unsafe {
-        JS_DefineProperties(cx, obj, properties) != 0
+        JS_DefineProperties(cx, obj, properties.as_ptr()) != 0
     }
 }
 
 fn CreateInterfacePrototypeObject(cx: *mut JSContext, global: *mut JSObject,
                                   parentProto: *mut JSObject, protoClass: *JSClass,
-                                  methods: *JSFunctionSpec,
-                                  properties: *JSPropertySpec,
-                                  constants: *ConstantSpec) -> *mut JSObject {
+                                  methods: Option<&'static [JSFunctionSpec]>,
+                                  properties: Option<&'static [JSPropertySpec]>,
+                                  constants: Option<&'static [ConstantSpec]>) -> *mut JSObject {
     unsafe {
         let ourProto = JS_NewObjectWithUniqueType(cx, protoClass, parentProto, global);
         if ourProto.is_null() {
             return ptr::mut_null();
         }
 
-        if methods.is_not_null() && !DefineMethods(cx, ourProto, methods) {
-            return ptr::mut_null();
+        match methods {
+            Some(methods) => {
+                if !DefineMethods(cx, ourProto, methods) {
+                    return ptr::mut_null();
+                }
+            },
+            _ => (),
         }
 
-        if properties.is_not_null() && !DefineProperties(cx, ourProto, properties) {
-            return ptr::mut_null();
+        match properties {
+            Some(properties) => {
+                if !DefineProperties(cx, ourProto, properties) {
+                    return ptr::mut_null();
+                }
+            },
+            _ => (),
         }
 
-        if constants.is_not_null() && !DefineConstants(cx, ourProto, constants) {
-            return ptr::mut_null();
+        match constants {
+            Some(constants) => {
+                if !DefineConstants(cx, ourProto, constants) {
+                    return ptr::mut_null();
+                }
+            },
+            _ => (),
         }
 
         return ourProto;
     }
 }
 
 pub extern fn ThrowingConstructor(_cx: *mut JSContext, _argc: c_uint, _vp: *mut JSVal) -> JSBool {
     //XXX should trigger exception here