Fix the no password save issue for ajax login
[chromium-blink-merge.git] / ppapi / generators / idl_gen_pnacl.py
blobbeb310f6ce208f013f4bf711b994df202dedd016
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Generator for Pnacl Shim functions that bridges the calling conventions
7 between GCC and PNaCl. """
9 from datetime import datetime
10 import difflib
11 import glob
12 import os
13 import sys
15 from idl_c_proto import CGen
16 from idl_gen_wrapper import Interface, WrapperGen
17 from idl_log import ErrOut, InfoOut, WarnOut
18 from idl_option import GetOption, Option, ParseOptions
19 from idl_parser import ParseFiles
21 Option('pnaclshim', 'Name of the pnacl shim file.',
22 default='temp_pnacl_shim.c')
24 Option('disable_pnacl_opt', 'Turn off optimization of pnacl shim.')
27 class PnaclGen(WrapperGen):
28 """PnaclGen generates shim code to bridge the Gcc ABI with PNaCl.
30 This subclass of WrapperGenerator takes the IDL sources and
31 generates shim methods for bridging the calling conventions between GCC
32 and PNaCl (LLVM). Some of the PPAPI methods do not need shimming, so
33 this will also detect those situations and provide direct access to the
34 original PPAPI methods (rather than the shim methods).
35 """
37 def __init__(self):
38 WrapperGen.__init__(self,
39 'Pnacl',
40 'Pnacl Shim Gen',
41 'pnacl',
42 'Generate the PNaCl shim.')
43 self.cgen = CGen()
44 self._skip_opt = False
45 self._pnacl_attribute = '__attribute__((pnaclcall))'
47 ############################################################
49 def OwnHeaderFile(self):
50 """Return the header file that specifies the API of this wrapper.
51 We do not generate the header files. """
52 return 'ppapi/generators/pnacl_shim.h'
54 def GetGuardStart(self):
55 return ('\n/* The PNaCl PPAPI shims are only needed on x86-64 and arm. */\n'
56 '#if defined(__x86_64__) || defined(__arm__)\n\n')
58 def GetGuardEnd(self):
59 return '\n#endif\n'
61 def InterfaceNeedsWrapper(self, iface, releases):
62 """Return true if the interface has ANY methods that need wrapping.
63 """
64 if self._skip_opt:
65 return True
66 for release in iface.GetUniqueReleases(releases):
67 version = iface.GetVersion(release)
68 if self.InterfaceVersionNeedsWrapping(iface, version):
69 return True
70 return False
73 def InterfaceVersionNeedsWrapping(self, iface, version):
74 """Return true if the interface+version has ANY methods that
75 need wrapping.
76 """
77 if self._skip_opt:
78 return True
79 for member in iface.GetListOf('Member'):
80 release = member.GetRelease(version)
81 if self.MemberNeedsWrapping(member, release):
82 return True
83 return False
86 def MemberNeedsWrapping(self, member, release):
87 """Return true if a particular member function at a particular
88 release needs wrapping.
89 """
90 if self._skip_opt:
91 return True
92 if not member.InReleases([release]):
93 return False
94 ret, name, array, args_spec = self.cgen.GetComponents(member,
95 release,
96 'store')
97 return self.TypeNeedsWrapping(ret, []) or self.ArgsNeedWrapping(args_spec)
100 def ArgsNeedWrapping(self, args):
101 """Return true if any parameter in the list needs wrapping.
103 for arg in args:
104 (type_str, name, array_dims, more_args) = arg
105 if self.TypeNeedsWrapping(type_str, array_dims):
106 return True
107 return False
110 def TypeNeedsWrapping(self, type_node, array_dims):
111 """Return true if a parameter type needs wrapping.
112 Currently, this is true for byval aggregates.
114 is_aggregate = type_node.startswith('struct') or \
115 type_node.startswith('union')
116 is_reference = (type_node.find('*') != -1 or array_dims != [])
117 return is_aggregate and not is_reference
119 ############################################################
122 def GenerateWrapperForPPBMethod(self, iface, member):
123 result = []
124 func_prefix = self.WrapperMethodPrefix(iface.node, iface.release)
125 sig = self.cgen.GetSignature(member, iface.release, 'store',
126 func_prefix, False)
127 result.append('static %s\n%s {\n' % (self._pnacl_attribute, sig))
128 result.append(' const struct %s *iface = %s.real_iface;\n' %
129 (iface.struct_name, self.GetWrapperInfoName(iface)))
130 ret, name, array, cspec = self.cgen.GetComponents(member,
131 iface.release,
132 'store')
133 ret_str, args_str = self.GetReturnArgs(ret, cspec)
134 result.append(' %siface->%s(%s);\n}\n\n' % (ret_str,
135 member.GetName(), args_str))
136 return result
139 def GenerateWrapperForPPPMethod(self, iface, member):
140 result = []
141 func_prefix = self.WrapperMethodPrefix(iface.node, iface.release)
142 sig = self.cgen.GetSignature(member, iface.release, 'store',
143 func_prefix, False)
144 result.append('static %s {\n' % sig)
145 result.append(' const struct %s *iface = %s.real_iface;\n' %
146 (iface.struct_name, self.GetWrapperInfoName(iface)))
147 temp_fp = self.cgen.GetSignature(member, iface.release, 'return',
148 'temp_fp',
149 func_as_ptr=True,
150 ptr_prefix=self._pnacl_attribute + ' ',
151 include_name=False)
152 cast = self.cgen.GetSignature(member, iface.release, 'return',
153 prefix='',
154 func_as_ptr=True,
155 ptr_prefix=self._pnacl_attribute + ' ',
156 include_name=False)
157 result.append(' %s = ((%s)iface->%s);\n' % (temp_fp,
158 cast,
159 member.GetName()))
160 ret, name, array, cspec = self.cgen.GetComponents(member,
161 iface.release,
162 'store')
163 ret_str, args_str = self.GetReturnArgs(ret, cspec)
164 result.append(' %stemp_fp(%s);\n}\n\n' % (ret_str, args_str))
165 return result
168 def GenerateRange(self, ast, releases, options):
169 """Generate shim code for a range of releases.
171 self._skip_opt = GetOption('disable_pnacl_opt')
172 self.SetOutputFile(GetOption('pnaclshim'))
173 return WrapperGen.GenerateRange(self, ast, releases, options)
175 pnaclgen = PnaclGen()
177 ######################################################################
178 # Tests.
180 # Clean a string representing an object definition and return then string
181 # as a single space delimited set of tokens.
182 def CleanString(instr):
183 instr = instr.strip()
184 instr = instr.split()
185 return ' '.join(instr)
188 def PrintErrorDiff(old, new):
189 oldlines = old.split(';')
190 newlines = new.split(';')
191 d = difflib.Differ()
192 diff = d.compare(oldlines, newlines)
193 ErrOut.Log('Diff is:\n%s' % '\n'.join(diff))
196 def GetOldTestOutput(ast):
197 # Scan the top-level comments in the IDL file for comparison.
198 old = []
199 for filenode in ast.GetListOf('File'):
200 for node in filenode.GetChildren():
201 instr = node.GetOneOf('Comment')
202 if not instr: continue
203 instr.Dump()
204 old.append(instr.GetName())
205 return CleanString(''.join(old))
208 def TestFiles(filenames, test_releases):
209 ast = ParseFiles(filenames)
210 iface_releases = pnaclgen.DetermineInterfaces(ast, test_releases)
211 new_output = CleanString(pnaclgen.GenerateWrapperForMethods(
212 iface_releases, comments=False))
213 old_output = GetOldTestOutput(ast)
214 if new_output != old_output:
215 PrintErrorDiff(old_output, new_output)
216 ErrOut.Log('Failed pnacl generator test.')
217 return 1
218 else:
219 InfoOut.Log('Passed pnacl generator test.')
220 return 0
223 def Main(args):
224 filenames = ParseOptions(args)
225 test_releases = ['M13', 'M14', 'M15']
226 if not filenames:
227 idldir = os.path.split(sys.argv[0])[0]
228 idldir = os.path.join(idldir, 'test_gen_pnacl', '*.idl')
229 filenames = glob.glob(idldir)
230 filenames = sorted(filenames)
231 if GetOption('test'):
232 # Run the tests.
233 return TestFiles(filenames, test_releases)
235 # Otherwise, generate the output file (for potential use as golden file).
236 ast = ParseFiles(filenames)
237 return pnaclgen.GenerateRange(ast, test_releases, filenames)
240 if __name__ == '__main__':
241 retval = Main(sys.argv[1:])
242 sys.exit(retval)