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..6157e50287d0f2489f2fc4dca63a8c7a5c543938 |
--- /dev/null |
+++ b/mojo/monacl/gen/generate_monacl_bindings.py |
@@ -0,0 +1,284 @@ |
+#!/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 |
+ code << f.returnType + " result;" |
+ |
+ # 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") |
+ |
+ iovLength = 1 |
+ code << "NaClAbiNaClImcMsgIoVec iov[%d] = {" % iovLength |
+ with Indent(code): |
+ code << "{params, sizeof(params)}" |
+ code << "};" |
+ |
+ code << "NaClAbiNaClImcMsgHdr msgh = {iov, %d, NULL, 0};" % iovLength |
+ code << "if (imc_sendmsg(NACL_MOJO_DESC, &msgh, 0) < 0) {" |
+ with Indent(code): |
+ code << "result = MOJO_RESULT_INVALID_ARGUMENT;" |
+ code << "}" |
+ |
+ 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) |
Mark Seaborn
2014/07/21 16:31:39
Lines >80 chars (and elsewhere too)
Nick Bray (chromium)
2014/07/21 22:38:36
This file needs to be cleaned up before commit, as
|
+ 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() |