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