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

Side by Side Diff: third_party/chrome/ppapi/generators/idl_gen_wrapper.py

Issue 12300042: Update idlsync.py to pull in dependencies required for chrome api generation. (Closed) Base URL: git://github.com/dart-lang/bleeding_edge.git@master
Patch Set: From another checkout Created 7 years, 9 months 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
OLDNEW
(Empty)
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """Base class for generating wrapper functions for PPAPI methods.
6 """
7
8 from datetime import datetime
9 import os
10 import sys
11
12 from idl_c_proto import CGen
13 from idl_generator import Generator
14 from idl_log import ErrOut, InfoOut, WarnOut
15 from idl_option import GetOption
16 from idl_outfile import IDLOutFile
17
18
19 class PPKind(object):
20 @staticmethod
21 def ChoosePPFunc(iface, ppb_func, ppp_func):
22 name = iface.node.GetName()
23 if name.startswith("PPP"):
24 return ppp_func
25 elif name.startswith("PPB"):
26 return ppb_func
27 else:
28 raise Exception('Unknown PPKind for ' + name)
29
30
31 class Interface(object):
32 """Tracks information about a particular interface version.
33
34 - struct_name: the struct type used by the ppapi headers to hold the
35 method pointers (the vtable).
36 - needs_wrapping: True if a method in the interface needs wrapping.
37 - header_file: the name of the header file that defined this interface.
38 """
39 def __init__(self, interface_node, release, version,
40 struct_name, needs_wrapping, header_file):
41 self.node = interface_node
42 self.release = release
43 self.version = version
44 self.struct_name = struct_name
45 # We may want finer grained filtering (method level), but it is not
46 # yet clear how to actually do that.
47 self.needs_wrapping = needs_wrapping
48 self.header_file = header_file
49
50
51 class WrapperGen(Generator):
52 """WrapperGen - An abstract class that generates wrappers for PPAPI methods.
53
54 This generates a wrapper PPB and PPP GetInterface, which directs users
55 to wrapper PPAPI methods. Wrapper PPAPI methods may perform arbitrary
56 work before invoking the real PPAPI method (supplied by the original
57 GetInterface functions).
58
59 Subclasses must implement GenerateWrapperForPPBMethod (and PPP).
60 Optionally, subclasses can implement InterfaceNeedsWrapper to
61 filter out interfaces that do not actually need wrappers (those
62 interfaces can jump directly to the original interface functions).
63 """
64
65 def __init__(self, wrapper_prefix, s1, s2, s3):
66 Generator.__init__(self, s1, s2, s3)
67 self.wrapper_prefix = wrapper_prefix
68 self._skip_opt = False
69 self.output_file = None
70 self.cgen = CGen()
71
72 def SetOutputFile(self, fname):
73 self.output_file = fname
74
75
76 def GenerateRelease(self, ast, release, options):
77 return self.GenerateRange(ast, [release], options)
78
79
80 @staticmethod
81 def GetHeaderName(name):
82 """Get the corresponding ppapi .h file from each IDL filename.
83 """
84 name = os.path.splitext(name)[0] + '.h'
85 name = name.replace(os.sep, '/')
86 return 'ppapi/c/' + name
87
88
89 def WriteCopyright(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 /* NOTE: this is auto-generated from IDL */
97 """ % now.year
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 if GetOption('verbose'):
224 InfoOut.Log('WrapperGen: Skipping %s due to errors\n' %
225 filenode.GetName())
226 continue
227
228 file_name = self.GetHeaderName(filenode.GetName())
229 ifaces = filenode.GetListOf('Interface')
230 for iface in ifaces:
231 releases_for_iface = iface.GetUniqueReleases(releases)
232 for release in releases_for_iface:
233 version = iface.GetVersion(release)
234 struct_name = self.cgen.GetStructName(iface, release,
235 include_version=True)
236 needs_wrap = self.InterfaceVersionNeedsWrapping(iface, version)
237 if not needs_wrap:
238 if GetOption('verbose'):
239 InfoOut.Log('Interface %s ver %s does not need wrapping' %
240 (struct_name, version))
241 iface_releases.append(
242 Interface(iface, release, version,
243 struct_name, needs_wrap, file_name))
244 return iface_releases
245
246
247 def GenerateIncludes(self, iface_releases, out):
248 """Generate the list of #include that define the original interfaces.
249 """
250 self.WriteCopyright(out)
251 # First include own header.
252 out.Write('#include "%s"\n\n' % self.OwnHeaderFile())
253
254 # Get typedefs for PPB_GetInterface.
255 out.Write('#include "%s"\n' % self.GetHeaderName('ppb.h'))
256
257 # Get a conservative list of all #includes that are needed,
258 # whether it requires wrapping or not. We currently depend on the macro
259 # string for comparison, even when it is not wrapped, to decide when
260 # to use the original/real interface.
261 header_files = set()
262 for iface in iface_releases:
263 header_files.add(iface.header_file)
264 for header in sorted(header_files):
265 out.Write('#include "%s"\n' % header)
266 out.Write('\n')
267
268
269 def WrapperMethodPrefix(self, iface, release):
270 return '%s_%s_%s_' % (self.wrapper_prefix, release, iface.GetName())
271
272
273 def GetReturnArgs(self, ret_type, args_spec):
274 if ret_type != 'void':
275 ret = 'return '
276 else:
277 ret = ''
278 if args_spec:
279 args = []
280 for arg in args_spec:
281 args.append(arg[1])
282 args = ', '.join(args)
283 else:
284 args = ''
285 return (ret, args)
286
287
288 def GenerateWrapperForPPBMethod(self, iface, member):
289 result = []
290 func_prefix = self.WrapperMethodPrefix(iface.node, iface.release)
291 sig = self.cgen.GetSignature(member, iface.release, 'store',
292 func_prefix, False)
293 result.append('static %s {\n' % sig)
294 result.append(' while(1) { /* Not implemented */ } \n')
295 result.append('}\n')
296 return result
297
298
299 def GenerateWrapperForPPPMethod(self, iface, member):
300 result = []
301 func_prefix = self.WrapperMethodPrefix(iface.node, iface.release)
302 sig = self.cgen.GetSignature(member, iface.release, 'store',
303 func_prefix, False)
304 result.append('static %s {\n' % sig)
305 result.append(' while(1) { /* Not implemented */ } \n')
306 result.append('}\n')
307 return result
308
309
310 def GenerateWrapperForMethods(self, iface_releases, comments=True):
311 """Return a string representing the code for each wrapper method
312 (using a string rather than writing to the file directly for testing.)
313 """
314 result = []
315 for iface in iface_releases:
316 if not iface.needs_wrapping:
317 if comments:
318 result.append('/* Not generating wrapper methods for %s */\n\n' %
319 iface.struct_name)
320 continue
321 if comments:
322 result.append('/* Begin wrapper methods for %s */\n\n' %
323 iface.struct_name)
324 generator = PPKind.ChoosePPFunc(iface,
325 self.GenerateWrapperForPPBMethod,
326 self.GenerateWrapperForPPPMethod)
327 for member in iface.node.GetListOf('Member'):
328 # Skip the method if it's not actually in the release.
329 if not member.InReleases([iface.release]):
330 continue
331 result.extend(generator(iface, member))
332 if comments:
333 result.append('/* End wrapper methods for %s */\n\n' %
334 iface.struct_name)
335 return ''.join(result)
336
337
338 def GenerateWrapperInterfaces(self, iface_releases, out):
339 for iface in iface_releases:
340 if not iface.needs_wrapping:
341 out.Write('/* Not generating wrapper interface for %s */\n\n' %
342 iface.struct_name)
343 continue
344
345 out.Write('struct %s %s_Wrappers_%s = {\n' % (iface.struct_name,
346 self.wrapper_prefix,
347 iface.struct_name))
348 methods = []
349 for member in iface.node.GetListOf('Member'):
350 # Skip the method if it's not actually in the release.
351 if not member.InReleases([iface.release]):
352 continue
353 prefix = self.WrapperMethodPrefix(iface.node, iface.release)
354 cast = self.cgen.GetSignature(member, iface.release, 'return',
355 prefix='',
356 func_as_ptr=True,
357 ptr_prefix='',
358 include_name=False)
359 methods.append(' .%s = (%s)&%s%s' % (member.GetName(),
360 cast,
361 prefix,
362 member.GetName()))
363 out.Write(' ' + ',\n '.join(methods) + '\n')
364 out.Write('};\n\n')
365
366
367 def GetWrapperInfoName(self, iface):
368 return '%s_WrapperInfo_%s' % (self.wrapper_prefix, iface.struct_name)
369
370
371 def GenerateWrapperInfoAndCollection(self, iface_releases, out):
372 for iface in iface_releases:
373 iface_macro = self.cgen.GetInterfaceMacro(iface.node, iface.version)
374 if iface.needs_wrapping:
375 wrap_iface = '(void *) &%s_Wrappers_%s' % (self.wrapper_prefix,
376 iface.struct_name)
377 else:
378 wrap_iface = 'NULL /* Still need slot for real_iface */'
379 out.Write("""static struct %s %s = {
380 .iface_macro = %s,
381 .wrapped_iface = %s,
382 .real_iface = NULL
383 };\n\n""" % (self.GetWrapperMetadataName(),
384 self.GetWrapperInfoName(iface),
385 iface_macro,
386 wrap_iface))
387
388 # Now generate NULL terminated arrays of the above wrapper infos.
389 ppb_wrapper_infos = []
390 ppp_wrapper_infos = []
391 for iface in iface_releases:
392 appender = PPKind.ChoosePPFunc(iface,
393 ppb_wrapper_infos.append,
394 ppp_wrapper_infos.append)
395 appender(' &%s' % self.GetWrapperInfoName(iface))
396 ppb_wrapper_infos.append(' NULL')
397 ppp_wrapper_infos.append(' NULL')
398 out.Write(
399 'static struct %s *s_ppb_wrappers[] = {\n%s\n};\n\n' %
400 (self.GetWrapperMetadataName(), ',\n'.join(ppb_wrapper_infos)))
401 out.Write(
402 'static struct %s *s_ppp_wrappers[] = {\n%s\n};\n\n' %
403 (self.GetWrapperMetadataName(), ',\n'.join(ppp_wrapper_infos)))
404
405
406 def DeclareWrapperInfos(self, iface_releases, out):
407 """The wrapper methods usually need access to the real_iface, so we must
408 declare these wrapper infos ahead of time (there is a circular dependency).
409 """
410 out.Write('/* BEGIN Declarations for all Wrapper Infos */\n\n')
411 for iface in iface_releases:
412 out.Write('static struct %s %s;\n' %
413 (self.GetWrapperMetadataName(), self.GetWrapperInfoName(iface)))
414 out.Write('/* END Declarations for all Wrapper Infos. */\n\n')
415
416
417 def GenerateRange(self, ast, releases, options):
418 """Generate shim code for a range of releases.
419 """
420
421 # Remember to set the output filename before running this.
422 out_filename = self.output_file
423 if out_filename is None:
424 ErrOut.Log('Did not set filename for writing out wrapper\n')
425 return 1
426
427 InfoOut.Log("Generating %s for %s" % (out_filename, self.wrapper_prefix))
428
429 out = IDLOutFile(out_filename)
430
431 # Get a list of all the interfaces along with metadata.
432 iface_releases = self.DetermineInterfaces(ast, releases)
433
434 # Generate the includes.
435 self.GenerateIncludes(iface_releases, out)
436
437 out.Write(self.GetGuardStart())
438
439 # Write out static helper functions (mystrcmp).
440 self.GenerateHelperFunctions(out)
441
442 # Declare list of WrapperInfo before actual wrapper methods, since
443 # they reference each other.
444 self.DeclareWrapperInfos(iface_releases, out)
445
446 # Generate wrapper functions for each wrapped method in the interfaces.
447 result = self.GenerateWrapperForMethods(iface_releases)
448 out.Write(result)
449
450 # Collect all the wrapper functions into interface structs.
451 self.GenerateWrapperInterfaces(iface_releases, out)
452
453 # Generate a table of the wrapped interface structs that can be looked up.
454 self.GenerateWrapperInfoAndCollection(iface_releases, out)
455
456 # Write out the IDL-invariant functions.
457 self.GenerateFixedFunctions(out)
458
459 out.Write(self.GetGuardEnd())
460 out.Close()
461 return 0
OLDNEW
« no previous file with comments | « third_party/chrome/ppapi/generators/idl_gen_pnacl.py ('k') | third_party/chrome/ppapi/generators/idl_generator.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698