mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 779048 part 5. Make js-to-native conversion support doing something other than "return false" on JS exceptions. r=peterv
This commit is contained in:
parent
01c98be853
commit
f7b9a5bdea
@ -1872,10 +1872,11 @@ class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
|
|||||||
"""
|
"""
|
||||||
As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails
|
As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails
|
||||||
"""
|
"""
|
||||||
def __init__(self, descriptor, source, target):
|
def __init__(self, descriptor, source, target, exceptionCode):
|
||||||
CastableObjectUnwrapper.__init__(self, descriptor, source, target,
|
CastableObjectUnwrapper.__init__(
|
||||||
"return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE," +
|
self, descriptor, source, target,
|
||||||
'"%s");' % descriptor.name)
|
'ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");\n'
|
||||||
|
'%s' % (descriptor.name, exceptionCode))
|
||||||
|
|
||||||
class CallbackObjectUnwrapper:
|
class CallbackObjectUnwrapper:
|
||||||
"""
|
"""
|
||||||
@ -1884,11 +1885,12 @@ class CallbackObjectUnwrapper:
|
|||||||
|source| is the JSObject we want to use in native code.
|
|source| is the JSObject we want to use in native code.
|
||||||
|target| is an nsCOMPtr of the appropriate type in which we store the result.
|
|target| is an nsCOMPtr of the appropriate type in which we store the result.
|
||||||
"""
|
"""
|
||||||
def __init__(self, descriptor, source, target, codeOnFailure=None):
|
def __init__(self, descriptor, source, target, exceptionCode,
|
||||||
|
codeOnFailure=None):
|
||||||
if codeOnFailure is None:
|
if codeOnFailure is None:
|
||||||
codeOnFailure = ("return ThrowErrorMessage(cx," +
|
codeOnFailure = (
|
||||||
'MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");' %
|
'ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");\n'
|
||||||
descriptor.name)
|
'%s' % (descriptor.name, exceptionCode))
|
||||||
self.descriptor = descriptor
|
self.descriptor = descriptor
|
||||||
self.substitution = { "nativeType" : descriptor.nativeType,
|
self.substitution = { "nativeType" : descriptor.nativeType,
|
||||||
"source" : source,
|
"source" : source,
|
||||||
@ -1957,7 +1959,8 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
|
|||||||
treatUndefinedAs="Default",
|
treatUndefinedAs="Default",
|
||||||
isEnforceRange=False,
|
isEnforceRange=False,
|
||||||
isClamp=False,
|
isClamp=False,
|
||||||
isNullOrUndefined=False):
|
isNullOrUndefined=False,
|
||||||
|
exceptionCode=None):
|
||||||
"""
|
"""
|
||||||
Get a template for converting a JS value to a native object based on the
|
Get a template for converting a JS value to a native object based on the
|
||||||
given type and descriptor. If failureCode is given, then we're actually
|
given type and descriptor. If failureCode is given, then we're actually
|
||||||
@ -1966,7 +1969,10 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
|
|||||||
value need to use failureCode instead of throwing exceptions. Failures to
|
value need to use failureCode instead of throwing exceptions. Failures to
|
||||||
convert that are due to JS exceptions (from toString or valueOf methods) or
|
convert that are due to JS exceptions (from toString or valueOf methods) or
|
||||||
out of memory conditions need to throw exceptions no matter what
|
out of memory conditions need to throw exceptions no matter what
|
||||||
failureCode is.
|
failureCode is. However what actually happens when throwing an exception
|
||||||
|
can be controlled by exceptionCode. The only requirement on that is that
|
||||||
|
exceptionCode must end up doing a return, and every return from this
|
||||||
|
function must happen via exceptionCode if exceptionCode is not None.
|
||||||
|
|
||||||
If isDefinitelyObject is True, that means we know the value
|
If isDefinitelyObject is True, that means we know the value
|
||||||
isObject() and we have no need to recheck that.
|
isObject() and we have no need to recheck that.
|
||||||
@ -2032,20 +2038,33 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
|
|||||||
# And we can't both be an object and be null or undefined
|
# And we can't both be an object and be null or undefined
|
||||||
assert not isDefinitelyObject or not isNullOrUndefined
|
assert not isDefinitelyObject or not isNullOrUndefined
|
||||||
|
|
||||||
|
# If exceptionCode is not set, we'll just rethrow the exception we got.
|
||||||
|
# Note that we can't just set failureCode to exceptionCode, because setting
|
||||||
|
# failureCode will prevent pending exceptions from being set in cases when
|
||||||
|
# they really should be!
|
||||||
|
if exceptionCode is None:
|
||||||
|
exceptionCode = "return false;"
|
||||||
|
# We often want exceptionCode to be indented, since it often appears in an
|
||||||
|
# if body.
|
||||||
|
exceptionCodeIndented = CGIndenter(CGGeneric(exceptionCode))
|
||||||
|
|
||||||
# Helper functions for dealing with failures due to the JS value being the
|
# Helper functions for dealing with failures due to the JS value being the
|
||||||
# wrong type of value
|
# wrong type of value
|
||||||
def onFailureNotAnObject(failureCode):
|
def onFailureNotAnObject(failureCode):
|
||||||
return CGWrapper(CGGeneric(
|
return CGWrapper(CGGeneric(
|
||||||
failureCode or
|
failureCode or
|
||||||
'return ThrowErrorMessage(cx, MSG_NOT_OBJECT);'), post="\n")
|
('ThrowErrorMessage(cx, MSG_NOT_OBJECT);\n'
|
||||||
|
'%s' % exceptionCode)), post="\n")
|
||||||
def onFailureBadType(failureCode, typeName):
|
def onFailureBadType(failureCode, typeName):
|
||||||
return CGWrapper(CGGeneric(
|
return CGWrapper(CGGeneric(
|
||||||
failureCode or
|
failureCode or
|
||||||
'return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");' % typeName), post="\n")
|
('ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");'
|
||||||
|
'%s' % (typeName, exceptionCode))), post="\n")
|
||||||
def onFailureNotCallable(failureCode):
|
def onFailureNotCallable(failureCode):
|
||||||
return CGWrapper(CGGeneric(
|
return CGWrapper(CGGeneric(
|
||||||
failureCode or
|
failureCode or
|
||||||
'return ThrowErrorMessage(cx, MSG_NOT_CALLABLE);'), post="\n")
|
('ThrowErrorMessage(cx, MSG_NOT_CALLABLE);\n'
|
||||||
|
'%s' % exceptionCode)), post="\n")
|
||||||
|
|
||||||
# A helper function for handling default values. Takes a template
|
# A helper function for handling default values. Takes a template
|
||||||
# body and the C++ code to set the default value and wraps the
|
# body and the C++ code to set the default value and wraps the
|
||||||
@ -2110,7 +2129,8 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
|
|||||||
assert not isEnforceRange and not isClamp
|
assert not isEnforceRange and not isClamp
|
||||||
|
|
||||||
if failureCode is None:
|
if failureCode is None:
|
||||||
notSequence = "return ThrowErrorMessage(cx, MSG_NOT_SEQUENCE);"
|
notSequence = ("ThrowErrorMessage(cx, MSG_NOT_SEQUENCE);\n"
|
||||||
|
"%s" % exceptionCode)
|
||||||
else:
|
else:
|
||||||
notSequence = failureCode
|
notSequence = failureCode
|
||||||
|
|
||||||
@ -2139,7 +2159,8 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
|
|||||||
|
|
||||||
(elementTemplate, elementDeclType,
|
(elementTemplate, elementDeclType,
|
||||||
elementHolderType, dealWithOptional) = getJSToNativeConversionTemplate(
|
elementHolderType, dealWithOptional) = getJSToNativeConversionTemplate(
|
||||||
elementType, descriptorProvider, isMember=True)
|
elementType, descriptorProvider, isMember=True,
|
||||||
|
exceptionCode=exceptionCode)
|
||||||
if dealWithOptional:
|
if dealWithOptional:
|
||||||
raise TypeError("Shouldn't have optional things in sequences")
|
raise TypeError("Shouldn't have optional things in sequences")
|
||||||
if elementHolderType is not None:
|
if elementHolderType is not None:
|
||||||
@ -2163,22 +2184,25 @@ if (!IsArrayLike(cx, seq)) {
|
|||||||
uint32_t length;
|
uint32_t length;
|
||||||
// JS_GetArrayLength actually works on all objects
|
// JS_GetArrayLength actually works on all objects
|
||||||
if (!JS_GetArrayLength(cx, seq, &length)) {
|
if (!JS_GetArrayLength(cx, seq, &length)) {
|
||||||
return false;
|
%s
|
||||||
}
|
}
|
||||||
Sequence< %s > &arr = const_cast< Sequence< %s >& >(%s);
|
Sequence< %s > &arr = const_cast< Sequence< %s >& >(%s);
|
||||||
if (!arr.SetCapacity(length)) {
|
if (!arr.SetCapacity(length)) {
|
||||||
JS_ReportOutOfMemory(cx);
|
JS_ReportOutOfMemory(cx);
|
||||||
return false;
|
%s
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < length; ++i) {
|
for (uint32_t i = 0; i < length; ++i) {
|
||||||
jsval temp;
|
jsval temp;
|
||||||
if (!JS_GetElement(cx, seq, i, &temp)) {
|
if (!JS_GetElement(cx, seq, i, &temp)) {
|
||||||
return false;
|
%s
|
||||||
}
|
}
|
||||||
""" % (CGIndenter(CGGeneric(notSequence)).define(),
|
""" % (CGIndenter(CGGeneric(notSequence)).define(),
|
||||||
|
exceptionCodeIndented.define(),
|
||||||
elementDeclType.define(),
|
elementDeclType.define(),
|
||||||
elementDeclType.define(),
|
elementDeclType.define(),
|
||||||
arrayRef))
|
arrayRef,
|
||||||
|
exceptionCodeIndented.define(),
|
||||||
|
CGIndenter(exceptionCodeIndented).define()))
|
||||||
|
|
||||||
templateBody += CGIndenter(CGGeneric(
|
templateBody += CGIndenter(CGGeneric(
|
||||||
string.Template(elementTemplate).substitute(
|
string.Template(elementTemplate).substitute(
|
||||||
@ -2346,11 +2370,14 @@ for (uint32_t i = 0; i < length; ++i) {
|
|||||||
|
|
||||||
templateBody = CGWrapper(templateBody, pre="bool done = false, failed = false, tryNext;\n")
|
templateBody = CGWrapper(templateBody, pre="bool done = false, failed = false, tryNext;\n")
|
||||||
throw = CGGeneric("if (failed) {\n"
|
throw = CGGeneric("if (failed) {\n"
|
||||||
" return false;\n"
|
"%s\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"if (!done) {\n"
|
"if (!done) {\n"
|
||||||
" return ThrowErrorMessage(cx, MSG_NOT_IN_UNION, \"%s\");\n"
|
" ThrowErrorMessage(cx, MSG_NOT_IN_UNION, \"%s\");\n"
|
||||||
"}" % ", ".join(names))
|
"%s\n"
|
||||||
|
"}" % (exceptionCodeIndented.define(),
|
||||||
|
", ".join(names),
|
||||||
|
exceptionCodeIndented.define()))
|
||||||
templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw], "\n")), pre="{\n", post="\n}")
|
templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw], "\n")), pre="{\n", post="\n}")
|
||||||
|
|
||||||
typeName = type.name
|
typeName = type.name
|
||||||
@ -2466,12 +2493,14 @@ for (uint32_t i = 0; i < length; ++i) {
|
|||||||
templateBody += str(FailureFatalCastableObjectUnwrapper(
|
templateBody += str(FailureFatalCastableObjectUnwrapper(
|
||||||
descriptor,
|
descriptor,
|
||||||
"&${val}.toObject()",
|
"&${val}.toObject()",
|
||||||
"${declName}"))
|
"${declName}",
|
||||||
|
exceptionCode))
|
||||||
elif descriptor.interface.isCallback():
|
elif descriptor.interface.isCallback():
|
||||||
templateBody += str(CallbackObjectUnwrapper(
|
templateBody += str(CallbackObjectUnwrapper(
|
||||||
descriptor,
|
descriptor,
|
||||||
"&${val}.toObject()",
|
"&${val}.toObject()",
|
||||||
"${declName}",
|
"${declName}",
|
||||||
|
exceptionCode,
|
||||||
codeOnFailure=failureCode))
|
codeOnFailure=failureCode))
|
||||||
elif descriptor.workers:
|
elif descriptor.workers:
|
||||||
templateBody += "${declName} = &${val}.toObject();"
|
templateBody += "${declName} = &${val}.toObject();"
|
||||||
@ -2597,8 +2626,9 @@ for (uint32_t i = 0; i < length; ++i) {
|
|||||||
def getConversionCode(varName):
|
def getConversionCode(varName):
|
||||||
conversionCode = (
|
conversionCode = (
|
||||||
"if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, %s)) {\n"
|
"if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, %s)) {\n"
|
||||||
" return false;\n"
|
"%s\n"
|
||||||
"}" % (nullBehavior, undefinedBehavior, varName))
|
"}" % (nullBehavior, undefinedBehavior, varName,
|
||||||
|
exceptionCodeIndented.define()))
|
||||||
if defaultValue is None:
|
if defaultValue is None:
|
||||||
return conversionCode
|
return conversionCode
|
||||||
|
|
||||||
@ -2648,6 +2678,7 @@ for (uint32_t i = 0; i < length; ++i) {
|
|||||||
if invalidEnumValueFatal:
|
if invalidEnumValueFatal:
|
||||||
handleInvalidEnumValueCode = " MOZ_ASSERT(index >= 0);\n"
|
handleInvalidEnumValueCode = " MOZ_ASSERT(index >= 0);\n"
|
||||||
else:
|
else:
|
||||||
|
assert exceptionCode == "return false;"
|
||||||
handleInvalidEnumValueCode = (
|
handleInvalidEnumValueCode = (
|
||||||
" if (index < 0) {\n"
|
" if (index < 0) {\n"
|
||||||
" return true;\n"
|
" return true;\n"
|
||||||
@ -2658,14 +2689,15 @@ for (uint32_t i = 0; i < length; ++i) {
|
|||||||
" bool ok;\n"
|
" bool ok;\n"
|
||||||
" int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, \"%(enumtype)s\", &ok);\n"
|
" int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, \"%(enumtype)s\", &ok);\n"
|
||||||
" if (!ok) {\n"
|
" if (!ok) {\n"
|
||||||
" return false;\n"
|
"%(exceptionCode)s\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"%(handleInvalidEnumValueCode)s"
|
"%(handleInvalidEnumValueCode)s"
|
||||||
" ${declName} = static_cast<%(enumtype)s>(index);\n"
|
" ${declName} = static_cast<%(enumtype)s>(index);\n"
|
||||||
"}" % { "enumtype" : enum,
|
"}" % { "enumtype" : enum,
|
||||||
"values" : enum + "Values::strings",
|
"values" : enum + "Values::strings",
|
||||||
"invalidEnumValueFatal" : toStringBool(invalidEnumValueFatal),
|
"invalidEnumValueFatal" : toStringBool(invalidEnumValueFatal),
|
||||||
"handleInvalidEnumValueCode" : handleInvalidEnumValueCode })
|
"handleInvalidEnumValueCode" : handleInvalidEnumValueCode,
|
||||||
|
"exceptionCode" : CGIndenter(exceptionCodeIndented).define() })
|
||||||
|
|
||||||
if defaultValue is not None:
|
if defaultValue is not None:
|
||||||
assert(defaultValue.type.tag() == IDLType.Tags.domstring)
|
assert(defaultValue.type.tag() == IDLType.Tags.domstring)
|
||||||
@ -2771,8 +2803,8 @@ for (uint32_t i = 0; i < length; ++i) {
|
|||||||
val = "${val}"
|
val = "${val}"
|
||||||
|
|
||||||
template = ("if (!%s.Init(cx, %s)) {\n"
|
template = ("if (!%s.Init(cx, %s)) {\n"
|
||||||
" return false;\n"
|
"%s\n"
|
||||||
"}" % (selfRef, val))
|
"}" % (selfRef, val, exceptionCodeIndented.define()))
|
||||||
|
|
||||||
return (template, declType, None, False)
|
return (template, declType, None, False)
|
||||||
|
|
||||||
@ -2800,16 +2832,18 @@ for (uint32_t i = 0; i < length; ++i) {
|
|||||||
"if (%s) {\n"
|
"if (%s) {\n"
|
||||||
" const_cast< %s >(${declName}).SetNull();\n"
|
" const_cast< %s >(${declName}).SetNull();\n"
|
||||||
"} else if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n"
|
"} else if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n"
|
||||||
" return false;\n"
|
"%s\n"
|
||||||
"}" % (nullCondition, mutableType, typeName, conversionBehavior, dataLoc))
|
"}" % (nullCondition, mutableType, typeName, conversionBehavior, dataLoc,
|
||||||
|
exceptionCodeIndented.define()))
|
||||||
else:
|
else:
|
||||||
assert(defaultValue is None or
|
assert(defaultValue is None or
|
||||||
not isinstance(defaultValue, IDLNullValue))
|
not isinstance(defaultValue, IDLNullValue))
|
||||||
dataLoc = "${declName}"
|
dataLoc = "${declName}"
|
||||||
template = (
|
template = (
|
||||||
"if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n"
|
"if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n"
|
||||||
" return false;\n"
|
"%s\n"
|
||||||
"}" % (typeName, conversionBehavior, dataLoc))
|
"}" % (typeName, conversionBehavior, dataLoc,
|
||||||
|
exceptionCodeIndented.define()))
|
||||||
declType = CGGeneric(typeName)
|
declType = CGGeneric(typeName)
|
||||||
if (defaultValue is not None and
|
if (defaultValue is not None and
|
||||||
# We already handled IDLNullValue, so just deal with the other ones
|
# We already handled IDLNullValue, so just deal with the other ones
|
||||||
@ -3913,7 +3947,7 @@ class CGAbstractBindingMethod(CGAbstractStaticMethod):
|
|||||||
# Our descriptor might claim that we're not castable, simply because
|
# Our descriptor might claim that we're not castable, simply because
|
||||||
# we're someone's consequential interface. But for this-unwrapping, we
|
# we're someone's consequential interface. But for this-unwrapping, we
|
||||||
# know that we're the real deal. So fake a descriptor here for
|
# know that we're the real deal. So fake a descriptor here for
|
||||||
# consumption by FailureFatalCastableObjectUnwrapper.
|
# consumption by CastableObjectUnwrapper.
|
||||||
getThis = CGGeneric("""js::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
|
getThis = CGGeneric("""js::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
Reference in New Issue
Block a user