OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 import os.path |
| 7 import string |
| 8 import sys |
| 9 |
| 10 import interface |
| 11 |
| 12 class CodeWriter(object): |
| 13 def __init__(self): |
| 14 self.lines = [] |
| 15 self.margin = "" |
| 16 self.margin_stack = [] |
| 17 |
| 18 def __lshift__(self, line): |
| 19 self.lines.append((self.margin + line).rstrip()) |
| 20 |
| 21 def pushMargin(self): |
| 22 self.margin_stack.append(self.margin) |
| 23 self.margin += " " |
| 24 |
| 25 def popMargin(self): |
| 26 self.margin = self.margin_stack.pop() |
| 27 |
| 28 def getValue(self): |
| 29 return "\n".join(self.lines).rstrip() + "\n" |
| 30 |
| 31 class Indent(object): |
| 32 def __init__(self, writer): |
| 33 self.writer = writer |
| 34 |
| 35 def __enter__(self): |
| 36 self.writer.pushMargin() |
| 37 |
| 38 def __exit__(self, type, value, traceback): |
| 39 self.writer.popMargin() |
| 40 |
| 41 def templateFile(name): |
| 42 return os.path.join(os.path.dirname(__file__), name) |
| 43 |
| 44 def wrap(pre, items, post): |
| 45 complete = pre + ", ".join(items) + post |
| 46 if len(complete) <= 80: |
| 47 return [complete] |
| 48 lines = [pre] |
| 49 indent = " " |
| 50 for i, item in enumerate(items): |
| 51 if i < len(items) - 1: |
| 52 lines.append(indent + item + ",") |
| 53 else: |
| 54 lines.append(indent + item + post) |
| 55 return lines |
| 56 |
| 57 def iovDecl(param): |
| 58 if param.isPassedByValue(): |
| 59 return "{&%s, sizeof(%s)}" % (param.name, param.name) |
| 60 elif param.isArray: |
| 61 sp = param.getSizeParam() |
| 62 if sp.isPassedByValue(): |
| 63 size = sp.name |
| 64 else: |
| 65 # TODO volatile read? |
| 66 size = "(*%s)" % sp.name |
| 67 if param.baseType == "void": |
| 68 return "{(void*)%s, %s}" % (param.name, size) |
| 69 else: |
| 70 return "{(void*)%s, sizeof(*%s)*%s}" % (param.name, param.name, size) |
| 71 else: |
| 72 return "{(void*)%s, sizeof(*%s)}" % (param.name, param.name) |
| 73 |
| 74 def loadTemplate(filename): |
| 75 data = open(templateFile(filename)).read() |
| 76 template = string.Template(data) |
| 77 return template |
| 78 |
| 79 def generateLibMojo(functions, out): |
| 80 template = loadTemplate("libmojo.cc.template") |
| 81 |
| 82 code = CodeWriter() |
| 83 |
| 84 for f in functions: |
| 85 for line in wrap("%s %s(" % (f.returnType, f.name), f.paramList(), "){"): |
| 86 code << line |
| 87 numParams = len(f.params) + 2 |
| 88 |
| 89 with Indent(code): |
| 90 code << "uint32_t params[%d];" % numParams |
| 91 if f.returnType == "MojoResult": |
| 92 default = "MOJO_RESULT_INVALID_ARGUMENT" |
| 93 elif f.returnType == "MojoTimeTicks": |
| 94 default = "0" |
| 95 else: |
| 96 raise Exception("Unhandled return type: " + f.returnType) |
| 97 code << "%s result = %s;" % (f.returnType, default); |
| 98 |
| 99 # Message ID |
| 100 code << "params[0] = %d;" % f.uid |
| 101 # Parameter pointers |
| 102 castTemplate = "params[%d] = reinterpret_cast<uint32_t>(%s);" |
| 103 for p in f.params: |
| 104 ptr = p.name |
| 105 if p.isPassedByValue(): |
| 106 ptr = "&" + ptr |
| 107 code << castTemplate % (p.uid + 1, ptr) |
| 108 # Return value pointer |
| 109 code << castTemplate % (numParams - 1, "&result") |
| 110 |
| 111 code << "DoMojoCall(params, sizeof(params));"; |
| 112 code << "return result;" |
| 113 |
| 114 code << "}" |
| 115 code << "" |
| 116 |
| 117 body = code.getValue() |
| 118 |
| 119 |
| 120 text = template.substitute( |
| 121 script_name=os.path.basename(__file__), |
| 122 body=body) |
| 123 |
| 124 print >>out, text |
| 125 |
| 126 def paramPtr(param): |
| 127 ptr = param.paramType |
| 128 if param.isPassedByValue(): |
| 129 ptr += " volatile*" |
| 130 return ptr |
| 131 |
| 132 def generateMojoSyscall(functions, out): |
| 133 template = loadTemplate("mojo_syscall.cc.template") |
| 134 |
| 135 code = CodeWriter() |
| 136 code.pushMargin() |
| 137 |
| 138 for f in functions: |
| 139 code << "case %d:" % f.uid |
| 140 |
| 141 code.pushMargin() |
| 142 |
| 143 code << "{" |
| 144 |
| 145 with Indent(code): |
| 146 numParams = len(f.params) + 2 |
| 147 code << "if (numParams != %d) {" % numParams |
| 148 with Indent(code): |
| 149 code << "return -1;" |
| 150 code << "}" |
| 151 |
| 152 def scalarNull(param): |
| 153 code << "%s_ptr = NULL;" % (param.name) |
| 154 if param.isInput: |
| 155 if param.isScalar(): |
| 156 # TODO can we alway zero scalar values? |
| 157 code << "%s = 0;" % (param.name) |
| 158 |
| 159 def scalarFinalize(param, src): |
| 160 if param.isOutput: |
| 161 # For outputs, we need to retain the pointer for later. |
| 162 code << "%s_ptr = reinterpret_cast<%s>(%s);" % (param.name, paramPtr(p
aram), src) |
| 163 if param.isInput: |
| 164 code << "// In/Out" |
| 165 code << "%s = *%s_ptr;" % (param.name, param.name) |
| 166 else: |
| 167 # For pure inputs, no need to retain the pointer |
| 168 code << "%s = *reinterpret_cast<%s>(%s);" % (param.name, paramPtr(para
m), src) |
| 169 |
| 170 def convertParam(param): |
| 171 if param.isScalar(): |
| 172 code << "uintptr_t temp = NaClUserToSysAddrRange(nap, params[%d], size
of(%s));" % (param.uid + 1, param.name) |
| 173 elif param.isArray: |
| 174 if param.baseType == "void": |
| 175 code << "uintptr_t temp = NaClUserToSysAddrRange(nap, params[%d], %s
);" % (param.uid + 1, param.size) |
| 176 else: |
| 177 code << "uintptr_t temp = NaClUserToSysAddrArray(nap, params[%d], %s
, sizeof(*%s));" % (param.uid + 1, param.size, param.name) |
| 178 else: |
| 179 code << "uintptr_t temp = NaClUserToSysAddrRange(nap, params[%d], size
of(*%s));" % (param.uid + 1, param.name) |
| 180 |
| 181 code << "if (temp == kNaClBadAddress) {" |
| 182 with Indent(code): |
| 183 code << "return -1;" |
| 184 code << "}" |
| 185 if param.isScalar(): |
| 186 scalarFinalize(param, 'temp') |
| 187 else: |
| 188 code << "%s = reinterpret_cast<%s>(%s);" % (param.name, param.paramTyp
e, 'temp') |
| 189 |
| 190 def convertPtr(param): |
| 191 if param.isScalar(): |
| 192 if param.isOutput: |
| 193 code << "%s %s_ptr;" % (paramPtr(param), param.name) |
| 194 code << "%s %s;" % (param.baseType, param.name) |
| 195 else: |
| 196 code << "%s %s;" % (param.paramType, param.name) |
| 197 |
| 198 code << "if (params[%d] == 0) {" % (param.uid + 1) |
| 199 with Indent(code): |
| 200 if param.isOptional: |
| 201 if param.isScalar(): |
| 202 scalarNull(param) |
| 203 else: |
| 204 code << "%s = NULL;" % (param.name) |
| 205 else: |
| 206 code << "return -1;" |
| 207 code << "} else {" |
| 208 with Indent(code): |
| 209 convertParam(param) |
| 210 code << "}" |
| 211 |
| 212 # Convert and validate pointers in two passes. |
| 213 # Arrays cannot be validated util the size parameter has been converted. |
| 214 code << "NaClCopyTakeLock(nap);" |
| 215 for param in f.params: |
| 216 if not param.isArray: |
| 217 convertPtr(param) |
| 218 for param in f.params: |
| 219 if param.isArray: |
| 220 convertPtr(param) |
| 221 convertPtr(f.resultParam) |
| 222 code << "NaClCopyDropLock(nap);" |
| 223 code << "" |
| 224 |
| 225 # Call |
| 226 getParams = [] |
| 227 for param in f.params: |
| 228 if param.isScalar() and not param.isPassedByValue(): |
| 229 if param.isOptional: |
| 230 getParams.append("%s_ptr ? &%s : NULL" % (param.name, param.name)) |
| 231 else: |
| 232 getParams.append("&%s" % (param.name)) |
| 233 else: |
| 234 getParams.append(param.name) |
| 235 |
| 236 code << "result = %s(%s);" % (f.name, ", ".join(getParams)) |
| 237 code << "" |
| 238 |
| 239 def copyOut(param): |
| 240 if param.isScalar(): |
| 241 if param.isOutput: |
| 242 if param.isOptional: |
| 243 code << "if (%s_ptr != NULL) {" % (param.name) |
| 244 with Indent(code): |
| 245 code << "*%s_ptr = %s;" % (param.name, param.name) |
| 246 code << "}" |
| 247 else: |
| 248 code << "*%s_ptr = %s;" % (param.name, param.name) |
| 249 |
| 250 # Write outputs |
| 251 code << "NaClCopyTakeLock(nap);" |
| 252 for param in f.params: |
| 253 copyOut(param) |
| 254 copyOut(f.resultParam) |
| 255 code << "NaClCopyDropLock(nap);" |
| 256 code << "" |
| 257 |
| 258 code << "return 0;" |
| 259 code << "}" |
| 260 |
| 261 code.popMargin() |
| 262 |
| 263 body = code.getValue() |
| 264 |
| 265 text = template.substitute( |
| 266 script_name=os.path.basename(__file__), |
| 267 body=body) |
| 268 |
| 269 print >>out, text |
| 270 |
| 271 def main(): |
| 272 outdir = os.path.dirname(os.path.dirname(__file__)) |
| 273 |
| 274 mojo = interface.makeInterface() |
| 275 generateLibMojo(mojo.functions, open(os.path.join(outdir, "libmojo.cc"), "w")) |
| 276 generateMojoSyscall(mojo.functions, open(os.path.join(outdir, "mojo_syscall.cc
"), "w")) |
| 277 |
| 278 if __name__ == "__main__": |
| 279 main() |
OLD | NEW |