From d70b01fd7791d5eeb28df8a7ffd6527896d25dc4 Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Thu, 10 Mar 2022 22:44:29 +0000 Subject: [PATCH] Bug 1683281 - Part 6-1: Create CGHelperFunctionGenerator and refactor into more generic base class; r=peterv So we could reuse it to generate helper function for observable array type Depends on D112280 Differential Revision: https://phabricator.services.mozilla.com/D113728 --- dom/bindings/Codegen.py | 186 +++++++++++++++++++++------------------- 1 file changed, 100 insertions(+), 86 deletions(-) diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 69773bc3ec89..fb18ea50fc48 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -21501,7 +21501,7 @@ class CGMaplikeOrSetlikeMethodGenerator(CGThing): def appendBoolResult(self): if self.helperImpl: - return ([CGGeneric()], ["&aRetVal"], []) + return ([CGGeneric("bool retVal;\n")], ["&retVal"], []) return ([CGGeneric("bool result;\n")], ["&result"], []) def forEach(self): @@ -21578,7 +21578,7 @@ class CGMaplikeOrSetlikeMethodGenerator(CGThing): code = [] # We don't need to create the result variable because it'll be created elsewhere # for JSObject Get method - if not self.helperImpl or not self.helperImpl.handleJSObjectGetHelper(): + if not self.helperImpl or not self.helperImpl.needsScopeBody(): code = [ CGGeneric( dedent( @@ -21647,19 +21647,20 @@ class CGMaplikeOrSetlikeMethodGenerator(CGThing): return self.cgRoot.define() -class CGMaplikeOrSetlikeHelperFunctionGenerator(CallbackMember): +class CGHelperFunctionGenerator(CallbackMember): """ - Generates code to allow C++ to perform operations on backing objects. Gets - a context from the binding wrapper, turns arguments into JS::Values (via + Generates code to allow C++ to perform operations. Gets a context from the + binding wrapper, turns arguments into JS::Values (via CallbackMember/CGNativeMember argument conversion), then uses - CGMaplikeOrSetlikeMethodGenerator to generate the body. - + getCall to generate the body for getting result, and maybe convert the + result into return type (via CallbackMember/CGNativeMember result + conversion) """ class HelperFunction(CGAbstractMethod): """ Generates context retrieval code and rooted JSObject for interface for - CGMaplikeOrSetlikeMethodGenerator to use + method generator to use """ def __init__(self, descriptor, name, args, code, returnType): @@ -21672,31 +21673,14 @@ class CGMaplikeOrSetlikeHelperFunctionGenerator(CallbackMember): def __init__( self, descriptor, - maplikeOrSetlike, name, - needsKeyArg=False, - needsValueArg=False, - needsValueTypeReturn=False, - needsBoolReturn=False, + args, + returnType=BuiltinTypes[IDLBuiltinType.Types.void], + needsResultConversion=True, ): - assert not (needsValueTypeReturn and needsBoolReturn) - args = [] - self.maplikeOrSetlike = maplikeOrSetlike - self.needsBoolReturn = needsBoolReturn - self.needsValueTypeReturn = needsValueTypeReturn + assert returnType.isType() + self.needsResultConversion = needsResultConversion - returnType = ( - BuiltinTypes[IDLBuiltinType.Types.void] - if not self.needsValueTypeReturn - else maplikeOrSetlike.valueType - ) - - if needsKeyArg: - args.append(FakeArgument(maplikeOrSetlike.keyType, "aKey")) - if needsValueArg: - assert needsKeyArg - assert not needsValueTypeReturn - args.append(FakeArgument(maplikeOrSetlike.valueType, "aValue")) # Run CallbackMember init function to generate argument conversion code. # wrapScope is set to 'obj' when generating maplike or setlike helper # functions, as we don't have access to the CallbackPreserveColor @@ -21708,26 +21692,21 @@ class CGMaplikeOrSetlikeHelperFunctionGenerator(CallbackMember): descriptor, False, wrapScope="obj", - passJSBitsAsNeeded=self.handleJSObjectGetHelper(), + passJSBitsAsNeeded=typeNeedsCx(returnType), ) - if self.needsValueTypeReturn: - finalReturnType = self.returnType - elif needsBoolReturn: - finalReturnType = "bool" - else: - finalReturnType = "void" # Wrap CallbackMember body code into a CGAbstractMethod to make # generation easier. - self.implMethod = CGMaplikeOrSetlikeHelperFunctionGenerator.HelperFunction( - descriptor, name, self.args, self.body, finalReturnType + self.implMethod = CGHelperFunctionGenerator.HelperFunction( + descriptor, name, self.args, self.body, self.returnType ) def getCallSetup(self): - # If handleJSObjectGetHelper is true, it means the caller will provide a JSContext, - # so we don't need to create JSContext and enter UnprivilegedJunkScopeOrWorkerGlobal here. + # If passJSBitsAsNeeded is true, it means the caller will provide a + # JSContext, so we don't need to create JSContext and enter + # UnprivilegedJunkScopeOrWorkerGlobal here. code = "MOZ_ASSERT(self);\n" - if not self.handleJSObjectGetHelper(): + if not self.passJSBitsAsNeeded: code += dedent( """ AutoJSAPI jsapi; @@ -21761,21 +21740,12 @@ class CGMaplikeOrSetlikeHelperFunctionGenerator(CallbackMember): % self.getDefaultRetval() ) - # For the JSObject Get method, we'd like wrap the inner code in a scope such that - # the code can use the same realm. So here we are creating the result variable - # outside of the scope. - if self.handleJSObjectGetHelper(): - code += dedent( - """ - JS::Rooted result(cx); - """ - ) - else: - code += dedent( - """ - JSAutoRealm reflectorRealm(cx, obj); - """ - ) + # We'd like wrap the inner code in a scope such that the code can use the + # same realm. So here we are creating the result variable outside of the + # scope. + if self.needsScopeBody(): + code += "JS::Rooted result(cx);\n" + return code def getArgs(self, returnType, argList): @@ -21785,20 +21755,15 @@ class CGMaplikeOrSetlikeHelperFunctionGenerator(CallbackMember): return [Argument(self.descriptorProvider.nativeType + "*", "self")] + args def needsScopeBody(self): - return self.handleJSObjectGetHelper() + return self.passJSBitsAsNeeded def getArgvDeclFailureCode(self): return "aRv.Throw(NS_ERROR_UNEXPECTED);\n" - def handleJSObjectGetHelper(self): - return self.needsValueTypeReturn and self.maplikeOrSetlike.valueType.isObject() - def getResultConversion(self): - if self.needsBoolReturn: - return "return aRetVal;\n" - elif self.needsValueTypeReturn: + if self.needsResultConversion: code = "" - if self.handleJSObjectGetHelper(): + if self.needsScopeBody(): code = dedent( """ if (!JS_WrapValue(cx, &result)) { @@ -21811,7 +21776,7 @@ class CGMaplikeOrSetlikeHelperFunctionGenerator(CallbackMember): failureCode = dedent("aRv.Throw(NS_ERROR_UNEXPECTED);\nreturn nullptr;\n") exceptionCode = None - if self.maplikeOrSetlike.valueType.isPrimitive(): + if self.retvalType.isPrimitive(): exceptionCode = dedent( "aRv.NoteJSContextException(cx);\nreturn%s;\n" % self.getDefaultRetval() @@ -21824,34 +21789,26 @@ class CGMaplikeOrSetlikeHelperFunctionGenerator(CallbackMember): isDefinitelyObject=True, exceptionCode=exceptionCode, ) - return "return;\n" + + assignRetval = string.Template( + self.getRetvalInfo(self.retvalType, False)[2] + ).substitute( + { + "declName": "retVal", + } + ) + return assignRetval def getRvalDecl(self): - if self.needsBoolReturn: - return "bool aRetVal;\n" - elif self.handleJSObjectGetHelper(): - return "JSAutoRealm reflectorRealm(cx, obj);\n" - return "" + # hack to make sure we put JSAutoRealm inside the body scope + return "JSAutoRealm reflectorRealm(cx, obj);\n" def getArgcDecl(self): # Don't need argc for anything. return None - def getDefaultRetval(self): - if self.needsBoolReturn: - return " false" - elif self.needsValueTypeReturn: - return CallbackMember.getDefaultRetval(self) - return "" - def getCall(self): - return CGMaplikeOrSetlikeMethodGenerator( - self.descriptorProvider, - self.maplikeOrSetlike, - self.name.lower(), - self.needsValueTypeReturn, - helperImpl=self, - ).define() + assert False # Override me! def getPrettyName(self): return self.name @@ -21863,6 +21820,61 @@ class CGMaplikeOrSetlikeHelperFunctionGenerator(CallbackMember): return self.implMethod.define() +class CGMaplikeOrSetlikeHelperFunctionGenerator(CGHelperFunctionGenerator): + """ + Generates code to allow C++ to perform operations on backing objects. Gets + a context from the binding wrapper, turns arguments into JS::Values (via + CallbackMember/CGNativeMember argument conversion), then uses + CGMaplikeOrSetlikeMethodGenerator to generate the body. + """ + + def __init__( + self, + descriptor, + maplikeOrSetlike, + name, + needsKeyArg=False, + needsValueArg=False, + needsValueTypeReturn=False, + needsBoolReturn=False, + needsResultConversion=True, + ): + self.maplikeOrSetlike = maplikeOrSetlike + self.needsValueTypeReturn = needsValueTypeReturn + + args = [] + if needsKeyArg: + args.append(FakeArgument(maplikeOrSetlike.keyType, "aKey")) + if needsValueArg: + assert needsKeyArg + assert not needsValueTypeReturn + args.append(FakeArgument(maplikeOrSetlike.valueType, "aValue")) + + returnType = BuiltinTypes[IDLBuiltinType.Types.void] + if needsBoolReturn: + returnType = BuiltinTypes[IDLBuiltinType.Types.boolean] + elif needsValueTypeReturn: + returnType = maplikeOrSetlike.valueType + + CGHelperFunctionGenerator.__init__( + self, + descriptor, + name, + args, + returnType, + needsResultConversion, + ) + + def getCall(self): + return CGMaplikeOrSetlikeMethodGenerator( + self.descriptorProvider, + self.maplikeOrSetlike, + self.name.lower(), + self.needsValueTypeReturn, + helperImpl=self, + ).define() + + class CGMaplikeOrSetlikeHelperGenerator(CGNamespace): """ Declares and defines convenience methods for accessing backing objects on @@ -21889,6 +21901,7 @@ class CGMaplikeOrSetlikeHelperGenerator(CGNamespace): "Delete", needsKeyArg=True, needsBoolReturn=True, + needsResultConversion=False, ), CGMaplikeOrSetlikeHelperFunctionGenerator( descriptor, @@ -21896,6 +21909,7 @@ class CGMaplikeOrSetlikeHelperGenerator(CGNamespace): "Has", needsKeyArg=True, needsBoolReturn=True, + needsResultConversion=False, ), ] if self.maplikeOrSetlike.isMaplike():