1# coding=utf-8 2# 3# Copyright (c) 2025 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16from taihe.codegen.abi.analyses import ( 17 IfaceABIInfo, 18) 19from taihe.codegen.abi.writer import CHeaderWriter, CSourceWriter 20from taihe.codegen.ani.analyses import ( 21 ANI_CLASS, 22 ANINativeFuncInfo, 23 ANIRegisterInfo, 24 GlobFuncANIInfo, 25 IfaceANIInfo, 26 IfaceMethodANIInfo, 27 PackageANIInfo, 28 StructANIInfo, 29 TypeANIInfo, 30 UnionANIInfo, 31 UnionFieldANIInfo, 32) 33from taihe.codegen.cpp.analyses import ( 34 GlobFuncCppUserInfo, 35 IfaceCppInfo, 36 IfaceMethodCppInfo, 37 PackageCppUserInfo, 38 StructCppInfo, 39 TypeCppInfo, 40 UnionCppInfo, 41) 42from taihe.semantics.declarations import ( 43 GlobFuncDecl, 44 IfaceDecl, 45 IfaceMethodDecl, 46 PackageDecl, 47 PackageGroup, 48 StructDecl, 49 UnionDecl, 50) 51from taihe.semantics.types import ( 52 Type, 53) 54from taihe.utils.analyses import AnalysisManager 55from taihe.utils.outputs import FileKind, OutputManager 56 57 58class ANICodeGenerator: 59 def __init__(self, om: OutputManager, am: AnalysisManager): 60 self.om = om 61 self.am = am 62 63 def generate(self, pg: PackageGroup): 64 for pkg in pg.packages: 65 self.gen_package(pkg) 66 self.gen_constructor(pg) 67 68 def gen_constructor(self, pg: PackageGroup): 69 with CSourceWriter( 70 self.om, 71 f"temp/ani_constructor.cpp", 72 FileKind.TEMPLATE, 73 ) as constructor_target: 74 constructor_target.writelns( 75 f"#if __has_include(<ani.h>)", 76 f"#include <ani.h>", 77 f"#elif __has_include(<ani/ani.h>)", 78 f"#include <ani/ani.h>", 79 f"#else", 80 f'#error "ani.h not found. Please ensure the Ani SDK is correctly installed."', 81 f"#endif", 82 ) 83 with constructor_target.indented( 84 f"ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) {{", 85 f"}}", 86 ): 87 constructor_target.writelns( 88 # f"::taihe::set_vm(vm);", 89 f"ani_env *env;", 90 ) 91 with constructor_target.indented( 92 f"if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {{", 93 f"}}", 94 ): 95 constructor_target.writelns( 96 f"return ANI_ERROR;", 97 ) 98 for pkg in pg.packages: 99 pkg_ani_info = PackageANIInfo.get(self.am, pkg) 100 constructor_target.add_include(pkg_ani_info.header) 101 with constructor_target.indented( 102 f"if (ANI_OK != {pkg_ani_info.cpp_ns}::ANIRegister(env)) {{", 103 f"}}", 104 ): 105 constructor_target.writelns( 106 f'std::cerr << "Error from {pkg_ani_info.cpp_ns}::ANIRegister" << std::endl;', 107 f"return ANI_ERROR;", 108 ) 109 constructor_target.writelns( 110 f"*result = ANI_VERSION_1;", 111 f"return ANI_OK;", 112 ) 113 114 def gen_package(self, pkg: PackageDecl): 115 for iface in pkg.interfaces: 116 self.gen_iface_files(iface) 117 for struct in pkg.structs: 118 self.gen_struct_files(struct) 119 for union in pkg.unions: 120 self.gen_union_files(union) 121 pkg_ani_info = PackageANIInfo.get(self.am, pkg) 122 pkg_cpp_user_info = PackageCppUserInfo.get(self.am, pkg) 123 self.gen_package_header(pkg, pkg_ani_info, pkg_cpp_user_info) 124 self.gen_package_source(pkg, pkg_ani_info, pkg_cpp_user_info) 125 126 def gen_package_header( 127 self, 128 pkg: PackageDecl, 129 pkg_ani_info: PackageANIInfo, 130 pkg_cpp_user_info: PackageCppUserInfo, 131 ): 132 with CHeaderWriter( 133 self.om, 134 f"include/{pkg_ani_info.header}", 135 FileKind.CPP_HEADER, 136 ) as pkg_ani_header_target: 137 pkg_ani_header_target.add_include("taihe/platform/ani.hpp") 138 with pkg_ani_header_target.indented( 139 f"namespace {pkg_ani_info.cpp_ns} {{", 140 f"}}", 141 indent="", 142 ): 143 pkg_ani_header_target.writelns( 144 f"ani_status ANIRegister(ani_env *env);", 145 ) 146 147 def gen_package_source( 148 self, 149 pkg: PackageDecl, 150 pkg_ani_info: PackageANIInfo, 151 pkg_cpp_user_info: PackageCppUserInfo, 152 ): 153 with CSourceWriter( 154 self.om, 155 f"src/{pkg_ani_info.source}", 156 FileKind.CPP_SOURCE, 157 ) as pkg_ani_source_target: 158 pkg_ani_source_target.add_include(pkg_ani_info.header) 159 pkg_ani_source_target.add_include(pkg_cpp_user_info.header) 160 161 # generate functions 162 with pkg_ani_source_target.indented( 163 f"namespace local {{", 164 f"}}", 165 indent="", 166 ): 167 for iface in pkg.interfaces: 168 with pkg_ani_source_target.indented( 169 f"namespace {iface.name} {{", 170 f"}}", 171 indent="", 172 ): 173 iface_abi_info = IfaceABIInfo.get(self.am, iface) 174 for ancestor in iface_abi_info.ancestor_dict: 175 for method in ancestor.methods: 176 self.gen_method( 177 iface, 178 method, 179 pkg_ani_source_target, 180 ancestor, 181 method.name, 182 ) 183 self.gen_obj_drop(pkg_ani_source_target, "_obj_drop") 184 self.gen_obj_dup(pkg_ani_source_target, "_obj_dup") 185 for func in pkg.functions: 186 self.gen_func(func, pkg_ani_source_target, func.name) 187 188 # register infos 189 register_infos: list[ANIRegisterInfo] = [] 190 191 pkg_register_info = ANIRegisterInfo( 192 parent_scope=pkg_ani_info.ns.scope, 193 impl_desc=pkg_ani_info.ns.impl_desc, 194 member_infos=[], 195 ) 196 register_infos.append(pkg_register_info) 197 for func in pkg.functions: 198 func_ani_info = GlobFuncANIInfo.get(self.am, func) 199 func_info = ANINativeFuncInfo( 200 sts_native_name=func_ani_info.sts_native_name, 201 full_name=f"local::{func.name}", 202 ) 203 pkg_register_info.member_infos.append(func_info) 204 for iface in pkg.interfaces: 205 iface_abi_info = IfaceABIInfo.get(self.am, iface) 206 iface_ani_info = IfaceANIInfo.get(self.am, iface) 207 iface_register_info = ANIRegisterInfo( 208 parent_scope=ANI_CLASS, 209 impl_desc=iface_ani_info.impl_desc, 210 member_infos=[], 211 ) 212 register_infos.append(iface_register_info) 213 for ancestor in iface_abi_info.ancestor_dict: 214 for method in ancestor.methods: 215 method_ani_info = IfaceMethodANIInfo.get(self.am, method) 216 method_info = ANINativeFuncInfo( 217 sts_native_name=method_ani_info.sts_native_name, 218 full_name=f"local::{iface.name}::{method.name}", 219 ) 220 iface_register_info.member_infos.append(method_info) 221 pkg_ani_source_target.add_include("taihe/object.hpp") 222 obj_drop_info = ANINativeFuncInfo( 223 sts_native_name="_obj_drop", 224 full_name=f"local::{iface.name}::_obj_drop", 225 ) 226 iface_register_info.member_infos.append(obj_drop_info) 227 obj_dup_info = ANINativeFuncInfo( 228 sts_native_name="_obj_dup", 229 full_name=f"local::{iface.name}::_obj_dup", 230 ) 231 iface_register_info.member_infos.append(obj_dup_info) 232 233 with pkg_ani_source_target.indented( 234 f"namespace {pkg_ani_info.cpp_ns} {{", 235 f"}}", 236 indent="", 237 ): 238 with pkg_ani_source_target.indented( 239 f"ani_status ANIRegister(ani_env *env) {{", 240 f"}}", 241 ): 242 # TODO: set_vm in constructor 243 with pkg_ani_source_target.indented( 244 f"if (::taihe::get_vm() == nullptr) {{", 245 f"}}", 246 ): 247 pkg_ani_source_target.writelns( 248 f"ani_vm *vm;", 249 ) 250 with pkg_ani_source_target.indented( 251 f"if (ANI_OK != env->GetVM(&vm)) {{", 252 f"}}", 253 ): 254 pkg_ani_source_target.writelns( 255 f"return ANI_ERROR;", 256 ) 257 pkg_ani_source_target.writelns( 258 f"::taihe::set_vm(vm);", 259 ) 260 for register_info in register_infos: 261 parent_scope = register_info.parent_scope 262 with pkg_ani_source_target.indented( 263 f"{{", 264 f"}}", 265 ): 266 pkg_ani_source_target.writelns( 267 f"{parent_scope} ani_env;", 268 ) 269 with pkg_ani_source_target.indented( 270 f'if (ANI_OK != env->Find{parent_scope.suffix}("{register_info.impl_desc}", &ani_env)) {{', 271 f"}}", 272 ): 273 pkg_ani_source_target.writelns( 274 f"return ANI_ERROR;", 275 ) 276 with pkg_ani_source_target.indented( 277 f"ani_native_function methods[] = {{", 278 f"}};", 279 ): 280 for member_info in register_info.member_infos: 281 pkg_ani_source_target.writelns( 282 f'{{"{member_info.sts_native_name}", nullptr, reinterpret_cast<void*>({member_info.full_name})}},', 283 ) 284 with pkg_ani_source_target.indented( 285 f"if (ANI_OK != env->{parent_scope.suffix}_BindNative{parent_scope.member.suffix}s(ani_env, methods, sizeof(methods) / sizeof(ani_native_function))) {{", 286 f"}}", 287 ): 288 pkg_ani_source_target.writelns( 289 f"return ANI_ERROR;", 290 ) 291 pkg_ani_source_target.writelns( 292 f"return ANI_OK;", 293 ) 294 295 def gen_func( 296 self, 297 func: GlobFuncDecl, 298 pkg_ani_source_target: CSourceWriter, 299 name: str, 300 ): 301 func_cpp_user_info = GlobFuncCppUserInfo.get(self.am, func) 302 ani_params = [] 303 ani_params.append("[[maybe_unused]] ani_env *env") 304 ani_args = [] 305 cpp_args = [] 306 for param in func.params: 307 type_ani_info = TypeANIInfo.get(self.am, param.ty_ref.resolved_ty) 308 ani_arg = f"ani_arg_{param.name}" 309 cpp_arg = f"cpp_arg_{param.name}" 310 ani_params.append(f"{type_ani_info.ani_type} {ani_arg}") 311 ani_args.append(ani_arg) 312 cpp_args.append(cpp_arg) 313 ani_params_str = ", ".join(ani_params) 314 if return_ty_ref := func.return_ty_ref: 315 type_ani_info = TypeANIInfo.get(self.am, return_ty_ref.resolved_ty) 316 ani_return_ty_name = type_ani_info.ani_type 317 else: 318 ani_return_ty_name = "void" 319 with pkg_ani_source_target.indented( 320 f"static {ani_return_ty_name} {name}({ani_params_str}) {{", 321 f"}}", 322 ): 323 for param, ani_arg, cpp_arg in zip( 324 func.params, ani_args, cpp_args, strict=True 325 ): 326 type_ani_info = TypeANIInfo.get(self.am, param.ty_ref.resolved_ty) 327 type_ani_info.from_ani(pkg_ani_source_target, "env", ani_arg, cpp_arg) 328 cpp_args_str = ", ".join(cpp_args) 329 if return_ty_ref := func.return_ty_ref: 330 type_cpp_info = TypeCppInfo.get(self.am, return_ty_ref.resolved_ty) 331 type_ani_info = TypeANIInfo.get(self.am, return_ty_ref.resolved_ty) 332 cpp_return_ty_name = type_cpp_info.as_owner 333 cpp_res = "cpp_result" 334 ani_res = "ani_result" 335 pkg_ani_source_target.writelns( 336 f"{cpp_return_ty_name} {cpp_res} = {func_cpp_user_info.full_name}({cpp_args_str});", 337 f"if (::taihe::has_error()) {{ return {type_ani_info.ani_type}{{}}; }}", 338 ) 339 type_ani_info.into_ani(pkg_ani_source_target, "env", cpp_res, ani_res) 340 pkg_ani_source_target.writelns( 341 f"return {ani_res};", 342 ) 343 else: 344 pkg_ani_source_target.writelns( 345 f"{func_cpp_user_info.full_name}({cpp_args_str});", 346 ) 347 348 def gen_method( 349 self, 350 iface: IfaceDecl, 351 method: IfaceMethodDecl, 352 pkg_ani_source_target: CSourceWriter, 353 ancestor: IfaceDecl, 354 name: str, 355 ): 356 method_cpp_info = IfaceMethodCppInfo.get(self.am, method) 357 iface_cpp_info = IfaceCppInfo.get(self.am, iface) 358 iface_abi_info = IfaceABIInfo.get(self.am, iface) 359 iface_ani_info = IfaceANIInfo.get(self.am, iface) 360 ancestor_cpp_info = IfaceCppInfo.get(self.am, ancestor) 361 ani_params = [] 362 ani_params.append("[[maybe_unused]] ani_env *env") 363 ani_params.append("[[maybe_unused]] ani_object object") 364 ani_args = [] 365 cpp_args = [] 366 for param in method.params: 367 type_ani_info = TypeANIInfo.get(self.am, param.ty_ref.resolved_ty) 368 ani_arg = f"ani_arg_{param.name}" 369 cpp_arg = f"cpp_arg_{param.name}" 370 ani_params.append(f"{type_ani_info.ani_type} {ani_arg}") 371 ani_args.append(ani_arg) 372 cpp_args.append(cpp_arg) 373 ani_params_str = ", ".join(ani_params) 374 if return_ty_ref := method.return_ty_ref: 375 type_ani_info = TypeANIInfo.get(self.am, return_ty_ref.resolved_ty) 376 ani_return_ty_name = type_ani_info.ani_type 377 else: 378 ani_return_ty_name = "void" 379 with pkg_ani_source_target.indented( 380 f"static {ani_return_ty_name} {name}({ani_params_str}) {{", 381 f"}}", 382 ): 383 pkg_ani_source_target.writelns( 384 f"ani_long ani_data_ptr;", 385 f'env->Object_GetField_Long(object, TH_ANI_FIND_CLASS_FIELD(env, "{iface_ani_info.impl_desc}", "_data_ptr"), reinterpret_cast<ani_long*>(&ani_data_ptr));', 386 f"ani_long ani_vtbl_ptr;", 387 f'env->Object_GetField_Long(object, TH_ANI_FIND_CLASS_FIELD(env, "{iface_ani_info.impl_desc}", "_vtbl_ptr"), reinterpret_cast<ani_long*>(&ani_vtbl_ptr));', 388 f"DataBlockHead* cpp_data_ptr = reinterpret_cast<DataBlockHead*>(ani_data_ptr);", 389 f"{iface_abi_info.vtable}* cpp_vtbl_ptr = reinterpret_cast<{iface_abi_info.vtable}*>(ani_vtbl_ptr);", 390 f"{iface_cpp_info.full_weak_name} cpp_iface = {iface_cpp_info.full_weak_name}({{cpp_vtbl_ptr, cpp_data_ptr}});", 391 ) 392 for param, ani_arg, cpp_arg in zip( 393 method.params, ani_args, cpp_args, strict=True 394 ): 395 type_ani_info = TypeANIInfo.get(self.am, param.ty_ref.resolved_ty) 396 type_ani_info.from_ani(pkg_ani_source_target, "env", ani_arg, cpp_arg) 397 cpp_args_str = ", ".join(cpp_args) 398 if return_ty_ref := method.return_ty_ref: 399 type_cpp_info = TypeCppInfo.get(self.am, return_ty_ref.resolved_ty) 400 type_ani_info = TypeANIInfo.get(self.am, return_ty_ref.resolved_ty) 401 cpp_return_ty_name = type_cpp_info.as_owner 402 cpp_res = "cpp_result" 403 ani_res = "ani_result" 404 pkg_ani_source_target.writelns( 405 f"{cpp_return_ty_name} {cpp_res} = {ancestor_cpp_info.as_param}(cpp_iface)->{method_cpp_info.call_name}({cpp_args_str});", 406 f"if (::taihe::has_error()) {{ return {type_ani_info.ani_type}{{}}; }}", 407 ) 408 type_ani_info.into_ani(pkg_ani_source_target, "env", cpp_res, ani_res) 409 pkg_ani_source_target.writelns( 410 f"return {ani_res};", 411 ) 412 else: 413 pkg_ani_source_target.writelns( 414 f"{ancestor_cpp_info.as_param}(cpp_iface)->{method_cpp_info.call_name}({cpp_args_str});", 415 ) 416 417 def gen_obj_drop( 418 self, 419 pkg_ani_source_target: CSourceWriter, 420 name: str, 421 ): 422 with pkg_ani_source_target.indented( 423 f"static void {name}([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_class clazz, ani_long data_ptr) {{", 424 f"}}", 425 ): 426 pkg_ani_source_target.writelns( 427 f"tobj_drop(reinterpret_cast<DataBlockHead*>(data_ptr));", 428 ) 429 430 def gen_obj_dup( 431 self, 432 pkg_ani_source_target: CSourceWriter, 433 name: str, 434 ): 435 with pkg_ani_source_target.indented( 436 f"static ani_long {name}([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_class clazz, ani_long data_ptr) {{", 437 f"}}", 438 ): 439 pkg_ani_source_target.writelns( 440 f"return reinterpret_cast<ani_long>(tobj_dup(reinterpret_cast<DataBlockHead*>(data_ptr)));", 441 ) 442 443 def gen_iface_files( 444 self, 445 iface: IfaceDecl, 446 ): 447 iface_abi_info = IfaceABIInfo.get(self.am, iface) 448 iface_cpp_info = IfaceCppInfo.get(self.am, iface) 449 iface_ani_info = IfaceANIInfo.get(self.am, iface) 450 self.gen_iface_conv_decl_file( 451 iface, 452 iface_abi_info, 453 iface_cpp_info, 454 iface_ani_info, 455 ) 456 self.gen_iface_conv_impl_file( 457 iface, 458 iface_abi_info, 459 iface_cpp_info, 460 iface_ani_info, 461 ) 462 463 def gen_iface_conv_decl_file( 464 self, 465 iface: IfaceDecl, 466 iface_abi_info: IfaceABIInfo, 467 iface_cpp_info: IfaceCppInfo, 468 iface_ani_info: IfaceANIInfo, 469 ): 470 with CHeaderWriter( 471 self.om, 472 f"include/{iface_ani_info.decl_header}", 473 FileKind.C_HEADER, 474 ) as iface_ani_decl_target: 475 iface_ani_decl_target.add_include("taihe/platform/ani.hpp") 476 iface_ani_decl_target.add_include(iface_cpp_info.defn_header) 477 with iface_ani_decl_target.indented( 478 f"template<> struct ::taihe::from_ani_t<{iface_cpp_info.as_owner}> {{", 479 f"}};", 480 ): 481 iface_ani_decl_target.writelns( 482 f"inline {iface_cpp_info.as_owner} operator()(ani_env* env, ani_object ani_obj) const;", 483 ) 484 with iface_ani_decl_target.indented( 485 f"template<> struct ::taihe::into_ani_t<{iface_cpp_info.as_owner}> {{", 486 f"}};", 487 ): 488 iface_ani_decl_target.writelns( 489 f"inline ani_object operator()(ani_env* env, {iface_cpp_info.as_owner} cpp_obj) const;", 490 ) 491 492 def gen_iface_conv_impl_file( 493 self, 494 iface: IfaceDecl, 495 iface_abi_info: IfaceABIInfo, 496 iface_cpp_info: IfaceCppInfo, 497 iface_ani_info: IfaceANIInfo, 498 ): 499 with CHeaderWriter( 500 self.om, 501 f"include/{iface_ani_info.impl_header}", 502 FileKind.C_HEADER, 503 ) as iface_ani_impl_target: 504 iface_ani_impl_target.add_include(iface_ani_info.decl_header) 505 iface_ani_impl_target.add_include(iface_cpp_info.impl_header) 506 self.gen_iface_from_ani_func( 507 iface, 508 iface_abi_info, 509 iface_cpp_info, 510 iface_ani_info, 511 iface_ani_impl_target, 512 ) 513 self.gen_iface_into_ani_func( 514 iface, 515 iface_abi_info, 516 iface_cpp_info, 517 iface_ani_info, 518 iface_ani_impl_target, 519 ) 520 521 def gen_iface_from_ani_func( 522 self, 523 iface: IfaceDecl, 524 iface_abi_info: IfaceABIInfo, 525 iface_cpp_info: IfaceCppInfo, 526 iface_ani_info: IfaceANIInfo, 527 iface_ani_impl_target: CHeaderWriter, 528 ): 529 with iface_ani_impl_target.indented( 530 f"inline {iface_cpp_info.as_owner} taihe::from_ani_t<{iface_cpp_info.as_owner}>::operator()(ani_env* env, ani_object ani_obj) const {{", 531 f"}}", 532 ): 533 with iface_ani_impl_target.indented( 534 f"struct cpp_impl_t : ::taihe::dref_guard {{", 535 f"}};", 536 ): 537 iface_ani_impl_target.writelns( 538 f"cpp_impl_t(ani_env* env, ani_ref val) : ::taihe::dref_guard(env, val) {{}}", 539 ) 540 for ancestor in iface_abi_info.ancestor_dict: 541 for method in ancestor.methods: 542 method_cpp_info = IfaceMethodCppInfo.get(self.am, method) 543 method_ani_info = IfaceMethodANIInfo.get(self.am, method) 544 inner_cpp_params = [] 545 inner_cpp_args = [] 546 inner_ani_args = [] 547 for param in method.params: 548 inner_cpp_arg = f"cpp_arg_{param.name}" 549 inner_ani_arg = f"ani_arg_{param.name}" 550 type_cpp_info = TypeCppInfo.get( 551 self.am, param.ty_ref.resolved_ty 552 ) 553 inner_cpp_params.append( 554 f"{type_cpp_info.as_param} {inner_cpp_arg}" 555 ) 556 inner_cpp_args.append(inner_cpp_arg) 557 inner_ani_args.append(inner_ani_arg) 558 inner_cpp_params_str = ", ".join(inner_cpp_params) 559 if return_ty_ref := method.return_ty_ref: 560 type_cpp_info = TypeCppInfo.get( 561 self.am, return_ty_ref.resolved_ty 562 ) 563 cpp_return_ty_name = type_cpp_info.as_owner 564 else: 565 cpp_return_ty_name = "void" 566 with iface_ani_impl_target.indented( 567 f"{cpp_return_ty_name} {method_cpp_info.impl_name}({inner_cpp_params_str}) {{", 568 f"}}", 569 ): 570 iface_ani_impl_target.writelns( 571 f"::taihe::env_guard guard;", 572 f"ani_env *env = guard.get_env();", 573 ) 574 for param, inner_cpp_arg, inner_ani_arg in zip( 575 method.params, 576 inner_cpp_args, 577 inner_ani_args, 578 strict=True, 579 ): 580 type_ani_info = TypeANIInfo.get( 581 self.am, param.ty_ref.resolved_ty 582 ) 583 type_ani_info.into_ani( 584 iface_ani_impl_target, 585 "env", 586 inner_cpp_arg, 587 inner_ani_arg, 588 ) 589 inner_ani_args_trailing = "".join( 590 ", " + inner_ani_arg for inner_ani_arg in inner_ani_args 591 ) 592 if return_ty_ref := method.return_ty_ref: 593 inner_ani_res = "ani_result" 594 inner_cpp_res = "cpp_result" 595 type_ani_info = TypeANIInfo.get( 596 self.am, return_ty_ref.resolved_ty 597 ) 598 iface_ani_impl_target.writelns( 599 f"{type_ani_info.ani_type} {inner_ani_res};", 600 f'env->Object_CallMethod_{type_ani_info.ani_type.suffix}(static_cast<ani_object>(this->ref), TH_ANI_FIND_CLASS_METHOD(env, "{iface_ani_info.type_desc}", "{method_ani_info.ani_method_name}", nullptr), reinterpret_cast<{type_ani_info.ani_type.base}*>(&{inner_ani_res}){inner_ani_args_trailing});', 601 ) 602 type_ani_info.from_ani( 603 iface_ani_impl_target, 604 "env", 605 inner_ani_res, 606 inner_cpp_res, 607 ) 608 iface_ani_impl_target.writelns( 609 f"return {inner_cpp_res};", 610 ) 611 else: 612 iface_ani_impl_target.writelns( 613 f'env->Object_CallMethod_Void(static_cast<ani_object>(this->ref), TH_ANI_FIND_CLASS_METHOD(env, "{iface_ani_info.type_desc}", "{method_ani_info.ani_method_name}", nullptr){inner_ani_args_trailing});', 614 ) 615 with iface_ani_impl_target.indented( 616 f"uintptr_t getGlobalReference() const {{", 617 f"}}", 618 ): 619 iface_ani_impl_target.writelns( 620 f"return reinterpret_cast<uintptr_t>(this->ref);", 621 ) 622 iface_ani_impl_target.writelns( 623 f"return ::taihe::make_holder<cpp_impl_t, {iface_cpp_info.as_owner}, ::taihe::platform::ani::AniObject>(env, ani_obj);", 624 ) 625 626 def gen_iface_into_ani_func( 627 self, 628 iface: IfaceDecl, 629 iface_abi_info: IfaceABIInfo, 630 iface_cpp_info: IfaceCppInfo, 631 iface_ani_info: IfaceANIInfo, 632 iface_ani_impl_target: CHeaderWriter, 633 ): 634 with iface_ani_impl_target.indented( 635 f"inline ani_object taihe::into_ani_t<{iface_cpp_info.as_owner}>::operator()(ani_env* env, {iface_cpp_info.as_owner} cpp_obj) const {{", 636 f"}}", 637 ): 638 iface_ani_impl_target.writelns( 639 f"ani_long ani_vtbl_ptr = reinterpret_cast<ani_long>(cpp_obj.m_handle.vtbl_ptr);", 640 f"ani_long ani_data_ptr = reinterpret_cast<ani_long>(cpp_obj.m_handle.data_ptr);", 641 f"cpp_obj.m_handle.data_ptr = nullptr;", 642 f"ani_object ani_obj;", 643 f'env->Object_New(TH_ANI_FIND_CLASS(env, "{iface_ani_info.impl_desc}"), TH_ANI_FIND_CLASS_METHOD(env, "{iface_ani_info.impl_desc}", "_initialize", "JJ:V"), &ani_obj, ani_vtbl_ptr, ani_data_ptr);', 644 f"return ani_obj;", 645 ) 646 647 def gen_struct_files( 648 self, 649 struct: StructDecl, 650 ): 651 struct_cpp_info = StructCppInfo.get(self.am, struct) 652 struct_ani_info = StructANIInfo.get(self.am, struct) 653 self.gen_struct_conv_decl_file( 654 struct, 655 struct_cpp_info, 656 struct_ani_info, 657 ) 658 self.gen_struct_conv_impl_file( 659 struct, 660 struct_cpp_info, 661 struct_ani_info, 662 ) 663 664 def gen_struct_conv_decl_file( 665 self, 666 struct: StructDecl, 667 struct_cpp_info: StructCppInfo, 668 struct_ani_info: StructANIInfo, 669 ): 670 with CHeaderWriter( 671 self.om, 672 f"include/{struct_ani_info.decl_header}", 673 FileKind.C_HEADER, 674 ) as struct_ani_decl_target: 675 struct_ani_decl_target.add_include("taihe/platform/ani.hpp") 676 struct_ani_decl_target.add_include(struct_cpp_info.defn_header) 677 with struct_ani_decl_target.indented( 678 f"template<> struct ::taihe::from_ani_t<{struct_cpp_info.as_owner}> {{", 679 f"}};", 680 ): 681 struct_ani_decl_target.writelns( 682 f"inline {struct_cpp_info.as_owner} operator()(ani_env* env, ani_object ani_obj) const;", 683 ) 684 with struct_ani_decl_target.indented( 685 f"template<> struct ::taihe::into_ani_t<{struct_cpp_info.as_owner}> {{", 686 f"}};", 687 ): 688 struct_ani_decl_target.writelns( 689 f"inline ani_object operator()(ani_env* env, {struct_cpp_info.as_owner} cpp_obj) const;", 690 ) 691 692 def gen_struct_conv_impl_file( 693 self, 694 struct: StructDecl, 695 struct_cpp_info: StructCppInfo, 696 struct_ani_info: StructANIInfo, 697 ): 698 with CHeaderWriter( 699 self.om, 700 f"include/{struct_ani_info.impl_header}", 701 FileKind.C_HEADER, 702 ) as struct_ani_impl_target: 703 struct_ani_impl_target.add_include(struct_ani_info.decl_header) 704 struct_ani_impl_target.add_include(struct_cpp_info.impl_header) 705 self.gen_struct_from_ani_func( 706 struct, 707 struct_cpp_info, 708 struct_ani_info, 709 struct_ani_impl_target, 710 ) 711 self.gen_struct_into_ani_func( 712 struct, 713 struct_cpp_info, 714 struct_ani_info, 715 struct_ani_impl_target, 716 ) 717 718 def gen_struct_from_ani_func( 719 self, 720 struct: StructDecl, 721 struct_cpp_info: StructCppInfo, 722 struct_ani_info: StructANIInfo, 723 struct_ani_impl_target: CHeaderWriter, 724 ): 725 with struct_ani_impl_target.indented( 726 f"inline {struct_cpp_info.as_owner} taihe::from_ani_t<{struct_cpp_info.as_owner}>::operator()(ani_env* env, ani_object ani_obj) const {{", 727 f"}}", 728 ): 729 cpp_field_results = [] 730 for parts in struct_ani_info.sts_final_fields: 731 final = parts[-1] 732 type_ani_info = TypeANIInfo.get(self.am, final.ty_ref.resolved_ty) 733 ani_field_value = f"ani_field_{final.name}" 734 cpp_field_result = f"cpp_field_{final.name}" 735 struct_ani_impl_target.writelns( 736 f"{type_ani_info.ani_type} {ani_field_value};", 737 ) 738 if struct_ani_info.is_class(): 739 struct_ani_impl_target.writelns( 740 f'env->Object_GetField_{type_ani_info.ani_type.suffix}(ani_obj, TH_ANI_FIND_CLASS_FIELD(env, "{struct_ani_info.type_desc}", "{final.name}"), reinterpret_cast<{type_ani_info.ani_type.base}*>(&{ani_field_value}));', 741 ) 742 else: 743 struct_ani_impl_target.writelns( 744 f'env->Object_CallMethod_{type_ani_info.ani_type.suffix}(ani_obj, TH_ANI_FIND_CLASS_METHOD(env, "{struct_ani_info.type_desc}", "<get>{final.name}", nullptr), reinterpret_cast<{type_ani_info.ani_type.base}*>(&{ani_field_value}));', 745 ) 746 type_ani_info.from_ani( 747 struct_ani_impl_target, "env", ani_field_value, cpp_field_result 748 ) 749 cpp_field_results.append(cpp_field_result) 750 cpp_moved_fields_str = ", ".join( 751 f"std::move({cpp_field_result})" 752 for cpp_field_result in cpp_field_results 753 ) 754 struct_ani_impl_target.writelns( 755 f"return {struct_cpp_info.as_owner}{{{cpp_moved_fields_str}}};", 756 ) 757 758 def gen_struct_into_ani_func( 759 self, 760 struct: StructDecl, 761 struct_cpp_info: StructCppInfo, 762 struct_ani_info: StructANIInfo, 763 struct_ani_impl_target: CHeaderWriter, 764 ): 765 ani_field_results = [] 766 with struct_ani_impl_target.indented( 767 f"inline ani_object taihe::into_ani_t<{struct_cpp_info.as_owner}>::operator()(ani_env* env, {struct_cpp_info.as_owner} cpp_obj) const {{", 768 f"}}", 769 ): 770 for parts in struct_ani_info.sts_final_fields: 771 final = parts[-1] 772 ani_field_result = f"ani_field_{final.name}" 773 type_ani_info = TypeANIInfo.get(self.am, final.ty_ref.resolved_ty) 774 type_ani_info.into_ani( 775 struct_ani_impl_target, 776 "env", 777 ".".join(("cpp_obj", *(part.name for part in parts))), 778 ani_field_result, 779 ) 780 ani_field_results.append(ani_field_result) 781 ani_field_results_trailing = "".join( 782 ", " + ani_field_result for ani_field_result in ani_field_results 783 ) 784 struct_ani_impl_target.writelns( 785 f"ani_object ani_obj;", 786 f'env->Object_New(TH_ANI_FIND_CLASS(env, "{struct_ani_info.impl_desc}"), TH_ANI_FIND_CLASS_METHOD(env, "{struct_ani_info.impl_desc}", "<ctor>", nullptr), &ani_obj{ani_field_results_trailing});', 787 f"return ani_obj;", 788 ) 789 790 def gen_union_files( 791 self, 792 union: UnionDecl, 793 ): 794 union_cpp_info = UnionCppInfo.get(self.am, union) 795 union_ani_info = UnionANIInfo.get(self.am, union) 796 self.gen_union_conv_decl_file( 797 union, 798 union_cpp_info, 799 union_ani_info, 800 ) 801 self.gen_union_conv_impl_file( 802 union, 803 union_cpp_info, 804 union_ani_info, 805 ) 806 807 def gen_union_conv_decl_file( 808 self, 809 union: UnionDecl, 810 union_cpp_info: UnionCppInfo, 811 union_ani_info: UnionANIInfo, 812 ): 813 with CHeaderWriter( 814 self.om, 815 f"include/{union_ani_info.decl_header}", 816 FileKind.C_HEADER, 817 ) as union_ani_decl_target: 818 union_ani_decl_target.add_include("taihe/platform/ani.hpp") 819 union_ani_decl_target.add_include(union_cpp_info.defn_header) 820 with union_ani_decl_target.indented( 821 f"template<> struct ::taihe::from_ani_t<{union_cpp_info.as_owner}> {{", 822 f"}};", 823 ): 824 union_ani_decl_target.writelns( 825 f"inline {union_cpp_info.as_owner} operator()(ani_env* env, ani_ref ani_value) const;", 826 ) 827 with union_ani_decl_target.indented( 828 f"template<> struct ::taihe::into_ani_t<{union_cpp_info.as_owner}> {{", 829 f"}};", 830 ): 831 union_ani_decl_target.writelns( 832 f"inline ani_ref operator()(ani_env* env, {union_cpp_info.as_owner} cpp_value) const;", 833 ) 834 835 def gen_union_conv_impl_file( 836 self, 837 union: UnionDecl, 838 union_cpp_info: UnionCppInfo, 839 union_ani_info: UnionANIInfo, 840 ): 841 with CHeaderWriter( 842 self.om, 843 f"include/{union_ani_info.impl_header}", 844 FileKind.C_HEADER, 845 ) as union_ani_impl_target: 846 union_ani_impl_target.add_include(union_ani_info.decl_header) 847 union_ani_impl_target.add_include(union_cpp_info.impl_header) 848 self.gen_union_from_ani_func( 849 union, 850 union_cpp_info, 851 union_ani_info, 852 union_ani_impl_target, 853 ) 854 self.gen_union_into_ani_func( 855 union, 856 union_cpp_info, 857 union_ani_info, 858 union_ani_impl_target, 859 ) 860 861 def gen_union_from_ani_func( 862 self, 863 union: UnionDecl, 864 union_cpp_info: UnionCppInfo, 865 union_ani_info: UnionANIInfo, 866 union_ani_impl_target: CHeaderWriter, 867 ): 868 with union_ani_impl_target.indented( 869 f"inline {union_cpp_info.as_owner} taihe::from_ani_t<{union_cpp_info.as_owner}>::operator()(ani_env* env, ani_ref ani_value) const {{", 870 f"}}", 871 ): 872 for parts in union_ani_info.sts_final_fields: 873 final = parts[-1] 874 static_tags = [] 875 for part in parts: 876 path_cpp_info = UnionCppInfo.get(self.am, part.parent_union) 877 static_tags.append( 878 f"::taihe::static_tag<{path_cpp_info.full_name}::tag_t::{part.name}>" 879 ) 880 static_tags_str = ", ".join(static_tags) 881 full_name = "_".join(part.name for part in parts) 882 is_field = f"ani_is_{full_name}" 883 final_ani_info = UnionFieldANIInfo.get(self.am, final) 884 if final_ani_info.field_ty == "null": 885 union_ani_impl_target.writelns( 886 f"ani_boolean {is_field};", 887 f"env->Reference_IsNull(ani_value, &{is_field});", 888 ) 889 with union_ani_impl_target.indented( 890 f"if ({is_field}) {{", 891 f"}}", 892 ): 893 union_ani_impl_target.writelns( 894 f"return {union_cpp_info.full_name}({static_tags_str});", 895 ) 896 if final_ani_info.field_ty == "undefined": 897 union_ani_impl_target.writelns( 898 f"ani_boolean {is_field};", 899 f"env->Reference_IsUndefined(ani_value, &{is_field});", 900 ) 901 with union_ani_impl_target.indented( 902 f"if ({is_field}) {{", 903 f"}}", 904 ): 905 union_ani_impl_target.writelns( 906 f"return {union_cpp_info.full_name}({static_tags_str});", 907 ) 908 for parts in union_ani_info.sts_final_fields: 909 final = parts[-1] 910 static_tags = [] 911 for part in parts: 912 path_cpp_info = UnionCppInfo.get(self.am, part.parent_union) 913 static_tags.append( 914 f"::taihe::static_tag<{path_cpp_info.full_name}::tag_t::{part.name}>" 915 ) 916 static_tags_str = ", ".join(static_tags) 917 full_name = "_".join(part.name for part in parts) 918 is_field = f"ani_is_{full_name}" 919 final_ani_info = UnionFieldANIInfo.get(self.am, final) 920 if isinstance(final_ty := final_ani_info.field_ty, Type): 921 type_ani_info = TypeANIInfo.get(self.am, final_ty) 922 union_ani_impl_target.writelns( 923 f"ani_boolean {is_field};", 924 f'env->Object_InstanceOf(static_cast<ani_object>(ani_value), TH_ANI_FIND_CLASS(env, "{type_ani_info.type_desc_boxed}"), &{is_field});', 925 ) 926 with union_ani_impl_target.indented( 927 f"if ({is_field}) {{", 928 f"}}", 929 ): 930 cpp_result_spec = f"cpp_field_{full_name}" 931 type_ani_info.from_ani_boxed( 932 union_ani_impl_target, 933 "env", 934 "ani_value", 935 cpp_result_spec, 936 ) 937 union_ani_impl_target.writelns( 938 f"return {union_cpp_info.full_name}({static_tags_str}, std::move({cpp_result_spec}));", 939 ) 940 union_ani_impl_target.writelns( 941 f"__builtin_unreachable();", 942 ) 943 944 def gen_union_into_ani_func( 945 self, 946 union: UnionDecl, 947 union_cpp_info: UnionCppInfo, 948 union_ani_info: UnionANIInfo, 949 union_ani_impl_target: CHeaderWriter, 950 ): 951 with union_ani_impl_target.indented( 952 f"inline ani_ref taihe::into_ani_t<{union_cpp_info.as_owner}>::operator()(ani_env* env, {union_cpp_info.as_owner} cpp_value) const {{", 953 f"}}", 954 ): 955 union_ani_impl_target.writelns( 956 f"ani_ref ani_value;", 957 ) 958 with union_ani_impl_target.indented( 959 f"switch (cpp_value.get_tag()) {{", 960 f"}}", 961 indent="", 962 ): 963 for field in union.fields: 964 field_ani_info = UnionFieldANIInfo.get(self.am, field) 965 with union_ani_impl_target.indented( 966 f"case {union_cpp_info.full_name}::tag_t::{field.name}: {{", 967 f"}}", 968 ): 969 match field_ani_info.field_ty: 970 case "null": 971 union_ani_impl_target.writelns( 972 f"env->GetNull(&ani_value);", 973 ) 974 case "undefined": 975 union_ani_impl_target.writelns( 976 f"env->GetUndefined(&ani_value);", 977 ) 978 case field_ty if isinstance(field_ty, Type): 979 ani_result_spec = f"ani_field_{field.name}" 980 type_ani_info = TypeANIInfo.get(self.am, field_ty) 981 type_ani_info.into_ani_boxed( 982 union_ani_impl_target, 983 "env", 984 f"cpp_value.get_{field.name}_ref()", 985 ani_result_spec, 986 ) 987 union_ani_impl_target.writelns( 988 f"ani_value = {ani_result_spec};", 989 ) 990 union_ani_impl_target.writelns( 991 f"break;", 992 ) 993 union_ani_impl_target.writelns( 994 f"return ani_value;", 995 )