Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(715)

Side by Side Diff: ppapi/generators/idl_gen_pnacl.py

Issue 8568025: Pnacl ppapi shim generator (from IDL), based on Noel's first cut. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 #!/usr/bin/python
2 #
3 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6
7 """ Generator for Pnacl Shim functions that bridge the calling conventions
8 between GCC and PNaCl. """
9
10 from datetime import datetime
11 import os
12 import sys
13
14 from idl_log import ErrOut, InfoOut, WarnOut
15 from idl_ast import IDLAst
16 from idl_option import GetOption, Option, ParseOptions
17 from idl_outfile import IDLOutFile
18 from idl_c_proto import CGen
19 from idl_generator import Generator
20
21 Option('pnaclglue', 'Name of the pnacl glue file.',
sehr (please use chromium) 2011/11/16 00:44:01 We should use either 'glue' or 'shim' consistently
jvoung - send to chromium... 2011/11/16 01:45:22 Changed to shim.
22 default=os.path.join('..',
23 'native_client',
24 'src',
25 'shared',
26 'ppapi_proxy',
27 'pnacl_glue.c'))
28
29 # TODO(jvoung): this doesn't do anything yet (except change some dbg messages).
30 Option('disable_pnacl_opt', 'Turn off optimization of pnacl glue.')
31
32
33 class PPKind(object):
34 @staticmethod
35 def ChoosePPFunc(iface, ppb_func, ppp_func):
36 name = iface.GetName()
37 if name.startswith("PPP"):
38 return ppp_func
39 elif name.startswith("PPB"):
40 return ppb_func
41 else:
42 raise Exception('Unknown PPKind for ' + name)
43
44
45 class InterfaceVersion(object):
46 """ Tracks information about a particular interface version, including
47 the ID assigned to it in the PNaCl glue namespace. """
48 def __init__(self, interface_node, release, version, pnacl_id):
49 self.node = interface_node
50 self.release = release
51 self.version = version
52 self.pnacl_id = pnacl_id
53
54
55 class PnaclGen(Generator):
56 """PnaclGen - A subclass of Generator which takes the IDL sources and
57 generates glue code for bridging the calling conventions between GCC
58 and PNaCl (LLVM).
59 """
60
61 def __init__(self):
62 Generator.__init__(self,
63 'Pnacl Glue Gen',
64 'pnacl',
65 'Generate the PNaCl glue.')
66 self.cgen = CGen()
67 self._skip_opt = False
68 self._pnacl_attribute = ' __attribute__((pnaclcall)) '
69
70
71 def GenerateRelease(self, ast, release, options):
72 return self.GenerateRange(ast, [release], options)
73
74
75 @staticmethod
76 def GetHeaderName(name):
77 """ Get the corresponding ppapi .h file from each IDL filename. """
78 name = os.path.splitext(name)[0] + '.h'
79 return 'ppapi/c/' + name
80
81
82 def GenerateHeaderFile(self, out):
83 """ Writes out an interface header file for the exported symbols. """
84 out.Write("""
85 /* Copyright (c) 2011 The Chromium Authors. All rights reserved.
86 * Use of this source code is governed by a BSD-style license that can be
87 * found in the LICENSE file.
88 */
89
90 /* Last generated: %(timestamp)s. */
91
92 #ifndef %(include_guard)s
93 #define %(include_guard)s
94
95 typedef void *(*get_interface_fp)(const char *interface_name);
96
97 get_interface_fp real_PPBGetInterface;
98 get_interface_fp real_PPPGetInterface;
99
100 void set_real_PPBGetInterface(get_interface_fp real);
101 void set_real_PPPGetInterface(get_interface_fp real);
102
103 void *Pnacl_PPBGetInterface(const char *name);
104 void *Pnacl_PPPGetInterface(const char *name);
105
106 #endif /* %(include_guard)s */
107 """ % {
108 "include_guard" : "PNACL_GLUE_H_",
109 "timestamp" : datetime.ctime(datetime.now()),
110 })
111
112
113 def GenerateFixedFunctions(self, out):
114 """ Write out the set of constant functions (do not depend on the
115 current Pepper IDL. """
116 out.Write("""
117
118 void set_real_PPBGetInterface(get_interface_fp real) {
119 real_PPBGetInterface = real;
120 }
121
122 void set_real_PPPGetInterface(get_interface_fp real) {
123 real_PPPGetInterface = real;
124 }
125
126 void *Pnacl_PPBGetInterface(const char *name) {
127 int id = PnaclGlueIfaceID(name);
128 if (id < 0) return NULL;
129
130 if (s_realPtrs[id] == NULL) {
131 void *iface = (*real_PPBGetInterface)(name);
132 if (NULL == iface) return NULL;
133 s_realPtrs[id] = iface;
134 }
135 return s_wrapPtrs[id];
136 }
137
138 void *Pnacl_PPPGetInterface(const char *name) {
139 int id = PnaclGlueIfaceID(name);
140 if (id < 0) return NULL;
141
142 if (s_realPtrs[id] == NULL) {
143 void *iface = (*real_PPPGetInterface)(name);
144 if (NULL == iface) return NULL;
145 s_realPtrs[id] = iface;
146 }
147 return s_wrapPtrs[id];
148 }
149 """)
150
151 def InterfaceNeedsWrapper(self, iface, releases):
152 """ Return true if the interface has ANY methods that need wrapping. """
153 if self._skip_opt:
154 return True
155 for release in iface.GetUniqueReleases(releases):
156 version = iface.GetVersion(release)
157 if self.InterfaceVersionNeedsWrapping(iface, version):
158 return True
159 return False
160
161
162 def InterfaceVersionNeedsWrapping(self, iface, version):
163 """ Return true if the interface+version has ANY methods that
164 need wrapping. """
165 if self._skip_opt:
166 return True
167 for member in iface.GetListOf('Member'):
168 release = member.GetRelease(version)
169 if self.MemberNeedsWrapping(member, release):
170 return True
171 return False
172
173 def MemberNeedsWrapping(self, member, release):
174 """ Return true if a particular member function at a particular
175 release needs wrapping. """
176 if self._skip_opt:
177 return True
178 ret, name, array, args_spec = self.cgen.GetComponents(member,
179 release,
180 'store')
181 return self.TypeNeedsWrapping(ret) or self.ArgsNeedWrapping(args_spec)
182
183
184 def ArgsNeedWrapping(self, args):
185 """ Return true if any parameter in the list needs wrapping. """
186 for arg in args:
187 if self.TypeNeedsWrapping(arg[0]):
188 return True
189 return False
190
191
192 def TypeNeedsWrapping(self, type_node):
193 """ Return true if a parameter type needs wrapping.
194 Currently, this is true for byval aggregates. """
195 return ((type_node.startswith('struct') or type_node.startswith('union'))
196 and not (type_node.find('*') != -1))
197
198
199 def GenerateIncludes(self, ast, releases, options, out):
200 """ Write out the includes and other headers and return a list
201 of the interface nodes that were ultimately included. """
202 out.Write('#include "pnacl_glue.h"\n\n')
203
204 # Get a conservative list of all the interfaces, as we are generating
205 # #includes for each.
206 # TODO(jvoung): Filter out interfaces that don't need wrapping.
207 # TODO(jvoung): Separate PPB and PPP interfaces to slightly shorten the
208 # big strcmp function.
209 wrapped_iface_list = []
210 skipped_iface_list = []
211 for filenode in ast.GetListOf('File'):
212 # If this file has errors, skip it
213 if filenode in self.skip_list: continue
214
215 name = self.GetHeaderName(filenode.GetName())
216 ifaces = filenode.GetListOf('Interface')
217 for iface in ifaces:
218 if not self.InterfaceNeedsWrapper(iface, releases):
219 print 'Interface %s does not need wrapping!' % iface.GetName()
220 skipped_iface_list.append(iface)
221 else:
222 print 'Interface %s does need wrapping!' % iface.GetName()
223
224 # TODO(jvoung): Don't #include if we didn't wrap any of the
225 # ifaces in the list / header file
226 if ifaces:
227 out.Write('#include "%s"\n' % name)
228 wrapped_iface_list.extend(ifaces)
229 return wrapped_iface_list, skipped_iface_list
230
231
232 def PnaclIdForInterfaceVersion(self, iface, version):
233 return 'PNACL_%s_%s' % (iface.GetName(), str(version).replace('.', '_'))
234
235
236 def EnumerateInterfaces(self, wrapped_iface_list, releases, out):
237 iface_releases = []
238 out.Write('\nenum PnaclId {\n')
239 for iface in wrapped_iface_list:
240 for release in iface.GetUniqueReleases(releases):
241 version = iface.GetVersion(release)
242 pnacl_id = self.PnaclIdForInterfaceVersion(iface, version)
243 iface_releases.append(
244 InterfaceVersion(iface, release, version, pnacl_id))
245 out.Write(' %s,\n' % pnacl_id)
246 out.Write(' PNACL_IFACE_COUNT\n')
247 out.Write('};\n\n')
248 out.Write('static void *s_realPtrs[PNACL_IFACE_COUNT];\n\n');
249
250 # Also create a function that maps interface name to ID. The ID will be
251 # used to look up the wrapped interface in a table
252 # (so really it's string -> interface, but there is an ID in the middle).
253 out.Write('/* Map interface string -> pnacl ID */\n')
254 out.Write('static enum PnaclId PnaclGlueIfaceID(const char *name) {\n')
255 for iface in iface_releases:
256 out.Write(' if (!strcmp(name, %s)) return %s;\n' %
257 (self.cgen.GetInterfaceMacro(
258 iface.node, iface.version), iface.pnacl_id))
259 out.Write(' return -1;\n}\n\n')
260 return iface_releases
261
262
263 def WrapperMethodPrefix(self, iface, release):
264 return 'PNACL_%s_%s_' % (release, iface.GetName())
265
266 def GetReturnArgs(self, ret_type, args_spec):
267 if ret_type != 'void':
268 ret = 'return '
269 else:
270 ret = ''
271 if args_spec:
272 args = []
273 for arg in args_spec:
274 args.append(arg[1])
275 args = ', '.join(args)
276 else:
277 args = ''
278 return (ret, args)
279
280 def GenerateWrapperForPPBMethods(self, iface, is_latest_release, out):
281 struct_name = self.cgen.GetStructName(iface.node,
282 iface.release,
283 is_latest_release=is_latest_release)
284 for member in iface.node.GetListOf('Member'):
285 # Skip the method if it's not actually in the release.
286 if not member.InReleases([iface.release]):
287 continue
288 func_prefix = self.WrapperMethodPrefix(iface.node, iface.release)
289 sig = self.cgen.GetSignature(member, iface.release, 'store',
290 func_prefix, False)
291 out.Write('static %s %s {\n' % (self._pnacl_attribute, sig))
292 out.Write(' struct %s *iface = s_realPtrs[%s];\n' % (
293 struct_name, iface.pnacl_id))
294 ret, name, array, cspec = self.cgen.GetComponents(member,
295 iface.release,
296 'store')
297 ret_str, args_str = self.GetReturnArgs(ret, cspec)
298 out.Write(' %siface->%s(%s);\n}\n\n' % (ret_str,
299 member.GetName(), args_str))
300
301
302 def GenerateWrapperForPPPMethods(self, iface, is_latest_release, out):
303 struct_name = self.cgen.GetStructName(iface.node,
304 iface.release,
305 is_latest_release=is_latest_release)
306 for member in iface.node.GetListOf('Member'):
307 # Skip the method if it's not actually in the release.
308 if not member.InReleases([iface.release]):
309 continue
310 func_prefix = self.WrapperMethodPrefix(iface.node, iface.release)
311 sig = self.cgen.GetSignature(member, iface.release, 'store',
312 func_prefix, False)
313 out.Write('static %s {\n' % sig)
314 out.Write(' struct %s *iface = s_realPtrs[%s];\n' % (
315 struct_name, iface.pnacl_id))
316 temp_fp = self.cgen.GetSignature(member, iface.release, 'return',
317 'temp_fp',
318 func_attributes=self._pnacl_attribute,
319 func_as_ptr=True)
320 cast = self.cgen.GetSignature(member, iface.release, 'return',
321 prefix='',
322 func_attributes=self._pnacl_attribute,
323 func_as_ptr=True,
324 is_cast=True)
325 out.Write(' %s = ((%s)iface->%s);\n' % (temp_fp,
326 cast,
327 member.GetName()))
328 ret, name, array, cspec = self.cgen.GetComponents(member,
329 iface.release,
330 'store')
331 ret_str, args_str = self.GetReturnArgs(ret, cspec)
332 out.Write(' %stemp_fp%s(%s);\n}\n\n' % (ret_str,
333 member.GetName(),
334 args_str))
335
336
337 def GenerateWrapperForMethods(self, iface_releases, releases, out):
338 for iface in iface_releases:
339 is_latest_release = (iface.release ==
340 iface.node.GetUniqueReleases(releases)[-1])
341 generator = PPKind.ChoosePPFunc(iface.node,
342 self.GenerateWrapperForPPBMethods,
343 self.GenerateWrapperForPPPMethods)
344 generator(iface, is_latest_release, out)
345
346
347 def GenerateWrapperInterfaces(self, iface_releases, releases, out):
348 for iface in iface_releases:
349 is_latest_release = (iface.release ==
350 iface.node.GetUniqueReleases(releases)[-1])
351 struct_name = self.cgen.GetStructName(iface.node,
352 iface.release,
353 is_latest_release=is_latest_release)
354 out.Write('struct %s PNACL_Wrappers_%s = {\n' % (struct_name,
355 struct_name))
356 methods = []
357 for member in iface.node.GetListOf('Member'):
358 # Skip the method if it's not actually in the release.
359 if not member.InReleases([iface.release]):
360 continue
361 prefix = self.WrapperMethodPrefix(iface.node, iface.release)
362 cast = self.cgen.GetSignature(member, iface.release, 'return',
363 prefix='',
364 func_attributes='',
365 func_as_ptr=True,
366 is_cast=True)
367 methods.append(' .%s = (%s)&%s%s' % (member.GetName(),
368 cast,
369 prefix,
370 member.GetName()))
371 out.Write(' ' + ',\n '.join(methods) + '\n')
372 out.Write('};\n\n')
373
374 # Write out a collection of the pnacl wrapper functions.
375 out.Write('static void *s_wrapPtrs[PNACL_IFACE_COUNT + 1] = {\n')
376 for iface in iface_releases:
377 is_latest_release = (iface.release ==
378 iface.node.GetUniqueReleases(releases)[-1])
379 struct_name = self.cgen.GetStructName(iface.node,
380 iface.release,
381 is_latest_release=is_latest_release)
382 out.Write(' (void *) &PNACL_Wrappers_%s,\n' % struct_name)
383 out.Write(' NULL\n};\n\n')
384
385
386 def GenerateRange(self, ast, releases, options):
387 """ Generate glue code for a range of releases. """
388
389 self._skip_opt = GetOption('disable_pnacl_opt')
390
391 out_filename = GetOption('pnaclglue')
392 out_header_filename = os.path.splitext(out_filename)[0] + '.h'
393 print "Generating %s and %s" % (out_filename, out_header_filename)
394
395 out_header = IDLOutFile(out_header_filename)
396 self.GenerateHeaderFile(out_header)
397 out_header.Close()
398
399 out = IDLOutFile(out_filename)
400
401 # Generate the includes.
402 wrapped_iface_list, skipped_iface_list = \
403 self.GenerateIncludes(ast, releases, options, out)
404
405 # Generate a list of interfaces and assign each an ID number which
406 # is listed in an ENUM.
407 iface_releases = self.EnumerateInterfaces(wrapped_iface_list, releases, out)
408
409 # Generate wrapper functions for each wrapped method in the interfaces.
410 self.GenerateWrapperForMethods(iface_releases, releases, out)
411
412 # Collect all the wrapper functions into interface structs. Then generate
413 # a table of the wrapped interface structs that can be looked up.
414 self.GenerateWrapperInterfaces(iface_releases, releases, out)
415
416 # Write out the IDL-invariant functions.
417 self.GenerateFixedFunctions(out)
418 out.Close()
419 return 0
420
421
422 pnaclgen = PnaclGen()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698