diff --git a/src/binding/kotlin_binding.cpp b/src/binding/kotlin_binding.cpp index 2ac0f55863..e0acdb7a89 100644 --- a/src/binding/kotlin_binding.cpp +++ b/src/binding/kotlin_binding.cpp @@ -13,7 +13,8 @@ void KotlinBinding::refcount_incremented_unsafe() { if (refcount > 1 && kt_binding->is_ref_weak()) { // The JVM holds a reference to that object already, if the counter is greater than 1, it means the native side holds a reference as well. // The reference is changed to a strong one so the JVM instance is not collected if it is not referenced anymore on the JVM side. - kt_binding->swap_to_strong_unsafe(); + jni::Env env {jni::Jvm::current_env()}; + kt_binding->swap_to_strong_unsafe(env); } } @@ -28,7 +29,8 @@ bool KotlinBinding::refcount_decremented_unsafe() { if (refcount == 1 && !kt_binding->is_ref_weak()) { // The JVM holds a reference to that object already, if the counter is equal to 1, it means the JVM is the only side with a reference to the object. // The reference is changed to a weak one so the JVM instance can be collected if it is not referenced anymore on the JVM side. - kt_binding->swap_to_weak_unsafe(); + jni::Env env {jni::Jvm::current_env()}; + kt_binding->swap_to_weak_unsafe(env); } // Return true when the counter is 0, it means that the JVM and the native side are no longer using the reference, so it can be safely deleted. return refcount == 0; @@ -36,7 +38,9 @@ bool KotlinBinding::refcount_decremented_unsafe() { void KotlinBinding::set_kt_binding(jni::JObject j_object) { JVM_CRASH_COND_MSG(kt_binding, "Trying to set a KtBinding on an already bound Object"); - kt_binding = memnew(KtBinding(j_object)); + + jni::Env env {jni::Jvm::current_env()}; + kt_binding = memnew(KtBinding(env, j_object)); if (!owner->is_ref_counted()) { return; @@ -48,7 +52,7 @@ void KotlinBinding::set_kt_binding(jni::JObject j_object) { if (refcount == 1 && !kt_binding->is_ref_weak()) { // The JVM holds a reference to that object already, if the counter is equal to 1, it means the JVM is the only side with a reference to the object. // The reference is changed to a weak one so the JVM instance can be collected if it is not referenced anymore on the JVM side. - kt_binding->swap_to_weak_unsafe(); + kt_binding->swap_to_weak_unsafe(env); } status = BindingStatus::BOUND; } diff --git a/src/gd_kotlin.cpp b/src/gd_kotlin.cpp index 60b1e389b9..498dcc7c01 100644 --- a/src/gd_kotlin.cpp +++ b/src/gd_kotlin.cpp @@ -203,11 +203,11 @@ void GDKotlin::init() { } #endif - JniLifecycleManager::initialize_jni_classes(); + JniLifecycleManager::initialize_jni_classes(env); int max_string_size {configuration.get_max_string_size()}; if (max_string_size != LongStringQueue::max_string_size) { - LongStringQueue::get_instance().set_string_max_size(max_string_size); + LongStringQueue::get_instance().set_string_max_size(env, max_string_size); } if (is_gc_activated) { @@ -217,7 +217,7 @@ void GDKotlin::init() { #endif } - MemoryManager::get_instance().start(is_gc_force_mode); + MemoryManager::get_instance().start(env, is_gc_force_mode); #ifdef DEBUG_ENABLED LOG_VERBOSE("GC thread started."); #endif @@ -225,10 +225,10 @@ void GDKotlin::init() { } if (!should_display_leaked_jvm_instances_on_close) { - MemoryManager::get_instance().setDisplayLeaks(false); + MemoryManager::get_instance().setDisplayLeaks(env, false); } - bootstrap = Bootstrap::create_instance(); + bootstrap = Bootstrap::create_instance(env); #ifdef TOOLS_ENABLED String jar_path {project_settings->globalize_path("res://build/libs/")}; @@ -268,15 +268,15 @@ void GDKotlin::finish() { TypeManager::get_instance().clear(); if (is_gc_started) { - MemoryManager::get_instance().close(); + MemoryManager::get_instance().close(env); - while (!MemoryManager::get_instance().is_closed()) { + while (!MemoryManager::get_instance().is_closed(env)) { OS::get_singleton()->delay_usec(600000); } #ifdef DEBUG_ENABLED LOG_VERBOSE("JVM GC thread was closed"); #endif - MemoryManager::get_instance().clean_up(); + MemoryManager::get_instance().clean_up(env); } JniLifecycleManager::destroy_jni_classes(); @@ -290,10 +290,12 @@ void GDKotlin::register_classes(jni::Env& p_env, jni::JObjectArray p_classes) { #ifdef DEV_ENABLED LOG_INFO("Loading classes ..."); #endif + + jni::Env env {jni::Jvm::current_env()}; Vector classes; for (auto i = 0; i < p_classes.length(p_env); i++) { - KtClass* kt_class = new KtClass(p_classes.get(p_env, i)); - kt_class->fetch_members(); + KtClass* kt_class = new KtClass(env, p_classes.get(p_env, i)); + kt_class->fetch_members(env); classes.append(kt_class); #ifdef DEV_ENABLED LOG_VERBOSE(vformat("Loaded class %s : %s", kt_class->registered_class_name, kt_class->base_godot_class)); diff --git a/src/jni/env.h b/src/jni/env.h index 590174adb3..ed78b03bb0 100644 --- a/src/jni/env.h +++ b/src/jni/env.h @@ -19,7 +19,7 @@ namespace jni { class Env { public: explicit Env(JNIEnv*); - // todo delete copy ctor and assignment? + Env(const Env&) = default; Env& operator=(const Env&) = default; diff --git a/src/jni/jvm.h b/src/jni/jvm.h index 9965cd4224..fc683b21d5 100644 --- a/src/jni/jvm.h +++ b/src/jni/jvm.h @@ -36,7 +36,6 @@ namespace jni { private: Jvm() = default; static JavaVM* vm; - static Env* env; static jint version; static Type vm_type; diff --git a/src/jni/platforms/jvm_android.cpp b/src/jni/platforms/jvm_android.cpp index a54106f289..0169cd14a7 100644 --- a/src/jni/platforms/jvm_android.cpp +++ b/src/jni/platforms/jvm_android.cpp @@ -6,7 +6,6 @@ namespace jni { JavaVM* Jvm::vm = nullptr; - Env* Jvm::env = nullptr; jint Jvm::version = 0; Jvm::Type Jvm::vm_type {Jvm::ART}; diff --git a/src/jni/platforms/jvm_default.cpp b/src/jni/platforms/jvm_default.cpp index 8f5ba5e248..4c2945f347 100644 --- a/src/jni/platforms/jvm_default.cpp +++ b/src/jni/platforms/jvm_default.cpp @@ -11,10 +11,10 @@ #include "../jvm_loader.h" #include "jni/jvm.h" - namespace jni { + static thread_local Env* env = nullptr; + JavaVM* Jvm::vm = nullptr; - Env* Jvm::env = nullptr; jint Jvm::version = 0; Jvm::Type Jvm::vm_type {Jvm::JVM}; @@ -63,6 +63,7 @@ namespace jni { delete[] options; JVM_CRASH_COND_MSG(result != JNI_OK, "Failed to create a new vm!"); + env = new Env(jni_env); return java_vm; } @@ -79,22 +80,25 @@ namespace jni { JNIEnv* r_env; auto result = vm->AttachCurrentThread((void**) &r_env, nullptr); JVM_CRASH_COND_MSG(result != JNI_OK, "Failed to attach vm to current thread!"); - Jvm::env = new Env(r_env); + env = new Env(r_env); return Env(r_env); } void Jvm::detach() { auto result = vm->DetachCurrentThread(); JVM_CRASH_COND_MSG(result != JNI_OK, "Failed to detach vm to current thread!"); - delete Jvm::env; - Jvm::env = nullptr; + delete env; + env = nullptr; } Env Jvm::current_env() { - JNIEnv* r_env; - auto result = vm->GetEnv((void**) &r_env, version); - JVM_CRASH_COND_MSG(result == JNI_EDETACHED, "Current thread is not attached!"); - return Env(r_env); + if (unlikely(!env)) { + JNIEnv* r_env; + auto result = vm->GetEnv((void**) &r_env, version); + JVM_CRASH_COND_MSG(result == JNI_EDETACHED, "Current thread is not attached!"); + env = new Env(r_env); + } + return *env; } Jvm::Type Jvm::get_type() { diff --git a/src/jni_lifecycle_manager.cpp b/src/jni_lifecycle_manager.cpp index d2c7fab5f8..876c1b9cc1 100644 --- a/src/jni_lifecycle_manager.cpp +++ b/src/jni_lifecycle_manager.cpp @@ -21,44 +21,44 @@ #include "jvm_wrapper/memory/transfer_context.h" #include "jvm_wrapper/registration//kt_class.h" -void JniLifecycleManager::initialize_jni_classes() { +void JniLifecycleManager::initialize_jni_classes(jni::Env& p_env) { // Singleton - TransferContext::initialize(); - TypeManager::initialize(); - LongStringQueue::initialize(); - MemoryManager::initialize(); + TransferContext::initialize(p_env); + TypeManager::initialize(p_env); + LongStringQueue::initialize(p_env); + MemoryManager::initialize(p_env); - bridges::GDPrintBridge::initialize(); + bridges::GDPrintBridge::initialize(p_env); - bridges::CallableBridge::initialize(); - bridges::DictionaryBridge::initialize(); - bridges::RidBridge::initialize(); - bridges::StringNameBridge::initialize(); - bridges::NodePathBridge::initialize(); - bridges::VariantArrayBridge::initialize(); + bridges::CallableBridge::initialize(p_env); + bridges::DictionaryBridge::initialize(p_env); + bridges::RidBridge::initialize(p_env); + bridges::StringNameBridge::initialize(p_env); + bridges::NodePathBridge::initialize(p_env); + bridges::VariantArrayBridge::initialize(p_env); - bridges::PackedByteArrayBridge::initialize(); - bridges::PackedColorArrayBridge::initialize(); - bridges::PackedFloat32ArrayBridge::initialize(); - bridges::PackedFloat64ArrayBridge::initialize(); - bridges::PackedInt32IntArrayBridge::initialize(); - bridges::PackedInt64IntArrayBridge::initialize(); - bridges::PackedStringArrayBridge::initialize(); - bridges::PackedVector2ArrayBridge::initialize(); - bridges::PackedVector3ArrayBridge::initialize(); + bridges::PackedByteArrayBridge::initialize(p_env); + bridges::PackedColorArrayBridge::initialize(p_env); + bridges::PackedFloat32ArrayBridge::initialize(p_env); + bridges::PackedFloat64ArrayBridge::initialize(p_env); + bridges::PackedInt32IntArrayBridge::initialize(p_env); + bridges::PackedInt64IntArrayBridge::initialize(p_env); + bridges::PackedStringArrayBridge::initialize(p_env); + bridges::PackedVector2ArrayBridge::initialize(p_env); + bridges::PackedVector3ArrayBridge::initialize(p_env); //Instance - Bootstrap::initialize_jni_binding(); - KtObject::initialize_jni_binding(); + Bootstrap::initialize_jni_binding(p_env); + KtObject::initialize_jni_binding(p_env); - KtPropertyInfo::initialize_jni_binding(); - KtProperty::initialize_jni_binding(); - KtConstructor::initialize_jni_binding(); - KtSignalInfo::initialize_jni_binding(); - KtRpcConfig::initialize_jni_binding(); - KtFunctionInfo::initialize_jni_binding(); - KtFunction::initialize_jni_binding(); - KtClass::initialize_jni_binding(); + KtPropertyInfo::initialize_jni_binding(p_env); + KtProperty::initialize_jni_binding(p_env); + KtConstructor::initialize_jni_binding(p_env); + KtSignalInfo::initialize_jni_binding(p_env); + KtRpcConfig::initialize_jni_binding(p_env); + KtFunctionInfo::initialize_jni_binding(p_env); + KtFunction::initialize_jni_binding(p_env); + KtClass::initialize_jni_binding(p_env); } void JniLifecycleManager::destroy_jni_classes() { diff --git a/src/jni_lifecycle_manager.h b/src/jni_lifecycle_manager.h index f580afaa3d..67b1b939e5 100644 --- a/src/jni_lifecycle_manager.h +++ b/src/jni_lifecycle_manager.h @@ -1,9 +1,11 @@ #ifndef GODOT_JVM_JNI_LIFECYCLE_MANAGER_H #define GODOT_JVM_JNI_LIFECYCLE_MANAGER_H +#include "jni/env.h" + class JniLifecycleManager { public: - static void initialize_jni_classes(); + static void initialize_jni_classes(jni::Env& p_env); static void destroy_jni_classes(); }; diff --git a/src/jvm_wrapper/bootstrap.cpp b/src/jvm_wrapper/bootstrap.cpp index f906f8f334..f96d4c6fd4 100644 --- a/src/jvm_wrapper/bootstrap.cpp +++ b/src/jvm_wrapper/bootstrap.cpp @@ -34,7 +34,7 @@ void Bootstrap::register_engine_type(JNIEnv* p_env, jobject p_this, jobjectArray #endif } -Bootstrap::Bootstrap(jni::JObject p_wrapped) : JvmInstanceWrapper(p_wrapped) {} +Bootstrap::Bootstrap(jni::Env& p_env, jni::JObject p_wrapped) : JvmInstanceWrapper(p_env, p_wrapped) {} void Bootstrap::init(jni::Env& p_env, bool p_is_editor, const String& p_project_path, const String& p_jar_path, const String& p_jar_file, const jni::JObject& p_class_loader) { diff --git a/src/jvm_wrapper/bootstrap.h b/src/jvm_wrapper/bootstrap.h index c94e8cc41a..8fba0650c1 100644 --- a/src/jvm_wrapper/bootstrap.h +++ b/src/jvm_wrapper/bootstrap.h @@ -25,7 +25,7 @@ JVM_INSTANCE_WRAPPER(Bootstrap, "godot.runtime.Bootstrap") { jobjectArray p_singleton_names ); - explicit Bootstrap(jni::JObject p_wrapped); + Bootstrap(jni::Env& p_env, jni::JObject p_wrapped); ~Bootstrap() = default; void init(jni::Env& p_env, bool p_is_editor, const String& p_project_path, const String& p_jar_path, const String& p_jar_file, const jni::JObject& p_class_loader); diff --git a/src/jvm_wrapper/jvm_instance_wrapper.h b/src/jvm_wrapper/jvm_instance_wrapper.h index 8005d71cae..0027df2291 100644 --- a/src/jvm_wrapper/jvm_instance_wrapper.h +++ b/src/jvm_wrapper/jvm_instance_wrapper.h @@ -4,30 +4,29 @@ #include "jni/class_loader.h" #include "jni/wrapper.h" -#define JVM_INSTANCE_WRAPPER(NAME, FQNAME) \ +#define JVM_INSTANCE_WRAPPER(NAME, FQNAME) \ inline constexpr char NAME##QualifiedName[] = FQNAME; \ class NAME : public JvmInstanceWrapper #define JNI_METHOD(var_name) inline static jni::MethodId var_name {nullptr}; -#define INIT_JNI_METHOD(var_name, name, signature) var_name = clazz.get_method_id(env, name, signature); +#define INIT_JNI_METHOD(var_name, name, signature) var_name = clazz.get_method_id(p_env, name, signature); #define INIT_NATIVE_METHOD(string_name, signature, function) \ methods.push_back({const_cast(string_name), const_cast(signature), (void*) function}); -#define INIT_JNI_BINDINGS(...) \ - \ -public: \ - static void initialize_jni_binding() { \ - jni::Env env {jni::Jvm::current_env()}; \ - Vector methods; \ - jni::JClass clazz {env.load_class(get_fully_qualified_name(), ClassLoader::get_default_loader())}; \ - \ - __VA_ARGS__ \ - if (methods.size() > 0) { clazz.register_natives(env, methods); } \ - clazz.delete_local_ref(env); \ - } \ - \ +#define INIT_JNI_BINDINGS(...) \ + \ +public: \ + static void initialize_jni_binding(jni::Env& p_env) { \ + Vector methods; \ + jni::JClass clazz {p_env.load_class(get_fully_qualified_name(), ClassLoader::get_default_loader())}; \ + \ + __VA_ARGS__ \ + if (methods.size() > 0) { clazz.register_natives(p_env, methods); } \ + clazz.delete_local_ref(p_env); \ + } \ + \ private: #define CALL_JVM_METHOD(ENV, METHOD) call_jvm_method(ENV, METHOD) @@ -46,8 +45,8 @@ class JvmInstanceWrapper { protected: bool is_weak; jni::JObject wrapped; - - explicit JvmInstanceWrapper(jni::JObject p_wrapped); + + explicit JvmInstanceWrapper(jni::Env& p_env, jni::JObject p_wrapped); ~JvmInstanceWrapper(); _FORCE_INLINE_ jni::JObject call_jvm_method(jni::Env& p_env, jni::MethodId p_method, jvalue* p_args = {}) const; @@ -57,30 +56,28 @@ class JvmInstanceWrapper { const jni::JObject& get_wrapped() const; - void swap_to_strong_unsafe(); + void swap_to_strong_unsafe(jni::Env& p_env); - void swap_to_weak_unsafe(); + void swap_to_weak_unsafe(jni::Env& p_env); static const char* get_fully_qualified_name(); - - static Derived* create_instance(); + + static Derived* create_instance(jni::Env& p_env); }; template -JvmInstanceWrapper::JvmInstanceWrapper(jni::JObject p_wrapped) : is_weak(false) { +JvmInstanceWrapper::JvmInstanceWrapper(jni::Env& p_env, jni::JObject p_wrapped) : is_weak(false) { // When created, it's a strong reference by default - jni::Env env {jni::Jvm::current_env()}; - wrapped = p_wrapped.new_global_ref(env); - p_wrapped.delete_local_ref(env); + wrapped = p_wrapped.new_global_ref(p_env); + p_wrapped.delete_local_ref(p_env); } template -Derived* JvmInstanceWrapper::create_instance() { - jni::Env env {jni::Jvm::current_env()}; - jni::JClass bootstrap_cls = env.load_class(FqName, ClassLoader::get_default_loader()); - jni::MethodId ctor = bootstrap_cls.get_constructor_method_id(env, "()V"); - jni::JObject instance = bootstrap_cls.new_instance(env, ctor); - return new Derived(instance); +Derived* JvmInstanceWrapper::create_instance(jni::Env& p_env) { + jni::JClass cls = p_env.load_class(FqName, ClassLoader::get_default_loader()); + jni::MethodId ctor = cls.get_constructor_method_id(p_env, "()V"); + jni::JObject instance = cls.new_instance(p_env, ctor); + return new Derived(p_env, instance); } template @@ -99,21 +96,19 @@ bool JvmInstanceWrapper::is_ref_weak() const { } template -void JvmInstanceWrapper::swap_to_strong_unsafe() { +void JvmInstanceWrapper::swap_to_strong_unsafe(jni::Env& p_env) { // Assume the reference is currently weak - jni::Env env {jni::Jvm::current_env()}; - jni::JObject new_ref = wrapped.new_global_ref(env); - wrapped.delete_weak_ref(env); + jni::JObject new_ref = wrapped.new_global_ref(p_env); + wrapped.delete_weak_ref(p_env); wrapped = new_ref; is_weak = false; } template -void JvmInstanceWrapper::swap_to_weak_unsafe() { +void JvmInstanceWrapper::swap_to_weak_unsafe(jni::Env& p_env) { // Assume the reference is currently strong - jni::Env env {jni::Jvm::current_env()}; - jni::JObject new_ref = wrapped.new_weak_ref(env); - wrapped.delete_global_ref(env); + jni::JObject new_ref = wrapped.new_weak_ref(p_env); + wrapped.delete_global_ref(p_env); wrapped = new_ref; is_weak = true; } diff --git a/src/jvm_wrapper/jvm_singleton_wrapper.h b/src/jvm_wrapper/jvm_singleton_wrapper.h index c1c57e6bd3..1d66faa175 100644 --- a/src/jvm_wrapper/jvm_singleton_wrapper.h +++ b/src/jvm_wrapper/jvm_singleton_wrapper.h @@ -1,24 +1,25 @@ #ifndef GODOT_JVM_JVM_SINGLETON_WRAPPER_H #define GODOT_JVM_JVM_SINGLETON_WRAPPER_H -#include "jvm_instance_wrapper.h" #include "jni_lifecycle_manager.h" +#include "jvm_instance_wrapper.h" -#define JVM_SINGLETON_WRAPPER(NAME, FQNAME) \ +#define JVM_SINGLETON_WRAPPER(NAME, FQNAME) \ inline constexpr char NAME##QualifiedName[] = FQNAME; \ class NAME : public JvmSingletonWrapper -#define SINGLETON_CLASS(NAME) \ - friend class JvmSingletonWrapper; \ - \ -public: \ - NAME(const NAME&) = delete; \ - void operator=(const NAME&) = delete; \ - NAME& operator=(NAME&&) noexcept = delete; \ - NAME(NAME&&) noexcept = delete; \ - \ -protected: \ - explicit NAME(jni::JObject p_wrapped) : JvmSingletonWrapper(p_wrapped) {} \ +#define SINGLETON_CLASS(NAME) \ + friend class JvmSingletonWrapper; \ + \ +public: \ + NAME(const NAME&) = delete; \ + void operator=(const NAME&) = delete; \ + NAME& operator=(NAME&&) noexcept = delete; \ + NAME(NAME&&) noexcept = delete; \ + \ +protected: \ + explicit NAME(jni::Env& p_env, jni::JObject p_wrapped) : \ + JvmSingletonWrapper(p_env, p_wrapped) {} \ ~NAME(); /** @@ -36,11 +37,11 @@ class JvmSingletonWrapper : public JvmInstanceWrapper { static Derived* _instance; - static void initialize(); + static void initialize(jni::Env& p_env); static void destroy(); protected: - explicit JvmSingletonWrapper(jni::JObject p_wrapped); + JvmSingletonWrapper(jni::Env& p_env, jni::JObject p_wrapped); ~JvmSingletonWrapper() = default; public: @@ -51,11 +52,11 @@ class JvmSingletonWrapper : public JvmInstanceWrapper { JvmSingletonWrapper& operator=(JvmSingletonWrapper&&) noexcept = delete; JvmSingletonWrapper(JvmSingletonWrapper&& instance) noexcept = delete; - static Derived* create_instance(); + static Derived* create_instance(jni::Env& p_env); }; template -Derived* JvmSingletonWrapper::create_instance() { +Derived* JvmSingletonWrapper::create_instance(jni::Env& p_env) { LOG_ERROR("Can't create a new instance of a this class. Returning the singleton instead"); return _instance; } @@ -70,22 +71,21 @@ Derived& JvmSingletonWrapper::get_instance() { } template -void JvmSingletonWrapper::initialize() { +void JvmSingletonWrapper::initialize(jni::Env& p_env) { JVM_CRASH_COND_MSG(_instance, String(FqName) + " singleton is already initialized."); - jni::Env env {jni::Jvm::current_env()}; jni::JObject class_loader = ClassLoader::get_default_loader(); - jni::JClass singleton_cls = env.load_class(FqName, class_loader); + jni::JClass singleton_cls = p_env.load_class(FqName, class_loader); jni::FieldId singleton_instance_field = - singleton_cls.get_static_field_id(env, "INSTANCE", vformat("L%s;", FqName).replace(".", "/").utf8().ptr()); - jni::JObject singleton_instance = singleton_cls.get_static_object_field(env, singleton_instance_field); + singleton_cls.get_static_field_id(p_env, "INSTANCE", vformat("L%s;", FqName).replace(".", "/").utf8().ptr()); + jni::JObject singleton_instance = singleton_cls.get_static_object_field(p_env, singleton_instance_field); JVM_CRASH_COND_MSG(singleton_instance.is_null(), "Failed to retrieve " + String(FqName) + " singleton"); - _instance = new Derived(singleton_instance); + _instance = new Derived(p_env, singleton_instance); - Derived::initialize_jni_binding(); + Derived::initialize_jni_binding(p_env); } template @@ -95,7 +95,7 @@ void JvmSingletonWrapper::destroy() { } template -JvmSingletonWrapper::JvmSingletonWrapper(jni::JObject p_wrapped) : - JvmInstanceWrapper(p_wrapped) {} +JvmSingletonWrapper::JvmSingletonWrapper(jni::Env& p_env, jni::JObject p_wrapped) : + JvmInstanceWrapper(p_env, p_wrapped) {} #endif// GODOT_JVM_JVM_SINGLETON_WRAPPER_H diff --git a/src/jvm_wrapper/memory/kt_binding.cpp b/src/jvm_wrapper/memory/kt_binding.cpp index 5929b4bb0e..b197ad5d17 100644 --- a/src/jvm_wrapper/memory/kt_binding.cpp +++ b/src/jvm_wrapper/memory/kt_binding.cpp @@ -1,5 +1,5 @@ #include "kt_binding.h" -KtBinding::KtBinding(jni::JObject p_wrapped) : JvmInstanceWrapper(p_wrapped) {} +KtBinding::KtBinding(jni::Env& p_env, jni::JObject p_wrapped) : JvmInstanceWrapper(p_env, p_wrapped) {} KtBinding::~KtBinding() = default; \ No newline at end of file diff --git a/src/jvm_wrapper/memory/kt_binding.h b/src/jvm_wrapper/memory/kt_binding.h index dcf07cc696..c72e4352e7 100644 --- a/src/jvm_wrapper/memory/kt_binding.h +++ b/src/jvm_wrapper/memory/kt_binding.h @@ -6,7 +6,7 @@ JVM_INSTANCE_WRAPPER(KtBinding, "godot.core.memory.GodotBinding") { public: - explicit KtBinding(jni::JObject p_wrapped); + explicit KtBinding(jni::Env& p_env, jni::JObject p_wrapped); ~KtBinding(); }; diff --git a/src/jvm_wrapper/memory/long_string_queue.cpp b/src/jvm_wrapper/memory/long_string_queue.cpp index 7a86ad11b8..cc47bb0e0e 100644 --- a/src/jvm_wrapper/memory/long_string_queue.cpp +++ b/src/jvm_wrapper/memory/long_string_queue.cpp @@ -8,11 +8,10 @@ int LongStringQueue::max_string_size = 512; thread_local static List string_queue;// NOLINT(cert-err58-cpp) -void LongStringQueue::set_string_max_size(int max_size) { - jni::Env env {jni::Jvm::current_env()}; +void LongStringQueue::set_string_max_size(jni::Env& p_env, int max_size) { LongStringQueue::max_string_size = max_size; jvalue buffer_size[1] = {jni::to_jni_arg(max_size)}; - wrapped.call_void_method(env, SET_STRING_MAX_SIZE, buffer_size); + wrapped.call_void_method(p_env, SET_STRING_MAX_SIZE, buffer_size); } String LongStringQueue::poll_string() { @@ -25,11 +24,10 @@ void LongStringQueue::queue_string(const String& str) { string_queue.push_back(str); } -void LongStringQueue::send_string_to_jvm(const String& str) { - jni::Env env {jni::Jvm::current_env()}; - jni::JString java_string = env.new_string(str.utf8().get_data()); +void LongStringQueue::send_string_to_jvm(jni::Env& p_env, const String& str) { + jni::JString java_string = p_env.new_string(str.utf8().get_data()); jvalue args[1] = {jni::to_jni_arg(java_string)}; - wrapped.call_void_method(env, QUEUE_STRING, args); + wrapped.call_void_method(p_env, QUEUE_STRING, args); } void LongStringQueue::send_string_to_cpp(JNIEnv* p_raw_env, jobject p_instance, jstring p_string) { @@ -38,19 +36,4 @@ void LongStringQueue::send_string_to_cpp(JNIEnv* p_raw_env, jobject p_instance, queue_string(nativeString); } -LongStringQueue* LongStringQueue::init() { - jni::Env env {jni::Jvm::current_env()}; - jni::JObject class_loader = ClassLoader::get_default_loader(); - - jni::JClass long_string_queue_cls = env.load_class("godot.core.LongStringQueue", class_loader); - jni::FieldId long_string_queue_instance_field = long_string_queue_cls.get_static_field_id(env, "INSTANCE", "Lgodot/core/LongStringQueue;"); - jni::JObject long_string_queue_instance = long_string_queue_cls.get_static_object_field(env, long_string_queue_instance_field); - JVM_CRASH_COND_MSG(long_string_queue_instance.is_null(), "Failed to retrieve LongStringQueue instance"); - - auto* instance {new LongStringQueue(long_string_queue_instance)}; - long_string_queue_cls.delete_local_ref(env); - - return instance; -} - LongStringQueue::~LongStringQueue() = default; \ No newline at end of file diff --git a/src/jvm_wrapper/memory/long_string_queue.h b/src/jvm_wrapper/memory/long_string_queue.h index 9e3b1064d3..720f5b401c 100644 --- a/src/jvm_wrapper/memory/long_string_queue.h +++ b/src/jvm_wrapper/memory/long_string_queue.h @@ -19,18 +19,14 @@ JVM_SINGLETON_WRAPPER(LongStringQueue, "godot.core.LongStringQueue") { public: static int max_string_size; - void set_string_max_size(int max_size); + void set_string_max_size(jni::Env& p_env, int max_size); + void send_string_to_jvm(jni::Env& p_env, const String& str); static String poll_string(); - static void queue_string(const String& str); - void send_string_to_jvm(const String& str); - static void send_string_to_cpp(JNIEnv* p_raw_env, jobject p_instance, jstring p_string); - static LongStringQueue* init(); - }; #endif// GODOT_JVM_LONG_STRING_QUEUE_H diff --git a/src/jvm_wrapper/memory/memory_manager.cpp b/src/jvm_wrapper/memory/memory_manager.cpp index 9fb88f6e68..1882771b3e 100644 --- a/src/jvm_wrapper/memory/memory_manager.cpp +++ b/src/jvm_wrapper/memory/memory_manager.cpp @@ -104,31 +104,26 @@ void MemoryManager::notify_leak(JNIEnv* p_raw_env, jobject p_instance) { #endif } -void MemoryManager::start(bool force_gc) { - jni::Env env {jni::Jvm::current_env()}; +void MemoryManager::start(jni::Env& p_env, bool force_gc) { jvalue start_args[1] = {jni::to_jni_arg(force_gc)}; - CALL_JVM_METHOD_WITH_ARG(env, START, start_args); + CALL_JVM_METHOD_WITH_ARG(p_env, START, start_args); } -void MemoryManager::setDisplayLeaks(bool b) { - jni::Env env {jni::Jvm::current_env()}; +void MemoryManager::setDisplayLeaks(jni::Env& p_env, bool b) { jvalue args[1] = {jni::to_jni_arg(b)}; - CALL_JVM_METHOD_WITH_ARG(env, SET_DISPLAY, args); + CALL_JVM_METHOD_WITH_ARG(p_env, SET_DISPLAY, args); } -void MemoryManager::clean_up() { - jni::Env env {jni::Jvm::current_env()}; - CALL_JVM_METHOD(env, CLEAN_UP); +void MemoryManager::clean_up(jni::Env& p_env) { + CALL_JVM_METHOD(p_env, CLEAN_UP); } -bool MemoryManager::is_closed() { - jni::Env env {jni::Jvm::current_env()}; - return wrapped.call_boolean_method(env, IS_CLOSED); +bool MemoryManager::is_closed(jni::Env& p_env) { + return wrapped.call_boolean_method(p_env, IS_CLOSED); } -void MemoryManager::close() { - jni::Env env {jni::Jvm::current_env()}; - CALL_JVM_METHOD(env, CLOSE); +void MemoryManager::close(jni::Env& p_env) { + CALL_JVM_METHOD(p_env, CLOSE); } MemoryManager::~MemoryManager() = default; \ No newline at end of file diff --git a/src/jvm_wrapper/memory/memory_manager.h b/src/jvm_wrapper/memory/memory_manager.h index cde2b6268b..45f2fe9478 100644 --- a/src/jvm_wrapper/memory/memory_manager.h +++ b/src/jvm_wrapper/memory/memory_manager.h @@ -43,11 +43,11 @@ JVM_SINGLETON_WRAPPER(MemoryManager, "godot.core.memory.MemoryManager") { static void notify_leak(JNIEnv* p_raw_env, jobject p_instance); public: - void start(bool force_gc); - void setDisplayLeaks(bool b); - void clean_up(); - bool is_closed(); - void close(); + void start(jni::Env& p_env, bool force_gc); + void setDisplayLeaks(jni::Env& p_env, bool b); + void clean_up(jni::Env& p_env); + bool is_closed(jni::Env& p_env); + void close(jni::Env& p_env); }; // clang-format on #endif// GODOT_JVM_MEMORY_MANAGER_H diff --git a/src/jvm_wrapper/memory/transfer_context.cpp b/src/jvm_wrapper/memory/transfer_context.cpp index 709fa339fd..868a911524 100644 --- a/src/jvm_wrapper/memory/transfer_context.cpp +++ b/src/jvm_wrapper/memory/transfer_context.cpp @@ -32,10 +32,9 @@ SharedBuffer* TransferContext::get_and_rewind_buffer(jni::Env& p_env) { return &shared_buffer; } -void TransferContext::remove_script_instance(uint64_t id) { - jni::Env env {jni::Jvm::current_env()}; +void TransferContext::remove_script_instance(jni::Env& p_env, uint64_t id) { jvalue args[1] = {jni::to_jni_arg(id)}; - CALL_JVM_METHOD_WITH_ARG(env, REMOVE_SCRIPT, args); + CALL_JVM_METHOD_WITH_ARG(p_env, REMOVE_SCRIPT, args); } void TransferContext::read_return_value(jni::Env& p_env, Variant& r_ret) { @@ -131,19 +130,19 @@ void TransferContext::create_native_object(JNIEnv* p_raw_env, jobject p_instance JVM_ERR_FAIL_COND_MSG(!ptr, vformat("Failed to instantiate class %s", class_name)); #endif + jni::Env env {p_raw_env}; + KotlinBindingManager::set_instance_binding(ptr); int script_index {static_cast(p_script_index)}; if (script_index != -1) { - KtObject* kt_object = memnew(KtObject(jni::JObject(p_object), ptr->is_ref_counted())); + KtObject* kt_object = memnew(KtObject(env, jni::JObject(p_object), ptr->is_ref_counted())); Ref kotlin_script {TypeManager::get_instance().get_user_script_for_index(script_index)}; - JvmInstance* script = memnew(JvmInstance(ptr, kt_object, kotlin_script.ptr())); + JvmInstance* script = memnew(JvmInstance(env, ptr, kt_object, kotlin_script.ptr())); ptr->set_script_instance(script); } id = ptr->get_instance_id(); - jni::Env env {p_raw_env}; - SharedBuffer* buffer {get_instance().get_and_rewind_buffer(env)}; buffer->increment_position(encode_uint64(raw_ptr, buffer->get_cursor())); buffer->increment_position(encode_uint64(id, buffer->get_cursor())); diff --git a/src/jvm_wrapper/memory/transfer_context.h b/src/jvm_wrapper/memory/transfer_context.h index 612f47afae..83a420ba2a 100644 --- a/src/jvm_wrapper/memory/transfer_context.h +++ b/src/jvm_wrapper/memory/transfer_context.h @@ -24,21 +24,15 @@ JVM_SINGLETON_WRAPPER(TransferContext, "godot.core.memory.TransferContext") { public: void write_return_value(jni::Env& p_env, Variant& variant); - void read_return_value(jni::Env& p_env, Variant& r_ret); - void write_args(jni::Env& p_env, const Variant** p_args, int args_size); - uint32_t read_args(jni::Env& p_env, Variant* args); - void remove_script_instance(uint64_t id); + void remove_script_instance(jni::Env& p_env, uint64_t id); static void icall(JNIEnv* rawEnv, jobject instance, jlong j_ptr, jlong j_method_ptr, jint expectedReturnType); - static void create_native_object(JNIEnv* p_raw_env, jobject instance, jint p_class_index, jobject p_object, jint p_script_index); - static void get_singleton(JNIEnv* p_raw_env, jobject p_instance, jint p_class_index); - static void free_object(JNIEnv* p_raw_env, jobject p_instance, jlong p_raw_ptr); private: diff --git a/src/jvm_wrapper/memory/type_manager.h b/src/jvm_wrapper/memory/type_manager.h index 93424475e3..4b465890e4 100644 --- a/src/jvm_wrapper/memory/type_manager.h +++ b/src/jvm_wrapper/memory/type_manager.h @@ -24,8 +24,8 @@ JVM_SINGLETON_WRAPPER(TypeManager, "godot.core.TypeManager") { const Ref& get_user_script_for_index(int p_index) const; Ref get_user_script_from_name(const StringName& name) const; - void register_engine_types(jni::Env & p_env, jni::JObjectArray & p_engine_types); - void register_engine_singletons(jni::Env & p_env, jni::JObjectArray & p_singletons); + void register_engine_types(jni::Env& p_env, jni::JObjectArray & p_engine_types); + void register_engine_singletons(jni::Env& p_env, jni::JObjectArray & p_singletons); void create_and_update_scripts(Vector & classes); template diff --git a/src/jvm_wrapper/registration/kt_class.cpp b/src/jvm_wrapper/registration/kt_class.cpp index af58087959..3067cf1800 100644 --- a/src/jvm_wrapper/registration/kt_class.cpp +++ b/src/jvm_wrapper/registration/kt_class.cpp @@ -4,16 +4,15 @@ #include "jvm_wrapper/memory/transfer_context.h" #include "gd_kotlin.h" -KtClass::KtClass(jni::JObject p_wrapped) : JvmInstanceWrapper(p_wrapped), +KtClass::KtClass(jni::Env& p_env, jni::JObject p_wrapped) : JvmInstanceWrapper(p_env, p_wrapped), constructors {}, _has_notification() { - jni::Env env {jni::Jvm::current_env()}; LOCAL_FRAME(4); - registered_class_name = get_registered_name(env); - relative_source_path = get_relative_source_path(env); - compilation_time_relative_registration_file_path = get_compilation_time_relative_registration_file_path(env); - base_godot_class = get_base_godot_class(env); - _has_notification = get_has_notification(env); + registered_class_name = get_registered_name(p_env); + relative_source_path = get_relative_source_path(p_env); + compilation_time_relative_registration_file_path = get_compilation_time_relative_registration_file_path(p_env); + base_godot_class = get_base_godot_class(p_env); + _has_notification = get_has_notification(p_env); } KtClass::~KtClass() { @@ -39,7 +38,7 @@ KtObject* KtClass::create_instance(jni::Env& env, const Variant** p_args, int p_ JVM_CRASH_COND_MSG(constructor == nullptr, vformat("Cannot find constructor with %s parameters for class %s", p_arg_count, registered_class_name)); #endif - KtObject* jvm_instance {constructor->create_instance(p_args, p_owner)}; + KtObject* jvm_instance {constructor->create_instance(env, p_args, p_owner)}; #ifdef DEV_ENABLED LOG_VERBOSE(vformat("Instantiated an object with resource path %s", registered_class_name)); @@ -103,7 +102,7 @@ void KtClass::fetch_methods(jni::Env& env) { jni::JObjectArray functionsArray = CALL_JVM_METHOD(env, GET_FUNCTIONS); for (int i = 0; i < functionsArray.length(env); i++) { jni::JObject object = functionsArray.get(env, i); - auto* ktFunction {new KtFunction(object)}; + auto* ktFunction {new KtFunction(env, object)}; methods[ktFunction->get_name()] = ktFunction; #ifdef DEV_ENABLED LOG_VERBOSE(vformat("Fetched method %s for class %s", ktFunction->get_name(), registered_class_name)); @@ -115,7 +114,7 @@ void KtClass::fetch_methods(jni::Env& env) { void KtClass::fetch_properties(jni::Env& env) { jni::JObjectArray propertiesArray = CALL_JVM_METHOD(env, GET_PROPERTIES); for (int i = 0; i < propertiesArray.length(env); i++) { - auto* ktProperty {new KtProperty(propertiesArray.get(env, i))}; + auto* ktProperty {new KtProperty(env, propertiesArray.get(env, i))}; properties[ktProperty->get_name()] = ktProperty; #ifdef DEV_ENABLED LOG_VERBOSE(vformat("Fetched property %s for class %s", ktProperty->get_name(), registered_class_name)); @@ -127,7 +126,7 @@ void KtClass::fetch_properties(jni::Env& env) { void KtClass::fetch_signals(jni::Env& env) { jni::JObjectArray signal_info_array = CALL_JVM_METHOD(env, GET_SIGNAL_INFOS); for (int i = 0; i < signal_info_array.length(env); i++) { - auto* kt_signal_info {new KtSignalInfo(signal_info_array.get(env, i))}; + auto* kt_signal_info {new KtSignalInfo(env, signal_info_array.get(env, i))}; signal_infos[kt_signal_info->name] = kt_signal_info; #ifdef DEV_ENABLED LOG_VERBOSE(vformat("Fetched signal %s for class %s", kt_signal_info->name, registered_class_name)); @@ -142,7 +141,7 @@ void KtClass::fetch_constructors(jni::Env& env) { const jni::JObject& constructor {constructors_array.get(env, i)}; KtConstructor* kt_constructor {nullptr}; if (constructor.obj != nullptr) { - kt_constructor = new KtConstructor(constructor); + kt_constructor = new KtConstructor(env, constructor); #ifdef DEV_ENABLED LOG_VERBOSE(vformat("Fetched constructor with %s parameters for class %s", i, registered_class_name)); #endif @@ -174,12 +173,11 @@ const Dictionary KtClass::get_rpc_config() { return rpc_configs; } -void KtClass::do_notification(KtObject* p_instance, int p_notification, bool p_reversed) { +void KtClass::do_notification(jni::Env& env, KtObject* p_instance, int p_notification, bool p_reversed) { if (!_has_notification) { return; } - jni::Env env { jni::Jvm::current_env() }; Variant notification = p_notification; Variant reversed = p_reversed; const int arg_size = 2; @@ -191,8 +189,7 @@ void KtClass::do_notification(KtObject* p_instance, int p_notification, bool p_r CALL_JVM_METHOD_WITH_ARG(env, DO_NOTIFICATION, call_args); } -void KtClass::fetch_members() { - jni::Env env {jni::Jvm::current_env()}; +void KtClass::fetch_members(jni::Env& env) { fetch_registered_supertypes(env); fetch_methods(env); fetch_properties(env); diff --git a/src/jvm_wrapper/registration/kt_class.h b/src/jvm_wrapper/registration/kt_class.h index c4d9cc581b..ced137b5c7 100644 --- a/src/jvm_wrapper/registration/kt_class.h +++ b/src/jvm_wrapper/registration/kt_class.h @@ -49,7 +49,7 @@ JVM_INSTANCE_WRAPPER(KtClass, "godot.core.KtClass") { Vector registered_supertypes; StringName base_godot_class; - explicit KtClass(jni::JObject p_wrapped); + explicit KtClass(jni::Env& p_env, jni::JObject p_wrapped); ~KtClass(); @@ -67,11 +67,11 @@ JVM_INSTANCE_WRAPPER(KtClass, "godot.core.KtClass") { void get_signal_list(List* p_list); - void fetch_members(); + void fetch_members(jni::Env& env); const Dictionary get_rpc_config(); - void do_notification(KtObject* p_instance, int p_notification, bool p_reversed); + void do_notification(jni::Env& env, KtObject* p_instance, int p_notification, bool p_reversed); private: HashMap methods; diff --git a/src/jvm_wrapper/registration/kt_constructor.cpp b/src/jvm_wrapper/registration/kt_constructor.cpp index c5de290c95..961f99bb31 100644 --- a/src/jvm_wrapper/registration/kt_constructor.cpp +++ b/src/jvm_wrapper/registration/kt_constructor.cpp @@ -2,18 +2,16 @@ #include "gd_kotlin.h" -KtConstructor::KtConstructor(jni::JObject p_wrapped) : JvmInstanceWrapper(p_wrapped), +KtConstructor::KtConstructor(jni::Env& p_env, jni::JObject p_wrapped) : JvmInstanceWrapper(p_env, p_wrapped), parameter_count(0) { - jni::Env env {jni::Jvm::current_env()}; - parameter_count = static_cast(wrapped.call_int_method(env, GET_PARAMETER_COUNT)); + parameter_count = static_cast(wrapped.call_int_method(p_env, GET_PARAMETER_COUNT)); } -KtObject* KtConstructor::create_instance(const Variant** p_args, Object* p_owner) { - jni::Env env {jni::Jvm::current_env()}; - TransferContext::get_instance().write_args(env, p_args, parameter_count); +KtObject* KtConstructor::create_instance(jni::Env& p_env, const Variant** p_args, Object* p_owner) { + TransferContext::get_instance().write_args(p_env, p_args, parameter_count); uint64_t id = p_owner->get_instance_id(); jvalue args[2] = {jni::to_jni_arg(p_owner), jni::to_jni_arg(id)}; - jni::JObject j_kt_object = CALL_JVM_METHOD_WITH_ARG(env, CONSTRUCT, args); - return memnew(KtObject(j_kt_object, p_owner->is_ref_counted())); + jni::JObject j_kt_object = CALL_JVM_METHOD_WITH_ARG(p_env, CONSTRUCT, args); + return memnew(KtObject(p_env, j_kt_object, p_owner->is_ref_counted())); } \ No newline at end of file diff --git a/src/jvm_wrapper/registration/kt_constructor.h b/src/jvm_wrapper/registration/kt_constructor.h index dff0be27d8..00a54e3ab2 100644 --- a/src/jvm_wrapper/registration/kt_constructor.h +++ b/src/jvm_wrapper/registration/kt_constructor.h @@ -16,9 +16,9 @@ JVM_INSTANCE_WRAPPER(KtConstructor, "godot.core.KtConstructor") { // clang-format on public: - explicit KtConstructor(jni::JObject p_wrapped); + explicit KtConstructor(jni::Env& p_env, jni::JObject p_wrapped); ~KtConstructor() = default; - KtObject* create_instance(const Variant** p_args, Object* p_owner); + KtObject* create_instance(jni::Env& env, const Variant** p_args, Object* p_owner); private: int parameter_count; diff --git a/src/jvm_wrapper/registration/kt_function.cpp b/src/jvm_wrapper/registration/kt_function.cpp index f9f5cabaf2..2a46798619 100644 --- a/src/jvm_wrapper/registration/kt_function.cpp +++ b/src/jvm_wrapper/registration/kt_function.cpp @@ -3,10 +3,9 @@ #include "gd_kotlin.h" #include "jni/class_loader.h" -KtFunction::KtFunction(jni::JObject p_wrapped) : JvmInstanceWrapper(p_wrapped), parameter_count(-1) { - jni::Env env {jni::Jvm::current_env()}; - method_info = new KtFunctionInfo( CALL_JVM_METHOD(env, GET_FUNCTION_INFO)); - parameter_count = wrapped.call_int_method(env, GET_PARAMETER_COUNT); +KtFunction::KtFunction(jni::Env& p_env, jni::JObject p_wrapped) : JvmInstanceWrapper(p_env, p_wrapped), parameter_count(-1) { + method_info = new KtFunctionInfo(p_env, CALL_JVM_METHOD(p_env, GET_FUNCTION_INFO)); + parameter_count = wrapped.call_int_method(p_env, GET_PARAMETER_COUNT); } KtFunction::~KtFunction() { @@ -33,32 +32,28 @@ KtFunctionInfo* KtFunction::get_kt_function_info() { return method_info; } -void KtFunction::invoke(const KtObject* instance, const Variant** p_args, int args_count, Variant& r_ret) { - jni::Env env {jni::Jvm::current_env()}; - +void KtFunction::invoke(jni::Env& p_env, const KtObject* instance, const Variant** p_args, int args_count, Variant& r_ret) { TransferContext& transferContext = TransferContext::get_instance(); - transferContext.write_args(env, p_args, args_count); + transferContext.write_args(p_env, p_args, args_count); jvalue call_args[1] = {jni::to_jni_arg(instance->get_wrapped())}; - CALL_JVM_METHOD_WITH_ARG(env, INVOKE, call_args); - transferContext.read_return_value(env, r_ret); + CALL_JVM_METHOD_WITH_ARG(p_env, INVOKE, call_args); + transferContext.read_return_value(p_env, r_ret); } -KtFunctionInfo::KtFunctionInfo(jni::JObject p_wrapped) : JvmInstanceWrapper(p_wrapped) { - jni::Env env {jni::Jvm::current_env()}; - - jni::JString string = CALL_JVM_METHOD(env, GET_NAME); - name = env.from_jstring(string); +KtFunctionInfo::KtFunctionInfo(jni::Env& p_env, jni::JObject p_wrapped) : JvmInstanceWrapper(p_env, p_wrapped) { + jni::JString string = CALL_JVM_METHOD(p_env, GET_NAME); + name = p_env.from_jstring(string); - jni::JObjectArray propertyInfoArray = CALL_JVM_METHOD(env, GET_ARGUMENTS); - for (int i = 0; i < propertyInfoArray.length(env); i++) { - arguments.push_back(new KtPropertyInfo(propertyInfoArray.get(env, i))); + jni::JObjectArray propertyInfoArray = CALL_JVM_METHOD(p_env, GET_ARGUMENTS); + for (int i = 0; i < propertyInfoArray.length(p_env); i++) { + arguments.push_back(new KtPropertyInfo(p_env, propertyInfoArray.get(p_env, i))); } - return_val = new KtPropertyInfo(CALL_JVM_METHOD(env, GET_RETURN_VAL)); - rpc_config = new KtRpcConfig(CALL_JVM_METHOD(env, GET_RPC_CONFIG)); + return_val = new KtPropertyInfo(p_env, CALL_JVM_METHOD(p_env, GET_RETURN_VAL)); + rpc_config = new KtRpcConfig(p_env, CALL_JVM_METHOD(p_env, GET_RPC_CONFIG)); - propertyInfoArray.delete_local_ref(env); - string.delete_local_ref(env); + propertyInfoArray.delete_local_ref(p_env); + string.delete_local_ref(p_env); } KtFunctionInfo::~KtFunctionInfo() { diff --git a/src/jvm_wrapper/registration/kt_function.h b/src/jvm_wrapper/registration/kt_function.h index 3e1d394f81..eddb1244f5 100644 --- a/src/jvm_wrapper/registration/kt_function.h +++ b/src/jvm_wrapper/registration/kt_function.h @@ -23,7 +23,7 @@ JVM_INSTANCE_WRAPPER(KtFunctionInfo, "godot.core.KtFunctionInfo") { // clang-format on public: - explicit KtFunctionInfo(jni::JObject p_wrapped); + explicit KtFunctionInfo(jni::Env& p_env, jni::JObject p_wrapped); ~KtFunctionInfo(); String name; @@ -54,7 +54,7 @@ JVM_INSTANCE_WRAPPER(KtFunction, "godot.core.KtFunction") { KtFunctionInfo* method_info; public: - explicit KtFunction(jni::JObject p_wrapped); + explicit KtFunction(jni::Env& p_env, jni::JObject p_wrapped); ~KtFunction(); StringName get_name() const; @@ -64,7 +64,7 @@ JVM_INSTANCE_WRAPPER(KtFunction, "godot.core.KtFunction") { MethodInfo get_member_info(); KtFunctionInfo* get_kt_function_info(); - void invoke(const KtObject* instance, const Variant** p_args, int args_count, Variant& r_ret); + void invoke(jni::Env& p_env, const KtObject* instance, const Variant** p_args, int args_count, Variant& r_ret); }; #endif// GODOT_JVM_KT_FUNCTION_H diff --git a/src/jvm_wrapper/registration/kt_object.cpp b/src/jvm_wrapper/registration/kt_object.cpp index dbbc171283..e9ef434db8 100644 --- a/src/jvm_wrapper/registration/kt_object.cpp +++ b/src/jvm_wrapper/registration/kt_object.cpp @@ -1,6 +1,6 @@ #include "kt_object.h" -KtObject::KtObject(jni::JObject p_wrapped, bool p_is_ref) : JvmInstanceWrapper(p_wrapped), is_ref(p_is_ref) {} +KtObject::KtObject(jni::Env& p_env, jni::JObject p_wrapped, bool p_is_ref) : JvmInstanceWrapper(p_env, p_wrapped), is_ref(p_is_ref) {} KtObject::~KtObject() { if (is_ref) { return; } diff --git a/src/jvm_wrapper/registration/kt_object.h b/src/jvm_wrapper/registration/kt_object.h index 5f2f30f171..56cbede065 100644 --- a/src/jvm_wrapper/registration/kt_object.h +++ b/src/jvm_wrapper/registration/kt_object.h @@ -21,7 +21,7 @@ JVM_INSTANCE_WRAPPER(KtObject, "godot.core.KtObject") { bool is_ref; public: - explicit KtObject(jni::JObject p_wrapped, bool p_is_ref); + explicit KtObject(jni::Env& p_env, jni::JObject p_wrapped, bool p_is_ref); ~KtObject(); }; diff --git a/src/jvm_wrapper/registration/kt_property.cpp b/src/jvm_wrapper/registration/kt_property.cpp index 495945147e..cc1dc30986 100644 --- a/src/jvm_wrapper/registration/kt_property.cpp +++ b/src/jvm_wrapper/registration/kt_property.cpp @@ -3,35 +3,25 @@ #include "gd_kotlin.h" #include "jni/class_loader.h" -// clang-format off +KtPropertyInfo::KtPropertyInfo(jni::Env& p_env, jni::JObject p_wrapped) : JvmInstanceWrapper(p_env, p_wrapped) { + type = static_cast(wrapped.call_int_method(p_env, GET_TYPE)); + jni::JString jname = CALL_JVM_METHOD(p_env, GET_NAME); + name = p_env.from_jstring(jname); + jni::JString jclass_name = CALL_JVM_METHOD(p_env, GET_CLASS_NAME); + class_name = p_env.from_jstring(jclass_name); + hint = static_cast(wrapped.call_int_method(p_env, GET_HINT)); -// clang-format on + jni::JString jhint_string = CALL_JVM_METHOD(p_env, GET_HINT_STRING); + hint_string = p_env.from_jstring(jhint_string); -KtPropertyInfo::KtPropertyInfo(jni::JObject p_wrapped) : JvmInstanceWrapper(p_wrapped) { - jni::Env env {jni::Jvm::current_env()}; + visible_in_editor = wrapped.call_boolean_method(p_env, GET_VISIBLE_IN_EDITOR); - - type = static_cast(wrapped.call_int_method(env, GET_TYPE)); - - jni::JString jname = CALL_JVM_METHOD(env, GET_NAME); - name = env.from_jstring(jname); - - jni::JString jclass_name = CALL_JVM_METHOD(env, GET_CLASS_NAME); - class_name = env.from_jstring(jclass_name); - - hint = static_cast(wrapped.call_int_method(env, GET_HINT)); - - jni::JString jhint_string = CALL_JVM_METHOD(env, GET_HINT_STRING); - hint_string = env.from_jstring(jhint_string); - - visible_in_editor = wrapped.call_boolean_method(env, GET_VISIBLE_IN_EDITOR); - - jhint_string.delete_local_ref(env); - jclass_name.delete_local_ref(env); - jname.delete_local_ref(env); + jhint_string.delete_local_ref(p_env); + jclass_name.delete_local_ref(p_env); + jname.delete_local_ref(p_env); } PropertyInfo KtPropertyInfo::toPropertyInfo() { @@ -49,10 +39,9 @@ PropertyInfo KtPropertyInfo::toPropertyInfo() { return info; } -KtProperty::KtProperty(jni::JObject p_wrapped) : JvmInstanceWrapper(p_wrapped) { - jni::Env env {jni::Jvm::current_env()}; - propertyInfo = new KtPropertyInfo(CALL_JVM_METHOD(env, GET_KT_PROPERTY_INFO)); - is_ref = wrapped.call_boolean_method(env, IS_REF); +KtProperty::KtProperty(jni::Env& p_env, jni::JObject p_wrapped) : JvmInstanceWrapper(p_env, p_wrapped) { + propertyInfo = new KtPropertyInfo(p_env, CALL_JVM_METHOD(p_env, GET_KT_PROPERTY_INFO)); + is_ref = wrapped.call_boolean_method(p_env, IS_REF); } KtProperty::~KtProperty() { @@ -67,32 +56,29 @@ PropertyInfo KtProperty::get_member_info() { return propertyInfo->toPropertyInfo(); } -void KtProperty::call_get(KtObject* instance, Variant& r_ret) { - jni::Env env {jni::Jvm::current_env()}; +void KtProperty::call_get(jni::Env& p_env, KtObject* instance, Variant& r_ret) { jvalue call_args[1] = {jni::to_jni_arg(instance->get_wrapped())}; - wrapped.call_void_method(env, CALL_GET, call_args); - TransferContext::get_instance().read_return_value(env, r_ret); + wrapped.call_void_method(p_env, CALL_GET, call_args); + TransferContext::get_instance().read_return_value(p_env, r_ret); } -void KtProperty::call_set(KtObject* instance, const Variant& p_value) { - jni::Env env {jni::Jvm::current_env()}; +void KtProperty::call_set(jni::Env& p_env, KtObject* instance, const Variant& p_value) { const Variant* arg[1] = {&p_value}; - TransferContext::get_instance().write_args(env, arg, 1); + TransferContext::get_instance().write_args(p_env, arg, 1); jvalue args[1] = {jni::to_jni_arg(instance->get_wrapped())}; - wrapped.call_void_method(env, CALL_SET, args); + wrapped.call_void_method(p_env, CALL_SET, args); } #ifdef TOOLS_ENABLED -void KtProperty::safe_call_get(KtObject* instance, Variant& r_ret) { - jni::Env env {jni::Jvm::current_env()}; +void KtProperty::safe_call_get(jni::Env& p_env, KtObject* instance, Variant& r_ret) { jvalue call_args[1] = {jni::to_jni_arg(instance->get_wrapped())}; - wrapped.call_void_method_noexcept(env, CALL_GET, call_args); - if (env.exception_check()) { + wrapped.call_void_method_noexcept(p_env, CALL_GET, call_args); + if (p_env.exception_check()) { Callable::CallError error; Variant::construct(propertyInfo->type, r_ret, {}, 0, error); - env.exception_clear(); + p_env.exception_clear(); return; } - TransferContext::get_instance().read_return_value(env, r_ret); + TransferContext::get_instance().read_return_value(p_env, r_ret); } #endif diff --git a/src/jvm_wrapper/registration/kt_property.h b/src/jvm_wrapper/registration/kt_property.h index 4d873c5a36..59a9f68c40 100644 --- a/src/jvm_wrapper/registration/kt_property.h +++ b/src/jvm_wrapper/registration/kt_property.h @@ -27,7 +27,7 @@ JVM_INSTANCE_WRAPPER(KtPropertyInfo, "godot.core.KtPropertyInfo") { // clang-format on public: - explicit KtPropertyInfo(jni::JObject p_wrapped); + explicit KtPropertyInfo(jni::Env& p_env, jni::JObject p_wrapped); ~KtPropertyInfo() = default; Variant::Type type; @@ -62,18 +62,18 @@ JVM_INSTANCE_WRAPPER(KtProperty, "godot.core.KtProperty") { bool is_ref; public: - explicit KtProperty(jni::JObject p_wrapped); + explicit KtProperty(jni::Env& p_env, jni::JObject p_wrapped); ~KtProperty(); StringName get_name() const; PropertyInfo get_member_info(); - void call_get(KtObject* instance, Variant& r_ret); - void call_set(KtObject* instance, const Variant& p_value); + void call_get(jni::Env& p_env, KtObject* instance, Variant& r_ret); + void call_set(jni::Env& p_env, KtObject* instance, const Variant& p_value); #ifdef TOOLS_ENABLED - void safe_call_get(KtObject* instance, Variant& r_ret); + void safe_call_get(jni::Env& p_env, KtObject* instance, Variant& r_ret); #endif }; diff --git a/src/jvm_wrapper/registration/kt_rpc_config.cpp b/src/jvm_wrapper/registration/kt_rpc_config.cpp index 182fd0ea65..568075e835 100644 --- a/src/jvm_wrapper/registration/kt_rpc_config.cpp +++ b/src/jvm_wrapper/registration/kt_rpc_config.cpp @@ -1,6 +1,6 @@ #include "kt_rpc_config.h" -KtRpcConfig::KtRpcConfig(jni::JObject p_wrapped) : JvmInstanceWrapper(p_wrapped) { +KtRpcConfig::KtRpcConfig(jni::Env& p_env, jni::JObject p_wrapped) : JvmInstanceWrapper(p_env, p_wrapped) { jni::Env env {jni::Jvm::current_env()}; rpc_mode = static_cast(wrapped.call_int_method(env, GET_RPC_MODE_ID)); diff --git a/src/jvm_wrapper/registration/kt_rpc_config.h b/src/jvm_wrapper/registration/kt_rpc_config.h index 22012daff1..40f42b3526 100644 --- a/src/jvm_wrapper/registration/kt_rpc_config.h +++ b/src/jvm_wrapper/registration/kt_rpc_config.h @@ -23,7 +23,7 @@ JVM_INSTANCE_WRAPPER(KtRpcConfig, "godot.core.KtRpcConfig") { // clang-format on public: - explicit KtRpcConfig(jni::JObject p_wrapped); + explicit KtRpcConfig(jni::Env& p_env, jni::JObject p_wrapped); ~KtRpcConfig() = default; MultiplayerAPI::RPCMode rpc_mode; diff --git a/src/jvm_wrapper/registration/kt_signal_info.cpp b/src/jvm_wrapper/registration/kt_signal_info.cpp index 187af84a15..dbb16e8d8a 100644 --- a/src/jvm_wrapper/registration/kt_signal_info.cpp +++ b/src/jvm_wrapper/registration/kt_signal_info.cpp @@ -2,20 +2,19 @@ #include "jni/class_loader.h" -KtSignalInfo::KtSignalInfo(jni::JObject p_wrapped) : JvmInstanceWrapper(p_wrapped) { - jni::Env env {jni::Jvm::current_env()}; +KtSignalInfo::KtSignalInfo(jni::Env& p_env, jni::JObject p_wrapped) : JvmInstanceWrapper(p_env, p_wrapped) { - jni::JString string = CALL_JVM_METHOD(env, GET_NAME); - name = env.from_jstring(string); + jni::JString string = CALL_JVM_METHOD(p_env, GET_NAME); + name = p_env.from_jstring(string); - jni::JObjectArray args_array {CALL_JVM_METHOD(env, GET_ARGUMENTS)}; + jni::JObjectArray args_array {CALL_JVM_METHOD(p_env, GET_ARGUMENTS)}; - for (int i = 0; i < args_array.length(env); i++) { - arguments.push_back(new KtPropertyInfo(args_array.get(env, i))); + for (int i = 0; i < args_array.length(p_env); i++) { + arguments.push_back(new KtPropertyInfo(p_env, args_array.get(p_env, i))); } - string.delete_local_ref(env); - args_array.delete_local_ref(env); + string.delete_local_ref(p_env); + args_array.delete_local_ref(p_env); } KtSignalInfo::~KtSignalInfo() { diff --git a/src/jvm_wrapper/registration/kt_signal_info.h b/src/jvm_wrapper/registration/kt_signal_info.h index da88606fd5..c76a47dd6f 100644 --- a/src/jvm_wrapper/registration/kt_signal_info.h +++ b/src/jvm_wrapper/registration/kt_signal_info.h @@ -18,7 +18,7 @@ JVM_INSTANCE_WRAPPER(KtSignalInfo, "godot.core.KtSignalInfo") { // clang-format on public: - explicit KtSignalInfo(jni::JObject p_wrapped); + explicit KtSignalInfo(jni::Env& p_env, jni::JObject p_wrapped); ~KtSignalInfo(); String name; diff --git a/src/kt_variant.h b/src/kt_variant.h index 4f80d5e021..8442447ad1 100644 --- a/src/kt_variant.h +++ b/src/kt_variant.h @@ -48,7 +48,8 @@ namespace ktvariant { int size = char_string.size(); if (unlikely(size > LongStringQueue::max_string_size)) { des->increment_position(encode_uint32(true, des->get_cursor())); - LongStringQueue::get_instance().send_string_to_jvm(str); + jni::Env env = jni::Jvm::current_env(); + LongStringQueue::get_instance().send_string_to_jvm(env, str); } else { des->increment_position(encode_uint32(false, des->get_cursor())); des->increment_position(encode_uint32(char_string.size(), des->get_cursor())); diff --git a/src/script/jvm_instance.cpp b/src/script/jvm_instance.cpp index d51f1d890b..995100599f 100644 --- a/src/script/jvm_instance.cpp +++ b/src/script/jvm_instance.cpp @@ -4,17 +4,18 @@ #include "jvm_wrapper/registration/kt_class.h" #include "language/kotlin_language.h" -JvmInstance::JvmInstance(Object* p_owner, KtObject* p_kt_object, JvmScript* p_script) : +JvmInstance::JvmInstance(jni::Env& p_env, Object* p_owner, KtObject* p_kt_object, JvmScript* p_script) : owner(p_owner), kt_object(p_kt_object), kt_class(p_script->kotlin_class), script(p_script), delete_flag(true) { - kt_object->swap_to_weak_unsafe(); + kt_object->swap_to_weak_unsafe(p_env); } JvmInstance::~JvmInstance() { - if (delete_flag) { TransferContext::get_instance().remove_script_instance(owner->get_instance_id()); } + jni::Env env {jni::Jvm::current_env()}; + if (delete_flag) { TransferContext::get_instance().remove_script_instance(env, owner->get_instance_id()); } memdelete(kt_object); } @@ -24,9 +25,10 @@ Object* JvmInstance::get_owner() { bool JvmInstance::set(const StringName& p_name, const Variant& p_value) { jni::LocalFrame localFrame(1000); + jni::Env env {jni::Jvm::current_env()}; if (KtProperty* ktProperty {kt_class->get_property(p_name)}) { - ktProperty->call_set(kt_object, p_value); + ktProperty->call_set(env, kt_object, p_value); return true; } @@ -35,7 +37,7 @@ bool JvmInstance::set(const StringName& p_name, const Variant& p_value) { const int arg_count = 2; Variant name = p_name; const Variant* args[arg_count] {&name, &p_value}; - function->invoke(kt_object, args, arg_count, ret); + function->invoke(env, kt_object, args, arg_count, ret); return true; } @@ -44,10 +46,11 @@ bool JvmInstance::set(const StringName& p_name, const Variant& p_value) { bool JvmInstance::get(const StringName& p_name, Variant& r_ret) const { jni::LocalFrame localFrame(1000); + jni::Env env {jni::Jvm::current_env()}; KtProperty* ktProperty {kt_class->get_property(p_name)}; if (ktProperty) { - ktProperty->call_get(kt_object, r_ret); + ktProperty->call_get(env, kt_object, r_ret); return true; } @@ -61,7 +64,7 @@ bool JvmInstance::get(const StringName& p_name, Variant& r_ret) const { const int arg_count = 1; Variant name = p_name; const Variant* args[arg_count] = {&name}; - function->invoke(kt_object, args, arg_count, r_ret); + function->invoke(env, kt_object, args, arg_count, r_ret); return true; } @@ -71,10 +74,11 @@ bool JvmInstance::get(const StringName& p_name, Variant& r_ret) const { #ifdef TOOLS_ENABLED bool JvmInstance::get_or_default(const StringName& p_name, Variant& r_ret) const { jni::LocalFrame localFrame(1000); + jni::Env env {jni::Jvm::current_env()}; KtProperty* ktProperty {kt_class->get_property(p_name)}; if (ktProperty) { - ktProperty->safe_call_get(kt_object, r_ret); + ktProperty->safe_call_get(env, kt_object, r_ret); return true; } else { return false; @@ -84,10 +88,11 @@ bool JvmInstance::get_or_default(const StringName& p_name, Variant& r_ret) const void JvmInstance::get_property_list(List* p_properties) const { kt_class->get_property_list(p_properties); + jni::Env env {jni::Jvm::current_env()}; if (KtFunction* function {kt_class->get_method(SNAME("_get_property_list"))}) { Variant ret_var; - function->invoke(kt_object, {}, 0, ret_var); + function->invoke(env, kt_object, {}, 0, ret_var); Array ret_array = ret_var; for (int i = 0; i < ret_array.size(); ++i) { p_properties->push_back(PropertyInfo::from_dict(ret_array.get(i))); @@ -112,10 +117,12 @@ bool JvmInstance::has_method(const StringName& p_method) const { } Variant JvmInstance::callp(const StringName& p_method, const Variant** p_args, int p_argcount, Callable::CallError& r_error) { + jni::Env env {jni::Jvm::current_env()}; + KtFunction* function {kt_class->get_method(p_method)}; Variant ret_var; if (function) { - function->invoke(kt_object, p_args, p_argcount, ret_var); + function->invoke(env, kt_object, p_args, p_argcount, ret_var); } else { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; } @@ -125,16 +132,19 @@ Variant JvmInstance::callp(const StringName& p_method, const Variant** p_args, i void JvmInstance::notification(int p_notification, bool p_reversed) { if (p_notification == Object::NOTIFICATION_PREDELETE) { delete_flag = false; } - kt_class->do_notification(kt_object, p_notification, p_reversed); + jni::Env env {jni::Jvm::current_env()}; + kt_class->do_notification(env, kt_object, p_notification, p_reversed); } void JvmInstance::validate_property(PropertyInfo& p_property) const { + jni::Env env {jni::Jvm::current_env()}; + if (KtFunction* function {kt_class->get_method(SNAME("_validate_property"))}) { Variant ret_var; Variant property_arg = (Dictionary) p_property; const int arg_count {1}; const Variant* args[arg_count] = {&property_arg}; - function->invoke(kt_object, args, arg_count, ret_var); + function->invoke(env, kt_object, args, arg_count, ret_var); p_property = PropertyInfo::from_dict(property_arg); } } @@ -174,12 +184,14 @@ ScriptLanguage* JvmInstance::get_language() { } bool JvmInstance::property_can_revert(const StringName& p_name) const { + jni::Env env {jni::Jvm::current_env()}; + if (KtFunction* function {kt_class->get_method(SNAME("_property_can_revert"))}) { const int arg_count = 1; Variant ret; Variant name = p_name; const Variant* args[arg_count] = {&name}; - function->invoke(kt_object, args, arg_count, ret); + function->invoke(env, kt_object, args, arg_count, ret); return ret.operator bool(); } @@ -187,11 +199,13 @@ bool JvmInstance::property_can_revert(const StringName& p_name) const { } bool JvmInstance::property_get_revert(const StringName& p_name, Variant& r_ret) const { + jni::Env env {jni::Jvm::current_env()}; + if (KtFunction* function {kt_class->get_method(SNAME("_property_get_revert"))}) { const int arg_count = 1; Variant name = p_name; const Variant* args[arg_count] = {&name}; - function->invoke(kt_object, args, arg_count, r_ret); + function->invoke(env, kt_object, args, arg_count, r_ret); return true; } diff --git a/src/script/jvm_instance.h b/src/script/jvm_instance.h index e210081781..40a01bedd4 100644 --- a/src/script/jvm_instance.h +++ b/src/script/jvm_instance.h @@ -15,7 +15,7 @@ class JvmInstance : public ScriptInstance { bool delete_flag; public: - JvmInstance(Object* p_owner, KtObject* p_kt_object, JvmScript* p_script); + JvmInstance(jni::Env& p_env, Object* p_owner, KtObject* p_kt_object, JvmScript* p_script); ~JvmInstance() override; bool set(const StringName& p_name, const Variant& p_value) override; @@ -30,7 +30,7 @@ class JvmInstance : public ScriptInstance { void get_method_list(List* p_list) const override; bool has_method(const StringName& p_method) const override; Variant callp(const StringName& p_method, const Variant** p_args, int p_argcount, Callable::CallError& r_error) override; - void notification(int p_notification, bool p_reversed = false) override; + void notification(int p_notification, bool p_reversed) override; virtual void validate_property(PropertyInfo& p_property) const override; String to_string(bool* r_valid) override; void refcount_incremented() override; diff --git a/src/script/jvm_script.cpp b/src/script/jvm_script.cpp index 55f622a61d..813661e75e 100644 --- a/src/script/jvm_script.cpp +++ b/src/script/jvm_script.cpp @@ -94,7 +94,7 @@ ScriptInstance* JvmScript::_instance_create(const Variant** p_args, int p_arg_co jni::Env env = jni::Jvm::current_env(); KtObject* wrapped = kotlin_class->create_instance(env, p_args, p_arg_count, p_this); - return memnew(JvmInstance(p_this, wrapped, this)); + return memnew(JvmInstance(env, p_this, wrapped, this)); } bool JvmScript::instance_has(const Object* p_this) const {