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

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

Powered by Google App Engine
This is Rietveld 408576698