diff options
author | Anthony Ramine <n.oxyde@gmail.com> | 2015-10-12 14:50:07 +0200 |
---|---|---|
committer | Anthony Ramine <n.oxyde@gmail.com> | 2015-12-02 22:15:11 +0100 |
commit | 60976406cc6ddf99b3d3a512dce0b4fd01b686f1 (patch) | |
tree | c32f5beeacaeab0375e7dfcaa79c34d21ca7bf00 /components/script/dom | |
parent | 29c42a9f78a20ddeb5aa89b79d578a039c087967 (diff) | |
download | servo-60976406cc6ddf99b3d3a512dce0b4fd01b686f1.tar.gz servo-60976406cc6ddf99b3d3a512dce0b4fd01b686f1.zip |
Implement [Unforgeable]
This is mostly stolen from Gecko. As there, we define the unforgeable members
on an object stored in the slots of the prototype object. They are then copied
onto instance objects when they are instantiated. It should be noted that
proxy objects see their unforgeable memebers defined on their expando object.
Unforgeable attributes aren't properly inherited in codegen (in a similar
fashion as getters and setters as filed in #5875) and require to be redefined
in derived interfaces. Fortunately, there are currently no such interfaces.
No unforgeable members can be included into the TestBinding interfaces for good
measure because they are not compatible with setters.
Given the unforgeable holder object has the same prototype as actual instances
of the interface, the finalize hook needs to check its slot pointer for nullity
before dropping it.
The new failing test isn't related to Unforgeable attributes, but to the fact
that all Document instances currently have a Location, even if their window
isn't in a browsing context.
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/codegen/CodegenRust.py | 303 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/Configuration.py | 10 | ||||
-rw-r--r-- | components/script/dom/bindings/utils.rs | 8 | ||||
-rw-r--r-- | components/script/dom/webidls/Document.webidl | 2 | ||||
-rw-r--r-- | components/script/dom/webidls/Location.webidl | 2 | ||||
-rw-r--r-- | components/script/dom/webidls/Window.webidl | 4 | ||||
-rw-r--r-- | components/script/dom/xmldocument.rs | 6 |
7 files changed, 253 insertions, 82 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index eaf2bbe0fe7..d88e6d9fa32 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -21,7 +21,12 @@ from WebIDL import ( IDLUndefinedValue, ) -from Configuration import getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback +from Configuration import ( + MemberIsUnforgeable, + getTypesFromCallback, + getTypesFromDescriptor, + getTypesFromDictionary, +) AUTOGENERATED_WARNING_COMMENT = \ "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n" @@ -1380,7 +1385,8 @@ class MethodDefiner(PropertyDefiner): """ A class for defining methods on a prototype object. """ - def __init__(self, descriptor, name, static): + def __init__(self, descriptor, name, static, unforgeable): + assert not (static and unforgeable) PropertyDefiner.__init__(self, descriptor, name) # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822 @@ -1391,36 +1397,40 @@ class MethodDefiner(PropertyDefiner): if not descriptor.interface.isCallback() or static: methods = [m for m in descriptor.interface.members if m.isMethod() and m.isStatic() == static and - not m.isIdentifierLess()] + not m.isIdentifierLess() and + MemberIsUnforgeable(m, descriptor) == unforgeable] else: methods = [] self.regular = [{"name": m.identifier.name, "methodInfo": not m.isStatic(), - "length": methodLength(m), - "flags": "JSPROP_ENUMERATE"} for m in methods] + "length": methodLength(m)} for m in methods] # FIXME Check for an existing iterator on the interface first. if any(m.isGetter() and m.isIndexed() for m in methods): self.regular.append({"name": '@@iterator', "methodInfo": False, "selfHostedName": "ArrayValues", - "length": 0, - "flags": "JSPROP_ENUMERATE"}) + "length": 0}) - if not static: + isUnforgeableInterface = bool(descriptor.interface.getExtendedAttribute("Unforgeable")) + if not static and unforgeable == isUnforgeableInterface: stringifier = descriptor.operations['Stringifier'] if stringifier: self.regular.append({ "name": "toString", "nativeName": stringifier.identifier.name, "length": 0, - "flags": "JSPROP_ENUMERATE" }) + self.unforgeable = unforgeable def generateArray(self, array, name): if len(array) == 0: return "" + flags = "JSPROP_ENUMERATE" + if self.unforgeable: + flags += " | JSPROP_PERMANENT | JSPROP_READONLY" + def specData(m): # TODO: Use something like JS_FNSPEC # https://github.com/servo/servo/issues/6391 @@ -1444,16 +1454,16 @@ class MethodDefiner(PropertyDefiner): accessor = 'Some(%s)' % m.get("nativeName", m["name"]) if m["name"].startswith("@@"): return ('(SymbolCode::%s as i32 + 1)' - % m["name"][2:], accessor, jitinfo, m["length"], m["flags"], selfHostedName) - return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], m["flags"], selfHostedName) + % m["name"][2:], accessor, jitinfo, m["length"], flags, selfHostedName) + return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], flags, selfHostedName) return self.generatePrefableArray( array, name, ' JSFunctionSpec {\n' ' name: %s as *const u8 as *const libc::c_char,\n' - ' call: JSNativeWrapper {op: %s, info: %s},\n' + ' call: JSNativeWrapper { op: %s, info: %s },\n' ' nargs: %s,\n' - ' flags: %s as u16,\n' + ' flags: (%s) as u16,\n' ' selfHostedName: %s\n' ' }', ' JSFunctionSpec {\n' @@ -1468,23 +1478,27 @@ class MethodDefiner(PropertyDefiner): class AttrDefiner(PropertyDefiner): - def __init__(self, descriptor, name, static): + def __init__(self, descriptor, name, static, unforgeable): + assert not (static and unforgeable) PropertyDefiner.__init__(self, descriptor, name) self.name = name self.descriptor = descriptor self.regular = [ m - for m in descriptor.interface.members - if m.isAttr() and m.isStatic() == static + for m in descriptor.interface.members if + m.isAttr() and m.isStatic() == static and + MemberIsUnforgeable(m, descriptor) == unforgeable ] self.static = static + self.unforgeable = unforgeable def generateArray(self, array, name): if len(array) == 0: return "" - def flags(attr): - return "JSPROP_SHARED | JSPROP_ENUMERATE" + flags = "JSPROP_ENUMERATE | JSPROP_SHARED" + if self.unforgeable: + flags += " | JSPROP_READONLY | JSPROP_PERMANENT" def getter(attr): if self.static: @@ -1520,7 +1534,7 @@ class AttrDefiner(PropertyDefiner): "native": accessor}) def specData(attr): - return (str_to_const_array(attr.identifier.name), flags(attr), getter(attr), + return (str_to_const_array(attr.identifier.name), flags, getter(attr), setter(attr)) return self.generatePrefableArray( @@ -1844,10 +1858,16 @@ class CGPrototypeJSClass(CGThing): self.descriptor = descriptor def define(self): + name = str_to_const_array(self.descriptor.interface.identifier.name + "Prototype") + slotCount = 0 + if self.descriptor.hasUnforgeableMembers: + slotCount += 1 return """\ static PrototypeClass: JSClass = JSClass { - name: %s as *const u8 as *const libc::c_char, - flags: 0, + name: %(name)s as *const u8 as *const libc::c_char, + flags: + // JSCLASS_HAS_RESERVED_SLOTS(%(slotCount)s) + (%(slotCount)s & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT, addProperty: None, delProperty: None, getProperty: None, @@ -1862,7 +1882,7 @@ static PrototypeClass: JSClass = JSClass { trace: None, reserved: [0 as *mut libc::c_void; 25] }; -""" % str_to_const_array(self.descriptor.interface.identifier.name + "Prototype") +""" % {'name': name, 'slotCount': slotCount} class CGInterfaceObjectJSClass(CGThing): @@ -2181,6 +2201,68 @@ JS_SetReservedSlot(obj.ptr, DOM_WEAK_SLOT, PrivateValue(ptr::null()));""" return create +def InitUnforgeablePropertiesOnHolder(descriptor, properties): + """ + Define the unforgeable properties on the unforgeable holder for + the interface represented by descriptor. + + properties is a PropertyArrays instance. + """ + unforgeables = [] + + defineUnforgeableAttrs = "define_properties(cx, unforgeable_holder.handle(), %s).unwrap();" + defineUnforgeableMethods = "define_methods(cx, unforgeable_holder.handle(), %s).unwrap();" + + unforgeableMembers = [ + (defineUnforgeableAttrs, properties.unforgeable_attrs), + (defineUnforgeableMethods, properties.unforgeable_methods), + ] + for template, array in unforgeableMembers: + if array.length() > 0: + unforgeables.append(CGGeneric(template % array.variableName())) + return CGList(unforgeables, "\n") + + +def CopyUnforgeablePropertiesToInstance(descriptor): + """ + Copy the unforgeable properties from the unforgeable holder for + this interface to the instance object we have. + """ + if not descriptor.hasUnforgeableMembers: + return "" + copyCode = "" + + # For proxies, we want to define on the expando object, not directly on the + # reflector, so we can make sure we don't get confused by named getters. + if descriptor.proxy: + copyCode += """\ +let mut expando = RootedObject::new(cx, ptr::null_mut()); +{ + let _ac = JSAutoCompartment::new(cx, scope.get()); + expando.handle_mut().set(ensure_expando_object(cx, obj.handle())); +} +""" + obj = "expando" + else: + obj = "obj" + + # We can't do the fast copy for globals, because we can't allocate the + # unforgeable holder for those with the right JSClass. Luckily, there + # aren't too many globals being created. + if descriptor.isGlobal(): + copyFunc = "JS_CopyPropertiesFrom" + else: + copyFunc = "JS_InitializePropertiesFromCompatibleNativeObject" + copyCode += """\ +let mut unforgeable_holder = RootedObject::new(cx, ptr::null_mut()); +unforgeable_holder.handle_mut().set( + JS_GetReservedSlot(proto.ptr, DOM_PROTO_UNFORGEABLE_HOLDER_SLOT).to_object()); +assert!(%(copyFunc)s(cx, %(obj)s.handle(), unforgeable_holder.handle())); +""" % {'copyFunc': copyFunc, 'obj': obj} + + return copyCode + + class CGWrapMethod(CGAbstractMethod): """ Class that generates the FooBinding::Wrap function for non-callback @@ -2199,7 +2281,9 @@ class CGWrapMethod(CGAbstractMethod): pub=True, unsafe=True) def definition_body(self): + unforgeable = CopyUnforgeablePropertiesToInstance(self.descriptor) if not self.descriptor.isGlobal(): + create = CreateBindingJSObject(self.descriptor, "scope") return CGGeneric("""\ let _ar = JSAutoRequest::new(cx); let scope = scope.reflector().get_jsobject(); @@ -2213,28 +2297,31 @@ let mut proto = RootedObject::new(cx, ptr::null_mut()); } assert!(!proto.ptr.is_null()); -%s +%(createObject)s +%(copyUnforgeable)s (*raw).init_reflector(obj.ptr); -Root::from_ref(&*raw)""" % CreateBindingJSObject(self.descriptor, "scope")) +Root::from_ref(&*raw)""" % {'copyUnforgeable': unforgeable, 'createObject': create}) else: + create = CreateBindingJSObject(self.descriptor) return CGGeneric("""\ let _ar = JSAutoRequest::new(cx); -%s +%(createObject)s let _ac = JSAutoCompartment::new(cx, obj.ptr); let mut proto = RootedObject::new(cx, ptr::null_mut()); GetProtoObject(cx, obj.handle(), obj.handle(), proto.handle_mut()); JS_SetPrototype(cx, obj.handle(), proto.handle()); +%(copyUnforgeable)s (*raw).init_reflector(obj.ptr); let ret = Root::from_ref(&*raw); RegisterBindings::Register(cx, obj.handle()); -ret""" % CreateBindingJSObject(self.descriptor)) +ret""" % {'copyUnforgeable': unforgeable, 'createObject': create}) class CGIDLInterface(CGThing): @@ -2279,17 +2366,29 @@ class CGAbstractExternMethod(CGAbstractMethod): class PropertyArrays(): def __init__(self, descriptor): self.static_methods = MethodDefiner(descriptor, "StaticMethods", - static=True) + static=True, unforgeable=False) self.static_attrs = AttrDefiner(descriptor, "StaticAttributes", - static=True) - self.methods = MethodDefiner(descriptor, "Methods", static=False) - self.attrs = AttrDefiner(descriptor, "Attributes", static=False) + static=True, unforgeable=False) + self.methods = MethodDefiner(descriptor, "Methods", static=False, unforgeable=False) + self.unforgeable_methods = MethodDefiner(descriptor, "UnforgeableMethods", + static=False, unforgeable=True) + self.attrs = AttrDefiner(descriptor, "Attributes", static=False, unforgeable=False) + self.unforgeable_attrs = AttrDefiner(descriptor, "UnforgeableAttributes", + static=False, unforgeable=True) self.consts = ConstDefiner(descriptor, "Constants") pass @staticmethod def arrayNames(): - return ["static_methods", "static_attrs", "methods", "attrs", "consts"] + return [ + "static_methods", + "static_attrs", + "methods", + "unforgeable_methods", + "attrs", + "unforgeable_attrs", + "consts", + ] def variableNames(self): names = {} @@ -2392,10 +2491,54 @@ let named_constructors: [(NonNullJSNative, &'static str, u32); %d] = [ createArray += "," createArray += "];" + if self.descriptor.hasUnforgeableMembers: + # We want to use the same JSClass and prototype as the object we'll + # end up defining the unforgeable properties on in the end, so that + # we can use JS_InitializePropertiesFromCompatibleNativeObject to do + # a fast copy. In the case of proxies that's null, because the + # expando object is a vanilla object, but in the case of other DOM + # objects it's whatever our class is. + # + # Also, for a global we can't use the global's class; just use + # nullpr and when we do the copy off the holder we'll take a slower + # path. This also means that we don't need to worry about matching + # the prototype. + if self.descriptor.proxy or self.descriptor.isGlobal(): + holderClass = "ptr::null()" + holderProto = "ptr::null_mut()" + else: + holderClass = "&Class.base as *const js::jsapi::Class as *const JSClass" + holderProto = "rval.get()" + # JS_NewObjectWithoutMetadata() is unsafe. + self.unsafe = True + createUnforgeableHolder = CGGeneric(""" +let mut unforgeable_holder = RootedObject::new(cx, ptr::null_mut()); +{ + let holder_class = %(holderClass)s; + let holder_proto = RootedObject::new(cx, %(holderProto)s); + unforgeable_holder.handle_mut().set( + JS_NewObjectWithoutMetadata(cx, holder_class, holder_proto.handle())); + assert!(!unforgeable_holder.ptr.is_null()); +}""" % {'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, + ObjectValue(&*unforgeable_holder.ptr))""") + + unforgeableHolderSetup = CGList( + [createUnforgeableHolder, installUnforgeableHolder], "\n") + else: + unforgeableHolderSetup = None + return CGList([ CGGeneric(getParentProto), CGGeneric(createArray), - CGGeneric(call % self.properties.variableNames()) + CGGeneric(call % self.properties.variableNames()), + unforgeableHolderSetup, ], "\n") @@ -4269,6 +4412,9 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): namedSetter = self.descriptor.operations['NamedSetter'] if namedSetter: + if self.descriptor.hasUnforgeableMembers: + raise TypeError("Can't handle a named setter on an interface that has " + "unforgeables. Figure out how that should work!") set += ("if RUST_JSID_IS_STRING(id) {\n" + CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + " (*opresult).code_ = 0; /* SpecialCodes::OkCode */\n" + @@ -4308,6 +4454,9 @@ class CGDOMJSProxyHandler_delete(CGAbstractExternMethod): def getBody(self): set = "" if self.descriptor.operations['NamedDeleter']: + if self.descriptor.hasUnforgeableMembers: + raise TypeError("Can't handle a deleter on an interface that has " + "unforgeables. Figure out how that should work!") set += CGProxyNamedDeleter(self.descriptor).define() set += "return proxyhandler::delete(%s);" % ", ".join(a.name for a in self.args) return set @@ -4422,7 +4571,7 @@ return true;""" class CGDOMJSProxyHandler_get(CGAbstractExternMethod): def __init__(self, descriptor): args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'), - Argument('HandleObject', '_receiver'), Argument('HandleId', 'id'), + Argument('HandleObject', 'receiver'), Argument('HandleId', 'id'), Argument('MutableHandleValue', 'vp')] CGAbstractExternMethod.__init__(self, descriptor, "get", "bool", args) self.descriptor = descriptor @@ -4437,7 +4586,7 @@ if !expando.ptr.is_null() { } if hasProp { - return JS_GetPropertyById(cx, expando.handle(), id, vp); + return JS_ForwardGetPropertyTo(cx, expando.handle(), id, receiver, vp); } }""" @@ -4554,7 +4703,10 @@ if !weak_box_ptr.is_null() { } """ % descriptor.concreteType release += """\ -let _ = Box::from_raw(this as *mut %s); +if !this.is_null() { + // The pointer can be null if the object is the unforgeable holder of that interface. + let _ = Box::from_raw(this as *mut %s); +} debug!("%s finalize: {:p}", this);\ """ % (descriptor.concreteType, descriptor.concreteType) return release @@ -5177,30 +5329,31 @@ class CGBindingRoot(CGThing): # Add imports curr = CGImports(curr, descriptors + callbackDescriptors, mainCallbacks, [ 'js', - 'js::JS_CALLEE', - 'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS, JSCLASS_IMPLEMENTS_BARRIERS}', - 'js::{JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_SHIFT}', - 'js::{JSCLASS_RESERVED_SLOTS_MASK}', - 'js::{JSPROP_ENUMERATE, JSPROP_SHARED}', - 'js::{JSITER_OWNONLY, JSITER_HIDDEN, JSITER_SYMBOLS}', + 'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IMPLEMENTS_BARRIERS}', + 'js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_MASK}', + 'js::{JSCLASS_RESERVED_SLOTS_SHIFT, JSITER_HIDDEN, JSITER_OWNONLY}', + 'js::{JSITER_SYMBOLS, JSPROP_ENUMERATE, JSPROP_PERMANENT, JSPROP_READONLY}', + 'js::{JSPROP_SHARED, JS_CALLEE}', 'js::error::throw_type_error', - 'js::jsapi::{JS_CallFunctionValue, JS_GetClass, JS_GetGlobalForObject}', - 'js::jsapi::{JS_GetObjectPrototype, JS_GetProperty, JS_GetPropertyById}', - 'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot}', - 'js::jsapi::{JS_HasProperty, JS_HasPropertyById, JS_IsExceptionPending}', - 'js::jsapi::{JS_NewObjectWithGivenProto, JS_NewObject, IsCallable, JS_SetProperty, JS_SetPrototype}', - 'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSContext}', - 'js::jsapi::{JSClass, FreeOp, JSFreeOp, JSFunctionSpec, jsid}', - 'js::jsapi::{MutableHandleValue, MutableHandleObject, HandleObject, HandleValue, RootedObject}', - 'js::jsapi::{RootedValue, JSNativeWrapper, JSNative, JSObject, JSPropertyDescriptor}', - 'js::jsapi::{RootedId, JS_InternString, RootedString, INTERNED_STRING_TO_JSID}', - 'js::jsapi::{JSPropertySpec}', - 'js::jsapi::{JSString, JSTracer, JSJitInfo, JSTypedMethodJitInfo, OpType, AliasSet, ArgType}', - 'js::jsapi::{MutableHandle, Handle, HandleId, JSType, JSValueType}', - 'js::jsapi::{SymbolCode, ObjectOpResult, HandleValueArray}', - 'js::jsapi::{JSJitGetterCallArgs, JSJitSetterCallArgs, JSJitMethodCallArgs, CallArgs}', - 'js::jsapi::{JSAutoCompartment, JSAutoRequest, JS_ComputeThis}', - 'js::jsapi::{GetGlobalForObjectCrossCompartment, AutoIdVector, GetPropertyKeys}', + 'js::jsapi::{AliasSet, ArgType, AutoIdVector, CallArgs, FreeOp}', + 'js::jsapi::{GetGlobalForObjectCrossCompartment , GetPropertyKeys, Handle}', + 'js::jsapi::{HandleId, HandleObject, HandleValue, HandleValueArray}', + 'js::jsapi::{INTERNED_STRING_TO_JSID, IsCallable, JS_CallFunctionValue}', + 'js::jsapi::{JS_ComputeThis, JS_CopyPropertiesFrom, JS_ForwardGetPropertyTo}', + 'js::jsapi::{JS_GetClass, JS_GetGlobalForObject, JS_GetObjectPrototype}', + 'js::jsapi::{JS_GetProperty, JS_GetPropertyById, JS_GetPropertyDescriptorById}', + 'js::jsapi::{JS_GetReservedSlot, JS_HasProperty, JS_HasPropertyById}', + 'js::jsapi::{JS_InitializePropertiesFromCompatibleNativeObject, JS_InternString}', + 'js::jsapi::{JS_IsExceptionPending, JS_NewObject, JS_NewObjectWithGivenProto}', + 'js::jsapi::{JS_NewObjectWithoutMetadata, JS_SetProperty, JS_SetPrototype}', + 'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSAutoCompartment, JSAutoRequest}', + 'js::jsapi::{JSContext, JSClass, JSFreeOp, JSFunctionSpec, JSJitGetterCallArgs}', + 'js::jsapi::{JSJitInfo, JSJitMethodCallArgs, JSJitSetterCallArgs, JSNative}', + 'js::jsapi::{JSObject, JSNativeWrapper, JSPropertyDescriptor, JSPropertySpec}', + 'js::jsapi::{JSString, JSTracer, JSType, JSTypedMethodJitInfo, JSValueType}', + 'js::jsapi::{ObjectOpResult, OpType, MutableHandle, MutableHandleObject}', + 'js::jsapi::{MutableHandleValue, RootedId, RootedObject, RootedString}', + 'js::jsapi::{RootedValue, SymbolCode, jsid}', 'js::jsval::JSVal', 'js::jsval::{ObjectValue, ObjectOrNullValue, PrivateValue}', 'js::jsval::{NullValue, UndefinedValue}', @@ -5209,30 +5362,24 @@ class CGBindingRoot(CGThing): 'js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO}', 'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING, int_to_jsid}', 'js::glue::AppendToAutoIdVector', - 'js::rust::GCMethods', + 'js::rust::{GCMethods, define_methods, define_properties}', 'dom::bindings', 'dom::bindings::global::{GlobalRef, global_root_from_object, global_root_from_reflector}', 'dom::bindings::js::{JS, Root, RootedReference}', 'dom::bindings::js::{OptionalRootedReference}', 'dom::bindings::reflector::{Reflectable}', - 'dom::bindings::utils::{create_dom_global, do_create_interface_objects}', - 'dom::bindings::utils::ConstantSpec', - 'dom::bindings::utils::{DOMClass}', - 'dom::bindings::utils::{DOMJSClass, JSCLASS_DOM_GLOBAL}', - 'dom::bindings::utils::{find_enum_string_index, get_array_index_from_id}', - 'dom::bindings::utils::{get_property_on_prototype, get_proto_or_iface_array}', - 'dom::bindings::utils::{finalize_global, trace_global}', - 'dom::bindings::utils::has_property_on_prototype', - 'dom::bindings::utils::is_platform_object', - 'dom::bindings::utils::throwing_constructor', - 'dom::bindings::utils::get_dictionary_property', - 'dom::bindings::utils::set_dictionary_property', - 'dom::bindings::utils::{NativeProperties, NativePropertyHooks}', + 'dom::bindings::utils::{ConstantSpec, DOMClass, DOMJSClass}', + 'dom::bindings::utils::{DOM_PROTO_UNFORGEABLE_HOLDER_SLOT, JSCLASS_DOM_GLOBAL}', + 'dom::bindings::utils::{NativeProperties, NativePropertyHooks, NonNullJSNative}', + 'dom::bindings::utils::{create_dom_global, do_create_interface_objects, finalize_global}', + 'dom::bindings::utils::{find_enum_string_index, generic_getter}', + 'dom::bindings::utils::{generic_lenient_getter, generic_lenient_setter}', + 'dom::bindings::utils::{generic_method, generic_setter, get_array_index_from_id}', + 'dom::bindings::utils::{get_dictionary_property, get_property_on_prototype}', + 'dom::bindings::utils::{get_proto_or_iface_array, has_property_on_prototype}', + 'dom::bindings::utils::{is_platform_object, set_dictionary_property}', + 'dom::bindings::utils::{throwing_constructor, trace_global}', 'dom::bindings::utils::ConstantVal::{IntVal, UintVal}', - 'dom::bindings::utils::NonNullJSNative', - 'dom::bindings::utils::{generic_getter, generic_lenient_getter}', - 'dom::bindings::utils::{generic_lenient_setter, generic_method}', - 'dom::bindings::utils::generic_setter', 'dom::bindings::trace::{JSTraceable, RootedTraceable}', 'dom::bindings::callback::{CallbackContainer,CallbackInterface,CallbackFunction}', 'dom::bindings::callback::{CallSetup,ExceptionHandling}', @@ -5248,8 +5395,8 @@ class CGBindingRoot(CGThing): 'dom::bindings::error::Error::JSFailed', 'dom::bindings::error::throw_dom_exception', 'dom::bindings::proxyhandler', - 'dom::bindings::proxyhandler::{fill_property_descriptor, get_expando_object}', - 'dom::bindings::proxyhandler::{get_property_descriptor}', + 'dom::bindings::proxyhandler::{ensure_expando_object, fill_property_descriptor}', + 'dom::bindings::proxyhandler::{get_expando_object, get_property_descriptor}', 'dom::bindings::num::Finite', 'dom::bindings::str::ByteString', 'dom::bindings::str::USVString', diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py index 4f59ff09f5b..d0af7e37929 100644 --- a/components/script/dom/bindings/codegen/Configuration.py +++ b/components/script/dom/bindings/codegen/Configuration.py @@ -139,6 +139,13 @@ class DescriptorProvider: return self.config.getDescriptor(interfaceName) +def MemberIsUnforgeable(member, descriptor): + return ((member.isAttr() or member.isMethod()) and + not member.isStatic() and + (member.isUnforgeable() or + bool(descriptor.interface.getExtendedAttribute("Unforgeable")))) + + class Descriptor(DescriptorProvider): """ Represents a single descriptor for an interface. See Bindings.conf. @@ -174,6 +181,9 @@ class Descriptor(DescriptorProvider): # them as having a concrete descendant. self.concrete = (not self.interface.isCallback() and desc.get('concrete', True)) + self.hasUnforgeableMembers = (self.concrete and + any(MemberIsUnforgeable(m, self) for m in + self.interface.members)) self.operations = { 'IndexedGetter': None, diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 97d5bb12eba..fe7c8030baa 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -78,6 +78,10 @@ impl GlobalStaticData { } } +/// The index of the slot where the object holder of that interface's +/// unforgeable members are defined. +pub const DOM_PROTO_UNFORGEABLE_HOLDER_SLOT: u32 = 0; + /// The index of the slot that contains a reference to the ProtoOrIfaceArray. // All DOM globals must have a slot at DOM_PROTOTYPE_SLOT. pub const DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT; @@ -181,8 +185,12 @@ pub fn get_proto_or_iface_array(global: *mut JSObject) -> *mut ProtoOrIfaceArray 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. diff --git a/components/script/dom/webidls/Document.webidl b/components/script/dom/webidls/Document.webidl index 863824338ed..9df747edc49 100644 --- a/components/script/dom/webidls/Document.webidl +++ b/components/script/dom/webidls/Document.webidl @@ -79,7 +79,7 @@ enum DocumentReadyState { "loading", "interactive", "complete" }; // [OverrideBuiltins] partial /*sealed*/ interface Document { // resource metadata management - // [PutForwards=href, Unforgeable] + [/*PutForwards=href, */Unforgeable] readonly attribute Location/*?*/ location; readonly attribute DOMString domain; // readonly attribute DOMString referrer; diff --git a/components/script/dom/webidls/Location.webidl b/components/script/dom/webidls/Location.webidl index f82031ac74b..8af05fbd178 100644 --- a/components/script/dom/webidls/Location.webidl +++ b/components/script/dom/webidls/Location.webidl @@ -4,7 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // https://html.spec.whatwg.org/multipage/#location -/*[Unforgeable]*/ interface Location { +[Unforgeable] interface Location { /*stringifier*/ attribute USVString href; // attribute USVString origin; attribute USVString protocol; diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl index 82a2f3fd34f..21ac6bf31a8 100644 --- a/components/script/dom/webidls/Window.webidl +++ b/components/script/dom/webidls/Window.webidl @@ -11,9 +11,9 @@ //[Replaceable] readonly attribute WindowProxy self; readonly attribute Window window; [BinaryName="Self_"] readonly attribute Window self; - /*[Unforgeable]*/ readonly attribute Document document; + [Unforgeable] readonly attribute Document document; // attribute DOMString name; - /*[PutForwards=href, Unforgeable]*/ readonly attribute Location location; + [/*PutForwards=href, */Unforgeable] readonly attribute Location location; //readonly attribute History history; //[Replaceable] readonly attribute BarProp locationbar; //[Replaceable] readonly attribute BarProp menubar; diff --git a/components/script/dom/xmldocument.rs b/components/script/dom/xmldocument.rs index 0553760ca6c..6f73ecbf8ea 100644 --- a/components/script/dom/xmldocument.rs +++ b/components/script/dom/xmldocument.rs @@ -12,6 +12,7 @@ use dom::bindings::inheritance::Castable; use dom::bindings::js::{Root, RootedReference}; use dom::bindings::reflector::{Reflectable, reflect_dom_object}; use dom::document::{Document, DocumentSource, IsHTMLDocument}; +use dom::location::Location; use dom::node::Node; use dom::window::Window; use js::jsapi::{JSContext, JSObject}; @@ -85,6 +86,11 @@ impl XMLDocument { } impl XMLDocumentMethods for XMLDocument { + // https://html.spec.whatwg.org/multipage/#dom-document-location + fn Location(&self) -> Root<Location> { + self.document.Location() + } + // https://html.spec.whatwg.org/multipage/#dom-tree-accessors:supported-property-names fn SupportedPropertyNames(&self) -> Vec<DOMString> { self.document.SupportedPropertyNames() |