vendor/tracemonkey/xpconnect/src/qsgen.py in johnson-2.0.0.pre0 vs vendor/tracemonkey/xpconnect/src/qsgen.py in johnson-2.0.0.pre1

- old
+ new

@@ -99,20 +99,10 @@ # that use GetCurrentNativeCallContext and are called indirectly from # quick-stubbed methods, because only the current top XPCCallContext is # exposed--nsAXPCNativeCallContext does not expose # XPCCallContext::GetPrevCallContext.) # -# - There are a few differences in how the "this" JSObject is unwrapped. -# Ordinarily, XPConnect searches the prototype chain of the "this" JSObject -# for an XPCOM object of the desired "proto". For details, see the parts of -# XPCWrappedNative::GetWrappedNativeOfJSObject that use "proto". Some quick -# stubs (methods, not getters or setters, that have XPCCallContexts) do this, -# but most instead look for an XPCOM object that supports the desired -# *interface*. This is more lenient. The difference is observable in some -# cases where a getter/setter/method is taken from one object and applied to -# another object. -# # - Quick stubs never suspend the JS request. So they are only suitable for # main-thread-only interfaces. # # - Quick stubs don't call XPCContext::SetLastResult. This is visible on the # Components object. @@ -130,11 +120,10 @@ import xpidl import header import os, re import sys -import sets # === Preliminaries # --makedepend-output support. make_dependencies = [] @@ -328,11 +317,10 @@ # === Generating the header file def writeHeaderFile(filename, name): print "Creating header file", filename - make_targets.append(filename) headerMacro = '__gen_%s__' % filename.replace('.', '_') f = open(filename, 'w') try: f.write("/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n" @@ -394,12 +382,11 @@ " if (!JS_ValueToNumber(cx, ${argVal}, &${name}))\n" " return JS_FALSE;\n", 'boolean': " PRBool ${name};\n" - " if (!JS_ValueToBoolean(cx, ${argVal}, &${name}))\n" - " return JS_FALSE;\n", + " JS_ValueToBoolean(cx, ${argVal}, &${name});\n", '[astring]': " xpc_qsAString ${name}(cx, ${argPtr});\n" " if (!${name}.IsValid())\n" " return JS_FALSE;\n", @@ -484,14 +471,15 @@ # 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(" %s *%s;\n" % (type.name, name)) + f.write(" xpc_qsSelfRef %sref;\n" % name) f.write(" rv = xpc_qsUnwrapArg<%s>(" - "cx, %s, getter_AddRefs(%s));\n" - % (type.name, argVal, name)) + "cx, %s, &%s, &%sref.ptr, %s);\n" + % (type.name, argVal, name, name, argPtr)) f.write(" if (NS_FAILED(rv)) {\n") if isSetter: f.write(" xpc_qsThrowBadSetterValue(" "cx, rv, JSVAL_TO_OBJECT(*tvr.addr()), id);\n") elif haveCcx: @@ -591,11 +579,11 @@ } def isVariantType(t): return isSpecificInterfaceType(t, 'nsIVariant') -def writeResultConv(f, type, paramNum, jsvalPtr, jsvalRef): +def writeResultConv(f, type, jsvalPtr, jsvalRef): """ Emit code to convert the C++ variable `result` to a jsval. The emitted code contains a return statement; it returns JS_TRUE on success, JS_FALSE on error. """ @@ -609,19 +597,18 @@ f.write(substitute(template, values)) return # else fall through; this type isn't supported yet elif isInterfaceType(type): if isVariantType(type): - f.write(" return xpc_qsVariantToJsval(ccx, result, %d, %s);\n" - % (paramNum, jsvalPtr)) + f.write(" return xpc_qsVariantToJsval(lccx, result, %s);\n" + % jsvalPtr) return else: - f.write(" AutoMarkingNativeInterfacePtr resultiface(ccx, " - "%s_Interface(ccx));\n" % type.name) - f.write(" return xpc_qsXPCOMObjectToJsval(ccx, result, " - "xpc_qsGetWrapperCache(result), resultiface, %s);\n" - % jsvalPtr) + f.write(" return xpc_qsXPCOMObjectToJsval(lccx, result, " + "xpc_qsGetWrapperCache(result), &NS_GET_IID(%s), " + "&interfaces[k_%s], %s);\n" + % (type.name, type.name, jsvalPtr)) return warn("Unable to convert result of type %s" % type.name) f.write(" !; // TODO - Convert `result` to jsval, store in `%s`.\n" % jsvalRef) @@ -678,46 +665,53 @@ f.write(" JSObject *obj = JS_THIS_OBJECT(cx, vp);\n" " if (!obj)\n" " return JS_FALSE;\n") # Create ccx if needed. - haveCcx = isMethod and (isInterfaceType(member.realtype) - or anyParamRequiresCcx(member)) + haveCcx = isMethod and anyParamRequiresCcx(member) if haveCcx: - f.write(" XPCCallContext ccx(JS_CALLER, cx, obj, " - "JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));\n") - else: - # In some cases we emit a ccx, but it does not count as - # "haveCcx" because it's not complete. - if isAttr and isInterfaceType(member.realtype): - f.write(" XPCCallContext ccx(JS_CALLER, cx, obj);\n") + f.write(" XPCCallContext ccx(JS_CALLER, cx, obj, " + "JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));\n") + if isInterfaceType(member.realtype): + f.write(" XPCLazyCallContext lccx(ccx);\n") + elif isInterfaceType(member.realtype): + if isMethod: + f.write(" JSObject *callee = " + "JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));\n") + elif isGetter: + f.write(" JSObject *callee = nsnull;\n") # Get the 'self' pointer. if customMethodCall is None or not 'thisType' in customMethodCall: f.write(" %s *self;\n" % member.iface.name) else: f.write(" %s *self;\n" % customMethodCall['thisType']) f.write(" xpc_qsSelfRef selfref;\n") # Don't use FromCcx for getters or setters; the way we construct the ccx in # a getter/setter causes it to find the wrong wrapper in some cases. - if isMethod and haveCcx: + if haveCcx: # Undocumented, but the interpreter puts 'this' at argv[-1], # which is vp[1]; and it's ok to overwrite it. f.write(" if (!xpc_qsUnwrapThisFromCcx(ccx, &self, &selfref.ptr, " "&vp[1]))\n") f.write(" return JS_FALSE;\n") else: if isGetter: pthisval = 'vp' elif isSetter: - f.write(" xpc_qsTempRoot tvr(cx);\n") + f.write(" JSAutoTempValueRooter tvr(cx);\n") pthisval = 'tvr.addr()' else: pthisval = '&vp[1]' # as above, ok to overwrite vp[1] - f.write(" if (!xpc_qsUnwrapThis(cx, obj, &self, &selfref.ptr, " - "%s))\n" % pthisval) + if not isSetter and isInterfaceType(member.realtype): + f.write(" XPCLazyCallContext lccx(JS_CALLER, cx, obj);\n") + f.write(" if (!xpc_qsUnwrapThis(cx, obj, callee, &self, " + "&selfref.ptr, %s, &lccx))\n" % pthisval) + else: + f.write(" if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, " + "&selfref.ptr, %s, nsnull))\n" % pthisval) f.write(" return JS_FALSE;\n") if isMethod: # If there are any required arguments, check argc. requiredArgs = len(member.params) @@ -807,14 +801,12 @@ " \"Got the wrong answer from the custom " "method call!\");\n") f.write("#endif\n") # Convert the return value. - if isMethod: - writeResultConv(f, member.realtype, len(member.params) + 1, 'vp', '*vp') - elif isGetter: - writeResultConv(f, member.realtype, None, 'vp', '*vp') + if isMethod or isGetter: + writeResultConv(f, member.realtype, 'vp', '*vp') else: f.write(" return JS_TRUE;\n") # Epilog. f.write("}\n\n") @@ -913,12 +905,11 @@ " const PRUnichar *${name} = JS_GetStringChars({argVal});\n", } def writeTraceableArgumentConversion(f, member, i, name, type, haveCcx, rvdeclared): - argVal = "arg%d" % i - argPtr = "&" + argVal + argVal = "_arg%d" % i params = { 'name': name, 'argVal': argVal } @@ -945,14 +936,15 @@ # 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(" %s *%s;\n" % (type.name, name)) + f.write(" xpc_qsSelfRef %sref;\n" % name) f.write(" rv = xpc_qsUnwrapArg<%s>(" - "cx, %s, getter_AddRefs(%s));\n" - % (type.name, argVal, name)) + "cx, %s, &%s, &%sref.ptr, &vp.array[%d]);\n" + % (type.name, argVal, name, name, 1 + i)) 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! @@ -990,11 +982,11 @@ " if (!xpc_qsStringToJsval(cx, result, &rval)) {\n" " JS_ReportOutOfMemory(cx);\n${errorStr}" " return rval;\n", } -def writeTraceableResultConv(f, type, paramNum): +def writeTraceableResultConv(f, type): typeName = getBuiltinOrNativeTypeName(type) if typeName is not None: template = traceableResultConvTemplates.get(typeName) if template is not None: values = { 'errorStr': getFailureString( @@ -1002,21 +994,20 @@ 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, result, %d, " - "tvr.addr());\n" % paramNum) + f.write(" JSBool ok = xpc_qsVariantToJsval(lccx, result, " + "&vp.array[0]);\n") else: - f.write(" AutoMarkingNativeInterfacePtr resultiface(ccx, " - "%s_Interface(ccx));\n" % type.name) - f.write(" JSBool ok = xpc_qsXPCOMObjectToJsval(ccx, result, " - "xpc_qsGetWrapperCache(result), resultiface, tvr.addr());" - "\n") + f.write(" JSBool ok = xpc_qsXPCOMObjectToJsval(lccx, result, " + "xpc_qsGetWrapperCache(result), &NS_GET_IID(%s), " + "&interfaces[k_%s], &vp.array[0]);" + "\n" % (type.name, type.name)) f.write(" if (!ok) {\n"); writeFailure(f, getTraceInfoDefaultReturn(type), 2) - f.write(" return *tvr.addr();\n") + f.write(" return vp.array[0];\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") @@ -1027,54 +1018,60 @@ traceInfo = { 'type': getTraceInfoType(member.type) + "_FAIL", 'params': ["CONTEXT", "THIS"] } - haveCcx = isInterfaceType(member.realtype) or anyParamRequiresCcx(member) + haveCcx = (member.kind == 'method') and anyParamRequiresCcx(member) customMethodCall = customMethodCalls.get(stubName, None) # Write the function f.write("static %sFASTCALL\n" % getTraceType(member.type)) f.write("%s(JSContext *cx, JSObject *obj" % (stubName + "_tn")) - if haveCcx: + if haveCcx or isInterfaceType(member.realtype): 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)) + f.write(", %s_arg%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") + if isInterfaceType(member.realtype): + f.write(" XPCLazyCallContext lccx(ccx);\n") # Get the 'self' pointer. if customMethodCall is None or not 'thisType' in customMethodCall: f.write(" %s *self;\n" % member.iface.name) else: f.write(" %s *self;\n" % customMethodCall['thisType']) f.write(" xpc_qsSelfRef selfref;\n") - f.write(" xpc_qsTempRoot tvr(cx);\n") + f.write(" xpc_qsArgValArray<%d> vp(cx);\n" % (1 + len(member.params))) if haveCcx: f.write(" if (!xpc_qsUnwrapThisFromCcx(ccx, &self, &selfref.ptr, " - "tvr.addr())) {\n") + "&vp.array[0])) {\n") + elif (member.kind == 'method') and isInterfaceType(member.realtype): + f.write(" XPCLazyCallContext lccx(JS_CALLER, cx, obj);\n") + f.write(" if (!xpc_qsUnwrapThis(cx, obj, callee, &self, &selfref.ptr, " + "&vp.array[0], &lccx)) {\n") else: - f.write(" if (!xpc_qsUnwrapThis(cx, obj, &self, &selfref.ptr, " - "tvr.addr())) {\n") + f.write(" if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, " + "&vp.array[0], nsnull)) {\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 + argName = "arg%d" % i rvdeclared = writeTraceableArgumentConversion(f, member, i, argName, param.realtype, haveCcx, rvdeclared) argNames.append(argName) @@ -1122,11 +1119,11 @@ " \"Got the wrong answer from the custom " "method call!\");\n") f.write("#endif\n") # Convert the return value. - writeTraceableResultConv(f, member.realtype, len(member.params) + 1) + writeTraceableResultConv(f, member.realtype) # Epilog. f.write("}\n\n") # Write the JS_DEFINE_TRCINFO block @@ -1138,11 +1135,11 @@ def writeAttrStubs(f, customMethodCalls, attr): getterName = (attr.iface.name + '_' + header.attributeNativeName(attr, True)) writeQuickStub(f, customMethodCalls, attr, getterName) if attr.readonly: - setterName = 'xpc_qsReadOnlySetter' + setterName = 'js_GetterOnlyPropertyStub' else: setterName = (attr.iface.name + '_' + header.attributeNativeName(attr, False)) writeQuickStub(f, customMethodCalls, attr, setterName, isSetter=True) @@ -1160,11 +1157,11 @@ def writeTraceableStub(f, customMethodCalls, method): """ Write a method stub to `f`. Return an xpc_qsTraceableSpec initializer. """ stubName = method.iface.name + '_' + header.methodNativeName(method) writeTraceableQuickStub(f, customMethodCalls, method, stubName) fs = '{"%s", %s, %d}' % (method.name, - "JS_DATA_TO_FUNC_PTR(JSNative, %s_trcinfo)" % stubName, + "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) @@ -1228,12 +1225,11 @@ f.write(" memset(interfaces, 0, %d * " "sizeof(XPCNativeInterface*));\n" % count) f.write("}\n\n") i = 0 for type in resulttypes: - f.write("XPC_QS_DEFINE_XPCNATIVEINTERFACE_GETTER(%s, interfaces[%d])\n" - % (type, i)) + f.write("static const PRUint32 k_%s = %d;\n" % (type, i)) i += 1 if count > 0: f.write("\n\n") def writeDefiner(f, conf, interfaces): @@ -1355,11 +1351,11 @@ def writeStubFile(filename, headerFilename, conf, interfaces): print "Creating stub file", filename make_targets.append(filename) f = open(filename, 'w') - filesIncluded = sets.Set() + filesIncluded = set() def includeType(type): type = unaliasType(type) if type.kind in ('builtin', 'native'): return None @@ -1396,10 +1392,10 @@ f.write('#include "%s"\n' % customInclude) resulttypes = [] for iface in interfaces: resulttypes.extend(writeIncludesForInterface(iface)) f.write("\n\n") - writeResultXPCInterfacesArray(f, conf, sets.ImmutableSet(resulttypes)) + writeResultXPCInterfacesArray(f, conf, frozenset(resulttypes)) for iface in interfaces: writeStubsForInterface(f, conf.customMethodCalls, iface) writeDefiner(f, conf, interfaces) finally: f.close()