Bug 1104955 part 3. Pass our unscopable names to CreateInterfaceObjects and have it define the right thing on the prototype. r=khuey

This commit is contained in:
Boris Zbarsky 2016-03-29 15:50:38 -04:00
parent 99babb71e8
commit 4622df74e0
5 changed files with 64 additions and 8 deletions

View File

@ -766,7 +766,8 @@ CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global,
JS::Handle<JSObject*> parentProto,
const js::Class* protoClass,
const NativeProperties* properties,
const NativeProperties* chromeOnlyProperties)
const NativeProperties* chromeOnlyProperties,
const char* const* unscopableNames)
{
JS::Rooted<JSObject*> ourProto(cx,
JS_NewObjectWithUniqueType(cx, Jsvalify(protoClass), parentProto));
@ -775,6 +776,28 @@ CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global,
return nullptr;
}
if (unscopableNames) {
JS::Rooted<JSObject*> unscopableObj(cx, JS_NewPlainObject(cx));
if (!unscopableObj) {
return nullptr;
}
for (; *unscopableNames; ++unscopableNames) {
if (!JS_DefineProperty(cx, unscopableObj, *unscopableNames,
JS::TrueHandleValue, JSPROP_ENUMERATE)) {
return nullptr;
}
}
JS::Rooted<jsid> unscopableId(cx,
SYMBOL_TO_JSID(JS::GetWellKnownSymbol(cx, JS::SymbolCode::unscopables)));
// Readonly and non-enumerable to match Array.prototype.
if (!JS_DefinePropertyById(cx, ourProto, unscopableId, unscopableObj,
JSPROP_READONLY)) {
return nullptr;
}
}
return ourProto;
}
@ -830,7 +853,8 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
JS::Heap<JSObject*>* constructorCache,
const NativeProperties* properties,
const NativeProperties* chromeOnlyProperties,
const char* name, bool defineOnGlobal)
const char* name, bool defineOnGlobal,
const char* const* unscopableNames)
{
MOZ_ASSERT(protoClass || constructorClass || constructor,
"Need at least one class or a constructor!");
@ -861,7 +885,8 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
if (protoClass) {
proto =
CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
properties, chromeOnlyProperties);
properties, chromeOnlyProperties,
unscopableNames);
if (!proto) {
return;
}

View File

@ -594,6 +594,8 @@ struct NamedConstructor
* false in situations where we want the properties to only
* appear on privileged Xrays but not on the unprivileged
* underlying global.
* unscopableNames if not null it points to a null-terminated list of const
* char* names of the unscopable properties for this interface.
*
* At least one of protoClass, constructorClass or constructor should be
* non-null. If constructorClass or constructor are non-null, the resulting
@ -610,7 +612,8 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
JS::Heap<JSObject*>* constructorCache,
const NativeProperties* regularProperties,
const NativeProperties* chromeOnlyProperties,
const char* name, bool defineOnGlobal);
const char* name, bool defineOnGlobal,
const char* const* unscopableNames);
/**
* Define the properties (regular and chrome-only) on obj.

View File

@ -2745,13 +2745,14 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
properties should be a PropertyArrays instance.
"""
def __init__(self, descriptor, properties):
def __init__(self, descriptor, properties, haveUnscopables):
args = [Argument('JSContext*', 'aCx'),
Argument('JS::Handle<JSObject*>', 'aGlobal'),
Argument('ProtoAndIfaceCache&', 'aProtoAndIfaceCache'),
Argument('bool', 'aDefineOnGlobal')]
CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args)
self.properties = properties
self.haveUnscopables = haveUnscopables
def definition_body(self):
(protoGetter, protoHandleGetter) = InterfacePrototypeObjectProtoGetter(self.descriptor)
@ -2891,7 +2892,8 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
interfaceCache,
${properties},
${chromeProperties},
${name}, aDefineOnGlobal);
${name}, aDefineOnGlobal,
${unscopableNames});
""",
protoClass=protoClass,
parentProto=parentProto,
@ -2903,7 +2905,8 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
interfaceCache=interfaceCache,
properties=properties,
chromeProperties=chromeProperties,
name='"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "nullptr")
name='"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "nullptr",
unscopableNames="unscopableNames" if self.haveUnscopables else "nullptr")
# If we fail after here, we must clear interface and prototype caches
# using this code: intermediate failure must not expose the interface in
@ -12078,7 +12081,8 @@ class CGDescriptor(CGThing):
# CGCreateInterfaceObjectsMethod needs to come after our
# CGDOMJSClass and unscopables, if any.
cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties,
haveUnscopables))
# CGGetProtoObjectMethod and CGGetConstructorObjectMethod need
# to come after CGCreateInterfaceObjectsMethod.

View File

@ -34873,6 +34873,12 @@
"url": "/dom/collections/HTMLCollection-as-proto-length-get-throws.html"
}
],
"dom/nodes/remove-unscopable.html": [
{
"path": "dom/nodes/remove-unscopable.html",
"url": "/dom/nodes/remove-unscopable.html"
}
],
"js/builtins/Promise-incumbent-global.sub.html": [
{
"path": "js/builtins/Promise-incumbent-global.sub.html",

View File

@ -0,0 +1,18 @@
<!doctype html>
<meta charset=utf-8>
<title></title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<div id="testDiv" onclick="result1 = remove; result2 = this.remove;"></div>
<script>
var remove = "Hello there";
var result1;
var result2;
test(function() {
assert_true(Element.prototype[Symbol.unscopables].remove);
var div = document.querySelector("#testDiv");
div.dispatchEvent(new Event("click"));
assert_equals(typeof result1, "string");
assert_equals(typeof result2, "function");
}, "remove() should be unscopable")
</script>