• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2023 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4"""Logic related to proxying calls through GEN_JNI.java."""
5
6import base64
7import collections
8import hashlib
9
10import common
11import java_types
12
13
14_MAX_CHARS_FOR_HASHED_NATIVE_METHODS = 8
15
16
17_MULTIPLEXED_CHAR_BY_TYPE = {
18    'byte': 'B',
19    'char': 'C',
20    'double': 'D',
21    'float': 'F',
22    'int': 'I',
23    'long': 'J',
24    'Object': 'O',
25    'short': 'S',
26    'void': 'V',
27    'boolean': 'Z',
28}
29
30
31def _muxed_type_char(java_type):
32  return _MULTIPLEXED_CHAR_BY_TYPE[java_type.to_java()]
33
34
35def muxed_name(muxed_signature):
36  # Proxy signatures for methods are named after their return type and
37  # parameters to ensure uniqueness, even for the same return types.
38  params_list = [_muxed_type_char(t) for t in muxed_signature.param_types]
39  params_part = ''
40  if params_list:
41    params_part = '_' + ''.join(p for p in params_list)
42
43  return_value_part = _muxed_type_char(muxed_signature.return_type)
44  return '_' + return_value_part + params_part
45
46
47def muxed_signature(proxy_signature):
48  sorted_params = sorted(proxy_signature.param_list,
49                         key=lambda x: _muxed_type_char(x.java_type))
50  param_list = java_types.JavaParamList(sorted_params)
51  return java_types.JavaSignature.from_params(proxy_signature.return_type,
52                                              param_list)
53
54
55def get_gen_jni_class(*,
56                      short=False,
57                      name_prefix=None,
58                      package_prefix=None,
59                      package_prefix_filter=None):
60  """Returns the JavaClass for GEN_JNI."""
61  package = 'J' if short else 'org/jni_zero'
62  name_prefix = name_prefix + '_' if name_prefix else ''
63  name = name_prefix + ('N' if short else 'GEN_JNI')
64  gen_jni_class = java_types.JavaClass(f'{package}/{name}')
65
66  if package_prefix and common.should_rename_package('org.jni_zero',
67                                                     package_prefix_filter):
68    return gen_jni_class.make_prefixed(package_prefix)
69
70  return gen_jni_class
71
72
73def hashed_name(non_hashed_name, is_test_only):
74  md5 = hashlib.md5(non_hashed_name.encode('utf8')).digest()
75  hash_b64 = base64.b64encode(md5, altchars=b'$_').decode('utf-8')
76
77  long_hash = ('M' + hash_b64).rstrip('=')
78  hashed_name = long_hash[:_MAX_CHARS_FOR_HASHED_NATIVE_METHODS]
79
80  # If the method is a test-only method, we don't care about saving size on
81  # the method name, since it shouldn't show up in the binary. Additionally,
82  # if we just hash the name, our checkers which enforce that we have no
83  # "ForTesting" methods by checking for the suffix "ForTesting" will miss
84  # these. We could preserve the name entirely and not hash anything, but
85  # that risks collisions. So, instead, we just append "ForTesting" to any
86  # test-only hashes, to ensure we catch any test-only methods that
87  # shouldn't be in our final binary.
88  if is_test_only:
89    return hashed_name + '_ForTesting'
90  return hashed_name
91
92
93def needs_implicit_array_element_class_param(return_type):
94  return (return_type.is_object_array() and return_type.converted_type
95          and not return_type.java_class.is_system_class())
96
97
98def add_implicit_array_element_class_param(signature):
99  param = java_types.JavaParam(java_types.OBJECT, '__arrayClazz')
100  param_list = java_types.JavaParamList(signature.param_list + (param, ))
101  return java_types.JavaSignature.from_params(signature.return_type, param_list)
102
103
104def populate_muxed_switch_num(jni_objs, never_omit_switch_num=False):
105  muxed_aliases_by_sig = collections.defaultdict(list)
106  for jni_obj in jni_objs:
107    for native in jni_obj.proxy_natives:
108      aliases = muxed_aliases_by_sig[native.muxed_signature]
109      native.muxed_switch_num = len(aliases)
110      aliases.append(native)
111  # Omit switch_num for unique signatures.
112  if not never_omit_switch_num:
113    for aliases in muxed_aliases_by_sig.values():
114      if len(aliases) == 1:
115        aliases[0].muxed_switch_num = -1
116  return muxed_aliases_by_sig
117