| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #define LOG_DOMAIN "vm.core.init" |
| #include "cxxlog.h" |
| |
| #include <apr_env.h> |
| #include <apr_general.h> |
| #include <apr_dso.h> |
| #include "port_dso.h" |
| |
| #include "open/vm_properties.h" |
| #include "open/gc.h" |
| #include "open/hythread_ext.h" |
| #include "open/vm_class_manipulation.h" |
| |
| #include "jthread.h" |
| #include "vtable.h" |
| #include "init.h" |
| #include "classloader.h" |
| #include "jni_utils.h" |
| #include "mon_enter_exit.h" |
| #include "heap.h" |
| #include "port_filepath.h" |
| #include "component_manager.h" |
| #include "dll_gc.h" |
| #include "compile.h" |
| #include "interpreter.h" |
| #include "em_intf.h" |
| #include "dll_jit_intf.h" |
| #include "jit_runtime_support.h" |
| #include "jni_utils.h" |
| #include "platform_lowlevel.h" |
| #include "verify_stack_enumeration.h" |
| #include "nogc.h" |
| #include "vm_strings.h" |
| #include "slot.h" |
| #include "classpath_const.h" |
| #include "finalize.h" |
| #include "jit_intf.h" |
| #include "signals.h" |
| |
| #ifdef _WIN32 |
| // 20040427 Used to turn on heap checking on every allocation |
| #include <crtdbg.h> |
| #endif |
| |
| VTable * cached_object_array_vtable_ptr; |
| bool parallel_jit = true; |
| VMEXPORT bool dump_stubs = false; |
| |
| void* Slot::heap_base = NULL; |
| void* Slot::heap_ceiling = NULL; |
| |
| Class* preload_class(Global_Env * vm_env, const char * classname) { |
| String * s = vm_env->string_pool.lookup(classname); |
| return vm_env->LoadCoreClass(s); |
| } |
| |
| Class * preload_class(Global_Env * vm_env, String* s) { |
| return vm_env->LoadCoreClass(s); |
| } |
| |
| static Class * preload_primitive_class(Global_Env * vm_env, const char * classname) { |
| String * s = vm_env->string_pool.lookup(classname); |
| ClassLoader * cl = vm_env->bootstrap_class_loader; |
| Class *clss = cl->NewClass(vm_env, s); |
| clss->setup_as_primitive(cl); |
| cl->InsertClass(clss); |
| |
| clss->prepare(vm_env); |
| return clss; |
| } |
| |
| |
| #ifdef LIB_DEPENDENT_OPTS |
| |
| static Class * class_initialize_by_name(Global_Env * vm_env, const char * classname) { |
| ASSERT_RAISE_AREA; |
| |
| String *s = vm_env->string_pool.lookup(classname); |
| Class *clss = vm_env->bootstrap_class_loader->LoadVerifyAndPrepareClass(vm_env, s); |
| if (clss != NULL) { |
| class_initialize(clss); |
| } |
| return clss; |
| } |
| |
| static jint lib_dependent_opts() { |
| ASSERT_RAISE_AREA; |
| return class_initialize_by_name("java/lang/Math") != null ? JNI_OK : JNI_ERR; |
| } |
| #endif |
| |
| |
| // Create the java_lang_Class instance for a struct Class |
| // and set its "vm_class" field to point back to that structure. |
| void create_instance_for_class(Global_Env * vm_env, Class *clss) |
| { |
| clss->get_class_loader()->AllocateAndReportInstance(vm_env, clss); |
| // set jlC to vtable - for non BS classes jlc is set in create_vtable |
| if (clss->get_vtable()) // vtable = NULL for interfaces |
| { |
| assert (!clss->get_vtable()->jlC); // used for BS classes only |
| clss->get_vtable()->jlC = *clss->get_class_handle(); |
| assert (!clss->get_class_loader()->GetLoader()); |
| } |
| } //create_instance_for_class |
| |
| // VM adapter part |
| |
| static apr_dso_handle_t* get_harmonyvm_handle(){ |
| apr_dso_handle_t* descriptor; |
| apr_pool_t* pool; |
| int ret = apr_pool_create(&pool, NULL); |
| assert(APR_SUCCESS == ret); |
| ret = apr_dso_load(&descriptor, PORT_DSO_NAME("harmonyvm"), pool); |
| assert(APR_SUCCESS == ret); |
| return descriptor; |
| } |
| |
| extern "C" VMEXPORT |
| void* vm_get_interface(const char* func_name){ |
| static apr_dso_handle_t* descriptor = get_harmonyvm_handle(); |
| void* p_func = NULL; |
| int ret = apr_dso_sym((apr_dso_handle_sym_t*) &p_func, descriptor, func_name); |
| |
| //assert(APR_SUCCESS == ret); |
| |
| //FIXME: temporary solution, should be fixed in next patch |
| if (p_func) { |
| return p_func; |
| |
| } else if (strcmp(func_name,"vector_get_first_element_offset") == 0) { |
| return (void*)vector_first_element_offset_class_handle; |
| } else if (strcmp(func_name,"vector_get_length_offset") == 0) { |
| return (void*)vector_length_offset; |
| } else if (strcmp(func_name,"vm_tls_alloc") == 0) { |
| return (void*)hythread_tls_alloc; |
| } else if (strcmp(func_name,"vm_tls_get_offset") == 0) { |
| return (void*)hythread_tls_get_offset; |
| } else if (strcmp(func_name,"vm_tls_get_request_offset") == 0) { |
| return (void*)hythread_tls_get_request_offset; |
| } else if (strcmp(func_name,"vm_tls_is_fast") == 0) { |
| return (void*)hythread_uses_fast_tls; |
| } else if (strcmp(func_name,"vm_get_tls_offset_in_segment") == 0) { |
| return (void*)hythread_get_hythread_offset_in_tls; |
| } else { |
| return NULL; |
| } |
| } |
| |
| #define GC_DLL_COMP PORT_DSO_NAME("gc_gen") |
| #define GC_DLL_UNCOMP PORT_DSO_NAME("gc_gen_uncomp") |
| |
| #if defined(REFS_USE_COMPRESSED) |
| #define GC_DLL GC_DLL_COMP |
| #elif defined(REFS_USE_UNCOMPRESSED) |
| #define GC_DLL GC_DLL_UNCOMP |
| #else // for REFS_USE_RUNTIME_SWITCH |
| #define GC_DLL (vm_env->compress_references ? GC_DLL_COMP : GC_DLL_UNCOMP) |
| #endif |
| |
| |
| /** |
| * Loads DLLs. |
| */ |
| static jint process_properties_dlls(Global_Env * vm_env) { |
| jint status; |
| |
| if (!vm_env->VmProperties()->is_set("vm.em_dll")) { |
| vm_env->VmProperties()->set("vm.em_dll", PORT_DSO_NAME("em")); |
| } |
| |
| char* dll = vm_env->VmProperties()->get("vm.em_dll"); |
| TRACE("analyzing em dll " << dll); |
| status = CmLoadComponent(dll, "EmInitialize"); |
| vm_env->VmProperties()->destroy(dll); |
| if (status != JNI_OK) { |
| LWARN(13, "Cannot load EM component from {0}" << dll); |
| return status; |
| } |
| |
| status = vm_env->cm->GetComponent(&(vm_env->em_component), OPEN_EM); |
| if (JNI_OK != status) { |
| return status; |
| } |
| |
| status = vm_env->cm->CreateInstance(&(vm_env->em_instance), OPEN_EM); |
| if (JNI_OK != status) { |
| LWARN(14, "Cannot instantiate EM"); |
| return status; |
| } |
| |
| status = vm_env->em_component->GetInterface((OpenInterfaceHandle*) &(vm_env->em_interface), OPEN_INTF_EM_VM); |
| if (JNI_OK != status) { |
| LWARN(15, "Cannot get EM_VM interface"); |
| return status; |
| } |
| |
| /* |
| * Preload <GC>.dll which is specified by 'gc.dll' property. |
| * 'gc.dll' property is set when specified in command line. |
| * When undefined, set default gc |
| */ |
| #ifndef USE_GC_STATIC |
| if (!vm_env->VmProperties()->is_set("gc.dll")) { |
| vm_env->VmProperties()->set_new("gc.dll", GC_DLL); |
| } |
| |
| char* gc_dll = vm_env->VmProperties()->get("gc.dll"); |
| |
| if (!gc_dll) { |
| LWARN(44, "{0} internal property is undefined" << "gc.dll"); |
| return JNI_ERR; |
| } |
| TRACE("analyzing gc.dll " << gc_dll); |
| |
| if (vm_is_a_gc_dll(gc_dll)) { |
| vm_add_gc(gc_dll); |
| } else { |
| LWARN(16, "GC library cannot be loaded: {0}" << gc_dll); |
| status = JNI_ERR; |
| } |
| vm_env->VmProperties()->destroy(gc_dll); |
| #endif |
| return status; |
| } |
| |
| /** |
| * Check compression modes and adjust if needed |
| */ |
| static jint process_compression_modes(Global_Env * vm_env) |
| { |
| #if !defined(POINTER64) || defined(REFS_USE_UNCOMPRESSED) |
| return JNI_OK; |
| #else |
| |
| if (!vm_env->VmProperties()->is_set("gc.ms") && |
| !vm_env->VmProperties()->is_set("gc.mx")) |
| { // Heap size is not specified, use default compressed mode |
| return JNI_OK; |
| } |
| |
| size_t ms = vm_property_get_size("gc.ms", 0, VM_PROPERTIES); |
| size_t mx = vm_property_get_size("gc.mx", 0, VM_PROPERTIES); |
| // Currently 4Gb is maximum for compressed mode |
| // If GC cannot allocate heap up to 4Gb, gc_init() will fail |
| size_t max_size = ((int64)4096)*1024*1024; |
| |
| #ifdef REFS_USE_COMPRESSED |
| if (ms >= max_size || mx >= max_size) |
| { // Heap is too large for compressed mode |
| LWARN(45, "ERROR: Heap size is too large for precompiled compressed mode."); |
| return JNI_ERR; |
| } |
| #elif defined(REFS_USE_RUNTIME_SWITCH) |
| if (ms >= max_size || mx >= max_size) |
| { // Large heap; use uncompressed references |
| vm_properties_set_value("vm.compress_references", "false", VM_PROPERTIES); |
| vm_env->compress_references = false; |
| return JNI_OK; |
| } |
| #endif // REFS_USE_RUNTIME_SWITCH |
| return JNI_OK; |
| #endif // !defined(POINTER64) || defined(REFS_USE_UNCOMPRESSED) |
| } |
| |
| /** |
| * Checks whether current platform is supported or not. |
| */ |
| static jint check_platform() { |
| #if defined(PLATFORM_NT) |
| OSVERSIONINFO osvi; |
| osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); |
| BOOL ok = GetVersionEx(&osvi); |
| if(!ok) { |
| DWORD e = GetLastError(); |
| printf("Windows error: %d\n", e); |
| return JNI_ERR; |
| } |
| if((osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) || // NT 4.0 |
| (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) || // Windows 2000 |
| (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) || // Windows XP |
| (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) || // Windows.NET |
| (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) || // Windows Vista |
| (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1)) { // Windows 7 |
| return JNI_OK; |
| } |
| printf("Windows %d.%d is not supported\n", osvi.dwMajorVersion, osvi.dwMinorVersion); |
| return JNI_ERR; |
| #else |
| return JNI_OK; |
| #endif |
| } |
| |
| /** |
| * Ensures that different VM components have consistent compression modes. |
| */ |
| static jint check_compression() { |
| // Check for a mismatch between whether the various VM components all compress references or not. |
| Boolean vm_compression = vm_is_heap_compressed(); |
| Boolean gc_compression = gc_supports_compressed_references(); |
| if (vm_compression) { |
| if (!gc_compression) { |
| LWARN(17, "VM component mismatch: the VM compresses references but the GC doesn't."); |
| return JNI_ERR; |
| } |
| |
| // We actually check the first element in the jit_compilers array, as current JIT |
| // always returns FALSE to the supports_compressed_references() call. |
| JIT **jit = &jit_compilers[0]; |
| if (!interpreter_enabled()) { |
| Boolean jit_compression = (*jit)->supports_compressed_references(); |
| if (!jit_compression) { |
| LWARN(18, "VM component mismatch: the VM compresses references but a JIT doesn't"); |
| return JNI_ERR; |
| } |
| } |
| } else { |
| if (gc_compression) { |
| LWARN(19, "VM component mismatch: the VM doesn't compress references but the GC does."); |
| return JNI_ERR; |
| } |
| JIT **jit = &jit_compilers[0]; |
| if (!interpreter_enabled()) { |
| Boolean jit_compression = (*jit)->supports_compressed_references(); |
| if (jit_compression) { |
| LWARN(20, "VM component mismatch: the VM doesn't compress references but a JIT does"); |
| return JNI_ERR; |
| } |
| } |
| } |
| return JNI_OK; |
| } |
| |
| typedef void* (JNICALL *GDBA) (JNIEnv* env, jobject buf); |
| typedef jobject (JNICALL *NDB)(JNIEnv* env, void* address, jlong capacity); |
| typedef jlong (JNICALL *GDBC)(JNIEnv* env, jobject buf); |
| |
| /** |
| * Imports NIO functions to JNI functions table from hynio lib. |
| * Note: bootstrap classloader is picky to load classlib's natives earliest, |
| * so this should be called after bcl initialization. |
| */ |
| static jint populate_jni_nio() { |
| bool just_loaded; |
| NativeLoadStatus loading_status; |
| NativeLibraryHandle handle = natives_load_library( |
| PORT_DSO_NAME("hynio"), &just_loaded, &loading_status); |
| if (!handle || loading_status) { |
| char error_message[1024]; |
| natives_describe_error(loading_status, error_message, sizeof(error_message)); |
| |
| LWARN(21, "Failed to initialize JNI NIO support: {0}" << error_message); |
| return JNI_ERR; |
| } |
| |
| apr_dso_handle_sym_t gdba, gdbc, ndb; |
| #if defined WIN32 && !defined HYX86_64 |
| #define GET_DIRECT_BUFFER_ADDRESS "_GetDirectBufferAddress@8" |
| #define GET_DIRECT_BUFFER_CAPACITY "_GetDirectBufferCapacity@8" |
| #define NEW_DIRECT_BYTE_BUFFER "_NewDirectByteBuffer@16" |
| #else |
| #define GET_DIRECT_BUFFER_ADDRESS "GetDirectBufferAddress" |
| #define GET_DIRECT_BUFFER_CAPACITY "GetDirectBufferCapacity" |
| #define NEW_DIRECT_BYTE_BUFFER "NewDirectByteBuffer" |
| #endif |
| if (APR_SUCCESS == apr_dso_sym(&gdba, handle, GET_DIRECT_BUFFER_ADDRESS) |
| && APR_SUCCESS == apr_dso_sym(&gdbc, handle, GET_DIRECT_BUFFER_CAPACITY) |
| && APR_SUCCESS == apr_dso_sym(&ndb, handle, NEW_DIRECT_BYTE_BUFFER)) |
| { |
| jni_vtable.GetDirectBufferAddress = (GDBA)gdba; |
| jni_vtable.GetDirectBufferCapacity = (GDBC)gdbc; |
| jni_vtable.NewDirectByteBuffer = (NDB)ndb; |
| return JNI_OK; |
| } |
| else |
| { |
| LWARN(22, "Failed to import JNI NIO functions."); |
| return JNI_ERR; |
| } |
| } |
| |
| /** |
| * Loads initial classes. For example j.l.Object, j.l.Class, etc. |
| */ |
| static void bootstrap_initial_java_classes(Global_Env * vm_env) |
| { |
| assert(hythread_is_suspend_enabled()); |
| TRACE("bootstrapping initial java classes"); |
| |
| vm_env->bootstrap_class_loader->Initialize(); |
| |
| /* |
| * Bootstrap java.lang.Class class. This requires also loading the other classes |
| * it inherits/implements: java.io.Serializable and java.lang.Object, and |
| * j.l.reflect.AnnotatedElement, GenericDeclaration and Type as per Java 5 |
| */ |
| vm_env->StartVMBootstrap(); |
| vm_env->JavaLangObject_Class = preload_class(vm_env, vm_env->JavaLangObject_String); |
| vm_env->java_io_Serializable_Class = preload_class(vm_env, vm_env->Serializable_String); |
| Class* AnnotatedElement_Class = preload_class(vm_env, "java/lang/reflect/AnnotatedElement"); |
| Class* GenericDeclaration_Class = preload_class(vm_env, "java/lang/reflect/GenericDeclaration"); |
| Class* Type_Class = preload_class(vm_env, "java/lang/reflect/Type"); |
| vm_env->JavaLangClass_Class = preload_class(vm_env, vm_env->JavaLangClass_String); |
| |
| vm_env->FinishVMBootstrap(); |
| |
| // Now create the java_lang_Class instance. |
| create_instance_for_class(vm_env, vm_env->JavaLangClass_Class); |
| |
| ClassTable* table = vm_env->bootstrap_class_loader->GetLoadedClasses(); |
| |
| unsigned num = 0; |
| for (ClassTable::const_iterator it = table->begin(), end = table->end(); |
| it != end; ++it, ++num) |
| { |
| Class* booted = (*it).second; |
| if (booted != vm_env->JavaLangClass_Class) { |
| create_instance_for_class(vm_env, booted); |
| } |
| jvmti_send_class_load_event(vm_env, booted); |
| jvmti_send_class_prepare_event(booted); |
| } |
| |
| TRACE("bootstrapping initial java classes complete"); |
| } // bootstrap_initial_java_classes |
| |
| /** |
| * Loads hot classes. |
| */ |
| static jint preload_classes(Global_Env * vm_env) { |
| // Bootstrap initial classes |
| bootstrap_initial_java_classes(vm_env); |
| |
| TRACE2("init", "preloading primitive type classes"); |
| vm_env->Boolean_Class = preload_primitive_class(vm_env, "boolean"); |
| vm_env->Char_Class = preload_primitive_class(vm_env, "char"); |
| vm_env->Float_Class = preload_primitive_class(vm_env, "float"); |
| vm_env->Double_Class = preload_primitive_class(vm_env, "double"); |
| vm_env->Byte_Class = preload_primitive_class(vm_env, "byte"); |
| vm_env->Short_Class = preload_primitive_class(vm_env, "short"); |
| vm_env->Int_Class = preload_primitive_class(vm_env, "int"); |
| vm_env->Long_Class = preload_primitive_class(vm_env, "long"); |
| |
| vm_env->Void_Class = preload_primitive_class(vm_env, "void"); |
| |
| vm_env->ArrayOfBoolean_Class = preload_class(vm_env, "[Z"); |
| vm_env->ArrayOfByte_Class = preload_class(vm_env, "[B"); |
| vm_env->ArrayOfChar_Class = preload_class(vm_env, "[C"); |
| vm_env->ArrayOfShort_Class = preload_class(vm_env, "[S"); |
| vm_env->ArrayOfInt_Class = preload_class(vm_env, "[I"); |
| vm_env->ArrayOfLong_Class = preload_class(vm_env, "[J"); |
| vm_env->ArrayOfFloat_Class = preload_class(vm_env, "[F"); |
| vm_env->ArrayOfDouble_Class = preload_class(vm_env, "[D"); |
| |
| TRACE2("init", "preloading string class"); |
| vm_env->JavaLangString_Class = preload_class(vm_env, vm_env->JavaLangString_String); |
| vm_env->strings_are_compressed = |
| (class_lookup_field_recursive(vm_env->JavaLangString_Class, "bvalue", "[B") != NULL); |
| vm_env->JavaLangString_VTable = vm_env->JavaLangString_Class->get_vtable(); |
| |
| Class* VM_class = preload_class(vm_env, "org/apache/harmony/kernel/vm/VM"); |
| vm_env->VM_intern = class_lookup_method_recursive(VM_class, "intern", |
| "(Ljava/lang/String;)Ljava/lang/String;"); |
| |
| TRACE2("init", "preloading exceptions"); |
| vm_env->java_lang_Throwable_Class = |
| preload_class(vm_env, vm_env->JavaLangThrowable_String); |
| vm_env->java_lang_StackTraceElement_Class = |
| preload_class(vm_env, "java/lang/StackTraceElement"); |
| vm_env->java_lang_Error_Class = |
| preload_class(vm_env, "java/lang/Error"); |
| vm_env->java_lang_ExceptionInInitializerError_Class = |
| preload_class(vm_env, "java/lang/ExceptionInInitializerError"); |
| vm_env->java_lang_NoClassDefFoundError_Class = |
| preload_class(vm_env, "java/lang/NoClassDefFoundError"); |
| vm_env->java_lang_ClassNotFoundException_Class = |
| preload_class(vm_env, "java/lang/ClassNotFoundException"); |
| vm_env->java_lang_NullPointerException_Class = |
| preload_class(vm_env, vm_env->JavaLangNullPointerException_String); |
| vm_env->java_lang_StackOverflowError_Class = |
| preload_class(vm_env, "java/lang/StackOverflowError"); |
| vm_env->java_lang_ArrayIndexOutOfBoundsException_Class = |
| preload_class(vm_env, vm_env->JavaLangArrayIndexOutOfBoundsException_String); |
| vm_env->java_lang_ArrayStoreException_Class = |
| preload_class(vm_env, "java/lang/ArrayStoreException"); |
| vm_env->java_lang_ArithmeticException_Class = |
| preload_class(vm_env, "java/lang/ArithmeticException"); |
| vm_env->java_lang_ClassCastException_Class = |
| preload_class(vm_env, "java/lang/ClassCastException"); |
| vm_env->java_lang_OutOfMemoryError_Class = |
| preload_class(vm_env, "java/lang/OutOfMemoryError"); |
| vm_env->java_lang_InternalError_Class = |
| preload_class(vm_env, "java/lang/InternalError"); |
| vm_env->java_lang_ThreadDeath_Class = |
| preload_class(vm_env, "java/lang/ThreadDeath"); |
| |
| // String must be initialized before strings from intern pool are |
| // used. But for initializing l.j.String we need to have exception |
| // classes loaded, because the first call to compilations |
| // initializes all of the JIT helpers that hardcode class handles |
| // inside of the helpers. |
| hythread_suspend_disable(); |
| class_initialize(vm_env->JavaLangString_Class); |
| hythread_suspend_enable(); |
| |
| vm_env->java_lang_Cloneable_Class = |
| preload_class(vm_env, vm_env->Clonable_String); |
| vm_env->java_lang_Thread_Class = |
| preload_class(vm_env, "java/lang/Thread"); |
| vm_env->java_lang_ThreadGroup_Class = |
| preload_class(vm_env, "java/lang/ThreadGroup"); |
| vm_env->java_util_LinkedList_Class = |
| preload_class(vm_env, "java/util/LinkedList"); |
| vm_env->java_util_Date_Class = |
| preload_class(vm_env, "java/util/Date"); |
| vm_env->java_util_Properties_Class = |
| preload_class(vm_env, "java/util/Properties"); |
| vm_env->java_lang_Runtime_Class = |
| preload_class(vm_env, "java/lang/Runtime"); |
| |
| vm_env->java_lang_reflect_Constructor_Class = |
| preload_class(vm_env, vm_env->JavaLangReflectConstructor_String); |
| vm_env->java_lang_reflect_Field_Class = |
| preload_class(vm_env, vm_env->JavaLangReflectField_String); |
| vm_env->java_lang_reflect_Method_Class = |
| preload_class(vm_env, vm_env->JavaLangReflectMethod_String); |
| |
| return JNI_OK; |
| } |
| |
| /** |
| * Calls java.lang.ClassLoader.getSystemClassLoader() to obtain system |
| * class loader object. |
| * @return JNI_OK on success. |
| */ |
| static jint initialize_system_class_loader(JNIEnv * jni_env) { |
| Global_Env * vm_env = jni_get_vm_env(jni_env); |
| jclass cl = jni_env->FindClass("java/lang/ClassLoader"); |
| if (! cl) |
| return JNI_ERR; |
| |
| jmethodID gcl = jni_env->GetStaticMethodID(cl, "getSystemClassLoader", "()Ljava/lang/ClassLoader;"); |
| if (! gcl) |
| return JNI_ERR; |
| |
| jobject scl = jni_env->CallStaticObjectMethod(cl, gcl); |
| if (! scl) |
| return JNI_ERR; |
| |
| hythread_suspend_disable(); |
| vm_env->system_class_loader = (UserDefinedClassLoader *) |
| ClassLoader::LookupLoader(((ObjectHandle)scl)->object); |
| hythread_suspend_enable(); |
| |
| return JNI_OK; |
| } |
| |
| jint set_current_thread_context_loader(JNIEnv* jni_env) { |
| jthread current_thread = jthread_self(); |
| jfieldID scl_field = jni_env->GetFieldID(jni_env->GetObjectClass(current_thread), |
| "contextClassLoader", "Ljava/lang/ClassLoader;"); |
| assert(scl_field); |
| Global_Env* vm_env = jni_get_vm_env(jni_env); |
| jobject loader = jni_env->NewLocalRef((jobject)(vm_env->system_class_loader->GetLoaderHandle())); |
| jni_env->SetObjectField(current_thread, scl_field, loader); |
| jni_env->DeleteLocalRef(loader); |
| |
| return JNI_OK; |
| } |
| |
| #define PROCESS_EXCEPTION(messageId, message) \ |
| { \ |
| LECHO(messageId, message << "Internal error: "); \ |
| \ |
| if (jni_env->ExceptionCheck()== JNI_TRUE) \ |
| { \ |
| jni_env->ExceptionDescribe(); \ |
| jni_env->ExceptionClear(); \ |
| } \ |
| \ |
| return JNI_ERR; \ |
| } \ |
| |
| /** |
| * Executes j.l.VMStart.initialize() method. |
| */ |
| static jint run_java_init(JNIEnv * jni_env) { |
| assert(hythread_is_suspend_enabled()); |
| |
| jclass start_class = jni_env->FindClass("java/lang/VMStart"); |
| if (jni_env->ExceptionCheck()== JNI_TRUE || start_class == NULL) { |
| PROCESS_EXCEPTION(35, "{0}can't find starter class: java.lang.VMStart."); |
| } |
| |
| jmethodID init_method = jni_env->GetStaticMethodID(start_class, "initialize", "()V"); |
| if (jni_env->ExceptionCheck()== JNI_TRUE || init_method == NULL) { |
| PROCESS_EXCEPTION(36, "{0}can't find java.lang.VMStart.initialize() method."); |
| } |
| |
| jni_env->CallStaticVoidMethod(start_class, init_method); |
| if (jni_env->ExceptionCheck()== JNI_TRUE) { |
| PROCESS_EXCEPTION(37, "{0}java.lang.VMStart.initialize() method completed with an exception."); |
| } |
| return JNI_OK; |
| } |
| |
| /** |
| * Creates new j.l.Thread object |
| * |
| * @param[out] thread_object pointer to created thread object |
| * @param[in] jni_env JNI environment associated with the current thread |
| * @param[in] group thread group where new thread should be placed in |
| * @param[in] name thread's name |
| * @param[in] daemon JNI_TRUE if new thread is a daemon, JNI_FALSE otherwise |
| */ |
| static jint vm_create_jthread(jthread * thread_object, JNIEnv * jni_env, jobject group, const char * name, jboolean daemon) { |
| static Method * constructor = NULL; |
| const char * descriptor = "(Ljava/lang/ThreadGroup;Ljava/lang/String;JJIZ)V"; |
| jvalue args[7]; |
| Global_Env * vm_env; |
| Class * thread_class; |
| ObjectHandle thread_handle; |
| hythread_t native_thread; |
| |
| |
| assert(!hythread_is_suspend_enabled()); |
| |
| vm_env = jni_get_vm_env(jni_env); |
| |
| thread_class = vm_env->java_lang_Thread_Class; |
| class_initialize(thread_class); |
| if (exn_raised()) |
| { |
| TRACE("Failed to initialize class for java/lang/Thread class = " << exn_get_name()); |
| hythread_suspend_enable(); |
| exn_print_stack_trace(stderr, exn_get()); |
| hythread_suspend_disable(); |
| return JNI_ERR; |
| } |
| |
| // Allocate new j.l.Thread object. |
| thread_handle = oh_allocate_global_handle(); |
| thread_handle->object = class_alloc_new_object(thread_class); |
| if (thread_handle->object == NULL) { |
| assert(!hythread_is_suspend_enabled()); |
| assert(exn_raised() && p_TLS_vmthread->thread_exception.exc_object == vm_env->java_lang_OutOfMemoryError->object); |
| return JNI_ENOMEM; |
| } |
| *thread_object = thread_handle; |
| |
| if (constructor == NULL) { |
| // Initialize created thread object. |
| constructor = thread_class->lookup_method(vm_env->Init_String, |
| vm_env->string_pool.lookup(descriptor)); |
| if (constructor == NULL) { |
| TRACE("Failed to find thread's constructor " << descriptor << " , exception = " << exn_get()); |
| return JNI_ERR; |
| } |
| } |
| |
| args[0].l = thread_handle; |
| args[1].l = group; |
| |
| if (name) { |
| args[2].l = oh_allocate_local_handle(); |
| args[2].l->object = string_create_from_utf8(name, |
| (unsigned)strlen(name)); |
| } else { |
| args[2].l = NULL; |
| } |
| native_thread = hythread_self(); |
| args[3].j = (POINTER_SIZE_INT) native_thread; |
| args[4].j = 0; |
| args[5].i = (jint)hythread_get_priority(native_thread); |
| args[6].z = daemon; |
| |
| DebugUtilsTI *ti = VM_Global_State::loader_env->TI; |
| if (ti->isEnabled()) { |
| ti->doNotReportLocally();//-----------------------------------V |
| vm_execute_java_method_array((jmethodID) constructor, 0, args); |
| ti->reportLocally(); //-----------------------------------^ |
| } else { |
| vm_execute_java_method_array((jmethodID) constructor, 0, args); |
| } |
| |
| if (exn_raised()) { |
| TRACE("Failed to initialize new thread object, exception = " << exn_get_name()); |
| hythread_suspend_enable(); |
| exn_print_stack_trace(stderr, exn_get()); |
| hythread_suspend_disable(); |
| return JNI_ERR; |
| } |
| return JNI_OK; |
| } |
| |
| /** |
| * Attaches current thread to VM and creates j.l.Thread instance. |
| * |
| * @param[out] p_jni_env points to created JNI environment |
| * @param[out] java_thread global reference holding j.l.Thread object |
| * @param[in] java_vm VM to attach thread to |
| * @param[in] group thread group for attaching thread |
| * @param[in] name thread name |
| * @param[in] daemon JNI_TRUE if thread is daemon, JNI_FALSE otherwise |
| * @return JNI_OK on success. |
| */ |
| jint vm_attach_internal(JNIEnv ** p_jni_env, jthread * java_thread, JavaVM * java_vm, jobject group, const char * name, jboolean daemon) { |
| JNIEnv * jni_env; |
| hythread_t native_thread; |
| jint status; |
| |
| native_thread = hythread_self(); |
| if (!native_thread) { |
| native_thread = (hythread_t)jthread_allocate_thread(); |
| IDATA hy_status = hythread_attach_ex(native_thread, NULL, NULL); |
| if (hy_status != TM_ERROR_NONE) |
| return JNI_ERR; |
| } |
| assert(native_thread); |
| |
| status = vm_attach(java_vm, &jni_env); |
| if (status != JNI_OK) |
| return status; |
| |
| *p_jni_env = jni_env; |
| |
| hythread_suspend_disable(); |
| // Global reference will be created for new thread object. |
| status = vm_create_jthread(java_thread, jni_env, group, name, daemon); |
| hythread_suspend_enable(); |
| |
| return status; |
| } |
| |
| /** |
| * First VM initialization step. At that moment neither JNI is available |
| * nor main thread is attached to VM. |
| */ |
| int vm_init1(JavaVM_Internal * java_vm, JavaVMInitArgs * vm_arguments) { |
| jint status; |
| Global_Env * vm_env; |
| JNIEnv * jni_env; |
| |
| TRACE("Initializing VM"); |
| |
| vm_env = java_vm->vm_env; |
| |
| vm_thread_t main_thread = jthread_allocate_thread(); |
| assert(main_thread); |
| if (hythread_attach_ex((hythread_t)main_thread, NULL, NULL) != TM_ERROR_NONE) { |
| return JNI_ERR; |
| } |
| |
| assert(hythread_is_suspend_enabled()); |
| |
| status = check_platform(); |
| if (status != JNI_OK) return status; |
| |
| // TODO: global variables should be removed for multi-VM support |
| VM_Global_State::loader_env = vm_env; |
| |
| // Initialize arguments |
| initialize_vm_cmd_state(vm_env, vm_arguments); |
| |
| vm_monitor_init(); |
| |
| /* BEGIN: Property processing. */ |
| |
| // 20030407 Note: property initialization must follow initialization of the default JITs to allow |
| // the command line to override those default JITs. |
| |
| status = initialize_properties(vm_env); |
| if (status != JNI_OK) return status; |
| |
| tm_properties = (struct tm_props*) STD_MALLOC(sizeof(struct tm_props)); |
| if (!tm_properties) { |
| LWARN(30, "failed to allocate mem for tp properties"); |
| return JNI_ERR; |
| } |
| |
| tm_properties->use_soft_unreservation = vm_property_get_boolean("thread.soft_unreservation", FALSE, VM_PROPERTIES); |
| |
| parse_vm_arguments2(vm_env); |
| |
| vm_env->verify = vm_property_get_boolean("vm.use_verifier", TRUE, VM_PROPERTIES); |
| #ifdef REFS_USE_RUNTIME_SWITCH |
| vm_env->compress_references = vm_property_get_boolean("vm.compress_references", TRUE, VM_PROPERTIES); |
| #endif |
| // use platform default values for field sorting and field compaction |
| // if these values are not specifed on command line |
| // see Global_Env::Global_Env for defaults |
| vm_env->sort_fields = vm_property_get_boolean("vm.sort_fields", vm_env->sort_fields, VM_PROPERTIES); |
| vm_env->compact_fields = vm_property_get_boolean("vm.compact_fields", vm_env->compact_fields, VM_PROPERTIES); |
| vm_env->use_common_jar_cache = vm_property_get_boolean("vm.common_jar_cache", TRUE, VM_PROPERTIES); |
| vm_env->map_bootsrtap_jars = vm_property_get_boolean("vm.map_bootstrap_jars", FALSE, VM_PROPERTIES); |
| |
| vm_env->init_pools(); |
| |
| // Check compression modes and heap size |
| status = process_compression_modes(vm_env); |
| if (status != JNI_OK) return status; |
| |
| // "Tool Interface" enabling. |
| vm_env->TI->setExecutionMode(vm_env); |
| |
| status = process_properties_dlls(vm_env); |
| if (status != JNI_OK) return status; |
| |
| parse_jit_arguments(&vm_env->vm_arguments); |
| |
| vm_env->pin_interned_strings = |
| (bool)vm_property_get_boolean("vm.pin_interned_strings", FALSE, VM_PROPERTIES); |
| |
| initialize_verify_stack_enumeration(); |
| |
| /* END: Property processing. */ |
| |
| // Initialize memory allocation. |
| status = gc_init(); |
| if (status != JNI_OK) return status; |
| |
| // TODO: change all uses of Class::heap_base to Slot::heap_base |
| Slot::init(gc_heap_base_address(), gc_heap_ceiling_address()); |
| |
| // TODO: find another way to initialize the following. |
| vm_env->heap_base = (U_8*)gc_heap_base_address(); |
| vm_env->heap_end = (U_8*)gc_heap_ceiling_address(); |
| vm_env->managed_null = REF_MANAGED_NULL; |
| |
| // 20030404 This handshaking protocol isn't quite correct. It doesn't |
| // work at the moment because JIT has not yet been modified to support |
| // compressed references, so it never answers "true" to supports_compressed_references(). |
| // ppervov: this check is not correct since a call to |
| // gc_supports_compressed_references returns capability while a call to |
| // vm_is_heap_compressed returns current VM state, not potential |
| // ability to support compressed mode |
| // So, this check is turned off for now and it is FIXME |
| // 20071109 process_compression_modes() now automatically selects compression |
| // mode depending on heap size requested. If compressed mode is selected, |
| // check_compression() should check if other components support this mode, |
| // and either fail or switch to uncompressed mode |
| //status = check_compression(); |
| //if (status != JNI_OK) return status; |
| |
| // Prepares to load natives |
| status = natives_init(); |
| if (status != JNI_OK) return status; |
| |
| if (vm_initialize_signals() != 0) |
| return JNI_ERR; |
| |
| status = vm_attach(java_vm, &jni_env); |
| if (status != JNI_OK) return status; |
| |
| // "Tool Interface" initialization |
| status = vm_env->TI->Init(java_vm); |
| if (status != JNI_OK) { |
| LWARN(24, "Failed to initialize JVMTI."); |
| return status; |
| } |
| |
| status = preload_classes(vm_env); |
| if (status != JNI_OK) return status; |
| |
| populate_jni_nio(); |
| |
| // Now the thread is attached to VM and it is valid to disable it. |
| hythread_suspend_disable(); |
| |
| // Create java.lang.Object. |
| vm_env->java_lang_Object = oh_allocate_global_handle(); |
| vm_env->java_lang_Object->object = |
| class_alloc_new_object(vm_env->JavaLangObject_Class); |
| // Create java.lang.OutOfMemoryError. |
| class_initialize(vm_env->java_lang_OutOfMemoryError_Class); |
| vm_env->java_lang_OutOfMemoryError = oh_allocate_global_handle(); |
| vm_env->java_lang_OutOfMemoryError->object = |
| class_alloc_new_object(vm_env->java_lang_OutOfMemoryError_Class); |
| // Create java.lang.ThreadDeath. |
| vm_env->java_lang_ThreadDeath = oh_allocate_global_handle(); |
| vm_env->java_lang_ThreadDeath->object = |
| class_alloc_new_object(vm_env->java_lang_ThreadDeath_Class); |
| |
| // Create pop frame exception. |
| vm_env->popFrameException = oh_allocate_global_handle(); |
| vm_env->popFrameException->object = |
| class_alloc_new_object(vm_env->java_lang_Error_Class); |
| |
| // Precompile StackOverflowError. |
| class_alloc_new_object_and_run_default_constructor(vm_env->java_lang_StackOverflowError_Class); |
| // Precompile ThreadDeath. |
| class_alloc_new_object_and_run_default_constructor(vm_env->java_lang_ThreadDeath_Class); |
| // Precompile InternalError. |
| class_alloc_new_object_and_run_default_constructor(vm_env->java_lang_InternalError_Class); |
| |
| // j.l.Class needs to be initialized for loading magics helper |
| // class |
| class_initialize(vm_env->JavaLangClass_Class); |
| hythread_suspend_enable(); |
| |
| Method * m; |
| |
| // pre compile detach and all includes |
| if (!interpreter_enabled()) { |
| m = vm_env->java_lang_Thread_Class->lookup_method( |
| vm_env->Detach_String, vm_env->DetachDescriptor_String); |
| assert(m); |
| vm_env->em_interface->CompileMethod(m); |
| |
| m = vm_env->java_lang_Thread_Class->lookup_method( |
| vm_env->GetUncaughtExceptionHandler_String, |
| vm_env->GetUncaughtExceptionHandlerDescriptor_String); |
| assert(m); |
| vm_env->em_interface->CompileMethod(m); |
| |
| m = vm_env->java_lang_ThreadGroup_Class->lookup_method( |
| vm_env->UncaughtException_String, vm_env->UncaughtExceptionDescriptor_String); |
| assert(m); |
| vm_env->em_interface->CompileMethod(m); |
| |
| m = vm_env->java_lang_Thread_Class->lookup_method( |
| vm_env->GetDefaultUncaughtExceptionHandler_String, |
| vm_env->GetDefaultUncaughtExceptionHandlerDescriptor_String); |
| assert(m); |
| vm_env->em_interface->CompileMethod(m); |
| |
| m = vm_env->java_lang_Thread_Class->lookup_method( |
| vm_env->GetName_String, vm_env->GetNameDescriptor_String); |
| assert(m); |
| vm_env->em_interface->CompileMethod(m); |
| |
| m = vm_env->java_lang_ThreadGroup_Class->lookup_method( |
| vm_env->Remove_String, vm_env->RemoveDescriptor_String); |
| assert(m); |
| vm_env->em_interface->CompileMethod(m); |
| |
| m = vm_env->java_util_LinkedList_Class->lookup_method( |
| vm_env->LLRemove_String, vm_env->LLRemoveDescriptor_String); |
| assert(m); |
| vm_env->em_interface->CompileMethod(m); |
| } |
| |
| // Mark j.l.Throwable() constructor as a side effects free. |
| m = vm_env->java_lang_Throwable_Class->lookup_method( |
| vm_env->Init_String, vm_env->VoidVoidDescriptor_String); |
| assert(m); |
| m->set_side_effects(MSE_False); |
| |
| // Mark j.l.Throwable(j.l.String) constructor as a side effects free. |
| m = vm_env->java_lang_Throwable_Class->lookup_method( |
| vm_env->Init_String, vm_env->FromStringConstructorDescriptor_String); |
| assert(m); |
| m->set_side_effects(MSE_False); |
| |
| void global_object_handles_init(JNIEnv *); |
| global_object_handles_init(jni_env); |
| |
| Class * aoObjectArray = preload_class(vm_env, "[Ljava/lang/Object;"); |
| cached_object_array_vtable_ptr = aoObjectArray->get_vtable(); |
| |
| // the following is required for creating exceptions |
| preload_class(vm_env, "[Ljava/lang/VMClassRegistry;"); |
| extern int resolve_const_pool(Global_Env& env, Class *clss); |
| status = resolve_const_pool(*vm_env, vm_env->java_lang_Throwable_Class); |
| if(status != 0) { |
| LWARN(25, "Failed to resolve class {0}" << "java/lang/Throwable"); |
| return JNI_ERR; |
| } |
| |
| // We assume, that at this point VM supports exception objects creation. |
| vm_env->ReadyForExceptions(); |
| |
| status = helper_magic_init(vm_env); |
| if(status != 0) { |
| return JNI_ERR; |
| } |
| |
| return JNI_OK; |
| } |
| |
| /** |
| * Second VM initialization stage. At that moment JNI services are available |
| * and main thread has been already attached to VM. |
| */ |
| jint vm_init2(JNIEnv * jni_env) { |
| jint status; |
| Global_Env * vm_env; |
| |
| assert(hythread_is_suspend_enabled()); |
| |
| vm_env = jni_get_vm_env(jni_env); |
| |
| |
| TRACE("Invoking the java.lang.Class constructor"); |
| Class * jlc = vm_env->JavaLangClass_Class; |
| jobject jlo = struct_Class_to_java_lang_Class_Handle(jlc); |
| |
| jmethodID java_lang_class_init = GetMethodID(jni_env, jlo, "<init>", "()V"); |
| jvalue args[1]; |
| args[0].l = jlo; |
| |
| hythread_suspend_disable(); |
| |
| vm_execute_java_method_array(java_lang_class_init, 0, args); |
| assert(!exn_raised()); |
| |
| void unsafe_global_object_handles_init(JNIEnv *); |
| unsafe_global_object_handles_init(jni_env); |
| |
| hythread_suspend_enable(); |
| |
| if (vm_property_get_boolean("vm.finalize", TRUE, VM_PROPERTIES)) { |
| // Load and initialize finalizer thread. |
| vm_env->java_lang_FinalizerThread_Class = |
| preload_class(vm_env, "java/lang/FinalizerThread"); |
| assert(vm_env->java_lang_FinalizerThread_Class); |
| |
| class_initialize_from_jni(vm_env->java_lang_FinalizerThread_Class); |
| vm_obtain_finalizer_fields(); |
| } |
| if(vm_env->TI->isEnabled() && vm_env->TI->needCreateEventThread() ) { |
| vm_env->TI->TIenvs_lock._lock(); |
| jvmti_create_event_thread(); |
| vm_env->TI->disableEventThreadCreation(); |
| vm_env->TI->TIenvs_lock._unlock(); |
| } |
| |
| TRACE("initialization of system classes completed"); |
| |
| #ifdef WIN32 |
| // Code to start up Networking on Win32 |
| WORD wVersionRequested; |
| WSADATA wsaData; |
| int err; |
| wVersionRequested = MAKEWORD(2, 2); |
| err = WSAStartup(wVersionRequested, &wsaData); |
| if (err != 0) { |
| // Tell the user that we could not find a usable WinSock DLL. |
| LWARN(26, "Couldn't startup Winsock 2.0 dll"); |
| } |
| #endif |
| |
| #ifdef LIB_DEPENDENT_OPTS |
| lib_dependent_opts(); |
| #endif |
| |
| TRACE2("init", "initializing system class loader"); |
| status = initialize_system_class_loader(jni_env); |
| if (status != JNI_OK) { |
| LWARN(27, "Failed to initialize system class loader."); |
| if(exn_raised()) { |
| print_uncaught_exception_message(stderr, |
| "system class loader initialization", exn_get()); |
| } |
| return status; |
| } |
| |
| TRACE("system class loader initialized"); |
| |
| set_current_thread_context_loader(jni_env); |
| |
| status = run_java_init(jni_env); |
| if (status != JNI_OK) return status; |
| |
| TRACE("VM initialization completed"); |
| assert(!exn_raised()); |
| |
| return JNI_OK; |
| } |
| |
| JIT_Handle vm_load_jit(const char* file_name, apr_dso_handle_t** handle) { |
| Dll_JIT* jit = new Dll_JIT(file_name); |
| *handle = jit->get_lib_handle(); |
| if(!*handle) { |
| delete jit; |
| return NULL; |
| } |
| vm_add_jit(jit); |
| return (JIT_Handle)jit; |
| } |