jni_generator.py revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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)"""Extracts native methods from a Java file and generates the JNI bindings.
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)If you change this, please run and update the tests."""
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import collections
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import errno
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import optparse
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import string
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from string import Template
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import textwrap
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import zipfile
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ParseError(Exception):
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Exception thrown when we can't parse the input file."""
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, description, *context_lines):
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Exception.__init__(self)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.description = description
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.context_lines = context_lines
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __str__(self):
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    context = '\n'.join(self.context_lines)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '***\nERROR: %s\n\n%s\n***' % (self.description, context)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Param(object):
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Describes a param for a method, either java or native."""
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, **kwargs):
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.datatype = kwargs['datatype']
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.name = kwargs['name']
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NativeMethod(object):
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Describes a C/C++ method that is called by Java code"""
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, **kwargs):
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.static = kwargs['static']
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.java_class_name = kwargs['java_class_name']
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.return_type = kwargs['return_type']
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.name = kwargs['name']
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.params = kwargs['params']
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.params:
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert type(self.params) is list
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert type(self.params[0]) is Param
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (self.params and
560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        self.params[0].datatype == kwargs.get('ptr_type', 'int') and
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.params[0].name.startswith('native')):
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.type = 'method'
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.p0_type = self.params[0].name[len('native'):]
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if kwargs.get('native_class_name'):
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self.p0_type = kwargs['native_class_name']
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.type = 'function'
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.method_id_var_name = kwargs.get('method_id_var_name', None)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CalledByNative(object):
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Describes a java method exported to c/c++"""
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, **kwargs):
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.system_class = kwargs['system_class']
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.unchecked = kwargs['unchecked']
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.static = kwargs['static']
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.java_class_name = kwargs['java_class_name']
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.return_type = kwargs['return_type']
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.name = kwargs['name']
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.params = kwargs['params']
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.method_id_var_name = kwargs.get('method_id_var_name', None)
791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.signature = kwargs.get('signature')
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.is_constructor = kwargs.get('is_constructor', False)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.env_call = GetEnvCall(self.is_constructor, self.static,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               self.return_type)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.static_cast = GetStaticCastForReturnType(self.return_type)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class ConstantField(object):
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def __init__(self, **kwargs):
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.name = kwargs['name']
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.value = kwargs['value']
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def JavaDataTypeToC(java_type):
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a C datatype for the given java type."""
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  java_pod_type_map = {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'int': 'jint',
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'byte': 'jbyte',
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'char': 'jchar',
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'short': 'jshort',
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'boolean': 'jboolean',
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'long': 'jlong',
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'double': 'jdouble',
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'float': 'jfloat',
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  java_type_map = {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'void': 'void',
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'String': 'jstring',
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      'java/lang/String': 'jstring',
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'java/lang/Class': 'jclass',
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if java_type in java_pod_type_map:
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return java_pod_type_map[java_type]
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif java_type in java_type_map:
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return java_type_map[java_type]
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif java_type.endswith('[]'):
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if java_type[:-2] in java_pod_type_map:
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return java_pod_type_map[java_type[:-2]] + 'Array'
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'jobjectArray'
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  elif java_type.startswith('Class'):
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Checking just the start of the name, rather than a direct comparison,
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # in order to handle generics.
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return 'jclass'
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'jobject'
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def JavaReturnValueToC(java_type):
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  """Returns a valid C return value for the given java type."""
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  java_pod_type_map = {
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'int': '0',
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'byte': '0',
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'char': '0',
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'short': '0',
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'boolean': 'false',
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'long': '0',
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'double': '0',
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'float': '0',
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'void': ''
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return java_pod_type_map.get(java_type, 'NULL')
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class JniParams(object):
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _imports = []
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _fully_qualified_class = ''
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _package = ''
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _inner_classes = []
148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  _remappings = []
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetFullyQualifiedClass(fully_qualified_class):
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams._fully_qualified_class = 'L' + fully_qualified_class
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams._package = '/'.join(fully_qualified_class.split('/')[:-1])
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ExtractImportsAndInnerClasses(contents):
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents = contents.replace('\n', '')
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    re_import = re.compile(r'import.*?(?P<class>\S*?);')
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for match in re.finditer(re_import, contents):
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      JniParams._imports += ['L' + match.group('class').replace('.', '/')]
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    re_inner = re.compile(r'(class|interface)\s+?(?P<name>\w+?)\W')
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for match in re.finditer(re_inner, contents):
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      inner = match.group('name')
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not JniParams._fully_qualified_class.endswith(inner):
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        JniParams._inner_classes += [JniParams._fully_qualified_class + '$' +
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     inner]
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
1701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  def ParseJavaPSignature(signature_line):
1711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    prefix = 'Signature: '
1721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return '"%s"' % signature_line[signature_line.index(prefix) + len(prefix):]
1731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  @staticmethod
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def JavaToJni(param):
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Converts a java param into a JNI signature type."""
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pod_param_map = {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'int': 'I',
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'boolean': 'Z',
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'char': 'C',
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'short': 'S',
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'long': 'J',
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'double': 'D',
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'float': 'F',
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'byte': 'B',
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'void': 'V',
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    object_param_list = [
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/Boolean',
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/Integer',
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/Long',
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/Object',
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'Ljava/lang/String',
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'Ljava/lang/Class',
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ]
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    prefix = ''
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Array?
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    while param[-2:] == '[]':
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      prefix += '['
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      param = param[:-2]
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Generic?
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if '<' in param:
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      param = param[:param.index('<')]
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if param in pod_param_map:
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return prefix + pod_param_map[param]
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if '/' in param:
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Coming from javap, use the fully qualified param directly.
208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return prefix + 'L' + JniParams.RemapClassName(param) + ';'
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for qualified_name in (object_param_list +
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           [JniParams._fully_qualified_class] +
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           JniParams._inner_classes):
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (qualified_name.endswith('/' + param) or
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          qualified_name.endswith('$' + param.replace('.', '$')) or
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          qualified_name == 'L' + param):
215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return prefix + JniParams.RemapClassName(qualified_name) + ';'
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Is it from an import? (e.g. referecing Class from import pkg.Class;
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # note that referencing an inner class Inner from import pkg.Class.Inner
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # is not supported).
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for qualified_name in JniParams._imports:
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if qualified_name.endswith('/' + param):
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        # Ensure it's not an inner class.
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        components = qualified_name.split('/')
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if len(components) > 2 and components[-2][0].isupper():
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          raise SyntaxError('Inner class (%s) can not be imported '
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            'and used by JNI (%s). Please import the outer '
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            'class and use Outer.Inner instead.' %
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            (qualified_name, param))
229868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return prefix + JniParams.RemapClassName(qualified_name) + ';'
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Is it an inner class from an outer class import? (e.g. referencing
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Class.Inner from import pkg.Class).
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if '.' in param:
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      components = param.split('.')
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      outer = '/'.join(components[:-1])
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      inner = components[-1]
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for qualified_name in JniParams._imports:
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if qualified_name.endswith('/' + outer):
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          return (prefix + JniParams.RemapClassName(qualified_name) +
240868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  '$' + inner + ';')
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Type not found, falling back to same package as this class.
243868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return (prefix + 'L' +
244868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            JniParams.RemapClassName(JniParams._package + '/' + param) + ';')
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Signature(params, returns, wrap):
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the JNI signature for the given datatypes."""
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items = ['(']
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items += [JniParams.JavaToJni(param.datatype) for param in params]
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items += [')']
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    items += [JniParams.JavaToJni(returns)]
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if wrap:
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return '\n' + '\n'.join(['"' + item + '"' for item in items])
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return '"' + ''.join(items) + '"'
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Parse(params):
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Parses the params into a list of Param objects."""
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not params:
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return []
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for p in [p.strip() for p in params.split(',')]:
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      items = p.split(' ')
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'final' in items:
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        items.remove('final')
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      param = Param(
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          datatype=items[0],
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name=(items[1] if len(items) > 1 else 'p%s' % len(ret)),
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      )
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [param]
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  @staticmethod
276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  def RemapClassName(class_name):
277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    """Remaps class names using the jarjar mapping table."""
278868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for old, new in JniParams._remappings:
279868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if old in class_name:
280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        return class_name.replace(old, new, 1)
281868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return class_name
282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  @staticmethod
284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  def SetJarJarMappings(mappings):
285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    """Parse jarjar mappings from a string."""
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    JniParams._remappings = []
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for line in mappings.splitlines():
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      keyword, src, dest = line.split()
289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if keyword != 'rule':
290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        continue
291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      assert src.endswith('.**')
292868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      src = src[:-2].replace('.', '/')
293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      dest = dest.replace('.', '/')
294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if dest.endswith('@0'):
295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        JniParams._remappings.append((src, dest[:-2] + src))
296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      else:
297868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        assert dest.endswith('@1')
298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        JniParams._remappings.append((src, dest[:-2]))
299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractJNINamespace(contents):
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  re_jni_namespace = re.compile('.*?@JNINamespace\("(.*?)"\)')
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  m = re.findall(re_jni_namespace, contents)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not m:
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ''
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return m[0]
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractFullyQualifiedJavaClassName(java_file_name, contents):
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  re_package = re.compile('.*?package (.*?);')
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  matches = re.findall(re_package, contents)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not matches:
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise SyntaxError('Unable to find "package" line in %s' % java_file_name)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (matches[0].replace('.', '/') + '/' +
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          os.path.splitext(os.path.basename(java_file_name))[0])
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)def ExtractNatives(contents, ptr_type):
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a list of dict containing information about a native method."""
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contents = contents.replace('\n', '')
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  natives = []
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  re_native = re.compile(r'(@NativeClassQualifiedName'
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         '\(\"(?P<native_class_name>.*?)\"\))?\s*'
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         '(@NativeCall(\(\"(?P<java_class_name>.*?)\"\)))?\s*'
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         '(?P<qualifiers>\w+\s\w+|\w+|\s+)\s*?native '
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         '(?P<return_type>\S*?) '
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         '(?P<name>native\w+?)\((?P<params>.*?)\);')
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for match in re.finditer(re_native, contents):
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    native = NativeMethod(
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static='static' in match.group('qualifiers'),
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        java_class_name=match.group('java_class_name'),
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        native_class_name=match.group('native_class_name'),
333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return_type=match.group('return_type'),
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        name=match.group('name').replace('native', ''),
3350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        params=JniParams.Parse(match.group('params')),
3360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        ptr_type=ptr_type)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    natives += [native]
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return natives
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetStaticCastForReturnType(return_type):
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  type_map = { 'String' : 'jstring',
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'java/lang/String' : 'jstring',
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'boolean[]': 'jbooleanArray',
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'byte[]': 'jbyteArray',
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'char[]': 'jcharArray',
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'short[]': 'jshortArray',
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'int[]': 'jintArray',
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'long[]': 'jlongArray',
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'double[]': 'jdoubleArray' }
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ret = type_map.get(return_type, None)
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ret:
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ret
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if return_type.endswith('[]'):
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'jobjectArray'
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return None
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetEnvCall(is_constructor, is_static, return_type):
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Maps the types availabe via env->Call__Method."""
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if is_constructor:
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 'NewObject'
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  env_call_map = {'boolean': 'Boolean',
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'byte': 'Byte',
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'char': 'Char',
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'short': 'Short',
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'int': 'Int',
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'long': 'Long',
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'float': 'Float',
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'void': 'Void',
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'double': 'Double',
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'Object': 'Object',
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 }
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  call = env_call_map.get(return_type, 'Object')
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if is_static:
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    call = 'Static' + call
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 'Call' + call + 'Method'
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetMangledParam(datatype):
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a mangled identifier for the datatype."""
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if len(datatype) <= 2:
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return datatype.replace('[', 'A')
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ret = ''
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for i in range(1, len(datatype)):
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = datatype[i]
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if c == '[':
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += 'A'
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif c.isupper() or datatype[i - 1] in ['/', 'L']:
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += c.upper()
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetMangledMethodName(name, params, return_type):
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a mangled method name for the given signature.
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     The returned name can be used as a C identifier and will be unique for all
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     valid overloads of the same method.
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     name: string.
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     params: list of Param.
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     return_type: string.
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A mangled name.
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mangled_items = []
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for datatype in [return_type] + [x.datatype for x in params]:
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mangled_items += [GetMangledParam(JniParams.JavaToJni(datatype))]
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mangled_name = name + '_'.join(mangled_items)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert re.match(r'[0-9a-zA-Z_]+', mangled_name)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return mangled_name
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def MangleCalledByNatives(called_by_natives):
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Mangles all the overloads from the call_by_natives list."""
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  method_counts = collections.defaultdict(
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      lambda: collections.defaultdict(lambda: 0))
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for called_by_native in called_by_natives:
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    java_class_name = called_by_native.java_class_name
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name = called_by_native.name
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    method_counts[java_class_name][name] += 1
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for called_by_native in called_by_natives:
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    java_class_name = called_by_native.java_class_name
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    method_name = called_by_native.name
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    method_id_var_name = method_name
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if method_counts[java_class_name][method_name] > 1:
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      method_id_var_name = GetMangledMethodName(method_name,
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                called_by_native.params,
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                called_by_native.return_type)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    called_by_native.method_id_var_name = method_id_var_name
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return called_by_natives
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Regex to match the JNI return types that should be included in a
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# ScopedJavaLocalRef.
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RE_SCOPED_JNI_RETURN_TYPES = re.compile('jobject|jclass|jstring|.*Array')
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Regex to match a string like "@CalledByNative public void foo(int bar)".
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RE_CALLED_BY_NATIVE = re.compile(
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '@CalledByNative(?P<Unchecked>(Unchecked)*?)(?:\("(?P<annotation>.*)"\))?'
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '\s+(?P<prefix>[\w ]*?)'
444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    '\s*(?P<return_type>\S+?)'
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '\s+(?P<name>\w+)'
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    '\s*\((?P<params>[^\)]*)\)')
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractCalledByNatives(contents):
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Parses all methods annotated with @CalledByNative.
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents: the contents of the java file.
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    A list of dict with information about the annotated methods.
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TODO(bulach): return a CalledByNative object.
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Raises:
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ParseError: if unable to parse.
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  called_by_natives = []
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for match in re.finditer(RE_CALLED_BY_NATIVE, contents):
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    called_by_natives += [CalledByNative(
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        system_class=False,
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unchecked='Unchecked' in match.group('Unchecked'),
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static='static' in match.group('prefix'),
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        java_class_name=match.group('annotation') or '',
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return_type=match.group('return_type'),
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        name=match.group('name'),
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        params=JniParams.Parse(match.group('params')))]
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Check for any @CalledByNative occurrences that weren't matched.
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unmatched_lines = re.sub(RE_CALLED_BY_NATIVE, '', contents).split('\n')
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line1, line2 in zip(unmatched_lines, unmatched_lines[1:]):
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if '@CalledByNative' in line1:
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise ParseError('could not parse @CalledByNative method signature',
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       line1, line2)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MangleCalledByNatives(called_by_natives)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class JNIFromJavaP(object):
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Uses 'javap' to parse a .class file and generate the JNI header file."""
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def __init__(self, contents, options):
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.contents = contents
4864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    self.namespace = options.namespace
487a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for line in contents:
488a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      class_name = re.match(
489a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          '.*?(public).*?(class|interface) (?P<class_name>\S+?)( |\Z)',
490a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          line)
491a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if class_name:
492a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        self.fully_qualified_class = class_name.group('class_name')
493a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        break
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.fully_qualified_class = self.fully_qualified_class.replace('.', '/')
49558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    # Java 7's javap includes type parameters in output, like HashSet<T>. Strip
49658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    # away the <...> and use the raw class name that Java 6 would've given us.
49758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    self.fully_qualified_class = self.fully_qualified_class.split('<', 1)[0]
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams.SetFullyQualifiedClass(self.fully_qualified_class)
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.java_class_name = self.fully_qualified_class.split('/')[-1]
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not self.namespace:
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.namespace = 'JNI_' + self.java_class_name
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)'
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           '\((?P<params>.*?)\)')
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.called_by_natives = []
5051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    for lineno, content in enumerate(contents[2:], 2):
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match = re.match(re_method, content)
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not match:
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.called_by_natives += [CalledByNative(
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          system_class=True,
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          unchecked=False,
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static='static' in match.group('prefix'),
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          java_class_name='',
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return_type=match.group('return_type').replace('.', '/'),
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name=match.group('name'),
5161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          params=JniParams.Parse(match.group('params').replace('.', '/')),
5171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          signature=JniParams.ParseJavaPSignature(contents[lineno + 1]))]
5181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    re_constructor = re.compile('(.*?)public ' +
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                self.fully_qualified_class.replace('/', '.') +
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                '\((?P<params>.*?)\)')
5211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    for lineno, content in enumerate(contents[2:], 2):
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      match = re.match(re_constructor, content)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not match:
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.called_by_natives += [CalledByNative(
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          system_class=True,
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          unchecked=False,
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          static=False,
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          java_class_name='',
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return_type=self.fully_qualified_class,
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name='Constructor',
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          params=JniParams.Parse(match.group('params').replace('.', '/')),
5331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          signature=JniParams.ParseJavaPSignature(contents[lineno + 1]),
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          is_constructor=True)]
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.called_by_natives = MangleCalledByNatives(self.called_by_natives)
536a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
537a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.constant_fields = []
538a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    re_constant_field = re.compile('.*?public static final int (?P<name>.*?);')
539a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    re_constant_field_value = re.compile(
540a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        '.*?Constant(Value| value): int (?P<value>(-*[0-9]+)?)')
541a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for lineno, content in enumerate(contents[2:], 2):
542a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      match = re.match(re_constant_field, content)
543a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if not match:
544a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        continue
545a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      value = re.match(re_constant_field_value, contents[lineno + 2])
546a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if not value:
547a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        value = re.match(re_constant_field_value, contents[lineno + 3])
548a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if value:
549a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        self.constant_fields.append(
550a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            ConstantField(name=match.group('name'),
551a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                          value=value.group('value')))
552a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.inl_header_file_generator = InlHeaderFileGenerator(
5544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        self.namespace, self.fully_qualified_class, [],
555a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        self.called_by_natives, self.constant_fields, options)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetContent(self):
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.inl_header_file_generator.GetContent()
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
5614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def CreateFromClass(class_file, options):
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    class_name = os.path.splitext(os.path.basename(class_file))[0]
563a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    p = subprocess.Popen(args=[options.javap, '-c', '-verbose',
564a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               '-s', class_name],
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         cwd=os.path.dirname(class_file),
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         stdout=subprocess.PIPE,
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         stderr=subprocess.PIPE)
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stdout, _ = p.communicate()
5694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    jni_from_javap = JNIFromJavaP(stdout.split('\n'), options)
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return jni_from_javap
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class JNIFromJavaSource(object):
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Uses the given java source file to generate the JNI header file."""
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def __init__(self, contents, fully_qualified_class, options):
5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    contents = self._RemoveComments(contents, options)
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams.SetFullyQualifiedClass(fully_qualified_class)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    JniParams.ExtractImportsAndInnerClasses(contents)
5805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    jni_namespace = ExtractJNINamespace(contents) or options.namespace
5810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    natives = ExtractNatives(contents, options.ptr_type)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    called_by_natives = ExtractCalledByNatives(contents)
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(natives) == 0 and len(called_by_natives) == 0:
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise SyntaxError('Unable to find any JNI methods for %s.' %
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        fully_qualified_class)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    inl_header_file_generator = InlHeaderFileGenerator(
5874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        jni_namespace, fully_qualified_class, natives, called_by_natives,
588a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        [], options)
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.content = inl_header_file_generator.GetContent()
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def _RemoveComments(self, contents, options):
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # We need to support both inline and block comments, and we need to handle
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # strings that contain '//' or '/*'. Rather than trying to do all that with
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # regexps, we just pipe the contents through the C preprocessor. We tell cpp
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # the file has already been preprocessed, so it just removes comments and
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # doesn't try to parse #include, #pragma etc.
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # TODO(husky): This is a bit hacky. It would be cleaner to use a real Java
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # parser. Maybe we could ditch JNIFromJavaSource and just always use
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # JNIFromJavaP; or maybe we could rewrite this script in Java and use APT.
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # http://code.google.com/p/chromium/issues/detail?id=138941
6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    p = subprocess.Popen(args=[options.cpp, '-fpreprocessed'],
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         stdin=subprocess.PIPE,
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         stdout=subprocess.PIPE,
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         stderr=subprocess.PIPE)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stdout, _ = p.communicate(contents)
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return stdout
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetContent(self):
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.content
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  @staticmethod
6134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def CreateFromFile(java_file_name, options):
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contents = file(java_file_name).read()
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fully_qualified_class = ExtractFullyQualifiedJavaClassName(java_file_name,
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                               contents)
6174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return JNIFromJavaSource(contents, fully_qualified_class, options)
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class InlHeaderFileGenerator(object):
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Generates an inline header file for JNI integration."""
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, namespace, fully_qualified_class, natives,
624a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)               called_by_natives, constant_fields, options):
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.namespace = namespace
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.fully_qualified_class = fully_qualified_class
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.class_name = self.fully_qualified_class.split('/')[-1]
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.natives = natives
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.called_by_natives = called_by_natives
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI'
631a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.constant_fields = constant_fields
6325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.options = options
6335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.init_native = self.ExtractInitNative(options)
6345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def ExtractInitNative(self, options):
6365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for native in self.natives:
6375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if options.jni_init_native_name == 'native' + native.name:
6385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.natives.remove(native)
6395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return native
6405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return None
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetContent(self):
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the content of the JNI binding file."""
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""\
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is autogenerated by
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     ${SCRIPT_NAME}
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     ${FULLY_QUALIFIED_CLASS}
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef ${HEADER_GUARD}
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ${HEADER_GUARD}
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <jni.h>
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${INCLUDES}
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Step 1: forward declarations.
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$CLASS_PATH_DEFINITIONS
6655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)$METHOD_ID_DEFINITIONS
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$OPEN_NAMESPACE
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$FORWARD_DECLARATIONS
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
671a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)$CONSTANT_FIELDS
672a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Step 2: method stubs.
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$METHOD_STUBS
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Step 3: RegisterNatives.
6775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)$JNI_NATIVE_METHODS
6785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)$REGISTER_NATIVES
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)$CLOSE_NAMESPACE
6805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)$JNI_REGISTER_NATIVES
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // ${HEADER_GUARD}
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {
6845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'SCRIPT_NAME': self.options.script_name,
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'FULLY_QUALIFIED_CLASS': self.fully_qualified_class,
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(),
6875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'METHOD_ID_DEFINITIONS': self.GetMethodIDDefinitionsString(),
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'FORWARD_DECLARATIONS': self.GetForwardDeclarationsString(),
689a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        'CONSTANT_FIELDS': self.GetConstantFieldsString(),
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'METHOD_STUBS': self.GetMethodStubsString(),
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'OPEN_NAMESPACE': self.GetOpenNamespaceString(),
6925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'JNI_NATIVE_METHODS': self.GetJNINativeMethodsString(),
6935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'REGISTER_NATIVES': self.GetRegisterNativesString(),
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'CLOSE_NAMESPACE': self.GetCloseNamespaceString(),
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'HEADER_GUARD': self.header_guard,
6965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'INCLUDES': self.GetIncludesString(),
6975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'JNI_REGISTER_NATIVES': self.GetJNIRegisterNativesString()
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return WrapOutput(template.substitute(values))
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetClassPathDefinitionsString(self):
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret += [self.GetClassPathDefinitions()]
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetMethodIDDefinitionsString(self):
7075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the definition of method ids for the called by native methods."""
7085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not self.options.eager_called_by_natives:
7095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return ''
7105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""\
7115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)jmethodID g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = NULL;""")
7125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ret = []
7135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for called_by_native in self.called_by_natives:
7145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      values = {
7155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
7165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
7175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
7185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ret += [template.substitute(values)]
7195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return '\n'.join(ret)
7205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetForwardDeclarationsString(self):
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for native in self.natives:
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if native.type != 'method':
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret += [self.GetForwardDeclaration(native)]
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
728a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def GetConstantFieldsString(self):
729a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if not self.constant_fields:
730a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return ''
731a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ret = ['enum Java_%s_constant_fields {' % self.class_name]
732a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for c in self.constant_fields:
733a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ret += ['  %s = %s,' % (c.name, c.value)]
734a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ret += ['};']
735a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return '\n'.join(ret)
736a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetMethodStubsString(self):
7385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the code corresponding to method stubs."""
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for native in self.natives:
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if native.type == 'method':
7425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ret += [self.GetNativeMethodStubString(native)]
7435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.options.eager_called_by_natives:
7445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ret += self.GetEagerCalledByNativeMethodStubs()
7455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else:
7465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ret += self.GetLazyCalledByNativeMethodStubs()
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetLazyCalledByNativeMethodStubs(self):
7505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return [self.GetLazyCalledByNativeMethodStub(called_by_native)
7515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            for called_by_native in self.called_by_natives]
7525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetEagerCalledByNativeMethodStubs(self):
7545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ret = []
7555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.called_by_natives:
7565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ret += ['namespace {']
7575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      for called_by_native in self.called_by_natives:
7585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ret += [self.GetEagerCalledByNativeMethodStub(called_by_native)]
7595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ret += ['}  // namespace']
7605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return ret
7615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetIncludesString(self):
7635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not self.options.includes:
7645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return ''
7655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    includes = self.options.includes.split(',')
7665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return '\n'.join('#include "%s"' % x for x in includes)
7675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetKMethodsString(self, clazz):
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for native in self.natives:
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (native.java_class_name == clazz or
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (not native.java_class_name and clazz == self.class_name)):
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret += [self.GetKMethodArrayEntry(native)]
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def SubstituteNativeMethods(self, template):
7775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Substitutes JAVA_CLASS and KMETHODS in the provided template."""
7785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ret = []
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_classes = self.GetUniqueClasses(self.natives)
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_classes[self.class_name] = self.fully_qualified_class
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for clazz in all_classes:
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kmethods = self.GetKMethodsString(clazz)
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if kmethods:
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        values = {'JAVA_CLASS': clazz,
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  'KMETHODS': kmethods}
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret += [template.substitute(values)]
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not ret: return ''
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n' + '\n'.join(ret)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetJNINativeMethodsString(self):
7915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the implementation of the array of native methods."""
7925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""\
7935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static const JNINativeMethod kMethods${JAVA_CLASS}[] = {
7945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${KMETHODS}
7955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
7965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)""")
7975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return self.SubstituteNativeMethods(template)
7985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetRegisterCalledByNativesImplString(self):
8005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the code for registering the called by native methods."""
8015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not self.options.eager_called_by_natives:
8025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return ''
8035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""\
8045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = ${GET_METHOD_ID_IMPL}
8055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} == NULL) {
8065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
8075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """)
8095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ret = []
8105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for called_by_native in self.called_by_natives:
8115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      values = {
8125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
8135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
8145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native),
8155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
8165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ret += [template.substitute(values)]
8175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return '\n'.join(ret)
8185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetRegisterNativesString(self):
8205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the code for RegisterNatives."""
8215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""\
8225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${REGISTER_NATIVES_SIGNATURE} {
8235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${CLASSES}
8245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${NATIVES}
8255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${CALLED_BY_NATIVES}
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
8275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)""")
8295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    signature = 'static bool RegisterNativesImpl(JNIEnv* env'
8305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.init_native:
8315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      signature += ', jclass clazz)'
8325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else:
8335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      signature += ')'
8345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    natives = self.GetRegisterNativesImplString()
8365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    called_by_natives = self.GetRegisterCalledByNativesImplString()
8375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    values = {'REGISTER_NATIVES_SIGNATURE': signature,
8385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              'CLASSES': self.GetFindClasses(),
8395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              'NATIVES': natives,
8405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              'CALLED_BY_NATIVES': called_by_natives,
8415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             }
8425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return template.substitute(values)
8435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetRegisterNativesImplString(self):
8455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the shared implementation for RegisterNatives."""
8465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""\
8475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS});
8485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (env->RegisterNatives(g_${JAVA_CLASS}_clazz,
8505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           kMethods${JAVA_CLASS},
8515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           kMethods${JAVA_CLASS}Size) < 0) {
8525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    jni_generator::HandleRegistrationError(
8535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        env, g_${JAVA_CLASS}_clazz, __FILE__);
8545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
8555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
8565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)""")
8575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return self.SubstituteNativeMethods(template)
8585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetJNIRegisterNativesString(self):
8605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the implementation for the JNI registration of native methods."""
8615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not self.init_native:
8625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return ''
8635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""\
8655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)extern "C" JNIEXPORT bool JNICALL
8665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) {
8675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return ${NAMESPACE}RegisterNativesImpl(env, clazz);
8685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)""")
8705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fully_qualified_class = self.fully_qualified_class.replace('/', '_')
8715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    namespace = ''
8725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.namespace:
8735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      namespace = self.namespace + '::'
8745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    values = {'FULLY_QUALIFIED_CLASS': fully_qualified_class,
8755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              'INIT_NATIVE_NAME': 'native' + self.init_native.name,
8765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              'NAMESPACE': namespace,
8775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString()
8785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             }
8795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return template.substitute(values)
8805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetOpenNamespaceString(self):
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.namespace:
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_namespaces = ['namespace %s {' % ns
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        for ns in self.namespace.split('::')]
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return '\n'.join(all_namespaces)
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ''
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetCloseNamespaceString(self):
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.namespace:
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_namespaces = ['}  // namespace %s' % ns
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        for ns in self.namespace.split('::')]
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      all_namespaces.reverse()
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return '\n'.join(all_namespaces) + '\n'
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ''
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetJNIFirstParam(self, native):
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if native.type == 'method':
8995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ret = ['jobject jcaller']
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif native.type == 'function':
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if native.static:
9025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ret = ['jclass jcaller']
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
9045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ret = ['jobject jcaller']
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetParamsInDeclaration(self, native):
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the params for the stub declaration.
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      native: the native dictionary describing the method.
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A string containing the params.
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ',\n    '.join(self.GetJNIFirstParam(native) +
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          [JavaDataTypeToC(param.datatype) + ' ' +
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           param.name
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           for param in native.params])
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetCalledByNativeParamsInDeclaration(self, called_by_native):
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ',\n    '.join([JavaDataTypeToC(param.datatype) + ' ' +
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           param.name
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           for param in called_by_native.params])
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetForwardDeclaration(self, native):
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS});
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {'RETURN': JavaDataTypeToC(native.return_type),
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'NAME': native.name,
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'PARAMS': self.GetParamsInDeclaration(native)}
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetNativeMethodStubString(self, native):
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns stubs for native methods."""
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""\
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME});
9405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN});
9415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL};
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
9445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    params = []
9455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not self.options.pure_native_methods:
9465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      params = ['env', 'jcaller']
9475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    params_in_call = ', '.join(params + [p.name for p in native.params[1:]])
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_type = JavaDataTypeToC(native.return_type)
9505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    optional_error_return = JavaReturnValueToC(native.return_type)
9515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if optional_error_return:
9525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      optional_error_return = ', ' + optional_error_return
9535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    post_call = ''
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      post_call = '.Release()'
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'RETURN': return_type,
9585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'OPTIONAL_ERROR_RETURN': optional_error_return,
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'NAME': native.name,
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native),
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'PARAM0_NAME': native.params[0].name,
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'P0_TYPE': native.p0_type,
9635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'PARAMS_IN_CALL': params_in_call,
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'POST_CALL': post_call
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetCalledByNativeValues(self, called_by_native):
9695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Fills in necessary values for the CalledByNative methods."""
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if called_by_native.static or called_by_native.is_constructor:
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_param_in_declaration = ''
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_param_in_call = ('g_%s_clazz' %
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             (called_by_native.java_class_name or
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              self.class_name))
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_param_in_declaration = ', jobject obj'
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_param_in_call = 'obj'
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    params_in_declaration = self.GetCalledByNativeParamsInDeclaration(
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        called_by_native)
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if params_in_declaration:
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      params_in_declaration = ', ' + params_in_declaration
9825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    params_in_call = ', '.join(param.name for param in called_by_native.params)
9835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if params_in_call:
9845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      params_in_call = ', ' + params_in_call
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pre_call = ''
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    post_call = ''
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if called_by_native.static_cast:
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pre_call = 'static_cast<%s>(' % called_by_native.static_cast
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      post_call = ')'
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    check_exception = ''
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not called_by_native.unchecked:
9925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      check_exception = 'jni_generator::CheckException(env);'
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_type = JavaDataTypeToC(called_by_native.return_type)
9945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    optional_error_return = JavaReturnValueToC(called_by_native.return_type)
9955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if optional_error_return:
9965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      optional_error_return = ', ' + optional_error_return
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_declaration = ''
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_clause = ''
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if return_type != 'void':
10005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      pre_call = ' ' + pre_call
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return_declaration = return_type + ' ret ='
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
10035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return_type = 'base::android::ScopedJavaLocalRef<' + return_type + '>'
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return_clause = 'return ' + return_type + '(env, ret);'
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return_clause = 'return ret;'
10075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return {
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'RETURN_TYPE': return_type,
10105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'OPTIONAL_ERROR_RETURN': optional_error_return,
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'RETURN_DECLARATION': return_declaration,
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'RETURN_CLAUSE': return_clause,
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration,
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'PARAMS_IN_DECLARATION': params_in_declaration,
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'PRE_CALL': pre_call,
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'POST_CALL': post_call,
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'ENV_CALL': called_by_native.env_call,
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'FIRST_PARAM_IN_CALL': first_param_in_call,
10195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'PARAMS_IN_CALL': params_in_call,
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'CHECK_EXCEPTION': check_exception,
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native)
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
10255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetEagerCalledByNativeMethodStub(self, called_by_native):
10265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the implementation of the called by native method."""
10275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""
10285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static ${RETURN_TYPE} ${METHOD_ID_VAR_NAME}(\
10295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION}) {
10305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ${RETURN_DECLARATION}${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
10315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}${PARAMS_IN_CALL})${POST_CALL};
10325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ${RETURN_CLAUSE}
10335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}""")
10345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    values = self.GetCalledByNativeValues(called_by_native)
10355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return template.substitute(values)
10365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
10375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def GetLazyCalledByNativeMethodStub(self, called_by_native):
10385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns a string."""
10395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    function_signature_template = Template("""\
10405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\
10415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""")
10425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    function_header_template = Template("""\
10435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${FUNCTION_SIGNATURE} {""")
10445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    function_header_with_unused_template = Template("""\
10455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${FUNCTION_SIGNATURE} __attribute__ ((unused));
10465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${FUNCTION_SIGNATURE} {""")
10475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    template = Template("""
10485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0;
10495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${FUNCTION_HEADER}
10505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  /* Must call RegisterNativesImpl()  */
10515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK_CLAZZ(env, ${FIRST_PARAM_IN_CALL},
10525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      g_${JAVA_CLASS}_clazz${OPTIONAL_ERROR_RETURN});
10535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  jmethodID method_id =
10545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ${GET_METHOD_ID_IMPL}
10555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ${RETURN_DECLARATION}
10565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
10575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          method_id${PARAMS_IN_CALL})${POST_CALL};
10585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ${CHECK_EXCEPTION}
10595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ${RETURN_CLAUSE}
10605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}""")
10615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    values = self.GetCalledByNativeValues(called_by_native)
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values['FUNCTION_SIGNATURE'] = (
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        function_signature_template.substitute(values))
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if called_by_native.system_class:
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values['FUNCTION_HEADER'] = (
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          function_header_with_unused_template.substitute(values))
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values['FUNCTION_HEADER'] = function_header_template.substitute(values)
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetKMethodArrayEntry(self, native):
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""\
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "native${NAME}", ${JNI_SIGNATURE}, reinterpret_cast<void*>(${NAME}) },""")
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {'NAME': native.name,
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              'JNI_SIGNATURE': JniParams.Signature(native.params,
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   native.return_type,
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   True)}
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetUniqueClasses(self, origin):
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = {self.class_name: self.fully_qualified_class}
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for entry in origin:
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      class_name = self.class_name
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jni_class_path = self.fully_qualified_class
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if entry.java_class_name:
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        class_name = entry.java_class_name
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        jni_class_path = self.fully_qualified_class + '$' + class_name
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret[class_name] = jni_class_path
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetClassPathDefinitions(self):
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the ClassPath constants."""
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    template = Template("""\
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""")
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    native_classes = self.GetUniqueClasses(self.natives)
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    called_by_native_classes = self.GetUniqueClasses(self.called_by_natives)
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_classes = native_classes
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_classes.update(called_by_native_classes)
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for clazz in all_classes:
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values = {
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'JAVA_CLASS': clazz,
1103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]),
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [template.substitute(values)]
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret += ''
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for clazz in called_by_native_classes:
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      template = Template("""\
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Leaking this jclass as we cannot use LazyInstance from some threads.
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)jclass g_${JAVA_CLASS}_clazz = NULL;""")
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values = {
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'JAVA_CLASS': clazz,
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [template.substitute(values)]
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetFindClasses(self):
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the imlementation of FindClass for all known classes."""
11195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.init_native:
11205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      template = Template("""\
11215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  g_${JAVA_CLASS}_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));""")
11225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else:
11235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      template = Template("""\
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_${JAVA_CLASS}_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
1125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::android::GetClass(env, k${JAVA_CLASS}ClassPath).obj()));""")
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = []
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for clazz in self.GetUniqueClasses(self.called_by_natives):
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      values = {'JAVA_CLASS': clazz}
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [template.substitute(values)]
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\n'.join(ret)
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def GetMethodIDImpl(self, called_by_native):
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the implementation of GetMethodID."""
11345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.options.eager_called_by_natives:
11355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      template = Template("""\
11365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)env->Get${STATIC_METHOD_PART}MethodID(
11375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      g_${JAVA_CLASS}_clazz,
11385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "${JNI_NAME}", ${JNI_SIGNATURE});""")
11395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else:
11405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      template = Template("""\
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::android::MethodID::LazyGet<
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::android::MethodID::TYPE_${STATIC}>(
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      env, g_${JAVA_CLASS}_clazz,
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "${JNI_NAME}",
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ${JNI_SIGNATURE},
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME});
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""")
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jni_name = called_by_native.name
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jni_return_type = called_by_native.return_type
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if called_by_native.is_constructor:
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jni_name = '<init>'
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      jni_return_type = 'void'
11531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if called_by_native.signature:
11541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      signature = called_by_native.signature
11551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    else:
11561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      signature = JniParams.Signature(called_by_native.params,
11571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                      jni_return_type,
11581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                      True)
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values = {
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'JNI_NAME': jni_name,
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE',
11645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'STATIC_METHOD_PART': 'Static' if called_by_native.static else '',
11651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        'JNI_SIGNATURE': signature,
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return template.substitute(values)
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def WrapOutput(output):
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ret = []
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for line in output.splitlines():
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Do not wrap lines under 80 characters or preprocessor directives.
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if len(line) < 80 or line.lstrip()[:1] == '#':
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stripped = line.rstrip()
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if len(ret) == 0 or len(ret[-1]) or len(stripped):
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ret.append(stripped)
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_line_indent = ' ' * (len(line) - len(line.lstrip()))
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      subsequent_indent =  first_line_indent + ' ' * 4
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if line.startswith('//'):
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        subsequent_indent = '//' + subsequent_indent
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wrapper = textwrap.TextWrapper(width=80,
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     subsequent_indent=subsequent_indent,
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     break_long_words=False)
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret += [wrapped.rstrip() for wrapped in wrapper.wrap(line)]
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ret += ['']
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return '\n'.join(ret)
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractJarInputFile(jar_file, input_file, out_dir):
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Extracts input file from jar and returns the filename.
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  The input file is extracted to the same directory that the generated jni
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  headers will be placed in.  This is passed as an argument to script.
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    jar_file: the jar file containing the input files to extract.
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    input_files: the list of files to extract from the jar file.
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out_dir: the name of the directories to extract to.
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    the name of extracted input file.
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  jar_file = zipfile.ZipFile(jar_file)
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  out_dir = os.path.join(out_dir, os.path.dirname(input_file))
12082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  try:
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.makedirs(out_dir)
12102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  except OSError as e:
12112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if e.errno != errno.EEXIST:
12122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extracted_file_name = os.path.join(out_dir, os.path.basename(input_file))
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  with open(extracted_file_name, 'w') as outfile:
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    outfile.write(jar_file.read(input_file))
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return extracted_file_name
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def GenerateJNIHeader(input_file, output_file, options):
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try:
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if os.path.splitext(input_file)[1] == '.class':
12234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      jni_from_javap = JNIFromJavaP.CreateFromClass(input_file, options)
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content = jni_from_javap.GetContent()
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
12264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      jni_from_java_source = JNIFromJavaSource.CreateFromFile(
12274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          input_file, options)
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content = jni_from_java_source.GetContent()
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  except ParseError, e:
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print e
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sys.exit(1)
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if output_file:
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not os.path.exists(os.path.dirname(os.path.abspath(output_file))):
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os.makedirs(os.path.dirname(os.path.abspath(output_file)))
12354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if options.optimize_generation and os.path.exists(output_file):
12362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      with file(output_file, 'r') as f:
12372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        existing_content = f.read()
12382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if existing_content == content:
12392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    with file(output_file, 'w') as f:
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      f.write(content)
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    print output
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)def GetScriptName():
12474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  script_components = os.path.abspath(sys.argv[0]).split(os.path.sep)
12484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base_index = 0
12494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for idx, value in enumerate(script_components):
12504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if value == 'base' or value == 'third_party':
12514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base_index = idx
12524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      break
12534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return os.sep.join(script_components[base_index:])
12544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
12554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main(argv):
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  usage = """usage: %prog [OPTIONS]
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This script will parse the given java source code extracting the native
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)declarations and print the header file to stdout (or a file).
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)See SampleForTests.java for more details.
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser = optparse.OptionParser(usage=usage)
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('-j', dest='jar_file',
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           help='Extract the list of input files from'
12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ' a specified jar file.'
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ' Uses javap to extract the methods from a'
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ' pre-compiled class. --input should point'
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ' to pre-compiled Java .class files.')
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('-n', dest='namespace',
12705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           help='Uses as a namespace in the generated header '
12715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'instead of the javap class name, or when there is '
12725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'no JNINamespace annotation in the java source.')
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('--input_file',
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           help='Single input file name. The output file name '
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           'will be derived from it. Must be used with '
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           '--output_dir.')
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  option_parser.add_option('--output_dir',
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           help='The output directory. Must be used with '
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           '--input')
12802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  option_parser.add_option('--optimize_generation', type="int",
12812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           default=0, help='Whether we should optimize JNI '
12822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           'generation by not regenerating files if they have '
12832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           'not changed.')
1284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  option_parser.add_option('--jarjar',
1285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                           help='Path to optional jarjar rules file.')
12864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  option_parser.add_option('--script_name', default=GetScriptName(),
12874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                           help='The name of this script in the generated '
12884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                           'header.')
12895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  option_parser.add_option('--includes',
12905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           help='The comma-separated list of header files to '
12915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'include in the generated header.')
12925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  option_parser.add_option('--pure_native_methods',
12935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           action='store_true', dest='pure_native_methods',
12945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           help='When true, the native methods will be called '
12955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'without any JNI-specific arguments.')
12960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  option_parser.add_option('--ptr_type', default='int',
12970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                           type='choice', choices=['int', 'long'],
12980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                           help='The type used to represent native pointers in '
12990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                           'Java code. For 32-bit, use int; '
13000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                           'for 64-bit, use long.')
13015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  option_parser.add_option('--jni_init_native_name', default='',
13025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           help='The name of the JNI registration method that '
13035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'is used to initialize all native methods. If a '
13045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'method with this name is not present in the Java '
13055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'source file, setting this option is a no-op. When '
13065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'a method with this name is found however, the '
13075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'naming convention Java_<packageName>_<className> '
13085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'will limit the initialization to only the '
13095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'top-level class.')
13105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  option_parser.add_option('--eager_called_by_natives',
13115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           action='store_true', dest='eager_called_by_natives',
13125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           help='When true, the called-by-native methods will '
13135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           'be initialized in a non-atomic way.')
13145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  option_parser.add_option('--cpp', default='cpp',
13155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           help='The path to cpp command.')
13165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  option_parser.add_option('--javap', default='javap',
13175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           help='The path to javap command.')
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  options, args = option_parser.parse_args(argv)
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if options.jar_file:
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    input_file = ExtractJarInputFile(options.jar_file, options.input_file,
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     options.output_dir)
13224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  elif options.input_file:
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    input_file = options.input_file
13244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  else:
13254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    option_parser.print_help()
13264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    print '\nError: Must specify --jar_file or --input_file.'
13274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return 1
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output_file = None
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if options.output_dir:
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    root_name = os.path.splitext(os.path.basename(input_file))[0]
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output_file = os.path.join(options.output_dir, root_name) + '_jni.h'
1332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if options.jarjar:
1333868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    with open(options.jarjar) as f:
1334868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      JniParams.SetJarJarMappings(f.read())
13354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  GenerateJNIHeader(input_file, output_file, options)
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__':
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sys.exit(main(sys.argv))
1340