--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -5074,92 +5074,100 @@ class CGProxyIndexedOperation(CGProxySpe
class CGProxyIndexedGetter(CGProxyIndexedOperation):
"""
Class to generate a call to an indexed getter. If templateValues is not None
the returned value will be wrapped with wrapForType using templateValues.
"""
def __init__(self, descriptor, templateValues=None):
self.templateValues = templateValues
- CGProxySpecialOperation.__init__(self, descriptor, 'IndexedGetter')
+ CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedGetter')
class CGProxyIndexedPresenceChecker(CGProxyIndexedGetter):
"""
Class to generate a call that checks whether an indexed property exists.
For now, we just delegate to CGProxyIndexedGetter
"""
def __init__(self, descriptor):
CGProxyIndexedGetter.__init__(self, descriptor)
class CGProxyIndexedSetter(CGProxyIndexedOperation):
"""
Class to generate a call to an indexed setter.
"""
def __init__(self, descriptor):
- CGProxySpecialOperation.__init__(self, descriptor, 'IndexedSetter')
+ CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedSetter')
class CGProxyNamedOperation(CGProxySpecialOperation):
"""
Class to generate a call to a named operation.
- """
- def __init__(self, descriptor, name):
+
+ 'value' is the jsval to use for the name; None indicates that it should be
+ gotten from the property id.
+ """
+ def __init__(self, descriptor, name, value=None):
CGProxySpecialOperation.__init__(self, descriptor, name)
+ if value is None:
+ value = "js::IdToValue(id)"
+ self.value = value
def define(self):
# Our first argument is the id we're getting.
argName = self.arguments[0].identifier.name
- return (("JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n"
+ return (("JS::Value nameVal = %s;\n"
"FakeDependentString %s;\n"
"if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n"
" eStringify, eStringify, %s)) {\n"
" return false;\n"
"}\n"
"\n"
"%s* self = UnwrapProxy(proxy);\n" %
- (argName, argName, self.descriptor.nativeType)) +
+ (self.value, argName, argName, self.descriptor.nativeType)) +
CGProxySpecialOperation.define(self))
class CGProxyNamedGetter(CGProxyNamedOperation):
"""
Class to generate a call to an named getter. If templateValues is not None
the returned value will be wrapped with wrapForType using templateValues.
- """
- def __init__(self, descriptor, templateValues=None):
+ 'value' is the jsval to use for the name; None indicates that it should be
+ gotten from the property id.
+ """
+ def __init__(self, descriptor, templateValues=None, value=None):
self.templateValues = templateValues
- CGProxySpecialOperation.__init__(self, descriptor, 'NamedGetter')
+ CGProxyNamedOperation.__init__(self, descriptor, 'NamedGetter', value)
class CGProxyNamedPresenceChecker(CGProxyNamedGetter):
"""
Class to generate a call that checks whether a named property exists.
For now, we just delegate to CGProxyNamedGetter
"""
def __init__(self, descriptor):
CGProxyNamedGetter.__init__(self, descriptor)
class CGProxyNamedSetter(CGProxyNamedOperation):
"""
Class to generate a call to a named setter.
"""
def __init__(self, descriptor):
- CGProxySpecialOperation.__init__(self, descriptor, 'NamedSetter')
+ CGProxyNamedOperation.__init__(self, descriptor, 'NamedSetter')
class CGProxyIndexedDeleter(CGProxyIndexedOperation):
"""
Class to generate a call to an indexed deleter.
"""
def __init__(self, descriptor):
- CGProxySpecialOperation.__init__(self, descriptor, 'IndexedDeleter')
+ CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedDeleter')
class CGProxyNamedDeleter(CGProxyNamedOperation):
"""
Class to generate a call to a named deleter.
"""
def __init__(self, descriptor):
- CGProxySpecialOperation.__init__(self, descriptor, 'NamedDeleter')
+ CGProxyNamedOperation.__init__(self, descriptor, 'NamedDeleter')
class CGProxyIsProxy(CGAbstractMethod):
def __init__(self, descriptor):
args = [Argument('JSObject*', 'obj')]
CGAbstractMethod.__init__(self, descriptor, "IsProxy", "bool", args, alwaysInline=True)
def declare(self):
return ""
def definition_body(self):
@@ -5209,38 +5217,44 @@ class CGDOMJSProxyHandler_getOwnProperty
setOrIndexedGet = ""
if self.descriptor.supportsIndexedProperties():
setOrIndexedGet += "int32_t index = GetArrayIndexFromId(cx, id);\n"
readonly = toStringBool(indexedSetter is None)
fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
templateValues = {'jsvalRef': 'desc->value', 'jsvalPtr': '&desc->value',
'obj': 'proxy', 'successCode': fillDescriptor}
- get = ("if (index >= 0) {\n" +
+ get = ("if (IsArrayIndex(index)) {\n" +
CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
"}\n") % (self.descriptor.nativeType)
if indexedSetter or self.descriptor.operations['NamedSetter']:
setOrIndexedGet += "if (set) {\n"
if indexedSetter:
- setOrIndexedGet += (" if (index >= 0) {\n")
+ setOrIndexedGet += (" if (IsArrayIndex(index)) {\n")
if not 'IndexedCreator' in self.descriptor.operations:
- # FIXME need to check that this is a 'supported property index'
+ # FIXME need to check that this is a 'supported property
+ # index'. But if that happens, watch out for the assumption
+ # below that the name setter always returns for
+ # IsArrayIndex(index).
assert False
setOrIndexedGet += (" FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n" +
" return true;\n" +
" }\n")
if self.descriptor.operations['NamedSetter']:
- setOrIndexedGet += " if (JSID_IS_STRING(id)) {\n"
if not 'NamedCreator' in self.descriptor.operations:
# FIXME need to check that this is a 'supported property name'
assert False
- setOrIndexedGet += (" FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n" +
- " return true;\n" +
- " }\n")
+ create = CGGeneric("FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n"
+ "return true;")
+ # If we have an indexed setter we've already returned
+ if (self.descriptor.supportsIndexedProperties() and
+ not indexedSetter):
+ create = CGIfWrapper(create, "!IsArrayIndex(index)")
+ setOrIndexedGet += CGIndenter(create).define() + "\n"
setOrIndexedGet += "}"
if indexedGetter:
setOrIndexedGet += (" else {\n" +
CGIndenter(CGGeneric(get)).define() +
"}")
setOrIndexedGet += "\n\n"
elif indexedGetter:
setOrIndexedGet += ("if (!set) {\n" +
@@ -5250,20 +5264,23 @@ class CGDOMJSProxyHandler_getOwnProperty
if self.descriptor.supportsNamedProperties():
readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None)
fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
templateValues = {'jsvalRef': 'desc->value', 'jsvalPtr': '&desc->value',
'obj': 'proxy', 'successCode': fillDescriptor}
# Once we start supporting OverrideBuiltins we need to make
# ResolveOwnProperty or EnumerateOwnProperties filter out named
# properties that shadow prototype properties.
+ condition = "!set && !HasPropertyOnPrototype(cx, proxy, this, id)"
+ if self.descriptor.supportsIndexedProperties():
+ condition = "!IsArrayIndex(index) && " + condition
namedGet = ("\n" +
- "if (!set && JSID_IS_STRING(id) && !HasPropertyOnPrototype(cx, proxy, this, id)) {\n" +
- CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "\n" +
- "}\n")
+ CGIfWrapper(CGProxyNamedGetter(self.descriptor, templateValues),
+ condition).define() +
+ "\n")
else:
namedGet = ""
return setOrIndexedGet + """JSObject* expando;
if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED;
if (!JS_GetPropertyDescriptorById(cx, expando, id, flags, desc)) {
return false;
@@ -5288,41 +5305,50 @@ class CGDOMJSProxyHandler_defineProperty
def getBody(self):
set = ""
indexedSetter = self.descriptor.operations['IndexedSetter']
if indexedSetter:
if not (self.descriptor.operations['IndexedCreator'] is indexedSetter):
raise TypeError("Can't handle creator that's different from the setter")
set += ("int32_t index = GetArrayIndexFromId(cx, id);\n" +
- "if (index >= 0) {\n" +
+ "if (IsArrayIndex(index)) {\n" +
CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() +
" return true;\n" +
"}\n") % (self.descriptor.nativeType)
elif self.descriptor.supportsIndexedProperties():
- set += ("if (GetArrayIndexFromId(cx, id) >= 0) {\n" +
+ # XXXbz Once this is fixed to only throw in strict mode, update the
+ # code that decides whether to do a
+ # CGDOMJSProxyHandler_defineProperty at all.
+ set += ("if (IsArrayIndex(GetArrayIndexFromId(cx, id))) {\n" +
" return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
"}\n") % self.descriptor.name
namedSetter = self.descriptor.operations['NamedSetter']
if namedSetter:
if not self.descriptor.operations['NamedCreator'] is namedSetter:
raise TypeError("Can't handle creator that's different from the setter")
- set += ("if (JSID_IS_STRING(id)) {\n" +
- CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + "\n" +
- " return true;\n" +
- "}\n")
- elif self.descriptor.supportsNamedProperties():
- set += ("if (JSID_IS_STRING(id)) {\n" +
- CGIndenter(CGProxyNamedPresenceChecker(self.descriptor)).define() +
- " if (found) {\n"
- " return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
- " }\n" +
- "}\n") % (self.descriptor.name)
- return set + """return mozilla::dom::DOMProxyHandler::defineProperty(%s);""" % ", ".join(a.name for a in self.args)
+ # If we support indexed properties, we won't get down here for
+ # indices, so we can just do our setter unconditionally here.
+ set += (CGProxyNamedSetter(self.descriptor).define() + "\n" +
+ "return true;\n")
+ else:
+ if self.descriptor.supportsNamedProperties():
+ # XXXbz Once this is fixed to only throw in strict mode, update
+ # the code that decides whether to do a
+ # CGDOMJSProxyHandler_defineProperty at all. If we support
+ # indexed properties, we won't get down here for indices, so we
+ # can just do our setter unconditionally here.
+ set += (CGProxyNamedPresenceChecker(self.descriptor).define() + "\n" +
+ "if (found) {\n"
+ " return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n"
+ "}" % self.descriptor.name)
+ set += ("return mozilla::dom::DOMProxyHandler::defineProperty(%s);" %
+ ", ".join(a.name for a in self.args))
+ return set
class CGDOMJSProxyHandler_delete(ClassMethod):
def __init__(self, descriptor):
args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
Argument('jsid', 'id'),
Argument('bool*', 'bp')]
ClassMethod.__init__(self, "delete_", "bool", args)
self.descriptor = descriptor
@@ -5360,25 +5386,28 @@ class CGDOMJSProxyHandler_delete(ClassMe
body = None
return body
delete = ""
indexedBody = getDeleterBody("Indexed")
if indexedBody is not None:
delete += ("int32_t index = GetArrayIndexFromId(cx, id);\n" +
- "if (index >= 0) {\n" +
+ "if (IsArrayIndex(index)) {\n" +
CGIndenter(CGGeneric(indexedBody)).define() + "\n"
" // We always return here, even if the property was not found\n"
" return true;\n" +
"}\n") % self.descriptor.nativeType
namedBody = getDeleterBody("Named")
if namedBody is not None:
- delete += ("if (JSID_IS_STRING(id) && !HasPropertyOnPrototype(cx, proxy, this, id)) {\n" +
+ # We always return above for an index id in the case when we support
+ # indexed properties, so we can just treat the id as a name
+ # unconditionally here.
+ delete += ("if (!HasPropertyOnPrototype(cx, proxy, this, id)) {\n" +
CGIndenter(CGGeneric(namedBody)).define() + "\n"
" if (found) {\n"
" return true;\n"
" }\n"
"}\n")
delete += "return dom::DOMProxyHandler::delete_(cx, proxy, id, bp);";
@@ -5428,26 +5457,28 @@ class CGDOMJSProxyHandler_hasOwn(ClassMe
def __init__(self, descriptor):
args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
Argument('jsid', 'id'), Argument('bool*', 'bp')]
ClassMethod.__init__(self, "hasOwn", "bool", args)
self.descriptor = descriptor
def getBody(self):
if self.descriptor.supportsIndexedProperties():
indexed = ("int32_t index = GetArrayIndexFromId(cx, id);\n" +
- "if (index >= 0) {\n" +
+ "if (IsArrayIndex(index)) {\n" +
CGIndenter(CGProxyIndexedPresenceChecker(self.descriptor)).define() + "\n" +
" *bp = found;\n" +
" return true;\n" +
"}\n\n") % (self.descriptor.nativeType)
else:
indexed = ""
if self.descriptor.supportsNamedProperties():
- named = ("if (JSID_IS_STRING(id) && !HasPropertyOnPrototype(cx, proxy, this, id)) {\n" +
+ # If we support indexed properties we always return above for index
+ # property names, so no need to check for those here.
+ named = ("if (!HasPropertyOnPrototype(cx, proxy, this, id)) {\n" +
CGIndenter(CGProxyNamedPresenceChecker(self.descriptor)).define() + "\n" +
" *bp = found;\n"
" return true;\n"
"}\n" +
"\n")
else:
named = ""
@@ -5483,46 +5514,49 @@ if (expando) {
return JS_GetPropertyById(cx, expando, id, vp);
}
}"""
templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp', 'obj': 'proxy'}
if self.descriptor.supportsIndexedProperties():
getIndexedOrExpando = ("int32_t index = GetArrayIndexFromId(cx, id);\n" +
- "if (index >= 0) {\n" +
+ "if (IsArrayIndex(index)) {\n" +
CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define()) % (self.descriptor.nativeType)
getIndexedOrExpando += """
// Even if we don't have this index, we don't forward the
// get on to our expando object.
} else {
%s
}
""" % (stripTrailingWhitespace(getFromExpando.replace('\n', '\n ')))
else:
getIndexedOrExpando = getFromExpando + "\n"
if self.descriptor.supportsNamedProperties():
- getNamed = ("if (JSID_IS_STRING(id)) {\n" +
- CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
- "}\n")
+ getNamed = CGProxyNamedGetter(self.descriptor, templateValues)
+ if self.descriptor.supportsIndexedProperties():
+ getNamed = CGIfWrapper(getNamed, "!IsArrayIndex(index)")
+ getNamed = getNamed.define() + "\n"
else:
getNamed = ""
return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
"Should not have a XrayWrapper here");
%s
-bool found;
-if (!GetPropertyOnPrototype(cx, proxy, id, &found, vp)) {
- return false;
-}
-
-if (found) {
- return true;
+{ // Scope for this "found" so it doesn't leak to things below
+ bool found;
+ if (!GetPropertyOnPrototype(cx, proxy, id, &found, vp)) {
+ return false;
+ }
+
+ if (found) {
+ return true;
+ }
}
%s
vp->setUndefined();
return true;""" % (getIndexedOrExpando, getNamed)
class CGDOMJSProxyHandler_obj_toString(ClassMethod):
def __init__(self, descriptor):
args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy')]
@@ -5544,26 +5578,30 @@ class CGDOMJSProxyHandler_getElementIfPr
def __init__(self, descriptor):
args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
Argument('JSObject*', 'receiver'),
Argument('uint32_t', 'index'),
Argument('JS::Value*', 'vp'), Argument('bool*', 'present')]
ClassMethod.__init__(self, "getElementIfPresent", "bool", args)
self.descriptor = descriptor
def getBody(self):
+ successCode = ("*present = found;\n"
+ "return true;")
+ templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp',
+ 'obj': 'proxy', 'successCode': successCode}
if self.descriptor.supportsIndexedProperties():
- successCode = """*present = found;
-return true;"""
- templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp',
- 'obj': 'proxy', 'successCode': successCode}
get = (CGProxyIndexedGetter(self.descriptor, templateValues).define() + "\n"
- "// We skip the expando object if there is an indexed getter.\n" +
+ "// We skip the expando object and any named getters if\n"
+ "// there is an indexed getter.\n" +
"\n") % (self.descriptor.nativeType)
else:
- get = """
+ if self.descriptor.supportsNamedProperties():
+ get = CGProxyNamedGetter(self.descriptor, templateValues,
+ "UINT_TO_JSVAL(index)").define()
+ get += """
JSObject* expando = GetExpandoObject(proxy);
if (expando) {
JSBool isPresent;
if (!JS_GetElementIfPresent(cx, expando, index, expando, vp, &isPresent)) {
return false;
}
if (isPresent) {
@@ -5572,18 +5610,16 @@ if (expando) {
}
}
"""
return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
"Should not have a XrayWrapper here");
""" + get + """
-// No need to worry about name getters here, so just check the proto.
-
JSObject *proto;
if (!js::GetObjectProto(cx, proxy, &proto)) {
return false;
}
if (proto) {
JSBool isPresent;
if (!JS_GetElementIfPresent(cx, proto, index, proxy, vp, &isPresent)) {
return false;
@@ -5602,16 +5638,19 @@ class CGDOMJSProxyHandler_getInstance(Cl
def getBody(self):
return """static DOMProxyHandler instance;
return &instance;"""
class CGDOMJSProxyHandler(CGClass):
def __init__(self, descriptor):
constructors = [CGDOMJSProxyHandler_CGDOMJSProxyHandler()]
methods = [CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor)]
+ # XXXbz This should really just test supportsIndexedProperties() and
+ # supportsNamedProperties(), but that would make us throw in all cases
+ # because we don't know whether we're in strict mode.
if descriptor.operations['IndexedSetter'] or descriptor.operations['NamedSetter']:
methods.append(CGDOMJSProxyHandler_defineProperty(descriptor))
methods.extend([CGDOMJSProxyHandler_getOwnPropertyNames(descriptor),
CGDOMJSProxyHandler_hasOwn(descriptor),
CGDOMJSProxyHandler_get(descriptor),
CGDOMJSProxyHandler_obj_toString(descriptor),
CGDOMJSProxyHandler_finalize(descriptor),
CGDOMJSProxyHandler_getElementIfPresent(descriptor),