Skip to content

Commit

Permalink
Auto merge of #13185 - nox:namespaces, r=jdm,Ms2ger
Browse files Browse the repository at this point in the history
Make console a namespace (fixes #13010)

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/13185)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Sep 10, 2016
2 parents 5e7d918 + 2bc0862 commit 84f3cf2
Show file tree
Hide file tree
Showing 16 changed files with 223 additions and 120 deletions.
85 changes: 62 additions & 23 deletions components/script/dom/bindings/codegen/CodegenRust.py
Expand Up @@ -26,6 +26,7 @@
)

from Configuration import (
MakeNativeName,
MemberIsUnforgeable,
getModuleFromObject,
getTypesFromCallback,
Expand Down Expand Up @@ -80,7 +81,7 @@ def toStringBool(arg):


def toBindingNamespace(arg):
return re.sub("((_workers)?$)", "Binding\\1", arg)
return re.sub("((_workers)?$)", "Binding\\1", MakeNativeName(arg))


def stripTrailingWhitespace(text):
Expand All @@ -96,9 +97,6 @@ def innerSequenceType(type):
return type.inner.inner if type.nullable() else type.inner


def MakeNativeName(name):
return name[0].upper() + name[1:]

builtinNames = {
IDLType.Tags.bool: 'bool',
IDLType.Tags.int8: 'i8',
Expand Down Expand Up @@ -1811,7 +1809,8 @@ def componentTypes(type):

def isImportable(type):
if not type.isType():
assert type.isInterface() or type.isDictionary() or type.isEnum()
assert (type.isInterface() or type.isDictionary() or
type.isEnum() or type.isNamespace())
return True
return not (type.builtin or type.isSequence() or type.isUnion())

Expand All @@ -1830,7 +1829,7 @@ def getIdentifier(t):
if t.isCallback():
return t.callback.identifier
return t.identifier
assert t.isInterface() or t.isDictionary() or t.isEnum()
assert t.isInterface() or t.isDictionary() or t.isEnum() or t.isNamespace()
return t.identifier

def removeWrapperAndNullableTypes(types):
Expand Down Expand Up @@ -1881,7 +1880,7 @@ def removeWrapperAndNullableTypes(types):
# Importing these types in the same module that defines them is an error.
if t in dictionaries or t in enums:
continue
if t.isInterface():
if t.isInterface() or t.isNamespace():
descriptor = descriptorProvider.getDescriptor(getIdentifier(t).name)
extras += [descriptor.path]
if descriptor.interface.parent:
Expand Down Expand Up @@ -2060,6 +2059,17 @@ def __init__(self, descriptor):
self.descriptor = descriptor

def define(self):
if self.descriptor.interface.isNamespace():
classString = self.descriptor.interface.getExtendedAttribute("ClassString")
if classString:
classString = classString[0]
else:
classString = "Object"
return """\
static NAMESPACE_OBJECT_CLASS: NamespaceObjectClass = unsafe {
NamespaceObjectClass::new(%s)
};
""" % str_to_const_array(classString)
if self.descriptor.interface.ctor():
constructorBehavior = "InterfaceConstructorBehavior::call(%s)" % CONSTRUCT_HOOK_NAME
else:
Expand Down Expand Up @@ -2659,6 +2669,28 @@ def __init__(self, descriptor, properties, haveUnscopables):

def definition_body(self):
name = self.descriptor.interface.identifier.name
if self.descriptor.interface.isNamespace():
if self.descriptor.interface.getExtendedAttribute("ProtoObjectHack"):
proto = "JS_GetObjectPrototype(cx, global)"
else:
proto = "JS_NewPlainObject(cx)"
if self.properties.static_methods.length():
methods = self.properties.static_methods.variableName()
else:
methods = "&[]"
return CGGeneric("""\
rooted!(in(cx) let proto = %(proto)s);
assert!(!proto.is_null());
rooted!(in(cx) let mut namespace = ptr::null_mut());
create_namespace_object(cx, global, proto.handle(), &NAMESPACE_OBJECT_CLASS,
%(methods)s, %(name)s, namespace.handle_mut());
assert!(!namespace.is_null());
assert!((*cache)[PrototypeList::Constructor::%(id)s as usize].is_null());
(*cache)[PrototypeList::Constructor::%(id)s as usize] = namespace.get();
<*mut JSObject>::post_barrier((*cache).as_mut_ptr().offset(PrototypeList::Constructor::%(id)s as isize),
ptr::null_mut(),
namespace.get());
""" % {"id": MakeNativeName(name), "methods": methods, "name": str_to_const_array(name), "proto": proto})
if self.descriptor.interface.isCallback():
assert not self.descriptor.interface.ctor() and self.descriptor.interface.hasConstants()
return CGGeneric("""\
Expand Down Expand Up @@ -2873,7 +2905,7 @@ def __init__(self, descriptor, name, idPrefix="", pub=False):
Argument('MutableHandleObject', 'rval')]
CGAbstractMethod.__init__(self, descriptor, name,
'void', args, pub=pub, unsafe=True)
self.id = idPrefix + "::" + self.descriptor.name
self.id = idPrefix + "::" + MakeNativeName(self.descriptor.name)

def definition_body(self):
return CGGeneric("""
Expand Down Expand Up @@ -3016,7 +3048,7 @@ def define(self):
return CGAbstractMethod.define(self)

def definition_body(self):
if self.descriptor.interface.isCallback():
if self.descriptor.interface.isCallback() or self.descriptor.interface.isNamespace():
function = "GetConstructorObject"
else:
function = "GetProtoObject"
Expand Down Expand Up @@ -3047,15 +3079,15 @@ class CGCallGenerator(CGThing):
exception from the native code, or None if no error reporting is needed.
"""
def __init__(self, errorResult, arguments, argsPre, returnType,
extendedAttributes, descriptorProvider, nativeMethodName,
extendedAttributes, descriptor, nativeMethodName,
static, object="this"):
CGThing.__init__(self)

assert errorResult is None or isinstance(errorResult, str)

isFallible = errorResult is not None

result = getRetvalDeclarationForType(returnType, descriptorProvider)
result = getRetvalDeclarationForType(returnType, descriptor)
if isFallible:
result = CGWrapper(result, pre="Result<", post=", Error>")

Expand All @@ -3076,7 +3108,7 @@ def __init__(self, errorResult, arguments, argsPre, returnType,

call = CGGeneric(nativeMethodName)
if static:
call = CGWrapper(call, pre="%s::" % descriptorProvider.interface.identifier.name)
call = CGWrapper(call, pre="%s::" % MakeNativeName(descriptor.interface.identifier.name))
else:
call = CGWrapper(call, pre="%s." % object)
call = CGList([call, CGWrapper(args, pre="(", post=")")])
Expand Down Expand Up @@ -5454,6 +5486,8 @@ def generate_imports(config, cgthings, descriptors, callbacks=None, dictionaries
'dom::bindings::js::OptionalRootedReference',
'dom::bindings::js::Root',
'dom::bindings::js::RootedReference',
'dom::bindings::namespace::NamespaceObjectClass',
'dom::bindings::namespace::create_namespace_object',
'dom::bindings::reflector::MutReflectable',
'dom::bindings::reflector::Reflectable',
'dom::bindings::utils::DOMClass',
Expand Down Expand Up @@ -5561,7 +5595,7 @@ def reexportedName(name):
return name

cgThings = []
if not descriptor.interface.isCallback():
if not descriptor.interface.isCallback() and not descriptor.interface.isNamespace():
cgThings.append(CGGetProtoObjectMethod(descriptor))
reexports.append('GetProtoObject')
if (descriptor.interface.hasInterfaceObject() and
Expand Down Expand Up @@ -5622,7 +5656,7 @@ def reexportedName(name):
if not descriptor.interface.isCallback():
cgThings.append(CGInterfaceObjectJSClass(descriptor))

if not descriptor.interface.isCallback():
if not descriptor.interface.isCallback() and not descriptor.interface.isNamespace():
cgThings.append(CGPrototypeJSClass(descriptor))

# If there are no constant members, don't make a module for constants
Expand Down Expand Up @@ -5679,7 +5713,7 @@ def reexportedName(name):
reexports.append('Wrap')

haveUnscopables = False
if not descriptor.interface.isCallback():
if not descriptor.interface.isCallback() and not descriptor.interface.isNamespace():
if unscopableNames:
haveUnscopables = True
cgThings.append(
Expand All @@ -5706,7 +5740,7 @@ def reexportedName(name):
cgThings, public=True),
post='\n')
reexports = ', '.join(map(lambda name: reexportedName(name), reexports))
self.cgRoot = CGList([CGGeneric('pub use self::%sBinding::{%s};' % (descriptor.name, reexports)),
self.cgRoot = CGList([CGGeneric('pub use self::%s::{%s};' % (toBindingNamespace(descriptor.name), reexports)),
cgThings], '\n')

def define(self):
Expand Down Expand Up @@ -6760,10 +6794,12 @@ def InterfaceObjectMap(config):
@staticmethod
def PrototypeList(config):
# Prototype ID enum.
interfaces = config.getDescriptors(isCallback=False)
interfaces = config.getDescriptors(isCallback=False, isNamespace=False)
protos = [d.name for d in interfaces]
constructors = [d.name for d in config.getDescriptors(hasInterfaceObject=True)
if d.shouldHaveGetConstructorObjectMethod()]
constructors = sorted([MakeNativeName(d.name)
for d in config.getDescriptors(hasInterfaceObject=True)
if d.shouldHaveGetConstructorObjectMethod()])

proxies = [d.name for d in config.getDescriptors(proxy=True)]

return CGList([
Expand Down Expand Up @@ -6800,10 +6836,13 @@ def RegisterBindings(config):

@staticmethod
def InterfaceTypes(config):
descriptors = [d.name for d in config.getDescriptors(register=True,
descriptors = sorted([MakeNativeName(d.name)
for d in config.getDescriptors(register=True,
isCallback=False,
isIteratorInterface=False)]
curr = CGList([CGGeneric("pub use dom::%s::%s;\n" % (name.lower(), name)) for name in descriptors])
isIteratorInterface=False)])
curr = CGList([CGGeneric("pub use dom::%s::%s;\n" % (name.lower(),
MakeNativeName(name)))
for name in descriptors])
curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
return curr

Expand All @@ -6814,7 +6853,7 @@ def leafModule(d):
return getModuleFromObject(d).split('::')[-1]

descriptors = config.getDescriptors(register=True, isIteratorInterface=False)
descriptors = (set(d.name + "Binding" for d in descriptors) |
descriptors = (set(toBindingNamespace(d.name) for d in descriptors) |
set(leafModule(d) for d in config.callbacks) |
set(leafModule(d) for d in config.getDictionaries()))
curr = CGList([CGGeneric("pub mod %s;\n" % name) for name in sorted(descriptors)])
Expand Down
22 changes: 15 additions & 7 deletions components/script/dom/bindings/codegen/Configuration.py
Expand Up @@ -4,7 +4,7 @@

import os

from WebIDL import IDLExternalInterface, IDLInterface, IDLWrapperType, WebIDLError
from WebIDL import IDLExternalInterface, IDLWrapperType, WebIDLError


class Configuration:
Expand All @@ -30,10 +30,9 @@ def __init__(self, filename, parseData):
raise WebIDLError("Servo does not support external interfaces.",
[thing.location])

# Some toplevel things are sadly types, and those have an
# isInterface that doesn't mean the same thing as IDLObject's
# isInterface()...
if not isinstance(thing, IDLInterface):
assert not thing.isType()

if not thing.isInterface() and not thing.isNamespace():
continue

iface = thing
Expand Down Expand Up @@ -83,6 +82,8 @@ def getDescriptors(self, **filters):
getter = lambda x: x.interface.hasInterfaceObject()
elif key == 'isCallback':
getter = lambda x: x.interface.isCallback()
elif key == 'isNamespace':
getter = lambda x: x.interface.isNamespace()
elif key == 'isJSImplemented':
getter = lambda x: x.interface.isJSImplemented()
elif key == 'isGlobal':
Expand Down Expand Up @@ -210,7 +211,7 @@ def __init__(self, config, interface, desc):
if self.interface.isIteratorInterface():
pathDefault = 'dom::bindings::iterable::IterableIterator'
else:
pathDefault = 'dom::types::%s' % typeName
pathDefault = 'dom::types::%s' % MakeNativeName(typeName)

self.concreteType = typeName
self.register = desc.get('register', True)
Expand All @@ -223,6 +224,7 @@ def __init__(self, config, interface, desc):
# If we're concrete, we need to crawl our ancestor interfaces and mark
# them as having a concrete descendant.
self.concrete = (not self.interface.isCallback() and
not self.interface.isNamespace() and
not self.interface.getExtendedAttribute("Abstract"))
self.hasUnforgeableMembers = (self.concrete and
any(MemberIsUnforgeable(m, self) for m in
Expand Down Expand Up @@ -381,7 +383,7 @@ def hasDescendants(self):

def shouldHaveGetConstructorObjectMethod(self):
assert self.interface.hasInterfaceObject()
return self.interface.isCallback() or self.hasDescendants()
return self.interface.isCallback() or self.interface.isNamespace() or self.hasDescendants()

def isExposedConditionally(self):
return self.interface.isExposedConditionally()
Expand All @@ -396,6 +398,12 @@ def isGlobal(self):


# Some utility methods


def MakeNativeName(name):
return name[0].upper() + name[1:]


def getModuleFromObject(object):
return ('dom::bindings::codegen::Bindings::' +
os.path.basename(object.location.filename()).split('.webidl')[0] + 'Binding')
Expand Down
9 changes: 9 additions & 0 deletions components/script/dom/bindings/global.rs
Expand Up @@ -13,6 +13,7 @@ use dom::bindings::conversions::root_from_object;
use dom::bindings::error::ErrorInfo;
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflectable, Reflector};
use dom::console::TimerSet;
use dom::window::{self, ScriptHelpers};
use dom::workerglobalscope::WorkerGlobalScope;
use ipc_channel::ipc::IpcSender;
Expand Down Expand Up @@ -271,6 +272,14 @@ impl<'a> GlobalRef<'a> {
}
}

/// Returns the global's timers for the Console API.
pub fn console_timers(&self) -> &TimerSet {
match *self {
GlobalRef::Window(ref window) => window.console_timers(),
GlobalRef::Worker(ref worker) => worker.console_timers(),
}
}

/// Returns a wrapper for runnables to ensure they are cancelled if the global
/// is being destroyed.
pub fn get_runnable_wrapper(&self) -> RunnableWrapper {
Expand Down
7 changes: 5 additions & 2 deletions components/script/dom/bindings/interface.rs
Expand Up @@ -257,7 +257,8 @@ pub unsafe fn create_named_constructors(
}
}

unsafe fn create_object(
/// Create a new object with a unique type.
pub unsafe fn create_object(
cx: *mut JSContext,
proto: HandleObject,
class: &'static JSClass,
Expand Down Expand Up @@ -316,7 +317,9 @@ pub unsafe fn is_exposed_in(object: HandleObject, globals: Globals) -> bool {
globals.contains(dom_class.global)
}

unsafe fn define_on_global_object(
/// Define a property with a given name on the global object. Should be called
/// through the resolve hook.
pub unsafe fn define_on_global_object(
cx: *mut JSContext,
global: HandleObject,
name: &[u8],
Expand Down
1 change: 1 addition & 0 deletions components/script/dom/bindings/mod.rs
Expand Up @@ -140,6 +140,7 @@ pub mod inheritance;
pub mod interface;
pub mod iterable;
pub mod js;
pub mod namespace;
pub mod num;
pub mod proxyhandler;
pub mod refcounted;
Expand Down
42 changes: 42 additions & 0 deletions components/script/dom/bindings/namespace.rs
@@ -0,0 +1,42 @@
/* 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 namespace objects.

use dom::bindings::guard::Guard;
use dom::bindings::interface::{create_object, define_on_global_object};
use js::jsapi::{HandleObject, JSClass, JSContext, JSFunctionSpec, MutableHandleObject};
use libc;
use std::ptr;

/// The class of a namespace object.
#[derive(Copy, Clone)]
pub struct NamespaceObjectClass(JSClass);

unsafe impl Sync for NamespaceObjectClass {}

impl NamespaceObjectClass {
/// Create a new `NamespaceObjectClass` structure.
pub const unsafe fn new(name: &'static [u8]) -> Self {
NamespaceObjectClass(JSClass {
name: name as *const _ as *const libc::c_char,
flags: 0,
cOps: ptr::null_mut(),
reserved: [ptr::null_mut(); 3],
})
}
}

/// Create a new namespace object.
pub unsafe fn create_namespace_object(
cx: *mut JSContext,
global: HandleObject,
proto: HandleObject,
class: &'static NamespaceObjectClass,
methods: &[Guard<&'static [JSFunctionSpec]>],
name: &[u8],
rval: MutableHandleObject) {
create_object(cx, proto, &class.0, methods, &[], &[], rval);
define_on_global_object(cx, global, name, rval.handle());
}

0 comments on commit 84f3cf2

Please sign in to comment.