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

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

Powered by Google App Engine
This is Rietveld 408576698