15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Generator for Pnacl Shim functions that bridges the calling conventions
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)between GCC and PNaCl.  """
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from datetime import datetime
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import difflib
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import glob
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_c_proto import CGen
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_gen_wrapper import Interface, WrapperGen
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_log import ErrOut, InfoOut, WarnOut
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_option import GetOption, Option, ParseOptions
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from idl_parser import ParseFiles
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('pnaclshim', 'Name of the pnacl shim file.',
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       default='temp_pnacl_shim.c')
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Option('disable_pnacl_opt', 'Turn off optimization of pnacl shim.')
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PnaclGen(WrapperGen):
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """PnaclGen generates shim code to bridge the Gcc ABI with PNaCl.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  This subclass of WrapperGenerator takes the IDL sources and
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  generates shim methods for bridging the calling conventions between GCC
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  and PNaCl (LLVM). Some of the PPAPI methods do not need shimming, so
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this will also detect those situations and provide direct access to the
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  original PPAPI methods (rather than the shim methods).
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self):
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WrapperGen.__init__(self,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        'Pnacl',
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        'Pnacl Shim Gen',
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        'pnacl',
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        'Generate the PNaCl shim.')
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.cgen = CGen()
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._skip_opt = False
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ############################################################
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def OwnHeaderFile(self):
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return the header file that specifies the API of this wrapper.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    We do not generate the header files.  """
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return 'ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.h'
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def InterfaceVersionNeedsWrapping(self, iface, version):
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return true if the interface+version has ANY methods that
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    need wrapping.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._skip_opt:
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return True
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if iface.GetName().endswith('Trusted'):
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return False
6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    # TODO(dmichael): We have no way to wrap PPP_ interfaces without an
6346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    # interface string. If any ever need wrapping, we'll need to figure out a
6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    # way to get the plugin-side of the Pepper proxy (within the IRT) to access
6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    # and use the wrapper.
6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if iface.GetProperty("no_interface_string"):
6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return False
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for member in iface.GetListOf('Member'):
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      release = member.GetRelease(version)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self.MemberNeedsWrapping(member, release):
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return True
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return False
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def MemberNeedsWrapping(self, member, release):
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return true if a particular member function at a particular
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    release needs wrapping.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self._skip_opt:
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return True
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not member.InReleases([release]):
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret, name, array, args_spec = self.cgen.GetComponents(member,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                          release,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                          'store')
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.TypeNeedsWrapping(ret, []) or self.ArgsNeedWrapping(args_spec)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ArgsNeedWrapping(self, args):
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return true if any parameter in the list needs wrapping.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for arg in args:
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (type_str, name, array_dims, more_args) = arg
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self.TypeNeedsWrapping(type_str, array_dims):
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return True
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return False
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def TypeNeedsWrapping(self, type_node, array_dims):
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Return true if a parameter type needs wrapping.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Currently, this is true for byval aggregates.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_aggregate = type_node.startswith('struct') or \
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        type_node.startswith('union')
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_reference = (type_node.find('*') != -1 or array_dims != [])
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return is_aggregate and not is_reference
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ############################################################
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def ConvertByValueReturnType(self, ret, args_spec):
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if self.TypeNeedsWrapping(ret, array_dims=[]):
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      args_spec = [(ret, '_struct_result', [], None)] + args_spec
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ret2 = 'void'
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      wrap_return = True
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    else:
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ret2 = ret
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      wrap_return = False
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return wrap_return, ret2, args_spec
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def ConvertByValueArguments(self, args_spec):
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    args = []
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for type_str, name, array_dims, more_args in args_spec:
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if self.TypeNeedsWrapping(type_str, array_dims):
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        type_str += '*'
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      args.append((type_str, name, array_dims, more_args))
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return args
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  def FormatArgs(self, c_operator, args_spec):
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    args = []
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for type_str, name, array_dims, more_args in args_spec:
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if self.TypeNeedsWrapping(type_str, array_dims):
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        args.append(c_operator + name)
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      else:
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        args.append(name)
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return ', '.join(args)
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GenerateWrapperForPPBMethod(self, iface, member):
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = []
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    func_prefix = self.WrapperMethodPrefix(iface.node, iface.release)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret, name, array, cspec = self.cgen.GetComponents(member,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      iface.release,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      'store')
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    wrap_return, ret2, cspec2 = self.ConvertByValueReturnType(ret, cspec)
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    cspec2 = self.ConvertByValueArguments(cspec2)
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    sig = self.cgen.Compose(ret2, name, array, cspec2,
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            prefix=func_prefix,
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            func_as_ptr=False,
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            include_name=True,
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            unsized_as_ptr=False)
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    result.append('static %s {\n' % sig)
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    result.append('  const struct %s *iface = %s.real_iface;\n' %
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                  (iface.struct_name, self.GetWrapperInfoName(iface)))
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return_prefix = ''
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if wrap_return:
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return_prefix = '*_struct_result = '
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    elif ret != 'void':
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return_prefix = 'return '
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    result.append('  %siface->%s(%s);\n}\n\n' % (return_prefix,
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 member.GetName(),
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 self.FormatArgs('*', cspec)))
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GenerateWrapperForPPPMethod(self, iface, member):
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = []
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    func_prefix = self.WrapperMethodPrefix(iface.node, iface.release)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sig = self.cgen.GetSignature(member, iface.release, 'store',
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 func_prefix, False)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result.append('static %s {\n' % sig)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result.append('  const struct %s *iface = %s.real_iface;\n' %
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  (iface.struct_name, self.GetWrapperInfoName(iface)))
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret, name, array, cspec = self.cgen.GetComponents(member,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      iface.release,
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      'store')
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    wrap_return, ret2, cspec = self.ConvertByValueReturnType(ret, cspec)
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    cspec2 = self.ConvertByValueArguments(cspec)
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    temp_fp = self.cgen.Compose(ret2, name, array, cspec2,
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                prefix='temp_fp',
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                func_as_ptr=True,
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                include_name=False,
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                unsized_as_ptr=False)
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    cast = self.cgen.Compose(ret2, name, array, cspec2,
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             prefix='',
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             func_as_ptr=True,
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             include_name=False,
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             unsized_as_ptr=False)
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    result.append('  %s =\n    ((%s)iface->%s);\n' % (temp_fp,
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                      cast,
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                      member.GetName()))
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return_prefix = ''
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if wrap_return:
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result.append('  %s _struct_result;\n' % ret)
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    elif ret != 'void':
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return_prefix = 'return '
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    result.append('  %stemp_fp(%s);\n' % (return_prefix,
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                          self.FormatArgs('&', cspec)))
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if wrap_return:
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result.append('  return _struct_result;\n')
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    result.append('}\n\n')
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GenerateRange(self, ast, releases, options):
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Generate shim code for a range of releases.
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._skip_opt = GetOption('disable_pnacl_opt')
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.SetOutputFile(GetOption('pnaclshim'))
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return WrapperGen.GenerateRange(self, ast, releases, options)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)pnaclgen = PnaclGen()
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)######################################################################
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Tests.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Clean a string representing an object definition and return then string
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# as a single space delimited set of tokens.
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def CleanString(instr):
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  instr = instr.strip()
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  instr = instr.split()
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ' '.join(instr)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def PrintErrorDiff(old, new):
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  oldlines = old.split(';')
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  newlines = new.split(';')
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  d = difflib.Differ()
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  diff = d.compare(oldlines, newlines)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ErrOut.Log('Diff is:\n%s' % '\n'.join(diff))
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetOldTestOutput(ast):
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Scan the top-level comments in the IDL file for comparison.
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  old = []
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for filenode in ast.GetListOf('File'):
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for node in filenode.GetChildren():
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      instr = node.GetOneOf('Comment')
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not instr: continue
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      instr.Dump()
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      old.append(instr.GetName())
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CleanString(''.join(old))
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def TestFiles(filenames, test_releases):
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ast = ParseFiles(filenames)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  iface_releases = pnaclgen.DetermineInterfaces(ast, test_releases)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_output = CleanString(pnaclgen.GenerateWrapperForMethods(
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iface_releases, comments=False))
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  old_output = GetOldTestOutput(ast)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if new_output != old_output:
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PrintErrorDiff(old_output, new_output)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ErrOut.Log('Failed pnacl generator test.')
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InfoOut.Log('Passed pnacl generator test.')
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def Main(args):
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filenames = ParseOptions(args)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  test_releases = ['M13', 'M14', 'M15']
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not filenames:
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    idldir = os.path.split(sys.argv[0])[0]
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    idldir = os.path.join(idldir, 'test_gen_pnacl', '*.idl')
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    filenames = glob.glob(idldir)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filenames = sorted(filenames)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if GetOption('test'):
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Run the tests.
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TestFiles(filenames, test_releases)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Otherwise, generate the output file (for potential use as golden file).
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ast = ParseFiles(filenames)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pnaclgen.GenerateRange(ast, test_releases, filenames)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  retval = Main(sys.argv[1:])
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.exit(retval)
285