xref: /aosp_15_r20/external/cronet/third_party/jni_zero/codegen/natives_header.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1# Copyright 2024 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"""Codegen for calling C++ methods from Java."""
5
6from codegen import convert_type
7from codegen import header_common
8import common
9
10
11def _return_type_cpp(java_type):
12  if converted_type := java_type.converted_type():
13    return converted_type
14  if java_type.is_primitive():
15    return java_type.to_cpp()
16  return f'jni_zero::ScopedJavaLocalRef<{java_type.to_cpp()}>'
17
18
19def _param_type_cpp(java_type):
20  if converted_type := java_type.converted_type():
21    # Drop & when the type is obviously a pointer to avoid "const char *&".
22    if not java_type.is_primitive() and not converted_type.endswith('*'):
23      converted_type += '&'
24    return converted_type
25
26  ret = java_type.to_cpp()
27  if java_type.is_primitive():
28    return ret
29  return f'const jni_zero::JavaParamRef<{ret}>&'
30
31
32def _impl_forward_declaration(sb, native, params):
33  sb('// Forward declaration. To be implemented by the including .cc file.\n')
34  with sb.statement():
35    sb(f'static {_return_type_cpp(native.return_type)} {native.cpp_impl_name}')
36    with sb.param_list() as plist:
37      plist.append('JNIEnv* env')
38      if not native.static:
39        plist.append('const jni_zero::JavaParamRef<jobject>& jcaller')
40      plist.extend(f'{_param_type_cpp(p.java_type)} {p.name}' for p in params)
41
42
43def _impl_call_params(sb, native, params):
44  with sb.param_list() as plist:
45    plist.append('env')
46    if not native.static:
47      plist.append(header_common.java_param_ref_expression(
48          'jobject', 'jcaller'))
49    for p in params:
50      if p.java_type.converted_type():
51        plist.append(f'{p.name}_converted')
52      elif p.java_type.is_primitive():
53        plist.append(p.name)
54      else:
55        c_type = p.java_type.to_cpp()
56        plist.append(header_common.java_param_ref_expression(c_type, p.name))
57
58
59def proxy_declaration(sb, jni_obj, native):
60  stub_name = jni_obj.GetStubName(native)
61  return_type_cpp = native.proxy_return_type.to_cpp()
62  sb(f'JNI_BOUNDARY_EXPORT {return_type_cpp} {stub_name}')
63  with sb.param_list() as plist:
64    plist.append('JNIEnv* env')
65    jtype = 'jclass' if native.static else 'jobject'
66    plist.append(f'{jtype} jcaller')
67    plist.extend(f'{p.java_type.to_cpp()} {p.name}'
68                 for p in native.proxy_params)
69
70
71def _single_method(sb, jni_obj, native):
72  cpp_class = native.first_param_cpp_type
73  if cpp_class:
74    params = native.proxy_params[1:]
75  else:
76    params = native.proxy_params
77  if native.needs_implicit_array_element_class_param:
78    params = params[:-1]
79
80  # Only non-class methods need to be forward-declared.
81  if not cpp_class:
82    _impl_forward_declaration(sb, native, params)
83    sb('\n')
84
85  proxy_declaration(sb, jni_obj, native)
86  with sb.block():
87    if cpp_class:
88      sb(f"""\
89{cpp_class}* native = reinterpret_cast<{cpp_class}*>({native.params[0].name});
90CHECK_NATIVE_PTR(env, jcaller, native, "{native.cpp_name}\"""")
91      if default_value := native.return_type.to_cpp_default_value():
92        sb(f', {default_value}')
93      sb(')\n')
94
95    for p in params:
96      if p.java_type.converted_type():
97        convert_type.from_jni_assignment(sb, f'{p.name}_converted', p.name,
98                                         p.java_type)
99
100    with sb.statement():
101      if not native.return_type.is_void():
102        sb('auto ret = ')
103      if cpp_class:
104        sb(f'native->{native.cpp_name}')
105      else:
106        sb(f'{native.cpp_impl_name}')
107      _impl_call_params(sb, native, params)
108
109    if not native.return_type.is_void():
110      with sb.statement():
111        sb('return ')
112        if native.return_type.converted_type():
113          if native.needs_implicit_array_element_class_param:
114            clazz_param = native.proxy_params[-1]
115          else:
116            clazz_param = None
117          convert_type.to_jni_expression(sb,
118                                         'ret',
119                                         native.return_type,
120                                         clazz_param=clazz_param)
121        else:
122          sb('ret')
123
124        if not native.return_type.is_primitive():
125          sb('.Release()')
126
127
128def methods(jni_obj):
129  if not jni_obj.natives:
130    return ''
131  sb = common.StringBuilder()
132  sb('// Java to native functions\n')
133  for native in jni_obj.natives:
134    _single_method(sb, jni_obj, native)
135    sb('\n')
136  return sb.to_string()
137