def writeMethodStub(f, customMethodCalls, stringtable, method):
    """ Write a method stub to `f`. Return an xpc_qsFunctionSpec initializer. """

    stubName = method.iface.name + "_" + header.methodNativeName(method)
    writeQuickStub(f, customMethodCalls, stringtable, method, stubName)
    fs = "{%d, %d, %s}" % (stringtable.stringIndex(method.name), len(method.params), stubName)
    return fs
Beispiel #2
0
def writeStub(f, customMethodCalls, member, stubName, writeThisUnwrapping, writeCheckForFailure, writeResultWrapping, isSetter=False):
    """ Write a single quick stub (a custom SpiderMonkey getter/setter/method)
    for the specified XPCOM interface-member. 
    """
    if member.kind == 'method' and member.forward:
        member = member.iface.namemap[member.forward]

    isAttr = (member.kind == 'attribute')
    isMethod = (member.kind == 'method')
    assert isAttr or isMethod
    isNotxpcom = isMethod and member.notxpcom
    isGetter = isAttr and not isSetter

    signature = "static JSBool\n"
    if isAttr:
        # JSPropertyOp signature.
        if isSetter:
            signature += "%s(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict,%s jsval *vp)\n"
        else:
            signature += "%s(JSContext *cx, JSHandleObject obj, JSHandleId id,%s jsval *vp)\n"
    else:
        # JSFastNative.
        signature += "%s(JSContext *cx, unsigned argc,%s jsval *vp)\n"

    customMethodCall = customMethodCalls.get(stubName, None)

    if customMethodCall is None:
        customMethodCall = customMethodCalls.get(member.iface.name + '_', None)
        if customMethodCall is not None:
            if isMethod:
                code = customMethodCall.get('code', None)
            elif isGetter:
                code = customMethodCall.get('getter_code', None)
            else:
                code = customMethodCall.get('setter_code', None)
        else:
            code = None

        if code is not None:
            templateName = member.iface.name
            if isGetter:
                templateName += '_Get'
            elif isSetter:
                templateName += '_Set'

            # Generate the code for the stub, calling the template function
            # that's shared between the stubs. The stubs can't have additional
            # arguments, only the template function can.
            callTemplate = signature % (stubName, '')
            callTemplate += "{\n"

            argumentValues = (customMethodCall['additionalArgumentValues']
                              % header.methodNativeName(member))
            if isAttr:
                callTemplate += ("    return %s(cx, obj, id%s, %s, vp);\n"
                                 % (templateName, ", strict" if isSetter else "", argumentValues))
            else:
                callTemplate += ("    return %s(cx, argc, %s, vp);\n"
                                 % (templateName, argumentValues))
            callTemplate += "}\n\n"

            # Fall through and create the template function stub called from the
            # real stubs, but only generate the stub once. Otherwise, just write
            # out the call to the template function and return.
            templateGenerated = templateName + '_generated'
            if templateGenerated in customMethodCall:
                f.write(callTemplate)
                return
            customMethodCall[templateGenerated] = True

            stubName = templateName
        else:
            callTemplate = ""
    else:
        callTemplate = ""
        code = customMethodCall.get('code', None)

    # Function prolog.

    # Only template functions can have additional arguments.
    if customMethodCall is None or not 'additionalArguments' in customMethodCall:
        additionalArguments = ''
    else:
        additionalArguments = " %s," % customMethodCall['additionalArguments']
    f.write(signature % (stubName, additionalArguments))
    f.write("{\n")
    f.write("    XPC_QS_ASSERT_CONTEXT_OK(cx);\n")

    # For methods, compute "this".
    if isMethod:
        f.write("    JSObject *obj = JS_THIS_OBJECT(cx, vp);\n"
                "    if (!obj)\n"
                "        return JS_FALSE;\n")

    # Create ccx if needed.
    haveCcx = memberNeedsCcx(member)
    if haveCcx:
        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")

    selfname = writeThisUnwrapping(f, member, isMethod, isGetter, customMethodCall, haveCcx)

    rvdeclared = False
    if isMethod:
        inArgs = argumentsLength(member)
        # If there are any required arguments, check argc.
        requiredArgs = inArgs
        while requiredArgs and member.params[requiredArgs-1].optional:
            requiredArgs -= 1
        if requiredArgs:
            f.write("    if (argc < %d)\n" % requiredArgs)
            f.write("        return xpc_qsThrow(cx, "
                    "NS_ERROR_XPC_NOT_ENOUGH_ARGS);\n")

        # Convert in-parameters.
        if inArgs > 0:
            f.write("    jsval *argv = JS_ARGV(cx, vp);\n")
        for i in range(inArgs):
            param = member.params[i]
            argName = 'arg%d' % i
            argTypeKey = argName + 'Type'
            if customMethodCall is None or not argTypeKey in customMethodCall:
                validateParam(member, param)
                realtype = param.realtype
            else:
                realtype = xpidl.Forward(name=customMethodCall[argTypeKey],
                                         location='', doccomments='')
            # Emit code to convert this argument from jsval.
            rvdeclared = writeArgumentUnboxing(
                f, i, argName, realtype,
                haveCcx=haveCcx,
                optional=param.optional,
                rvdeclared=rvdeclared,
                nullBehavior=param.null,
                undefinedBehavior=param.undefined)
        if inArgs < len(member.params):
            f.write("    nsWrapperCache *cache;\n")
    elif isSetter:
        rvdeclared = writeArgumentUnboxing(f, None, 'arg0', member.realtype,
                                           haveCcx=False, optional=False,
                                           rvdeclared=rvdeclared,
                                           nullBehavior=member.null,
                                           undefinedBehavior=member.undefined)

    canFail = not isNotxpcom and (customMethodCall is None or customMethodCall.get('canFail', True))
    if canFail and not rvdeclared:
        f.write("    nsresult rv;\n")
        rvdeclared = True

    if code is not None:
        f.write("%s\n" % code)

    if code is None or (isGetter and callTemplate is ""):
        debugGetter = code is not None
        if debugGetter:
            f.write("#ifdef DEBUG\n")
            f.write("    nsresult debug_rv;\n")
            f.write("    nsCOMPtr<%s> debug_self;\n"
                    "    CallQueryInterface(self, getter_AddRefs(debug_self));\n"
                    % member.iface.name);
            prefix = 'debug_'
        else:
            prefix = ''

        resultname = prefix + 'result'
        selfname = prefix + selfname
        nsresultname = prefix + 'rv'

        # Prepare out-parameter.
        if isMethod or isGetter:
            writeResultDecl(f, member, resultname)

        # Call the method.
        if isMethod:
            comName = header.methodNativeName(member)
            argv = ['arg' + str(i) for i in range(inArgs)]
            if inArgs < len(member.params):
                argv.append(outParamForm('cache', member.params[inArgs].realtype))
            if member.implicit_jscontext:
                argv.append('cx')
            if member.optional_argc:
                argv.append('argc - %d' % requiredArgs)
            if not isNotxpcom and not isVoidType(member.realtype):
                argv.append(outParamForm(resultname, member.realtype))
            args = ', '.join(argv)
        else:
            comName = header.attributeNativeName(member, isGetter)
            if isGetter:
                args = outParamForm(resultname, member.realtype)
            else:
                args = "arg0"
            if member.implicit_jscontext:
                args = "cx, " + args

        f.write("    ")
        if canFail or debugGetter:
            f.write("%s = " % nsresultname)
        elif isNotxpcom:
            f.write("%s = " % resultname)
        f.write("%s->%s(%s);\n" % (selfname, comName, args))

        if debugGetter:
            checkSuccess = "NS_SUCCEEDED(debug_rv)"
            if canFail:
                checkSuccess += " == NS_SUCCEEDED(rv)"
            f.write("    NS_ASSERTION(%s && "
                    "xpc_qsSameResult(debug_result, result),\n"
                    "                 \"Got the wrong answer from the custom "
                    "method call!\");\n" % checkSuccess)
            f.write("#endif\n")

    if canFail:
        # Check for errors.
        writeCheckForFailure(f, isMethod, isGetter, haveCcx)

    # Convert the return value.
    if isMethod or isGetter:
        writeResultWrapping(f, member, 'vp', '*vp')
    else:
        f.write("    return JS_TRUE;\n")

    # Epilog.
    f.write("}\n\n")

    # Now write out the call to the template function.
    if customMethodCall is not None:
        f.write(callTemplate)
def writeQuickStub(f, customMethodCalls, stringtable, member, stubName, isSetter=False):
    """ Write a single quick stub (a custom SpiderMonkey getter/setter/method)
    for the specified XPCOM interface-member. 
    """
    # Workaround for suspected compiler bug.
    # See https://bugzilla.mozilla.org/show_bug.cgi?id=750019
    disableOptimizationForMSVC = stubName == "nsIDOMHTMLDocument_Write"

    isAttr = member.kind == "attribute"
    isMethod = member.kind == "method"
    assert isAttr or isMethod
    isGetter = isAttr and not isSetter

    signature = "static bool\n" + "%s(JSContext *cx, unsigned argc,%s jsval *vp)\n"

    customMethodCall = customMethodCalls.get(stubName, None)

    if customMethodCall is None:
        customMethodCall = customMethodCalls.get(member.iface.name + "_", None)
        if customMethodCall is not None:
            if isMethod:
                code = customMethodCall.get("code", None)
            elif isGetter:
                code = customMethodCall.get("getter_code", None)
            else:
                code = customMethodCall.get("setter_code", None)
        else:
            code = None

        if code is not None:
            templateName = member.iface.name
            if isGetter:
                templateName += "_Get"
            elif isSetter:
                templateName += "_Set"

            # Generate the code for the stub, calling the template function
            # that's shared between the stubs. The stubs can't have additional
            # arguments, only the template function can.
            callTemplate = signature % (stubName, "")
            callTemplate += "{\n"

            nativeName = member.binaryname is not None and member.binaryname or header.firstCap(member.name)
            argumentValues = customMethodCall["additionalArgumentValues"] % nativeName
            callTemplate += "    return %s(cx, argc, %s, vp);\n" % (templateName, argumentValues)
            callTemplate += "}\n\n"

            # Fall through and create the template function stub called from the
            # real stubs, but only generate the stub once. Otherwise, just write
            # out the call to the template function and return.
            templateGenerated = templateName + "_generated"
            if templateGenerated in customMethodCall:
                f.write(callTemplate)
                return
            customMethodCall[templateGenerated] = True

            stubName = templateName
        else:
            callTemplate = ""
    else:
        callTemplate = ""
        code = customMethodCall.get("code", None)

    unwrapThisFailureFatal = customMethodCall is None or customMethodCall.get("unwrapThisFailureFatal", True)
    if not unwrapThisFailureFatal and not isAttr:
        raise UserError(
            member.iface.name + "." + member.name + ": " "Unwrapping this failure must be fatal for methods"
        )

    # Function prolog.

    # Only template functions can have additional arguments.
    if customMethodCall is None or not "additionalArguments" in customMethodCall:
        additionalArguments = ""
    else:
        additionalArguments = " %s," % customMethodCall["additionalArguments"]
    if disableOptimizationForMSVC:
        setOptimizationForMSVC(f, False)
    f.write(signature % (stubName, additionalArguments))
    f.write("{\n")
    f.write("    XPC_QS_ASSERT_CONTEXT_OK(cx);\n")

    # Compute "args".
    f.write("    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);\n")
    f.write("    (void) args;\n")

    # Compute "this".
    f.write("    JS::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));\n" "    if (!obj)\n" "        return false;\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")
    pthisval = "JS::MutableHandleValue::fromMarkedLocation(&vp[1])"  # as above, ok to overwrite vp[1]

    if unwrapThisFailureFatal:
        unwrapFatalArg = "true"
    else:
        unwrapFatalArg = "false"

    f.write("    if (!xpc_qsUnwrapThis(cx, obj, &self, " "&selfref.ptr, %s, %s))\n" % (pthisval, unwrapFatalArg))
    f.write("        return false;\n")

    if not unwrapThisFailureFatal:
        f.write("      if (!self) {\n")
        if isGetter:
            f.write("        args.rval().setNull();\n")
        f.write("        return true;\n")
        f.write("    }\n")

    if isMethod:
        # If there are any required arguments, check argc.
        requiredArgs = len(member.params)
        while requiredArgs and member.params[requiredArgs - 1].optional:
            requiredArgs -= 1
    elif isSetter:
        requiredArgs = 1
    else:
        requiredArgs = 0
    if requiredArgs:
        f.write("    if (argc < %d)\n" % requiredArgs)
        f.write("        return xpc_qsThrow(cx, " "NS_ERROR_XPC_NOT_ENOUGH_ARGS);\n")

    # Convert in-parameters.
    rvdeclared = False
    if isMethod:
        for i, param in enumerate(member.params):
            argName = "arg%d" % i
            argTypeKey = argName + "Type"
            if customMethodCall is None or not argTypeKey in customMethodCall:
                validateParam(member, param)
                realtype = param.realtype
            else:
                realtype = xpidl.Forward(name=customMethodCall[argTypeKey], location="", doccomments="")
            # Emit code to convert this argument from jsval.
            rvdeclared = writeArgumentUnboxing(
                f,
                i,
                argName,
                realtype,
                optional=param.optional,
                rvdeclared=rvdeclared,
                nullBehavior=param.null,
                undefinedBehavior=param.undefined,
            )
    elif isSetter:
        rvdeclared = writeArgumentUnboxing(
            f,
            None,
            "arg0",
            member.realtype,
            optional=False,
            rvdeclared=rvdeclared,
            nullBehavior=member.null,
            undefinedBehavior=member.undefined,
            propIndex=stringtable.stringIndex(member.name),
        )

    canFail = customMethodCall is None or customMethodCall.get("canFail", True)
    if canFail and not rvdeclared:
        f.write("    nsresult rv;\n")
        rvdeclared = True

    if code is not None:
        f.write("%s\n" % code)

    if code is None or (isGetter and callTemplate is ""):
        debugGetter = code is not None
        if debugGetter:
            f.write("#ifdef DEBUG\n")
            f.write("    nsresult debug_rv;\n")
            f.write(
                "    nsCOMPtr<%s> debug_self;\n"
                "    CallQueryInterface(self, getter_AddRefs(debug_self));\n" % member.iface.name
            )
            prefix = "debug_"
        else:
            prefix = ""

        resultname = prefix + "result"
        selfname = prefix + "self"
        nsresultname = prefix + "rv"

        # Prepare out-parameter.
        if isMethod or isGetter:
            writeResultDecl(f, member.realtype, resultname)

        # Call the method.
        if isMethod:
            comName = header.methodNativeName(member)
            argv = ["arg" + str(i) for i, p in enumerate(member.params)]
            if member.implicit_jscontext:
                argv.append("cx")
            if member.optional_argc:
                argv.append("std::min<uint32_t>(argc, %d) - %d" % (len(member.params), requiredArgs))
            if not isVoidType(member.realtype):
                argv.append(outParamForm(resultname, member.realtype))
            args = ", ".join(argv)
        else:
            comName = header.attributeNativeName(member, isGetter)
            if isGetter:
                args = outParamForm(resultname, member.realtype)
            else:
                args = "arg0"
            if member.implicit_jscontext:
                args = "cx, " + args

        f.write("    ")
        if canFail or debugGetter:
            f.write("%s = " % nsresultname)
        f.write("%s->%s(%s);\n" % (selfname, comName, args))

        if debugGetter:
            checkSuccess = "NS_SUCCEEDED(debug_rv)"
            if canFail:
                checkSuccess += " == NS_SUCCEEDED(rv)"
            f.write(
                "    MOZ_ASSERT(%s && "
                "xpc_qsSameResult(debug_result, result),\n"
                '               "Got the wrong answer from the custom '
                'method call!");\n' % checkSuccess
            )
            f.write("#endif\n")

    if canFail:
        # Check for errors.
        f.write("    if (NS_FAILED(rv))\n")
        if isMethod:
            f.write("        return xpc_qsThrowMethodFailed(" "cx, rv, vp);\n")
        else:
            f.write(
                "        return xpc_qsThrowGetterSetterFailed(cx, rv, "
                + "JSVAL_TO_OBJECT(vp[1]), (uint16_t)%d);\n" % stringtable.stringIndex(member.name)
            )

    # Convert the return value.
    if isMethod or isGetter:
        writeResultConv(f, member.realtype, "args.rval()", "*vp")
    else:
        f.write("    return true;\n")

    # Epilog.
    f.write("}\n")
    if disableOptimizationForMSVC:
        setOptimizationForMSVC(f, True)
    f.write("\n")

    # Now write out the call to the template function.
    if customMethodCall is not None:
        f.write(callTemplate)
Beispiel #4
0
def writeStub(f,
              customMethodCalls,
              member,
              stubName,
              writeThisUnwrapping,
              writeCheckForFailure,
              writeResultWrapping,
              isSetter=False):
    """ Write a single quick stub (a custom SpiderMonkey getter/setter/method)
    for the specified XPCOM interface-member. 
    """
    if member.kind == 'method' and member.forward:
        member = member.iface.namemap[member.forward]

    isAttr = (member.kind == 'attribute')
    isMethod = (member.kind == 'method')
    assert isAttr or isMethod
    isNotxpcom = isMethod and member.notxpcom
    isGetter = isAttr and not isSetter

    signature = "static JSBool\n"
    if isAttr:
        # JSPropertyOp signature.
        if isSetter:
            signature += "%s(JSContext *cx, JSObject *obj, jsid id, JSBool strict,%s jsval *vp)\n"
        else:
            signature += "%s(JSContext *cx, JSObject *obj, jsid id,%s jsval *vp)\n"
    else:
        # JSFastNative.
        signature += "%s(JSContext *cx, uintN argc,%s jsval *vp)\n"

    customMethodCall = customMethodCalls.get(stubName, None)

    if customMethodCall is None:
        customMethodCall = customMethodCalls.get(member.iface.name + '_', None)
        if customMethodCall is not None:
            if isMethod:
                code = customMethodCall.get('code', None)
            elif isGetter:
                code = customMethodCall.get('getter_code', None)
            else:
                code = customMethodCall.get('setter_code', None)
        else:
            code = None

        if code is not None:
            templateName = member.iface.name
            if isGetter:
                templateName += '_Get'
            elif isSetter:
                templateName += '_Set'

            # Generate the code for the stub, calling the template function
            # that's shared between the stubs. The stubs can't have additional
            # arguments, only the template function can.
            callTemplate = signature % (stubName, '')
            callTemplate += "{\n"

            argumentValues = (customMethodCall['additionalArgumentValues'] %
                              header.methodNativeName(member))
            if isAttr:
                callTemplate += ("    return %s(cx, obj, id%s, %s, vp);\n" %
                                 (templateName, ", strict" if isSetter else "",
                                  argumentValues))
            else:
                callTemplate += ("    return %s(cx, argc, %s, vp);\n" %
                                 (templateName, argumentValues))
            callTemplate += "}\n\n"

            # Fall through and create the template function stub called from the
            # real stubs, but only generate the stub once. Otherwise, just write
            # out the call to the template function and return.
            templateGenerated = templateName + '_generated'
            if templateGenerated in customMethodCall:
                f.write(callTemplate)
                return
            customMethodCall[templateGenerated] = True

            stubName = templateName
        else:
            callTemplate = ""
    else:
        callTemplate = ""
        code = customMethodCall.get('code', None)

    # Function prolog.

    # Only template functions can have additional arguments.
    if customMethodCall is None or not 'additionalArguments' in customMethodCall:
        additionalArguments = ''
    else:
        additionalArguments = " %s," % customMethodCall['additionalArguments']
    f.write(signature % (stubName, additionalArguments))
    f.write("{\n")
    f.write("    XPC_QS_ASSERT_CONTEXT_OK(cx);\n")

    # For methods, compute "this".
    if isMethod:
        f.write("    JSObject *obj = JS_THIS_OBJECT(cx, vp);\n"
                "    if (!obj)\n"
                "        return JS_FALSE;\n")

    # Create ccx if needed.
    haveCcx = memberNeedsCcx(member)
    if haveCcx:
        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")

    selfname = writeThisUnwrapping(f, member, isMethod, isGetter,
                                   customMethodCall, haveCcx)

    rvdeclared = False
    if isMethod:
        inArgs = argumentsLength(member)
        # If there are any required arguments, check argc.
        requiredArgs = inArgs
        while requiredArgs and member.params[requiredArgs - 1].optional:
            requiredArgs -= 1
        if requiredArgs:
            f.write("    if (argc < %d)\n" % requiredArgs)
            f.write("        return xpc_qsThrow(cx, "
                    "NS_ERROR_XPC_NOT_ENOUGH_ARGS);\n")

        # Convert in-parameters.
        if inArgs > 0:
            f.write("    jsval *argv = JS_ARGV(cx, vp);\n")
        for i in range(inArgs):
            param = member.params[i]
            argName = 'arg%d' % i
            argTypeKey = argName + 'Type'
            if customMethodCall is None or not argTypeKey in customMethodCall:
                validateParam(member, param)
                realtype = param.realtype
            else:
                realtype = xpidl.Forward(name=customMethodCall[argTypeKey],
                                         location='',
                                         doccomments='')
            # Emit code to convert this argument from jsval.
            rvdeclared = writeArgumentUnboxing(
                f,
                i,
                argName,
                realtype,
                haveCcx=haveCcx,
                optional=param.optional,
                rvdeclared=rvdeclared,
                nullBehavior=param.null,
                undefinedBehavior=param.undefined)
        if inArgs < len(member.params):
            f.write("    nsWrapperCache *cache;\n")
    elif isSetter:
        rvdeclared = writeArgumentUnboxing(f,
                                           None,
                                           'arg0',
                                           member.realtype,
                                           haveCcx=False,
                                           optional=False,
                                           rvdeclared=rvdeclared,
                                           nullBehavior=member.null,
                                           undefinedBehavior=member.undefined)

    canFail = not isNotxpcom and (customMethodCall is None
                                  or customMethodCall.get('canFail', True))
    if canFail and not rvdeclared:
        f.write("    nsresult rv;\n")
        rvdeclared = True

    if code is not None:
        f.write("%s\n" % code)

    if code is None or (isGetter and callTemplate is ""):
        debugGetter = code is not None
        if debugGetter:
            f.write("#ifdef DEBUG\n")
            f.write("    nsresult debug_rv;\n")
            f.write(
                "    nsCOMPtr<%s> debug_self;\n"
                "    CallQueryInterface(self, getter_AddRefs(debug_self));\n" %
                member.iface.name)
            prefix = 'debug_'
        else:
            prefix = ''

        resultname = prefix + 'result'
        selfname = prefix + selfname
        nsresultname = prefix + 'rv'

        # Prepare out-parameter.
        if isMethod or isGetter:
            writeResultDecl(f, member, resultname)

        # Call the method.
        if isMethod:
            comName = header.methodNativeName(member)
            argv = ['arg' + str(i) for i in range(inArgs)]
            if inArgs < len(member.params):
                argv.append(
                    outParamForm('cache', member.params[inArgs].realtype))
            if member.implicit_jscontext:
                argv.append('cx')
            if member.optional_argc:
                argv.append('argc - %d' % requiredArgs)
            if not isNotxpcom and not isVoidType(member.realtype):
                argv.append(outParamForm(resultname, member.realtype))
            args = ', '.join(argv)
        else:
            comName = header.attributeNativeName(member, isGetter)
            if isGetter:
                args = outParamForm(resultname, member.realtype)
            else:
                args = "arg0"
            if member.implicit_jscontext:
                args = "cx, " + args

        f.write("    ")
        if canFail or debugGetter:
            f.write("%s = " % nsresultname)
        elif isNotxpcom:
            f.write("%s = " % resultname)
        f.write("%s->%s(%s);\n" % (selfname, comName, args))

        if debugGetter:
            checkSuccess = "NS_SUCCEEDED(debug_rv)"
            if canFail:
                checkSuccess += " == NS_SUCCEEDED(rv)"
            f.write("    NS_ASSERTION(%s && "
                    "xpc_qsSameResult(debug_result, result),\n"
                    "                 \"Got the wrong answer from the custom "
                    "method call!\");\n" % checkSuccess)
            f.write("#endif\n")

    if canFail:
        # Check for errors.
        writeCheckForFailure(f, isMethod, isGetter, haveCcx)

    # Convert the return value.
    if isMethod or isGetter:
        writeResultWrapping(f, member, 'vp', '*vp')
    else:
        f.write("    return JS_TRUE;\n")

    # Epilog.
    f.write("}\n\n")

    # Now write out the call to the template function.
    if customMethodCall is not None:
        f.write(callTemplate)