Bug 747287 - Part 2: Generate infalliblity data for further JIT optimization. (r=peterv)

This commit is contained in:
Eric Faust 2012-08-07 22:26:18 -07:00
parent b451a97a53
commit 513357911e

View File

@ -2404,6 +2404,8 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
"successCode" is the code to run once we have successfully done the "successCode" is the code to run once we have successfully done the
conversion. The resulting string should be used with string.Template, it conversion. The resulting string should be used with string.Template, it
needs the following keys when substituting: jsvalPtr/jsvalRef/obj. needs the following keys when substituting: jsvalPtr/jsvalRef/obj.
Returns (templateString, infallibility of conversion template)
""" """
haveSuccessCode = successCode is not None haveSuccessCode = successCode is not None
if not haveSuccessCode: if not haveSuccessCode:
@ -2442,7 +2444,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
return str return str
if type is None or type.isVoid(): if type is None or type.isVoid():
return setValue("JSVAL_VOID") return (setValue("JSVAL_VOID"), True)
if type.isArray(): if type.isArray():
raise TypeError("Can't handle array return values yet") raise TypeError("Can't handle array return values yet")
@ -2450,14 +2452,14 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
if type.isSequence(): if type.isSequence():
if type.nullable(): if type.nullable():
# Nullable sequences are Nullable< nsTArray<T> > # Nullable sequences are Nullable< nsTArray<T> >
return """ (recTemplate, recInfall) = getWrapTemplateForType(type.inner, descriptorProvider,
"%s.Value()" % result, successCode,
isCreator)
return ("""
if (%s.IsNull()) { if (%s.IsNull()) {
%s %s
} }
%s""" % (result, CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define(), %s""" % (result, CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define(), recTemplate), recInfall)
getWrapTemplateForType(type.inner, descriptorProvider,
"%s.Value()" % result, successCode,
isCreator))
# Now do non-nullable sequences. We use setting the element # Now do non-nullable sequences. We use setting the element
# in the array as our succcess code because when we succeed in # in the array as our succcess code because when we succeed in
@ -2476,7 +2478,7 @@ if (%s.IsNull()) {
} }
) )
innerTemplate = CGIndenter(CGGeneric(innerTemplate)).define() innerTemplate = CGIndenter(CGGeneric(innerTemplate)).define()
return (""" return (("""
uint32_t length = %s.Length(); uint32_t length = %s.Length();
JSObject *returnArray = JS_NewArrayObject(cx, length, NULL); JSObject *returnArray = JS_NewArrayObject(cx, length, NULL);
if (!returnArray) { if (!returnArray) {
@ -2485,7 +2487,7 @@ if (!returnArray) {
jsval tmp; jsval tmp;
for (uint32_t i = 0; i < length; ++i) { for (uint32_t i = 0; i < length; ++i) {
%s %s
}\n""" % (result, innerTemplate)) + setValue("JS::ObjectValue(*returnArray)") }\n""" % (result, innerTemplate)) + setValue("JS::ObjectValue(*returnArray)"), False)
if type.isGeckoInterface(): if type.isGeckoInterface():
descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name) descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name)
@ -2527,26 +2529,27 @@ for (uint32_t i = 0; i < length; ++i) {
getIID = "" getIID = ""
wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalPtr})" % (result, getIID) wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalPtr})" % (result, getIID)
wrappingCode += wrapAndSetPtr(wrap) wrappingCode += wrapAndSetPtr(wrap)
return wrappingCode return (wrappingCode, False)
if type.isString(): if type.isString():
if type.nullable(): if type.nullable():
return wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalPtr})" % result) return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalPtr})" % result), False)
else: else:
return wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalPtr})" % result) return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalPtr})" % result), False)
if type.isEnum(): if type.isEnum():
if type.nullable(): if type.nullable():
raise TypeError("We don't support nullable enumerated return types " raise TypeError("We don't support nullable enumerated return types "
"yet") "yet")
return """MOZ_ASSERT(uint32_t(%(result)s) < ArrayLength(%(strings)s)); return ("""MOZ_ASSERT(uint32_t(%(result)s) < ArrayLength(%(strings)s));
JSString* %(resultStr)s = JS_NewStringCopyN(cx, %(strings)s[uint32_t(%(result)s)].value, %(strings)s[uint32_t(%(result)s)].length); JSString* %(resultStr)s = JS_NewStringCopyN(cx, %(strings)s[uint32_t(%(result)s)].value, %(strings)s[uint32_t(%(result)s)].length);
if (!%(resultStr)s) { if (!%(resultStr)s) {
return false; return false;
} }
""" % { "result" : result, """ % { "result" : result,
"resultStr" : result + "_str", "resultStr" : result + "_str",
"strings" : type.inner.identifier.name + "Values::strings" } + setValue("JS::StringValue(%s_str)" % result) "strings" : type.inner.identifier.name + "Values::strings" } +
setValue("JS::StringValue(%s_str)" % result), False)
if type.isCallback(): if type.isCallback():
assert not type.isInterface() assert not type.isInterface()
@ -2554,12 +2557,14 @@ if (!%(resultStr)s) {
# nullable and always have [TreatNonCallableAsNull] for now. # nullable and always have [TreatNonCallableAsNull] for now.
# See comments in WrapNewBindingObject explaining why we need # See comments in WrapNewBindingObject explaining why we need
# to wrap here. # to wrap here.
return setValue("JS::ObjectOrNullValue(%s)" % result, True) # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
return (setValue("JS::ObjectOrNullValue(%s)" % result, True), False)
if type.tag() == IDLType.Tags.any: if type.tag() == IDLType.Tags.any:
# See comments in WrapNewBindingObject explaining why we need # See comments in WrapNewBindingObject explaining why we need
# to wrap here. # to wrap here.
return setValue(result, True) # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
return (setValue(result, True), False)
if type.isObject(): if type.isObject():
# See comments in WrapNewBindingObject explaining why we need # See comments in WrapNewBindingObject explaining why we need
@ -2568,36 +2573,37 @@ if (!%(resultStr)s) {
toValue = "JS::ObjectOrNullValue(%s)" toValue = "JS::ObjectOrNullValue(%s)"
else: else:
toValue = "JS::ObjectValue(*%s)" toValue = "JS::ObjectValue(*%s)"
return setValue(toValue % result, True) # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
return (setValue(toValue % result, True), False)
if not type.isPrimitive(): if not type.isPrimitive():
raise TypeError("Need to learn to wrap %s" % type) raise TypeError("Need to learn to wrap %s" % type)
if type.nullable(): if type.nullable():
(recTemplate, recInfal) = getWrapTemplateForType(type.inner, descriptorProvider,
"%s.Value()" % result, successCode,
isCreator)
return ("if (%s.IsNull()) {\n" % result + return ("if (%s.IsNull()) {\n" % result +
CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" + CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" +
"}\n" + "}\n" + recTemplate, recInfal)
getWrapTemplateForType(type.inner, descriptorProvider,
"%s.Value()" % result, successCode,
isCreator))
tag = type.tag() tag = type.tag()
if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16, if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
IDLType.Tags.uint16, IDLType.Tags.int32]: IDLType.Tags.uint16, IDLType.Tags.int32]:
return setValue("INT_TO_JSVAL(int32_t(%s))" % result) return (setValue("INT_TO_JSVAL(int32_t(%s))" % result), True)
elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64, IDLType.Tags.float, elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64, IDLType.Tags.float,
IDLType.Tags.double]: IDLType.Tags.double]:
# XXXbz will cast to double do the "even significand" thing that webidl # XXXbz will cast to double do the "even significand" thing that webidl
# calls for for 64-bit ints? Do we care? # calls for for 64-bit ints? Do we care?
return setValue("JS_NumberValue(double(%s))" % result) return (setValue("JS_NumberValue(double(%s))" % result), True)
elif tag == IDLType.Tags.uint32: elif tag == IDLType.Tags.uint32:
return setValue("UINT_TO_JSVAL(%s)" % result) return (setValue("UINT_TO_JSVAL(%s)" % result), True)
elif tag == IDLType.Tags.bool: elif tag == IDLType.Tags.bool:
return setValue("BOOLEAN_TO_JSVAL(%s)" % result) return (setValue("BOOLEAN_TO_JSVAL(%s)" % result), True)
else: else:
raise TypeError("Need to learn to wrap primitive: %s" % type) raise TypeError("Need to learn to wrap primitive: %s" % type)
@ -2626,11 +2632,25 @@ def wrapForType(type, descriptorProvider, templateValues):
wrap = getWrapTemplateForType(type, descriptorProvider, wrap = getWrapTemplateForType(type, descriptorProvider,
templateValues.get('result', 'result'), templateValues.get('result', 'result'),
templateValues.get('successCode', None), templateValues.get('successCode', None),
templateValues.get('isCreator', False)) templateValues.get('isCreator', False))[0]
defaultValues = {'obj': 'obj'} defaultValues = {'obj': 'obj'}
return string.Template(wrap).substitute(defaultValues, **templateValues) return string.Template(wrap).substitute(defaultValues, **templateValues)
def infallibleForAttr(attr, descriptorProvider):
"""
Determine the fallibility of changing a C++ value of IDL type "type" into
JS for the given attribute. Apart from isCreator, all the defaults are used,
since the fallbility does not change based on the boolean values,
and the template will be discarded.
CURRENT ASSUMPTIONS:
We assume that successCode for wrapping up return values cannot contain
failure conditions.
"""
return getWrapTemplateForType(attr.type, descriptorProvider, 'result', None,\
memberIsCreator(attr))[1]
def typeNeedsCx(type): def typeNeedsCx(type):
return (type is not None and return (type is not None and
(type.isCallback() or type.isAny() or type.isObject() or (type.isCallback() or type.isAny() or type.isObject() or
@ -2825,7 +2845,7 @@ class CGPerSignatureCall(CGThing):
return not 'infallible' in self.extendedAttributes return not 'infallible' in self.extendedAttributes
def wrap_return_value(self): def wrap_return_value(self):
isCreator = self.idlNode.getExtendedAttribute("Creator") is not None isCreator = memberIsCreator(self.idlNode)
if isCreator: if isCreator:
# We better be returning addrefed things! # We better be returning addrefed things!
assert isResultAlreadyAddRefed(self.descriptor, assert isResultAlreadyAddRefed(self.descriptor,
@ -3365,6 +3385,9 @@ class CGSpecializedSetter(CGAbstractStaticMethod):
return CGIndenter(CGSetterCall(self.attr.type, nativeName, return CGIndenter(CGSetterCall(self.attr.type, nativeName,
self.descriptor, self.attr)).define() self.descriptor, self.attr)).define()
def memberIsCreator(member):
return member.getExtendedAttribute("Creator") is not None
class CGPropertyJITInfo(CGThing): class CGPropertyJITInfo(CGThing):
""" """
A class for generating the JITInfo for a property that points to A class for generating the JITInfo for a property that points to
@ -3394,9 +3417,9 @@ class CGPropertyJITInfo(CGThing):
getterinfo = ("%s_getterinfo" % self.attr.identifier.name) getterinfo = ("%s_getterinfo" % self.attr.identifier.name)
getter = ("(JSJitPropertyOp)specialized_get_%s" % getter = ("(JSJitPropertyOp)specialized_get_%s" %
self.attr.identifier.name) self.attr.identifier.name)
# For now, mark all getters fallible, until argument wrapping has been getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.attr, getter=True)
# handled. getterinfal = getterinfal and infallibleForAttr(self.attr, self.descriptor)
result = self.defineJitInfo(getterinfo, getter, False) result = self.defineJitInfo(getterinfo, getter, getterinfal)
if not self.attr.readonly: if not self.attr.readonly:
setterinfo = ("%s_setterinfo" % self.attr.identifier.name) setterinfo = ("%s_setterinfo" % self.attr.identifier.name)
setter = ("(JSJitPropertyOp)specialized_set_%s" % setter = ("(JSJitPropertyOp)specialized_set_%s" %