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

Side by Side Diff: ppapi/generators/idl_gen_wrapper.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: Fix presubmit.wq Created 9 years 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 """ Base class for generating wrapper functions for PPAPI methods. """
8
9 from datetime import datetime
10 import os
11 import sys
12
13 from idl_ast import IDLAst
14 from idl_c_proto import CGen
15 from idl_generator import Generator
16 from idl_log import ErrOut, InfoOut, WarnOut
17 from idl_option import Option
18 from idl_outfile import IDLOutFile
19
20
21 class PPKind(object):
22 @staticmethod
23 def ChoosePPFunc(iface, ppb_func, ppp_func):
24 name = iface.node.GetName()
25 if name.startswith("PPP"):
26 return ppp_func
27 elif name.startswith("PPB"):
28 return ppb_func
29 else:
30 raise Exception('Unknown PPKind for ' + name)
31
32
33 class Interface(object):
34 """ Tracks information about a particular interface version
35 - struct_name: the struct type used by the ppapi headers to hold the
36 method pointers (the vtable).
37 - needs_wrapping: True if there is a method in the interface that needs
38 shimming
39 - header_file: the name of the header file that defined this interface
40 """
41 def __init__(self, interface_node, release, version,
42 struct_name, needs_wrapping, header_file):
43 self.node = interface_node
44 self.release = release
45 self.version = version
46 self.struct_name = struct_name
47 # We may want finer grained filtering (method level), but it is not
48 # yet clear how to actually do that.
49 self.needs_wrapping = needs_wrapping
50 self.header_file = header_file
51
52
53 class WrapperGen(Generator):
54 """WrapperGen - A subclass of Generator which takes the IDL sources and
noelallen1 2011/11/23 18:06:11 """One Line Multi Line """
55 generates wrapper code for each method and allows redirecting the
56 the GetInterface functions to these new wrappers.
57 """
58
59 def __init__(self, wrapper_prefix, s1, s2, s3):
60 Generator.__init__(self, s1, s2, s3)
61 self.wrapper_prefix = wrapper_prefix
62 self._skip_opt = False
63 self.output_file = None
64 self.cgen = CGen()
65
66 def SetOutputFile(self, fname):
67 self.output_file = fname
68
69
70 def GenerateRelease(self, ast, release, options):
71 return self.GenerateRange(ast, [release], options)
72
73
74 @staticmethod
75 def GetHeaderName(name):
76 """ Get the corresponding ppapi .h file from each IDL filename. """
77 name = os.path.splitext(name)[0] + '.h'
78 return 'ppapi/c/' + name
79
80
81 def WriteCopyrightGeneratedTime(self, out):
82 now = datetime.now()
83 c = """/* Copyright (c) %s The Chromium Authors. All rights reserved.
84 * Use of this source code is governed by a BSD-style license that can be
85 * found in the LICENSE file.
86 */
87
88 /* Last generated from IDL: %s. */
89 """ % (now.year, datetime.ctime(now))
90 out.Write(c)
91
92 def GetWrapperMetadataName(self):
93 return '__%sWrapperInfo' % self.wrapper_prefix
94
95
96 def GetHeaderGuard(self, header_filename):
97 g = header_filename.upper().replace(os.path.sep, '_').replace('.','_') + '_'
98 return g
99
100 def GenerateHeaderFile(self, header_filename, out):
101 """ Writes out an interface header file for the exported symbols. """
102 self.WriteCopyrightGeneratedTime(out)
103 include_guard = self.GetHeaderGuard(header_filename)
104 out.Write("""
105 #ifndef %(include_guard)s
106 #define %(include_guard)s
107
108 #include "ppapi/c/ppb.h"
109
110 /* There is not a typedef for PPP_GetInterface_type, but it is currently
111 * the same as PPB_GetInterface. */
112 typedef PPB_GetInterface PPP_GetInterface_type;
113
114 void __set_real_%(wrapper_prefix)s_PPBGetInterface(PPB_GetInterface real);
115 void __set_real_%(wrapper_prefix)s_PPPGetInterface(PPP_GetInterface_type real);
116
117 const void *__%(wrapper_prefix)s_PPBGetInterface(const char *name);
118 const void *__%(wrapper_prefix)s_PPPGetInterface(const char *name);
119
120 struct %(wrapper_struct)s {
121 const char* iface_macro;
122 const void* wrapped_iface; /* If NULL then it was not wrapped! */
123 const void* real_iface;
124 };
125
126 #endif /* %(include_guard)s */
127 """ % {
128 'include_guard' : include_guard,
129 'timestamp' : datetime.ctime(datetime.now()),
130 'wrapper_prefix' : self.wrapper_prefix,
131 'wrapper_struct' : self.GetWrapperMetadataName(),
132 })
133
134
135 def GenerateHelperFunctions(self, out):
136 """ Write helper functions to avoid dependencies on libc. """
137 out.Write("""/* Use local strcmp to avoid dependency on libc. */
138 static int mystrcmp(const char* s1, const char *s2) {
139 while((*s1 && *s2) && (*s1++ == *s2++));
140 return *(--s1) - *(--s2);
141 }\n
142 """)
143
144
145 def GenerateFixedFunctions(self, out):
146 """ Write out the set of constant functions (those that do not depend on
147 the current Pepper IDL). """
148 out.Write("""
149
150 static PPB_GetInterface __real_PPBGetInterface;
151 static PPP_GetInterface_type __real_PPPGetInterface;
152
153 void __set_real_%(wrapper_prefix)s_PPBGetInterface(PPB_GetInterface real) {
154 __real_PPBGetInterface = real;
155 }
156
157 void __set_real_%(wrapper_prefix)s_PPPGetInterface(PPP_GetInterface_type real) {
158 __real_PPPGetInterface = real;
159 }
160
161 /* Map interface string -> wrapper metadata */
162 static struct %(wrapper_struct)s *%(wrapper_prefix)sPPBShimIface(
163 const char *name) {
164 struct %(wrapper_struct)s **next = s_ppb_wrappers;
165 while (*next != NULL) {
166 if (mystrcmp(name, (*next)->iface_macro) == 0) return *next;
167 ++next;
168 }
169 return NULL;
170 }
171
172 /* Map interface string -> wrapper metadata */
173 static struct %(wrapper_struct)s *%(wrapper_prefix)sPPPShimIface(
174 const char *name) {
175 struct %(wrapper_struct)s **next = s_ppp_wrappers;
176 while (*next != NULL) {
177 if (mystrcmp(name, (*next)->iface_macro) == 0) return *next;
178 ++next;
179 }
180 return NULL;
181 }
182
183 const void *__%(wrapper_prefix)s_PPBGetInterface(const char *name) {
184 struct %(wrapper_struct)s *wrapper = %(wrapper_prefix)sPPBShimIface(name);
185 if (wrapper == NULL) {
186 /* We don't have an IDL for this, for some reason. Take our chances. */
187 return (*__real_PPBGetInterface)(name);
188 }
189
190 /* Initialize the real_iface if it hasn't been. The wrapper depends on it. */
191 if (wrapper->real_iface == NULL) {
192 const void *iface = (*__real_PPBGetInterface)(name);
193 if (NULL == iface) return NULL;
194 wrapper->real_iface = iface;
195 }
196
197 if (wrapper->wrapped_iface) {
198 return wrapper->wrapped_iface;
199 } else {
200 return wrapper->real_iface;
201 }
202 }
203
204 const void *__%(wrapper_prefix)s_PPPGetInterface(const char *name) {
205 struct %(wrapper_struct)s *wrapper = %(wrapper_prefix)sPPPShimIface(name);
206 if (wrapper == NULL) {
207 /* We don't have an IDL for this, for some reason. Take our chances. */
208 return (*__real_PPPGetInterface)(name);
209 }
210
211 /* Initialize the real_iface if it hasn't been. The wrapper depends on it. */
212 if (wrapper->real_iface == NULL) {
213 const void *iface = (*__real_PPPGetInterface)(name);
214 if (NULL == iface) return NULL;
215 wrapper->real_iface = iface;
216 }
217
218 if (wrapper->wrapped_iface) {
219 return wrapper->wrapped_iface;
220 } else {
221 return wrapper->real_iface;
222 }
223 }
224 """ % { 'wrapper_struct' : self.GetWrapperMetadataName(),
225 'wrapper_prefix' : self.wrapper_prefix,
226 } )
227
228
229 ############################################################
230
231 def InterfaceNeedsWrapper(self, iface, releases):
232 """ Return true if the interface has ANY methods that need wrapping. """
233 return True
234
235
236 ############################################################
237
238 def DetermineInterfaces(self, ast, releases):
239 """ Get a list of interfaces along with whatever metadata we need. """
240 iface_releases = []
241 for filenode in ast.GetListOf('File'):
242 # If this file has errors, skip it
243 if filenode in self.skip_list:
244 InfoOut.Log('WrapperGen: Skipping %s due to errors\n' %
245 filenode.GetName())
246 continue
247
248 file_name = self.GetHeaderName(filenode.GetName())
249 ifaces = filenode.GetListOf('Interface')
250 for iface in ifaces:
251 releases_for_iface = iface.GetUniqueReleases(releases)
252 for release in releases_for_iface:
253 version = iface.GetVersion(release)
254 not_latest = release != releases_for_iface[-1]
255 struct_name = self.cgen.GetStructName(iface, release,
256 include_version=not_latest)
257 needs_wrap = self.InterfaceVersionNeedsWrapping(iface, version)
258 if not needs_wrap:
259 InfoOut.Log('Interface %s ver %s does not need wrapping' %
260 (struct_name, version))
261 iface_releases.append(
262 Interface(iface, release, version,
263 struct_name, needs_wrap, file_name))
264 return iface_releases
265
266
267 def GenerateIncludes(self, iface_releases, out_header_filename, out):
268 """ Write out the includes and other headers and return a list
269 of the interface nodes that were ultimately included. """
270 self.WriteCopyrightGeneratedTime(out)
271 # First include own header.
272 out.Write('#include "%s"\n\n' % out_header_filename)
273
274 # Get typedefs for PPB_GetInterface.
275 out.Write('#include "%s"\n' % self.GetHeaderName('ppb.h'))
276
277 # Get a conservative list of all #includes that are needed,
278 # whether it requires wrapping or not. We currently depend on the macro
279 # string for comparison, even when it is not wrapped, to decide when
280 # to use the original/real interface.
281 header_files = set()
282 for iface in iface_releases:
283 header_files.add(iface.header_file)
284 for header in sorted(header_files):
285 out.Write('#include "%s"\n' % header)
286 out.Write('\n')
287
288
289 def WrapperMethodPrefix(self, iface, release):
290 return '%s_%s_%s_' % (self.wrapper_prefix, release, iface.GetName())
291
292
293 def GetReturnArgs(self, ret_type, args_spec):
294 if ret_type != 'void':
295 ret = 'return '
296 else:
297 ret = ''
298 if args_spec:
299 args = []
300 for arg in args_spec:
301 args.append(arg[1])
302 args = ', '.join(args)
303 else:
304 args = ''
305 return (ret, args)
306
307
308 def GenerateWrapperForPPBMethod(self, iface, member):
309 result = []
310 func_prefix = self.WrapperMethodPrefix(iface.node, iface.release)
311 sig = self.cgen.GetSignature(member, iface.release, 'store',
312 func_prefix, False)
313 result.append('static %s {\n' % sig)
314 result.append(' while(1) { /* Not implemented */ } \n')
315 result.append('}\n')
316 return result
317
318
319 def GenerateWrapperForPPPMethod(self, iface, member):
320 result = []
321 func_prefix = self.WrapperMethodPrefix(iface.node, iface.release)
322 sig = self.cgen.GetSignature(member, iface.release, 'store',
323 func_prefix, False)
324 result.append('static %s {\n' % sig)
325 result.append(' while(1) { /* Not implemented */ } \n')
326 result.append('}\n')
327 return result
328
329
330 def GenerateWrapperForMethods(self, iface_releases, comments=True):
331 """ Return a string representing the code for each wrapper method
332 (using a string rather than writing to the file directly for testing.) """
333 result = []
334 for iface in iface_releases:
335 if not iface.needs_wrapping:
336 if comments:
337 result.append('/* Not generating wrapper methods for %s */\n\n' %
338 iface.struct_name)
339 continue
340 if comments:
341 result.append('/* Begin wrapper methods for %s */\n\n' %
342 iface.struct_name)
343 generator = PPKind.ChoosePPFunc(iface,
344 self.GenerateWrapperForPPBMethod,
345 self.GenerateWrapperForPPPMethod)
346 for member in iface.node.GetListOf('Member'):
347 # Skip the method if it's not actually in the release.
348 if not member.InReleases([iface.release]):
349 continue
350 result.extend(generator(iface, member))
351 if comments:
352 result.append('/* End wrapper methods for %s */\n\n' %
353 iface.struct_name)
354 return ''.join(result)
355
356
357 def GenerateWrapperInterfaces(self, iface_releases, out):
358 for iface in iface_releases:
359 if not iface.needs_wrapping:
360 out.Write('/* Not generating wrapper interface for %s */\n\n' %
361 iface.struct_name)
362 continue
363
364 out.Write('struct %s %s_Wrappers_%s = {\n' % (iface.struct_name,
365 self.wrapper_prefix,
366 iface.struct_name))
367 methods = []
368 for member in iface.node.GetListOf('Member'):
369 # Skip the method if it's not actually in the release.
370 if not member.InReleases([iface.release]):
371 continue
372 prefix = self.WrapperMethodPrefix(iface.node, iface.release)
373 cast = self.cgen.GetSignature(member, iface.release, 'return',
374 prefix='',
375 func_as_ptr=True,
376 ptr_prefix='',
377 include_name=False)
378 methods.append(' .%s = (%s)&%s%s' % (member.GetName(),
379 cast,
380 prefix,
381 member.GetName()))
382 out.Write(' ' + ',\n '.join(methods) + '\n')
383 out.Write('};\n\n')
384
385
386 def GetWrapperInfoName(self, iface):
387 return '%s_WrapperInfo_%s' % (self.wrapper_prefix, iface.struct_name)
388
389
390 def GenerateWrapperInfoAndCollection(self, iface_releases, out):
391 for iface in iface_releases:
392 iface_macro = self.cgen.GetInterfaceMacro(iface.node, iface.version)
393 if iface.needs_wrapping:
394 wrap_iface = '(void *) &%s_Wrappers_%s' % (self.wrapper_prefix,
395 iface.struct_name)
396 else:
397 wrap_iface = 'NULL /* Still need slot for real_iface */'
398 out.Write("""static struct %s %s = {
399 .iface_macro = %s,
400 .wrapped_iface = %s,
401 .real_iface = NULL
402 };\n\n""" % (self.GetWrapperMetadataName(),
403 self.GetWrapperInfoName(iface),
404 iface_macro,
405 wrap_iface))
406
407 # Now generate NULL terminated arrays of the above wrapper infos.
408 ppb_wrapper_infos = []
409 ppp_wrapper_infos = []
410 for iface in iface_releases:
411 appender = PPKind.ChoosePPFunc(iface,
412 ppb_wrapper_infos.append,
413 ppp_wrapper_infos.append)
414 appender(' &%s' % self.GetWrapperInfoName(iface))
415 ppb_wrapper_infos.append(' NULL')
416 ppp_wrapper_infos.append(' NULL')
417 out.Write(
418 'static struct %s *s_ppb_wrappers[] = {\n%s\n};\n\n' %
419 (self.GetWrapperMetadataName(), ',\n'.join(ppb_wrapper_infos)))
420 out.Write(
421 'static struct %s *s_ppp_wrappers[] = {\n%s\n};\n\n' %
422 (self.GetWrapperMetadataName(), ',\n'.join(ppp_wrapper_infos)))
423
424
425 def DeclareWrapperInfos(self, iface_releases, out):
426 """ The wrapper methods usually need access to the real_iface, so we must
427 declare these wrapper infos ahead of time (there is a circular dependency).
428 """
429 out.Write('/* BEGIN Declarations for all Wrapper Infos */\n\n')
430 for iface in iface_releases:
431 out.Write('static struct %s %s;\n' %
432 (self.GetWrapperMetadataName(), self.GetWrapperInfoName(iface)))
433 out.Write('/* END Declarations for all Wrapper Infos. */\n\n')
434
435
436 def GenerateRange(self, ast, releases, options):
437 """ Generate shim code for a range of releases. """
438
439 # Remember to set the output filename before running this.
440 out_filename = self.output_file
441 if out_filename is None:
442 ErrOut.Log('Did not set filename for writing out wrapper\n')
443 return 1
444
445 out_header_filename = os.path.splitext(out_filename)[0] + '.h'
446 InfoOut.Log("Generating %s and %s for %s" %
447 (out_filename, out_header_filename, self.wrapper_prefix))
448
449 out_header = IDLOutFile(out_header_filename)
450 self.GenerateHeaderFile(out_header_filename, out_header)
451 out_header.Close()
452
453 out = IDLOutFile(out_filename)
454
455 # Get a list of all the interfaces along with metadata.
456 iface_releases = self.DetermineInterfaces(ast, releases)
457
458 # Generate the includes.
459 self.GenerateIncludes(iface_releases, out_header_filename, out)
460
461 # Write out static helper functions (mystrcmp).
462 self.GenerateHelperFunctions(out)
463
464 # Declare list of WrapperInfo before actual wrapper methods, since
465 # they reference each other.
466 self.DeclareWrapperInfos(iface_releases, out)
467
468 # Generate wrapper functions for each wrapped method in the interfaces.
469 result = self.GenerateWrapperForMethods(iface_releases)
470 out.Write(result)
471
472 # Collect all the wrapper functions into interface structs.
473 self.GenerateWrapperInterfaces(iface_releases, out)
474
475 # Generate a table of the wrapped interface structs that can be looked up.
476 self.GenerateWrapperInfoAndCollection(iface_releases, out)
477
478 # Write out the IDL-invariant functions.
479 self.GenerateFixedFunctions(out)
480 out.Close()
481 return 0
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698