11extern crate anyhow;
22extern crate jni;
33extern crate kcl_lang;
4+ extern crate kclvm_api;
5+ extern crate kclvm_parser;
6+ extern crate kclvm_sema;
47extern crate lazy_static;
58extern crate once_cell;
9+ extern crate prost;
610
711use anyhow:: Result ;
812use jni:: objects:: { JByteArray , JClass , JObject } ;
913use jni:: sys:: jbyteArray;
1014use jni:: JNIEnv ;
15+ use kcl_lang:: API ;
16+ use kclvm_api:: gpyrpc:: LoadPackageArgs ;
17+ use kclvm_api:: service:: KclvmServiceImpl ;
18+ use kclvm_parser:: KCLModuleCache ;
19+ use kclvm_sema:: resolver:: scope:: KCLScopeCache ;
1120use lazy_static:: lazy_static;
1221use once_cell:: sync:: OnceCell ;
22+ use prost:: Message ;
1323use std:: sync:: Mutex ;
1424
1525lazy_static ! {
16- static ref API_INSTANCE : Mutex <OnceCell <kcl_lang:: API >> = Mutex :: new( OnceCell :: new( ) ) ;
26+ static ref API_INSTANCE : Mutex <OnceCell <API >> = Mutex :: new( OnceCell :: new( ) ) ;
27+ static ref MODULE_CACHE : Mutex <OnceCell <KCLModuleCache >> = Mutex :: new( OnceCell :: new( ) ) ;
28+ static ref SCOPE_CACHE : Mutex <OnceCell <KCLScopeCache >> = Mutex :: new( OnceCell :: new( ) ) ;
1729}
1830
1931#[ no_mangle]
@@ -29,6 +41,18 @@ pub extern "system" fn Java_com_kcl_api_API_callNative(
2941 } )
3042}
3143
44+ #[ no_mangle]
45+ pub extern "system" fn Java_com_kcl_api_API_loadPackageWithCache (
46+ mut env : JNIEnv ,
47+ _: JClass ,
48+ args : JByteArray ,
49+ ) -> jbyteArray {
50+ intern_load_package_with_cache ( & mut env, args) . unwrap_or_else ( |e| {
51+ let _ = throw ( & mut env, e) ;
52+ JObject :: default ( ) . into_raw ( )
53+ } )
54+ }
55+
3256fn intern_call_native ( env : & mut JNIEnv , name : JByteArray , args : JByteArray ) -> Result < jbyteArray > {
3357 let binding = API_INSTANCE . lock ( ) . unwrap ( ) ;
3458 let api = binding. get_or_init ( || kcl_lang:: API :: new ( ) . expect ( "Failed to create API instance" ) ) ;
@@ -39,6 +63,25 @@ fn intern_call_native(env: &mut JNIEnv, name: JByteArray, args: JByteArray) -> R
3963 Ok ( j_byte_array. into_raw ( ) )
4064}
4165
66+ /// This is a stateful API, so we avoid serialization overhead and directly use JVM
67+ /// to instantiate global variables here.
68+ fn intern_load_package_with_cache ( env : & mut JNIEnv , args : JByteArray ) -> Result < jbyteArray > {
69+ // AST module cache
70+ let binding = MODULE_CACHE . lock ( ) . unwrap ( ) ;
71+ let module_cache = binding. get_or_init ( || KCLModuleCache :: default ( ) ) ;
72+ // Resolver scope cache
73+ let binding = SCOPE_CACHE . lock ( ) . unwrap ( ) ;
74+ let scope_cache = binding. get_or_init ( || KCLScopeCache :: default ( ) ) ;
75+ // Load package arguments from protobuf bytes.
76+ let args = env. convert_byte_array ( args) ?;
77+ let args: LoadPackageArgs = <LoadPackageArgs as Message >:: decode ( args. as_ref ( ) ) ?;
78+ let svc = KclvmServiceImpl :: default ( ) ;
79+ // Call load package API and decode the result to protobuf bytes.
80+ let packages = svc. load_package_with_cache ( & args, module_cache. clone ( ) , scope_cache. clone ( ) ) ?;
81+ let j_byte_array = env. byte_array_from_slice ( & packages. encode_to_vec ( ) ) ?;
82+ Ok ( j_byte_array. into_raw ( ) )
83+ }
84+
4285fn throw ( env : & mut JNIEnv , error : anyhow:: Error ) -> jni:: errors:: Result < ( ) > {
4386 env. throw ( ( "java/lang/Exception" , error. to_string ( ) ) )
4487}
0 commit comments