mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 748267 part 2. Implement codegen for dealing with sequence arguments. r=peterv
This commit is contained in:
parent
47ff20f5dc
commit
2e5443afcb
@ -138,18 +138,25 @@ inline bool
|
|||||||
IsArrayLike(JSContext* cx, JSObject* obj)
|
IsArrayLike(JSContext* cx, JSObject* obj)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(obj);
|
MOZ_ASSERT(obj);
|
||||||
// For simplicity, check for security wrappers up front
|
// For simplicity, check for security wrappers up front. In case we
|
||||||
|
// have a security wrapper, don't forget to enter the compartment of
|
||||||
|
// the underlying object after unwrapping.
|
||||||
|
JSAutoEnterCompartment ac;
|
||||||
if (js::IsWrapper(obj)) {
|
if (js::IsWrapper(obj)) {
|
||||||
obj = XPCWrapper::Unwrap(cx, obj, false);
|
obj = XPCWrapper::Unwrap(cx, obj, false);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
// Let's say it's not
|
// Let's say it's not
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ac.enter(cx, obj)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXXbz need to detect platform objects (including listbinding
|
// XXXbz need to detect platform objects (including listbinding
|
||||||
// ones) with indexGetters here!
|
// ones) with indexGetters here!
|
||||||
return JS_IsArrayObject(cx, obj);
|
return JS_IsArrayObject(cx, obj) || JS_IsTypedArrayObject(obj, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
|
@ -1178,8 +1178,9 @@ if (!tmp) {
|
|||||||
}
|
}
|
||||||
${target} = tmp.forget();""").substitute(self.substitution)
|
${target} = tmp.forget();""").substitute(self.substitution)
|
||||||
|
|
||||||
def getJSToNativeConversionTemplate(type, descriptor, failureCode=None,
|
def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
|
||||||
isDefinitelyObject=False):
|
isDefinitelyObject=False,
|
||||||
|
isSequenceMember=False):
|
||||||
"""
|
"""
|
||||||
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
|
||||||
@ -1215,21 +1216,114 @@ def getJSToNativeConversionTemplate(type, descriptor, failureCode=None,
|
|||||||
If holderType is not None then ${holderName} must be in scope
|
If holderType is not None then ${holderName} must be in scope
|
||||||
before the generated code is entered.
|
before the generated code is entered.
|
||||||
"""
|
"""
|
||||||
if type.isSequence() or type.isArray():
|
|
||||||
raise TypeError("Can't handle sequence or array arguments yet")
|
|
||||||
|
|
||||||
if descriptor is not None:
|
# A helper function for wrapping up the template body for
|
||||||
assert(type.isInterface())
|
# possibly-nullable objecty stuff
|
||||||
|
def wrapObjectTemplate(templateBody, isDefinitelyObject, type,
|
||||||
|
codeToSetNull, isWorker):
|
||||||
|
if not isDefinitelyObject:
|
||||||
|
# Handle the non-object cases by wrapping up the whole
|
||||||
|
# thing in an if cascade.
|
||||||
|
templateBody = (
|
||||||
|
"if (${val}.isObject()) {\n" +
|
||||||
|
CGIndenter(CGGeneric(templateBody)).define() + "\n")
|
||||||
|
if type.nullable():
|
||||||
|
templateBody += (
|
||||||
|
"} else if (${val}.isNullOrUndefined()) {\n"
|
||||||
|
" %s;\n" % codeToSetNull)
|
||||||
|
templateBody += (
|
||||||
|
"} else {\n"
|
||||||
|
" return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
|
||||||
|
"}" % toStringBool(not isWorker))
|
||||||
|
return templateBody
|
||||||
|
|
||||||
|
if type.isArray():
|
||||||
|
raise TypeError("Can't handle array arguments yet")
|
||||||
|
|
||||||
|
if type.isSequence():
|
||||||
|
if isSequenceMember:
|
||||||
|
raise TypeError("Can't handle sequences of sequences")
|
||||||
|
if failureCode is not None:
|
||||||
|
raise TypeError("Can't handle sequences when failureCode is not None")
|
||||||
|
nullable = type.nullable();
|
||||||
|
if nullable:
|
||||||
|
type = type.inner;
|
||||||
|
|
||||||
|
elementType = type.inner;
|
||||||
|
# We don't know anything about the object-ness of the things
|
||||||
|
# we wrap, so don't pass through isDefinitelyObject
|
||||||
|
(elementTemplate, elementDeclType,
|
||||||
|
elementHolderType) = getJSToNativeConversionTemplate(
|
||||||
|
elementType, descriptorProvider, isSequenceMember=True)
|
||||||
|
if elementHolderType is not None:
|
||||||
|
raise TypeError("Shouldn't need holders for sequences")
|
||||||
|
|
||||||
|
# Have to make sure to use a fallible array, because it's trivial for
|
||||||
|
# page JS to create things with very large lengths.
|
||||||
|
typeName = CGWrapper(elementDeclType, pre="nsTArray< ", post=" >")
|
||||||
|
if nullable:
|
||||||
|
typeName = CGWrapper(typeName, pre="Nullable< ", post=" >")
|
||||||
|
templateBody = ("""JSObject* seq = &${val}.toObject();\n
|
||||||
|
if (!IsArrayLike(cx, seq)) {
|
||||||
|
return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
|
||||||
|
}
|
||||||
|
uint32_t length;
|
||||||
|
// JS_GetArrayLength actually works on all objects
|
||||||
|
if (!JS_GetArrayLength(cx, seq, &length)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Jump through a hoop to do a fallible allocation but later end up with
|
||||||
|
// an infallible array.
|
||||||
|
FallibleTArray< %s > arr;
|
||||||
|
if (!arr.SetCapacity(length)) {
|
||||||
|
return Throw<%s>(cx, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
}
|
||||||
|
for (uint32_t i = 0; i < length; ++i) {
|
||||||
|
jsval temp;
|
||||||
|
if (!JS_GetElement(cx, seq, i, &temp)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
""" % (toStringBool(descriptorProvider.workers),
|
||||||
|
elementDeclType.define(),
|
||||||
|
toStringBool(descriptorProvider.workers)))
|
||||||
|
|
||||||
|
templateBody += CGIndenter(CGGeneric(
|
||||||
|
string.Template(elementTemplate).substitute(
|
||||||
|
{
|
||||||
|
"val" : "temp",
|
||||||
|
"declName" : "*arr.AppendElement()"
|
||||||
|
}
|
||||||
|
))).define()
|
||||||
|
|
||||||
|
templateBody += """
|
||||||
|
}
|
||||||
|
// And the other half of the hoop-jump"""
|
||||||
|
if nullable:
|
||||||
|
templateBody += """
|
||||||
|
${declName}.SetValue().SwapElements(arr);
|
||||||
|
"""
|
||||||
|
else:
|
||||||
|
templateBody += """
|
||||||
|
${declName}.SwapElements(arr);
|
||||||
|
"""
|
||||||
|
templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
|
||||||
|
type, "${declName}.SetNull()",
|
||||||
|
descriptorProvider.workers)
|
||||||
|
return (templateBody, typeName, None)
|
||||||
|
|
||||||
|
if type.isInterface() and not type.isArrayBuffer():
|
||||||
|
descriptor = descriptorProvider.getDescriptor(
|
||||||
|
type.unroll().inner.identifier.name)
|
||||||
# This is an interface that we implement as a concrete class
|
# This is an interface that we implement as a concrete class
|
||||||
# or an XPCOM interface.
|
# or an XPCOM interface.
|
||||||
|
|
||||||
# Allow null pointers for nullable types and old-binding classes
|
# Allow null pointers for nullable types and old-binding classes
|
||||||
argIsPointer = type.nullable() or type.unroll().inner.isExternal()
|
argIsPointer = type.nullable() or type.unroll().inner.isExternal()
|
||||||
|
|
||||||
# Non-worker callbacks have to hold a strong ref to the thing being
|
# Sequences and non-worker callbacks have to hold a strong ref to the
|
||||||
# passed down.
|
# thing being passed down.
|
||||||
forceOwningType = (descriptor.interface.isCallback() and
|
forceOwningType = (descriptor.interface.isCallback() and
|
||||||
not descriptor.workers)
|
not descriptor.workers) or isSequenceMember
|
||||||
|
|
||||||
typeName = descriptor.nativeType
|
typeName = descriptor.nativeType
|
||||||
typePtr = typeName + "*"
|
typePtr = typeName + "*"
|
||||||
@ -1284,7 +1378,12 @@ def getJSToNativeConversionTemplate(type, descriptor, failureCode=None,
|
|||||||
# to addref when unwrapping or not. So we just pass an
|
# to addref when unwrapping or not. So we just pass an
|
||||||
# getter_AddRefs(nsCOMPtr) to XPConnect and if we'll need a release
|
# getter_AddRefs(nsCOMPtr) to XPConnect and if we'll need a release
|
||||||
# it'll put a non-null pointer in there.
|
# it'll put a non-null pointer in there.
|
||||||
holderType = "nsCOMPtr<" + typeName + ">"
|
if forceOwningType:
|
||||||
|
# Don't return a holderType in this case; our declName
|
||||||
|
# will just own stuff.
|
||||||
|
templateBody += "nsCOMPtr<" + typeName + "> ${holderName};"
|
||||||
|
else:
|
||||||
|
holderType = "nsCOMPtr<" + typeName + ">"
|
||||||
templateBody += (
|
templateBody += (
|
||||||
"jsval tmpVal = ${val};\n" +
|
"jsval tmpVal = ${val};\n" +
|
||||||
typePtr + " tmp;\n"
|
typePtr + " tmp;\n"
|
||||||
@ -1311,20 +1410,9 @@ def getJSToNativeConversionTemplate(type, descriptor, failureCode=None,
|
|||||||
# And store our tmp, before it goes out of scope.
|
# And store our tmp, before it goes out of scope.
|
||||||
templateBody += "${declName} = tmp;"
|
templateBody += "${declName} = tmp;"
|
||||||
|
|
||||||
if not isDefinitelyObject:
|
templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
|
||||||
# Handle the non-object cases by wrapping up the whole
|
type, "${declName} = NULL",
|
||||||
# thing in an if cascade.
|
descriptor.workers)
|
||||||
templateBody = (
|
|
||||||
"if (${val}.isObject()) {\n" +
|
|
||||||
CGIndenter(CGGeneric(templateBody)).define() + "\n")
|
|
||||||
if type.nullable():
|
|
||||||
templateBody += (
|
|
||||||
"} else if (${val}.isNullOrUndefined()) {\n"
|
|
||||||
" ${declName} = NULL;\n")
|
|
||||||
templateBody += (
|
|
||||||
"} else {\n"
|
|
||||||
" return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
|
|
||||||
"}" % toStringBool(not descriptor.workers))
|
|
||||||
|
|
||||||
declType = CGGeneric(declType)
|
declType = CGGeneric(declType)
|
||||||
if holderType is not None:
|
if holderType is not None:
|
||||||
@ -1332,6 +1420,8 @@ def getJSToNativeConversionTemplate(type, descriptor, failureCode=None,
|
|||||||
return (templateBody, declType, holderType)
|
return (templateBody, declType, holderType)
|
||||||
|
|
||||||
if type.isArrayBuffer():
|
if type.isArrayBuffer():
|
||||||
|
if isSequenceMember:
|
||||||
|
raise TypeError("Can't handle sequences of arraybuffers")
|
||||||
declType = "JSObject*"
|
declType = "JSObject*"
|
||||||
template = (
|
template = (
|
||||||
"if (${val}.isObject() && JS_IsArrayBufferObject(&${val}.toObject(), cx)) {\n"
|
"if (${val}.isObject() && JS_IsArrayBufferObject(&${val}.toObject(), cx)) {\n"
|
||||||
@ -1351,10 +1441,9 @@ def getJSToNativeConversionTemplate(type, descriptor, failureCode=None,
|
|||||||
|
|
||||||
return (template, CGGeneric(declType), None)
|
return (template, CGGeneric(declType), None)
|
||||||
|
|
||||||
if type.isInterface():
|
|
||||||
raise TypeError("Interface type with no descriptor: " + type)
|
|
||||||
|
|
||||||
if type.isString():
|
if type.isString():
|
||||||
|
if isSequenceMember:
|
||||||
|
raise TypeError("Can't handle sequences of strings")
|
||||||
# XXXbz Need to figure out string behavior based on extended args? Also, how to
|
# XXXbz Need to figure out string behavior based on extended args? Also, how to
|
||||||
# detect them?
|
# detect them?
|
||||||
|
|
||||||
@ -1392,6 +1481,8 @@ def getJSToNativeConversionTemplate(type, descriptor, failureCode=None,
|
|||||||
CGGeneric(enum), None)
|
CGGeneric(enum), None)
|
||||||
|
|
||||||
if type.isCallback():
|
if type.isCallback():
|
||||||
|
if isSequenceMember:
|
||||||
|
raise TypeError("Can't handle sequences of callbacks")
|
||||||
# XXXbz we're going to assume that callback types are always
|
# XXXbz we're going to assume that callback types are always
|
||||||
# nullable and always have [TreatNonCallableAsNull] for now.
|
# nullable and always have [TreatNonCallableAsNull] for now.
|
||||||
return (
|
return (
|
||||||
@ -1402,6 +1493,8 @@ def getJSToNativeConversionTemplate(type, descriptor, failureCode=None,
|
|||||||
"}", CGGeneric("JSObject*"), None)
|
"}", CGGeneric("JSObject*"), None)
|
||||||
|
|
||||||
if type.isAny():
|
if type.isAny():
|
||||||
|
if isSequenceMember:
|
||||||
|
raise TypeError("Can't handle sequences of 'any'")
|
||||||
return ("${declName} = ${val};", CGGeneric("JS::Value"), None)
|
return ("${declName} = ${val};", CGGeneric("JS::Value"), None)
|
||||||
|
|
||||||
if not type.isPrimitive():
|
if not type.isPrimitive():
|
||||||
@ -1506,16 +1599,12 @@ class CGArgumentConverter(CGThing):
|
|||||||
).substitute(replacer)
|
).substitute(replacer)
|
||||||
self.replacementVariables["valPtr"] = (
|
self.replacementVariables["valPtr"] = (
|
||||||
"&" + self.replacementVariables["val"])
|
"&" + self.replacementVariables["val"])
|
||||||
if argument.type.isInterface() and not argument.type.isArrayBuffer():
|
self.descriptorProvider = descriptorProvider
|
||||||
self.descriptor = descriptorProvider.getDescriptor(
|
|
||||||
argument.type.unroll().inner.identifier.name)
|
|
||||||
else:
|
|
||||||
self.descriptor = None
|
|
||||||
|
|
||||||
def define(self):
|
def define(self):
|
||||||
return instantiateJSToNativeConversionTemplate(
|
return instantiateJSToNativeConversionTemplate(
|
||||||
getJSToNativeConversionTemplate(self.argument.type,
|
getJSToNativeConversionTemplate(self.argument.type,
|
||||||
self.descriptor),
|
self.descriptorProvider),
|
||||||
self.replacementVariables).define()
|
self.replacementVariables).define()
|
||||||
|
|
||||||
def getWrapTemplateForType(type, descriptorProvider, result, successCode):
|
def getWrapTemplateForType(type, descriptorProvider, result, successCode):
|
||||||
@ -2062,11 +2151,8 @@ class CGMethodCall(CGThing):
|
|||||||
caseBody.append(CGIndenter(CGGeneric("do {")));
|
caseBody.append(CGIndenter(CGGeneric("do {")));
|
||||||
type = sig[1][distinguishingIndex].type
|
type = sig[1][distinguishingIndex].type
|
||||||
|
|
||||||
interfaceDesc = descriptor.getDescriptor(
|
|
||||||
type.unroll().inner.identifier.name)
|
|
||||||
|
|
||||||
testCode = instantiateJSToNativeConversionTemplate(
|
testCode = instantiateJSToNativeConversionTemplate(
|
||||||
getJSToNativeConversionTemplate(type, interfaceDesc,
|
getJSToNativeConversionTemplate(type, descriptor,
|
||||||
failureCode="break;",
|
failureCode="break;",
|
||||||
isDefinitelyObject=True),
|
isDefinitelyObject=True),
|
||||||
{
|
{
|
||||||
@ -2090,7 +2176,7 @@ class CGMethodCall(CGThing):
|
|||||||
# XXXbz Now we're supposed to check for distinguishingArg being
|
# XXXbz Now we're supposed to check for distinguishingArg being
|
||||||
# an array or a platform object that supports indexed
|
# an array or a platform object that supports indexed
|
||||||
# properties... skip that last for now. It's a bit of a pain.
|
# properties... skip that last for now. It's a bit of a pain.
|
||||||
pickFirstSignature("%s.isObject() && IsArrayLike(cx, &%s.toObject()" %
|
pickFirstSignature("%s.isObject() && IsArrayLike(cx, &%s.toObject())" %
|
||||||
(distinguishingArg, distinguishingArg),
|
(distinguishingArg, distinguishingArg),
|
||||||
lambda s:
|
lambda s:
|
||||||
(s[1][distinguishingIndex].type.isArray() or
|
(s[1][distinguishingIndex].type.isArray() or
|
||||||
|
Loading…
Reference in New Issue
Block a user