mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 480187 - 'Make qsgen.py generate traceable natives'. r+sr=jst.
This commit is contained in:
parent
2868deb3e6
commit
38cd49ea51
@ -186,12 +186,16 @@ struct JSTraceableNative {
|
||||
#define _JS_CTYPE_JSVAL_RETRY _JS_JSVAL_CTYPE( _JS_PTR, --, --, FAIL_COOKIE)
|
||||
#define _JS_CTYPE_JSVAL_FAIL _JS_JSVAL_CTYPE( _JS_PTR, --, --, FAIL_STATUS)
|
||||
#define _JS_CTYPE_BOOL _JS_CTYPE(JSBool, _JS_I32, "","i", INFALLIBLE)
|
||||
#define _JS_CTYPE_BOOL_RETRY _JS_CTYPE(int32, _JS_I32, --, --, FAIL_VOID)
|
||||
#define _JS_CTYPE_BOOL_FAIL _JS_CTYPE(int32, _JS_I32, --, --, FAIL_STATUS)
|
||||
#define _JS_CTYPE_BOOL_RETRY _JS_CTYPE(JSBool, _JS_I32, --, --, FAIL_VOID)
|
||||
#define _JS_CTYPE_BOOL_FAIL _JS_CTYPE(JSBool, _JS_I32, --, --, FAIL_STATUS)
|
||||
#define _JS_CTYPE_INT32 _JS_CTYPE(int32, _JS_I32, "","i", INFALLIBLE)
|
||||
#define _JS_CTYPE_INT32_RETRY _JS_CTYPE(int32, _JS_I32, --, --, FAIL_NEG)
|
||||
#define _JS_CTYPE_UINT32 _JS_CTYPE(uint32, _JS_I32, --, --, INFALLIBLE)
|
||||
#define _JS_CTYPE_INT32_FAIL _JS_CTYPE(int32, _JS_I32, --, --, FAIL_STATUS)
|
||||
#define _JS_CTYPE_UINT32 _JS_CTYPE(uint32, _JS_I32, "","i", INFALLIBLE)
|
||||
#define _JS_CTYPE_UINT32_RETRY _JS_CTYPE(uint32, _JS_I32, --, --, FAIL_NEG)
|
||||
#define _JS_CTYPE_UINT32_FAIL _JS_CTYPE(uint32, _JS_I32, --, --, FAIL_STATUS)
|
||||
#define _JS_CTYPE_DOUBLE _JS_CTYPE(jsdouble, _JS_F64, "","d", INFALLIBLE)
|
||||
#define _JS_CTYPE_DOUBLE_FAIL _JS_CTYPE(jsdouble, _JS_F64, --, --, FAIL_STATUS)
|
||||
#define _JS_CTYPE_STRING _JS_CTYPE(JSString *, _JS_PTR, "","s", INFALLIBLE)
|
||||
#define _JS_CTYPE_STRING_RETRY _JS_CTYPE(JSString *, _JS_PTR, --, --, FAIL_NULL)
|
||||
#define _JS_CTYPE_STRING_FAIL _JS_CTYPE(JSString *, _JS_PTR, --, --, FAIL_STATUS)
|
||||
@ -282,6 +286,15 @@ struct JSTraceableNative {
|
||||
(_JS_CTYPE_ARGSIZE(at4) << 2) | _JS_CTYPE_RETSIZE(rt), \
|
||||
cse, fold)
|
||||
|
||||
#define JS_DEFINE_CALLINFO_6(linkage, rt, op, at0, at1, at2, at3, at4, at5, cse, fold) \
|
||||
_JS_DEFINE_CALLINFO(linkage, op, _JS_CTYPE_TYPE(rt), \
|
||||
(_JS_CTYPE_TYPE(at0), _JS_CTYPE_TYPE(at1), _JS_CTYPE_TYPE(at2), \
|
||||
_JS_CTYPE_TYPE(at3), _JS_CTYPE_TYPE(at4), _JS_CTYPE_TYPE(at5)), \
|
||||
(_JS_CTYPE_ARGSIZE(at0) << 12) | (_JS_CTYPE_ARGSIZE(at1) << 10) | \
|
||||
(_JS_CTYPE_ARGSIZE(at2) << 8) | (_JS_CTYPE_ARGSIZE(at3) << 6) | \
|
||||
(_JS_CTYPE_ARGSIZE(at4) << 4) | (_JS_CTYPE_ARGSIZE(at5) << 2) | \
|
||||
_JS_CTYPE_RETSIZE(rt), cse, fold)
|
||||
|
||||
#define JS_DECLARE_CALLINFO(name) extern const nanojit::CallInfo _JS_CALLINFO(name);
|
||||
|
||||
#define _JS_TN_INIT_HELPER_n(n, args) _JS_TN_INIT_HELPER_##n args
|
||||
@ -318,6 +331,14 @@ struct JSTraceableNative {
|
||||
_JS_CTYPE_ACH(at0), \
|
||||
_JS_CTYPE_FLAGS(rt)
|
||||
|
||||
#define _JS_TN_INIT_HELPER_6(linkage, rt, op, at0, at1, at2, at3, at4, at5, cse, fold) \
|
||||
&_JS_CALLINFO(op), \
|
||||
_JS_CTYPE_PCH(at5) _JS_CTYPE_PCH(at4) _JS_CTYPE_PCH(at3) _JS_CTYPE_PCH(at2) \
|
||||
_JS_CTYPE_PCH(at1) _JS_CTYPE_PCH(at0), \
|
||||
_JS_CTYPE_ACH(at5) _JS_CTYPE_ACH(at4) _JS_CTYPE_ACH(at3) _JS_CTYPE_ACH(at2) \
|
||||
_JS_CTYPE_ACH(at1) _JS_CTYPE_ACH(at0), \
|
||||
_JS_CTYPE_FLAGS(rt)
|
||||
|
||||
#define JS_DEFINE_TRCINFO_1(name, tn0) \
|
||||
_JS_DEFINE_CALLINFO_n tn0 \
|
||||
JSTraceableNative name##_trcinfo[] = { \
|
||||
|
@ -131,6 +131,8 @@ include $(topsrcdir)/config/config.mk
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(srcdir)/../loader \
|
||||
-I$(topsrcdir)/js/src \
|
||||
-I$(topsrcdir)/js/src/nanojit \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DSO_LDOPTS += \
|
||||
@ -146,7 +148,29 @@ endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
DEFINES += -DJSFILE -DJS_THREADSAFE -DEXPORT_XPC_API
|
||||
DEFINES += \
|
||||
-DJSFILE \
|
||||
-DJS_THREADSAFE \
|
||||
-DEXPORT_XPC_API \
|
||||
$(NULL)
|
||||
|
||||
CONFIG := $(shell cat $(DEPTH)/js/src/mozilla-config.h)
|
||||
|
||||
ENABLE_JIT = $(filter JS_TRACER, $(CONFIG))
|
||||
|
||||
ifneq (,$(ENABLE_JIT))
|
||||
|
||||
# Ugly! We need the AVMPLUS defines out of js/src/mozilla-config.h to make the
|
||||
# nanojit headers happy. Gotta figure out a better way to get them, bug 483677.
|
||||
DEFINES += \
|
||||
-DJS_TRACER=1 \
|
||||
-DFEATURE_NANOJIT=1 \
|
||||
$(addprefix -D,$(filter AVMPLUS%,$(CONFIG))) \
|
||||
$(NULL)
|
||||
|
||||
ENABLE_TRACEABLE_FLAGS = --enable-traceables
|
||||
|
||||
endif # ENABLE_JIT
|
||||
|
||||
ifdef MOZ_XPCTOOLS
|
||||
DEFINES += -DXPC_TOOLS_SUPPORT
|
||||
@ -182,7 +206,8 @@ xpcjsruntime.$(OBJ_SUFFIX): dom_quickstubs.h
|
||||
dom_quickstubs.h dom_quickstubs.cpp: $(srcdir)/dom_quickstubs.qsconf \
|
||||
$(srcdir)/qsgen.py \
|
||||
$(topsrcdir)/xpcom/idl-parser/header.py \
|
||||
$(topsrcdir)/xpcom/idl-parser/xpidl.py
|
||||
$(topsrcdir)/xpcom/idl-parser/xpidl.py \
|
||||
$(DEPTH)/js/src/mozilla-config.h
|
||||
PYTHONPATH=$(topsrcdir)/xpcom/idl-parser \
|
||||
$(PYTHON) $(srcdir)/qsgen.py \
|
||||
--idlpath=$(DEPTH)/dist/idl \
|
||||
@ -190,6 +215,7 @@ dom_quickstubs.h dom_quickstubs.cpp: $(srcdir)/dom_quickstubs.qsconf \
|
||||
--header-output dom_quickstubs.h \
|
||||
--stub-output dom_quickstubs.cpp \
|
||||
--makedepend-output $(MDDEPDIR)/dom_qsgen.pp \
|
||||
$(ENABLE_TRACEABLE_FLAGS) \
|
||||
$(srcdir)/dom_quickstubs.qsconf
|
||||
|
||||
GARBAGE += \
|
||||
|
@ -71,6 +71,8 @@ members = [
|
||||
# These do not need quick stubs.
|
||||
#'nsIDOMWindow.document',
|
||||
'nsIDOMWindow.getSelection',
|
||||
'nsIDOMWindow.scrollByLines',
|
||||
'nsIDOMJSWindow.dump',
|
||||
'nsIDOMScreen.top',
|
||||
'nsIDOMScreen.height',
|
||||
'nsIDOMScreen.width',
|
||||
|
@ -203,8 +203,9 @@ def loadIDL(parser, includePath, filename):
|
||||
idl.resolve(includePath, parser)
|
||||
return idl
|
||||
|
||||
def addStubMember(memberId, member):
|
||||
def addStubMember(memberId, member, traceable):
|
||||
# Check that the member is ok.
|
||||
mayTrace = False
|
||||
if member.kind not in ('method', 'attribute'):
|
||||
raise UserError("Member %s is %r, not a method or attribute."
|
||||
% (memberId, member.kind))
|
||||
@ -237,6 +238,10 @@ def addStubMember(memberId, member):
|
||||
raise UserError("Method %s, parameter %s: "
|
||||
"unrecognized property %r"
|
||||
% (memberId, param.name, attrname))
|
||||
if len(member.params) <= 3:
|
||||
mayTrace = True
|
||||
|
||||
member.traceable = traceable and mayTrace
|
||||
|
||||
# Add this member to the list.
|
||||
member.iface.stubMembers.append(member)
|
||||
@ -265,7 +270,7 @@ class Configuration:
|
||||
self.customIncludes = config.get('customIncludes', [])
|
||||
self.customMethodCalls = config.get('customMethodCalls', {})
|
||||
|
||||
def readConfigFile(filename, includePath, cachedir):
|
||||
def readConfigFile(filename, includePath, cachedir, traceable):
|
||||
# Read the config file.
|
||||
conf = Configuration(filename, includePath)
|
||||
|
||||
@ -303,7 +308,8 @@ def readConfigFile(filename, includePath, cachedir):
|
||||
# Stub all scriptable members of this interface.
|
||||
for member in iface.members:
|
||||
if member.kind in ('method', 'attribute') and not member.noscript:
|
||||
addStubMember(iface.name + '.' + member.name, member)
|
||||
addStubMember(iface.name + '.' + member.name, member,
|
||||
traceable)
|
||||
else:
|
||||
# Look up a member by name.
|
||||
if memberName not in iface.namemap:
|
||||
@ -315,7 +321,7 @@ def readConfigFile(filename, includePath, cachedir):
|
||||
if member in iface.stubMembers:
|
||||
raise UserError("Member %s is specified more than once."
|
||||
% memberId)
|
||||
addStubMember(memberId, member)
|
||||
addStubMember(memberId, member, traceable)
|
||||
|
||||
return conf, interfaces
|
||||
|
||||
@ -582,7 +588,7 @@ resultConvTemplates = {
|
||||
|
||||
'[domstring]':
|
||||
" return xpc_qsStringToJsval(cx, result, ${jsvalPtr});\n"
|
||||
}
|
||||
}
|
||||
|
||||
def isVariantType(t):
|
||||
return isSpecificInterfaceType(t, 'nsIVariant')
|
||||
@ -627,6 +633,23 @@ def anyParamRequiresCcx(member):
|
||||
return True
|
||||
return False
|
||||
|
||||
def validateParam(member, param):
|
||||
def pfail(msg):
|
||||
raise UserError(
|
||||
member.iface.name + '.' + member.name + ": "
|
||||
"parameter " + param.name + ": " + msg)
|
||||
|
||||
if param.iid_is is not None:
|
||||
pfail("iid_is parameters are not supported.")
|
||||
if param.size_is is not None:
|
||||
pfail("size_is parameters are not supported.")
|
||||
if param.retval:
|
||||
pfail("Unexpected retval parameter!")
|
||||
if param.paramtype in ('out', 'inout'):
|
||||
pfail("Out parameters are not supported.")
|
||||
if param.const or param.array or param.shared:
|
||||
pfail("I am a simple caveman.")
|
||||
|
||||
def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
|
||||
""" Write a single quick stub (a custom SpiderMonkey getter/setter/method)
|
||||
for the specified XPCOM interface-member.
|
||||
@ -705,27 +728,13 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
|
||||
f.write(" return xpc_qsThrow(cx, "
|
||||
"NS_ERROR_XPC_NOT_ENOUGH_ARGS);\n")
|
||||
|
||||
def pfail(msg):
|
||||
raise UserError(
|
||||
member.iface.name + '.' + member.name + ": "
|
||||
"parameter " + param.name + ": " + msg)
|
||||
|
||||
# Convert in-parameters.
|
||||
rvdeclared = False
|
||||
if isMethod:
|
||||
if len(member.params) > 0:
|
||||
f.write(" jsval *argv = JS_ARGV(cx, vp);\n")
|
||||
for i, param in enumerate(member.params):
|
||||
if param.iid_is is not None:
|
||||
pfail("iid_is parameters are not supported.")
|
||||
if param.size_is is not None:
|
||||
pfail("size_is parameters are not supported.")
|
||||
if param.retval:
|
||||
pfail("Unexpected retval parameter!")
|
||||
if param.paramtype in ('out', 'inout'):
|
||||
pfail("Out parameters are not supported.")
|
||||
if param.const or param.array or param.shared:
|
||||
pfail("I am a simple caveman.")
|
||||
validateParam(member, param)
|
||||
# Emit code to convert this argument from jsval.
|
||||
rvdeclared = writeArgumentUnboxing(
|
||||
f, i, 'arg%d' % i, param.realtype,
|
||||
@ -807,6 +816,300 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False):
|
||||
# Epilog.
|
||||
f.write("}\n\n")
|
||||
|
||||
traceTypeMap = {
|
||||
'void':
|
||||
["jsval ", "JSVAL", "JSVAL_VOID"],
|
||||
'boolean':
|
||||
["JSBool ", "BOOL", "JS_FALSE"],
|
||||
'short':
|
||||
["int32 ", "INT32", "0"],
|
||||
'unsigned short':
|
||||
["uint32 ", "UINT32", "0"],
|
||||
'long':
|
||||
["int32 ", "INT32", "0"],
|
||||
'unsigned long':
|
||||
["uint32 ", "UINT32", "0"],
|
||||
'float':
|
||||
["jsdouble ", "DOUBLE", "0"],
|
||||
'double':
|
||||
["jsdouble ", "DOUBLE", "0"],
|
||||
|
||||
# XXX STRING_FAIL can't return a null'd string, ask jorendorff, maybe a JSVAL_FAIL
|
||||
'[astring]':
|
||||
["JSString *", "STRING", "nsnull"],
|
||||
'[domstring]':
|
||||
["JSString *", "STRING", "nsnull"],
|
||||
'[cstring]':
|
||||
["JSString *", "STRING", "nsnull"],
|
||||
'string':
|
||||
["JSString *", "STRING", "nsnull"],
|
||||
'wstring':
|
||||
["JSString *", "STRING", "nsnull"],
|
||||
|
||||
'_default':
|
||||
["jsval ", "JSVAL", "JSVAL_VOID"]
|
||||
}
|
||||
|
||||
def getTraceType(type):
|
||||
traceType = traceTypeMap.get(type) or traceTypeMap.get("_default")
|
||||
assert traceType
|
||||
return traceType[0]
|
||||
|
||||
def getTraceInfoType(type):
|
||||
traceType = traceTypeMap.get(type) or traceTypeMap.get("_default")
|
||||
assert traceType
|
||||
return traceType[1]
|
||||
|
||||
def getTraceInfoDefaultReturn(type):
|
||||
traceType = traceTypeMap.get(type) or traceTypeMap.get("_default")
|
||||
assert traceType
|
||||
return traceType[2]
|
||||
|
||||
def getFailureString(retval, indent):
|
||||
assert indent > 0
|
||||
ret = " " * (4 * indent)
|
||||
ret += "cx->builtinStatus |= JSBUILTIN_ERROR;\n"
|
||||
ret += " " * (4 * indent)
|
||||
ret += "return %s;\n" % retval
|
||||
ret += " " * (4 * (indent - 1))
|
||||
ret += "}\n"
|
||||
return ret
|
||||
|
||||
def writeFailure(f, retval, indent):
|
||||
f.write(getFailureString(retval, indent))
|
||||
|
||||
traceableArgumentConversionTemplates = {
|
||||
'short':
|
||||
" PRint16 ${name} = (PRint16) ${argVal};\n",
|
||||
'unsigned short':
|
||||
" PRUint16 ${name} = (PRUint16) ${argVal};\n",
|
||||
'long':
|
||||
" PRInt32 ${name} = (PRInt32) ${argVal};\n",
|
||||
'unsigned long':
|
||||
" PRUint32 ${name} = (PRUint32) ${argVal};\n",
|
||||
'boolean':
|
||||
" PRBool ${name} = (PRBool) ${argVal};\n",
|
||||
'float':
|
||||
" float ${name} = (float) ${argVal};\n",
|
||||
'double':
|
||||
" jsdouble ${name} = ${argVal};\n",
|
||||
'[astring]':
|
||||
" xpc_qsDependentJSString ${name}(${argVal});\n",
|
||||
'[domstring]':
|
||||
" xpc_qsDependentJSString ${name}(${argVal});\n",
|
||||
'[cstring]':
|
||||
" xpc_qsDependentJSString ${name}_utf16(${argVal});\n"
|
||||
" NS_ConvertUTF16toUTF8 ${name}(${name}_utf16);\n",
|
||||
'string':
|
||||
" xpc_qsDependentJSString ${name}_utf16(${argVal});\n"
|
||||
" NS_ConvertUTF16toUTF8 ${name}_utf8(${name}_utf16);\n"
|
||||
" const char *${name} = ${name}_utf8.get();\n",
|
||||
'wstring':
|
||||
" const PRUnichar *${name} = JS_GetStringChars({argVal});\n",
|
||||
}
|
||||
|
||||
def writeTraceableArgumentConversion(f, member, i, name, type, haveCcx,
|
||||
rvdeclared):
|
||||
argVal = "arg%d" % i
|
||||
argPtr = "&" + argVal
|
||||
|
||||
params = {
|
||||
'name': name,
|
||||
'argVal': argVal
|
||||
}
|
||||
|
||||
typeName = getBuiltinOrNativeTypeName(type)
|
||||
if typeName is not None:
|
||||
template = traceableArgumentConversionTemplates.get(typeName)
|
||||
if template is not None:
|
||||
f.write(substitute(template, params))
|
||||
return rvdeclared
|
||||
# else fall through; the type isn't supported yet.
|
||||
elif isInterfaceType(type):
|
||||
if type.name == 'nsIVariant':
|
||||
# Totally custom.
|
||||
assert haveCcx
|
||||
template = (
|
||||
" nsCOMPtr<nsIVariant> ${name}(already_AddRefed<nsIVariant>("
|
||||
"XPCVariant::newVariant(ccx, ${argVal})));\n"
|
||||
" if (!${name}) {\n")
|
||||
f.write(substitute(template, params))
|
||||
writeFailure(f, getTraceInfoDefaultReturn(member.type), 2)
|
||||
return rvdeclared
|
||||
elif type.name == 'nsIAtom':
|
||||
# Should have special atomizing behavior. Fall through.
|
||||
pass
|
||||
else:
|
||||
if not rvdeclared:
|
||||
f.write(" nsresult rv;\n");
|
||||
f.write(" nsCOMPtr<%s> %s;\n" % (type.name, name))
|
||||
f.write(" rv = xpc_qsUnwrapArg<%s>("
|
||||
"cx, %s, getter_AddRefs(%s));\n"
|
||||
% (type.name, argVal, name))
|
||||
f.write(" if (NS_FAILED(rv)) {\n")
|
||||
if haveCcx:
|
||||
f.write(" xpc_qsThrowBadArgWithCcx(ccx, rv, %d);\n" % i)
|
||||
else:
|
||||
# XXX Fix this to return a real error!
|
||||
f.write(" xpc_qsThrowBadArgWithDetails(cx, rv, %d, "
|
||||
"\"%s\", \"%s\");\n"
|
||||
% (i, member.iface.name, member.name))
|
||||
writeFailure(f, getTraceInfoDefaultReturn(member.type), 2)
|
||||
return True
|
||||
|
||||
print member
|
||||
warn("Unable to unbox argument of type %s" % type.name)
|
||||
f.write(" !; // TODO - Unbox argument %s = arg%d\n" % (name, i))
|
||||
return rvdeclared
|
||||
|
||||
traceableResultConvTemplates = {
|
||||
'void':
|
||||
" return JSVAL_VOID;\n",
|
||||
'short':
|
||||
" return int32(${result});\n",
|
||||
'unsigned short':
|
||||
" return uint32(${result});\n",
|
||||
'long':
|
||||
" return int32(${result});\n",
|
||||
'unsigned long':
|
||||
" return uint32(${result});\n",
|
||||
'boolean':
|
||||
" return ${result} ? JS_TRUE : JS_FALSE;\n",
|
||||
'[domstring]':
|
||||
" jsval rval;\n"
|
||||
" if (!xpc_qsStringToJsval(cx, ${result}, &rval)) {\n"
|
||||
" JS_ReportOutOfMemory(cx);\n${errorStr}"
|
||||
" return rval;\n",
|
||||
'[astring]':
|
||||
" jsval rval;\n"
|
||||
" if (!xpc_qsStringToJsval(cx, ${result}, &rval)) {\n"
|
||||
" JS_ReportOutOfMemory(cx);\n${errorStr}"
|
||||
" return rval;\n",
|
||||
}
|
||||
|
||||
def writeTraceableResultConv(f, type, paramNum, result):
|
||||
typeName = getBuiltinOrNativeTypeName(type)
|
||||
if typeName is not None:
|
||||
template = traceableResultConvTemplates.get(typeName)
|
||||
if template is not None:
|
||||
values = { 'result': result,
|
||||
'errorStr': getFailureString(
|
||||
getTraceInfoDefaultReturn(type), 2) }
|
||||
f.write(substitute(template, values))
|
||||
return
|
||||
# else fall through; this type isn't supported yet
|
||||
elif isInterfaceType(type):
|
||||
if isVariantType(type):
|
||||
f.write(" JSBool ok = xpc_qsVariantToJsval(ccx, %s, %d, "
|
||||
"tvr.addr());\n" % (result, paramNum))
|
||||
else:
|
||||
f.write(" AutoMarkingNativeInterfacePtr resultiface(ccx, "
|
||||
"%s_Interface(ccx));\n" % type.name)
|
||||
f.write(" JSBool ok = xpc_qsXPCOMObjectToJsval(ccx, %s, "
|
||||
"xpc_qsGetWrapperCache(%s), resultiface, tvr.addr());\n"
|
||||
% (result, result))
|
||||
f.write(" if (!ok) {\n");
|
||||
writeFailure(f, getTraceInfoDefaultReturn(type), 2)
|
||||
f.write(" return *tvr.addr();\n")
|
||||
return
|
||||
|
||||
warn("Unable to convert result of type %s" % typeName)
|
||||
f.write(" !; // TODO - Convert `result` to jsval, store in rval.\n")
|
||||
f.write(" return xpc_qsThrow(cx, NS_ERROR_UNEXPECTED); // FIXME\n")
|
||||
|
||||
def writeTraceableQuickStub(f, member, stubName):
|
||||
assert member.traceable
|
||||
|
||||
traceInfo = {
|
||||
'type': getTraceInfoType(member.type) + "_FAIL",
|
||||
'params': ["CONTEXT", "THIS"]
|
||||
}
|
||||
|
||||
haveCcx = isInterfaceType(member.realtype) or anyParamRequiresCcx(member)
|
||||
|
||||
# Write the function
|
||||
f.write("static %sFASTCALL\n" % getTraceType(member.type))
|
||||
f.write("%s(JSContext *cx, JSObject *obj" % (stubName + "_tn"))
|
||||
if haveCcx:
|
||||
f.write(", JSObject *callee")
|
||||
traceInfo["params"].append("CALLEE")
|
||||
for i, param in enumerate(member.params):
|
||||
type = getBuiltinOrNativeTypeName(param.realtype)
|
||||
f.write(", %sarg%d" % (getTraceType(type), i))
|
||||
traceInfo["params"].append(getTraceInfoType(type))
|
||||
f.write(")\n{\n");
|
||||
f.write(" XPC_QS_ASSERT_CONTEXT_OK(cx);\n")
|
||||
|
||||
# Create ccx if needed.
|
||||
if haveCcx:
|
||||
f.write(" XPCCallContext ccx(JS_CALLER, cx, obj, callee);\n")
|
||||
|
||||
# Get the 'self' pointer.
|
||||
selfName = "self"
|
||||
f.write(" %s *%s;\n" % (member.iface.name, selfName))
|
||||
f.write(" xpc_qsSelfRef selfref;\n")
|
||||
f.write(" xpc_qsTempRoot tvr(cx);\n")
|
||||
if haveCcx:
|
||||
f.write(" if (!xpc_qsUnwrapThisFromCcx(ccx, &self, &selfref.ptr, "
|
||||
"tvr.addr())) {\n")
|
||||
else:
|
||||
f.write(" if (!xpc_qsUnwrapThis(cx, obj, &self, &selfref.ptr, "
|
||||
"tvr.addr())) {\n")
|
||||
writeFailure(f, getTraceInfoDefaultReturn(member.type), 2)
|
||||
|
||||
argNames = []
|
||||
|
||||
# Convert in-parameters.
|
||||
rvdeclared = False
|
||||
for i, param in enumerate(member.params):
|
||||
validateParam(member, param)
|
||||
type = unaliasType(param.realtype)
|
||||
argName = "_arg%d" % i
|
||||
rvdeclared = writeTraceableArgumentConversion(f, member, i, argName,
|
||||
param.realtype,
|
||||
haveCcx, rvdeclared)
|
||||
argNames.append(argName)
|
||||
|
||||
# Prepare out-parameter.
|
||||
resultName = "_retval"
|
||||
writeResultDecl(f, member.realtype, resultName)
|
||||
|
||||
# Call the method.
|
||||
comName = header.methodNativeName(member)
|
||||
if not isVoidType(member.realtype):
|
||||
argNames.append(outParamForm(resultName, member.realtype))
|
||||
args = ', '.join(argNames)
|
||||
|
||||
if not rvdeclared:
|
||||
f.write(" nsresult ")
|
||||
rvdeclared = True
|
||||
else:
|
||||
f.write(" ")
|
||||
f.write("rv = %s->%s(%s);\n" % (selfName, comName, args))
|
||||
|
||||
# Check for errors.
|
||||
f.write(" if (NS_FAILED(rv)) {\n")
|
||||
if haveCcx:
|
||||
f.write(" xpc_qsThrowMethodFailedWithCcx(ccx, rv);\n")
|
||||
else:
|
||||
# XXX Replace with a real error message!
|
||||
f.write(" xpc_qsThrowMethodFailedWithDetails(cx, rv, \"%s\", "
|
||||
"\"%s\");\n" % (member.iface.name, member.name))
|
||||
writeFailure(f, getTraceInfoDefaultReturn(member.type), 2)
|
||||
|
||||
# Convert the return value.
|
||||
writeTraceableResultConv(f, member.realtype, len(member.params) + 1,
|
||||
resultName)
|
||||
|
||||
# Epilog.
|
||||
f.write("}\n\n")
|
||||
|
||||
# Write the JS_DEFINE_TRCINFO block
|
||||
f.write("JS_DEFINE_TRCINFO_1(%s,\n" % stubName)
|
||||
f.write(" (%d, (static, %s, %s, %s, 0, 0)))\n\n"
|
||||
% (len(traceInfo["params"]), traceInfo["type"], stubName + "_tn",
|
||||
", ".join(traceInfo["params"])))
|
||||
|
||||
def writeAttrStubs(f, customMethodCalls, attr):
|
||||
getterName = (attr.iface.name + '_'
|
||||
+ header.attributeNativeName(attr, True))
|
||||
@ -829,17 +1132,31 @@ def writeMethodStub(f, customMethodCalls, method):
|
||||
fs = '{"%s", %s, %d}' % (method.name, stubName, len(method.params))
|
||||
return fs
|
||||
|
||||
def writeTraceableStub(f, method):
|
||||
""" Write a method stub to `f`. Return an xpc_qsTraceableSpec initializer. """
|
||||
stubName = method.iface.name + '_' + header.methodNativeName(method)
|
||||
writeTraceableQuickStub(f, method, stubName)
|
||||
fs = '{"%s", %s, %d}' % (method.name,
|
||||
"JS_DATA_TO_FUNC_PTR(JSNative, %s_trcinfo)" % stubName,
|
||||
len(method.params))
|
||||
return fs
|
||||
|
||||
def writeStubsForInterface(f, customMethodCalls, iface):
|
||||
f.write("// === interface %s\n\n" % iface.name)
|
||||
propspecs = []
|
||||
funcspecs = []
|
||||
tracespecs = []
|
||||
for member in iface.stubMembers:
|
||||
if member.kind == 'attribute':
|
||||
ps = writeAttrStubs(f, customMethodCalls, member)
|
||||
propspecs.append(ps)
|
||||
elif member.kind == 'method':
|
||||
fs = writeMethodStub(f, customMethodCalls, member)
|
||||
funcspecs.append(fs)
|
||||
if member.traceable:
|
||||
ts = writeTraceableStub(f, member)
|
||||
tracespecs.append(ts)
|
||||
else:
|
||||
funcspecs.append(fs)
|
||||
else:
|
||||
raise TypeError('expected attribute or method, not %r'
|
||||
% member.__class__.__name__)
|
||||
@ -855,6 +1172,11 @@ def writeStubsForInterface(f, customMethodCalls, iface):
|
||||
for fs in funcspecs:
|
||||
f.write(" %s,\n" % fs)
|
||||
f.write(" {nsnull}};\n")
|
||||
if tracespecs:
|
||||
f.write("static const xpc_qsTraceableSpec %s_traceables[] = {\n" % iface.name)
|
||||
for ts in tracespecs:
|
||||
f.write(" %s,\n" % ts)
|
||||
f.write(" {nsnull}};\n")
|
||||
f.write('\n\n')
|
||||
|
||||
def hashIID(iid):
|
||||
@ -916,7 +1238,7 @@ def writeDefiner(f, conf, interfaces):
|
||||
arraySize += 1
|
||||
|
||||
entries = [" {{0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}, "
|
||||
"nsnull, nsnull, XPC_QS_NULL_INDEX, XPC_QS_NULL_INDEX}"
|
||||
"nsnull, nsnull, nsnull, XPC_QS_NULL_INDEX, XPC_QS_NULL_INDEX}"
|
||||
for i in range(arraySize)]
|
||||
for i, bucket in enumerate(buckets):
|
||||
for j, iface in enumerate(bucket):
|
||||
@ -934,16 +1256,24 @@ def writeDefiner(f, conf, interfaces):
|
||||
properties = "nsnull"
|
||||
for member in iface.stubMembers:
|
||||
if member.kind == 'attribute':
|
||||
assert not member.traceable
|
||||
properties = iface.name + "_properties"
|
||||
break
|
||||
functions = "nsnull"
|
||||
|
||||
# member field
|
||||
functions = "nsnull"
|
||||
for member in iface.stubMembers:
|
||||
if member.kind == 'method':
|
||||
if member.kind == 'method' and not member.traceable:
|
||||
functions = iface.name + "_functions"
|
||||
break
|
||||
|
||||
# traceables field
|
||||
traceables = "nsnull"
|
||||
for member in iface.stubMembers:
|
||||
if member.traceable:
|
||||
traceables = iface.name + "_traceables"
|
||||
break
|
||||
|
||||
# parentInterface field
|
||||
baseName = iface.base
|
||||
while baseName is not None:
|
||||
@ -964,8 +1294,8 @@ def writeDefiner(f, conf, interfaces):
|
||||
chain = str(k)
|
||||
|
||||
# add entry
|
||||
entry = " {%s, %s, %s, %s, %s}" % (
|
||||
iid, properties, functions, parentInterface, chain)
|
||||
entry = " {%s, %s, %s, %s, %s, %s}" % (
|
||||
iid, properties, functions, traceables, parentInterface, chain)
|
||||
entries[entryIndexes[iface.attributes.uuid]] = entry
|
||||
|
||||
f.write("static const xpc_qsHashEntry tableData[] = {\n")
|
||||
@ -994,7 +1324,7 @@ stubTopTemplate = '''\
|
||||
#include "nsDependentString.h"
|
||||
#include "xpcprivate.h" // for XPCCallContext
|
||||
#include "xpcquickstubs.h"
|
||||
|
||||
#include "jsbuiltins.h"
|
||||
'''
|
||||
|
||||
def writeStubFile(filename, headerFilename, conf, interfaces):
|
||||
@ -1084,6 +1414,8 @@ def main():
|
||||
help="Directory in which to cache lex/parse tables.")
|
||||
o.add_option("--verbose-errors", action='store_true', default=False,
|
||||
help="When an error happens, display the Python traceback.")
|
||||
o.add_option("--enable-traceables", action='store_true', default=False,
|
||||
help="Whether or not traceable methods are generated.")
|
||||
(options, filenames) = o.parse_args()
|
||||
|
||||
if len(filenames) != 1:
|
||||
@ -1108,7 +1440,8 @@ def main():
|
||||
includePath = options.idlpath.split(':')
|
||||
conf, interfaces = readConfigFile(filename,
|
||||
includePath=includePath,
|
||||
cachedir=options.cachedir)
|
||||
cachedir=options.cachedir,
|
||||
traceable=options.enable_traceables)
|
||||
writeHeaderFile(options.header_output, conf.name)
|
||||
writeStubFile(options.stub_output, options.header_output,
|
||||
conf, interfaces)
|
||||
|
@ -419,6 +419,19 @@ xpc_qsDefineQuickStubs(JSContext *cx, JSObject *proto, uintN flags,
|
||||
}
|
||||
}
|
||||
|
||||
const xpc_qsTraceableSpec *ts = entry->traceables;
|
||||
if(ts)
|
||||
{
|
||||
for(; ts->name; ts++)
|
||||
{
|
||||
if(!JS_DefineFunction(
|
||||
cx, proto, ts->name, ts->native, ts->arity,
|
||||
flags | JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS |
|
||||
JSFUN_TRACEABLE))
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Next.
|
||||
size_t j = entry->parentInterface;
|
||||
if(j == XPC_QS_NULL_INDEX)
|
||||
@ -580,6 +593,14 @@ xpc_qsThrowMethodFailedWithCcx(XPCCallContext &ccx, nsresult rv)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
xpc_qsThrowMethodFailedWithDetails(JSContext *cx, nsresult rv,
|
||||
const char *ifaceName,
|
||||
const char *memberName)
|
||||
{
|
||||
ThrowCallFailed(cx, rv, ifaceName, memberName);
|
||||
}
|
||||
|
||||
static void
|
||||
ThrowBadArg(JSContext *cx, nsresult rv,
|
||||
const char *ifaceName, const char *memberName, uintN paramnum)
|
||||
@ -614,6 +635,13 @@ xpc_qsThrowBadArgWithCcx(XPCCallContext &ccx, nsresult rv, uintN paramnum)
|
||||
XPCThrower::ThrowBadParam(rv, paramnum, ccx);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_qsThrowBadArgWithDetails(JSContext *cx, nsresult rv, uintN paramnum,
|
||||
const char *ifaceName, const char *memberName)
|
||||
{
|
||||
ThrowBadArg(cx, rv, ifaceName, memberName, paramnum);
|
||||
}
|
||||
|
||||
void
|
||||
xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv,
|
||||
JSObject *obj, jsval propId)
|
||||
|
@ -58,11 +58,18 @@ struct xpc_qsFunctionSpec {
|
||||
uintN arity;
|
||||
};
|
||||
|
||||
struct xpc_qsTraceableSpec {
|
||||
const char *name;
|
||||
JSNative native;
|
||||
uintN arity;
|
||||
};
|
||||
|
||||
/** A table mapping interfaces to quick stubs. */
|
||||
struct xpc_qsHashEntry {
|
||||
nsID iid;
|
||||
const xpc_qsPropertySpec *properties;
|
||||
const xpc_qsFunctionSpec *functions;
|
||||
const xpc_qsTraceableSpec *traceables;
|
||||
// These last two fields index to other entries in the same table.
|
||||
// XPC_QS_NULL_ENTRY indicates there are no more entries in the chain.
|
||||
size_t parentInterface;
|
||||
@ -106,6 +113,11 @@ xpc_qsThrowMethodFailed(JSContext *cx, nsresult rv, jsval *vp);
|
||||
JSBool
|
||||
xpc_qsThrowMethodFailedWithCcx(XPCCallContext &ccx, nsresult rv);
|
||||
|
||||
void
|
||||
xpc_qsThrowMethodFailedWithDetails(JSContext *cx, nsresult rv,
|
||||
const char *ifaceName,
|
||||
const char *memberName);
|
||||
|
||||
/**
|
||||
* Fail after converting a method argument fails.
|
||||
*
|
||||
@ -117,6 +129,10 @@ xpc_qsThrowBadArg(JSContext *cx, nsresult rv, jsval *vp, uintN paramnum);
|
||||
void
|
||||
xpc_qsThrowBadArgWithCcx(XPCCallContext &ccx, nsresult rv, uintN paramnum);
|
||||
|
||||
void
|
||||
xpc_qsThrowBadArgWithDetails(JSContext *cx, nsresult rv, uintN paramnum,
|
||||
const char *ifaceName, const char *memberName);
|
||||
|
||||
/**
|
||||
* Fail after converting a setter argument fails.
|
||||
*
|
||||
@ -461,4 +477,12 @@ _iface##_Interface(XPCCallContext& ccx) \
|
||||
return (_iface_cache); \
|
||||
}
|
||||
|
||||
class xpc_qsDependentJSString : public nsDependentString
|
||||
{
|
||||
public:
|
||||
explicit xpc_qsDependentJSString(JSString *str)
|
||||
: nsDependentString((PRUnichar *)::JS_GetStringChars(str),
|
||||
::JS_GetStringLength(str)) { }
|
||||
};
|
||||
|
||||
#endif /* xpcquickstubs_h___ */
|
||||
|
Loading…
Reference in New Issue
Block a user