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