| Index: mojo/monacl/gen/generate_monacl_bindings.py
|
| diff --git a/mojo/monacl/gen/generate_monacl_bindings.py b/mojo/monacl/gen/generate_monacl_bindings.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..c60e986c3cba9a046dcf8a41baf86a6a84300f8b
|
| --- /dev/null
|
| +++ b/mojo/monacl/gen/generate_monacl_bindings.py
|
| @@ -0,0 +1,279 @@
|
| +#!/usr/bin/python
|
| +# Copyright 2014 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +import os.path
|
| +import string
|
| +import sys
|
| +
|
| +import interface
|
| +
|
| +class CodeWriter(object):
|
| + def __init__(self):
|
| + self.lines = []
|
| + self.margin = ""
|
| + self.margin_stack = []
|
| +
|
| + def __lshift__(self, line):
|
| + self.lines.append((self.margin + line).rstrip())
|
| +
|
| + def pushMargin(self):
|
| + self.margin_stack.append(self.margin)
|
| + self.margin += " "
|
| +
|
| + def popMargin(self):
|
| + self.margin = self.margin_stack.pop()
|
| +
|
| + def getValue(self):
|
| + return "\n".join(self.lines).rstrip() + "\n"
|
| +
|
| +class Indent(object):
|
| + def __init__(self, writer):
|
| + self.writer = writer
|
| +
|
| + def __enter__(self):
|
| + self.writer.pushMargin()
|
| +
|
| + def __exit__(self, type, value, traceback):
|
| + self.writer.popMargin()
|
| +
|
| +def templateFile(name):
|
| + return os.path.join(os.path.dirname(__file__), name)
|
| +
|
| +def wrap(pre, items, post):
|
| + complete = pre + ", ".join(items) + post
|
| + if len(complete) <= 80:
|
| + return [complete]
|
| + lines = [pre]
|
| + indent = " "
|
| + for i, item in enumerate(items):
|
| + if i < len(items) - 1:
|
| + lines.append(indent + item + ",")
|
| + else:
|
| + lines.append(indent + item + post)
|
| + return lines
|
| +
|
| +def iovDecl(param):
|
| + if param.isPassedByValue():
|
| + return "{&%s, sizeof(%s)}" % (param.name, param.name)
|
| + elif param.isArray:
|
| + sp = param.getSizeParam()
|
| + if sp.isPassedByValue():
|
| + size = sp.name
|
| + else:
|
| + # TODO volatile read?
|
| + size = "(*%s)" % sp.name
|
| + if param.baseType == "void":
|
| + return "{(void*)%s, %s}" % (param.name, size)
|
| + else:
|
| + return "{(void*)%s, sizeof(*%s)*%s}" % (param.name, param.name, size)
|
| + else:
|
| + return "{(void*)%s, sizeof(*%s)}" % (param.name, param.name)
|
| +
|
| +def loadTemplate(filename):
|
| + data = open(templateFile(filename)).read()
|
| + template = string.Template(data)
|
| + return template
|
| +
|
| +def generateLibMojo(functions, out):
|
| + template = loadTemplate("libmojo.cc.template")
|
| +
|
| + code = CodeWriter()
|
| +
|
| + for f in functions:
|
| + for line in wrap("%s %s(" % (f.returnType, f.name), f.paramList(), "){"):
|
| + code << line
|
| + numParams = len(f.params) + 2
|
| +
|
| + with Indent(code):
|
| + code << "uint32_t params[%d];" % numParams
|
| + if f.returnType == "MojoResult":
|
| + default = "MOJO_RESULT_INVALID_ARGUMENT"
|
| + elif f.returnType == "MojoTimeTicks":
|
| + default = "0"
|
| + else:
|
| + raise Exception("Unhandled return type: " + f.returnType)
|
| + code << "%s result = %s;" % (f.returnType, default);
|
| +
|
| + # Message ID
|
| + code << "params[0] = %d;" % f.uid
|
| + # Parameter pointers
|
| + castTemplate = "params[%d] = reinterpret_cast<uint32_t>(%s);"
|
| + for p in f.params:
|
| + ptr = p.name
|
| + if p.isPassedByValue():
|
| + ptr = "&" + ptr
|
| + code << castTemplate % (p.uid + 1, ptr)
|
| + # Return value pointer
|
| + code << castTemplate % (numParams - 1, "&result")
|
| +
|
| + code << "DoMojoCall(params, sizeof(params));";
|
| + code << "return result;"
|
| +
|
| + code << "}"
|
| + code << ""
|
| +
|
| + body = code.getValue()
|
| +
|
| +
|
| + text = template.substitute(
|
| + script_name=os.path.basename(__file__),
|
| + body=body)
|
| +
|
| + print >>out, text
|
| +
|
| +def paramPtr(param):
|
| + ptr = param.paramType
|
| + if param.isPassedByValue():
|
| + ptr += " volatile*"
|
| + return ptr
|
| +
|
| +def generateMojoSyscall(functions, out):
|
| + template = loadTemplate("mojo_syscall.cc.template")
|
| +
|
| + code = CodeWriter()
|
| + code.pushMargin()
|
| +
|
| + for f in functions:
|
| + code << "case %d:" % f.uid
|
| +
|
| + code.pushMargin()
|
| +
|
| + code << "{"
|
| +
|
| + with Indent(code):
|
| + numParams = len(f.params) + 2
|
| + code << "if (numParams != %d) {" % numParams
|
| + with Indent(code):
|
| + code << "return -1;"
|
| + code << "}"
|
| +
|
| + def scalarNull(param):
|
| + code << "%s_ptr = NULL;" % (param.name)
|
| + if param.isInput:
|
| + if param.isScalar():
|
| + # TODO can we alway zero scalar values?
|
| + code << "%s = 0;" % (param.name)
|
| +
|
| + def scalarFinalize(param, src):
|
| + if param.isOutput:
|
| + # For outputs, we need to retain the pointer for later.
|
| + code << "%s_ptr = reinterpret_cast<%s>(%s);" % (param.name, paramPtr(param), src)
|
| + if param.isInput:
|
| + code << "// In/Out"
|
| + code << "%s = *%s_ptr;" % (param.name, param.name)
|
| + else:
|
| + # For pure inputs, no need to retain the pointer
|
| + code << "%s = *reinterpret_cast<%s>(%s);" % (param.name, paramPtr(param), src)
|
| +
|
| + def convertParam(param):
|
| + if param.isScalar():
|
| + code << "uintptr_t temp = NaClUserToSysAddrRange(nap, params[%d], sizeof(%s));" % (param.uid + 1, param.name)
|
| + elif param.isArray:
|
| + if param.baseType == "void":
|
| + code << "uintptr_t temp = NaClUserToSysAddrRange(nap, params[%d], %s);" % (param.uid + 1, param.size)
|
| + else:
|
| + code << "uintptr_t temp = NaClUserToSysAddrArray(nap, params[%d], %s, sizeof(*%s));" % (param.uid + 1, param.size, param.name)
|
| + else:
|
| + code << "uintptr_t temp = NaClUserToSysAddrRange(nap, params[%d], sizeof(*%s));" % (param.uid + 1, param.name)
|
| +
|
| + code << "if (temp == kNaClBadAddress) {"
|
| + with Indent(code):
|
| + code << "return -1;"
|
| + code << "}"
|
| + if param.isScalar():
|
| + scalarFinalize(param, 'temp')
|
| + else:
|
| + code << "%s = reinterpret_cast<%s>(%s);" % (param.name, param.paramType, 'temp')
|
| +
|
| + def convertPtr(param):
|
| + if param.isScalar():
|
| + if param.isOutput:
|
| + code << "%s %s_ptr;" % (paramPtr(param), param.name)
|
| + code << "%s %s;" % (param.baseType, param.name)
|
| + else:
|
| + code << "%s %s;" % (param.paramType, param.name)
|
| +
|
| + code << "if (params[%d] == 0) {" % (param.uid + 1)
|
| + with Indent(code):
|
| + if param.isOptional:
|
| + if param.isScalar():
|
| + scalarNull(param)
|
| + else:
|
| + code << "%s = NULL;" % (param.name)
|
| + else:
|
| + code << "return -1;"
|
| + code << "} else {"
|
| + with Indent(code):
|
| + convertParam(param)
|
| + code << "}"
|
| +
|
| + # Convert and validate pointers in two passes.
|
| + # Arrays cannot be validated util the size parameter has been converted.
|
| + code << "NaClCopyTakeLock(nap);"
|
| + for param in f.params:
|
| + if not param.isArray:
|
| + convertPtr(param)
|
| + for param in f.params:
|
| + if param.isArray:
|
| + convertPtr(param)
|
| + convertPtr(f.resultParam)
|
| + code << "NaClCopyDropLock(nap);"
|
| + code << ""
|
| +
|
| + # Call
|
| + getParams = []
|
| + for param in f.params:
|
| + if param.isScalar() and not param.isPassedByValue():
|
| + if param.isOptional:
|
| + getParams.append("%s_ptr ? &%s : NULL" % (param.name, param.name))
|
| + else:
|
| + getParams.append("&%s" % (param.name))
|
| + else:
|
| + getParams.append(param.name)
|
| +
|
| + code << "result = %s(%s);" % (f.name, ", ".join(getParams))
|
| + code << ""
|
| +
|
| + def copyOut(param):
|
| + if param.isScalar():
|
| + if param.isOutput:
|
| + if param.isOptional:
|
| + code << "if (%s_ptr != NULL) {" % (param.name)
|
| + with Indent(code):
|
| + code << "*%s_ptr = %s;" % (param.name, param.name)
|
| + code << "}"
|
| + else:
|
| + code << "*%s_ptr = %s;" % (param.name, param.name)
|
| +
|
| + # Write outputs
|
| + code << "NaClCopyTakeLock(nap);"
|
| + for param in f.params:
|
| + copyOut(param)
|
| + copyOut(f.resultParam)
|
| + code << "NaClCopyDropLock(nap);"
|
| + code << ""
|
| +
|
| + code << "return 0;"
|
| + code << "}"
|
| +
|
| + code.popMargin()
|
| +
|
| + body = code.getValue()
|
| +
|
| + text = template.substitute(
|
| + script_name=os.path.basename(__file__),
|
| + body=body)
|
| +
|
| + print >>out, text
|
| +
|
| +def main():
|
| + outdir = os.path.dirname(os.path.dirname(__file__))
|
| +
|
| + mojo = interface.makeInterface()
|
| + generateLibMojo(mojo.functions, open(os.path.join(outdir, "libmojo.cc"), "w"))
|
| + generateMojoSyscall(mojo.functions, open(os.path.join(outdir, "mojo_syscall.cc"), "w"))
|
| +
|
| +if __name__ == "__main__":
|
| + main()
|
|
|