/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This source file is part of SableVM. * * * * See the file "LICENSE" for the copyright information and for * * the terms and conditions for copying, distribution and * * modification of this source file. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* all created VMs */ static pthread_mutex_t _svmv_vm_list_mutex = PTHREAD_MUTEX_INITIALIZER; /* protected by a mutex */ static _svmt_JavaVM *_svmv_vm_list = NULL; /* list of vms */ /* interface table */ static JNIInvokeInterface _svmv_invoke_interface = { NULL, NULL, NULL, DestroyJavaVM, AttachCurrentThread, DetachCurrentThread, GetEnv }; /* ---------------------------------------------------------------------- JNI_GetDefaultJavaVMInitArgs ---------------------------------------------------------------------- */ JNIEXPORT jint JNICALL JNI_GetDefaultJavaVMInitArgs (void *_vm_args) { JavaVMInitArgs *vm_args = (JavaVMInitArgs *) _vm_args; if (_svmf_init () != JNI_OK) { goto error; } /* we only communicate using the 1.2 interface version */ if (vm_args->version != JNI_VERSION_1_2) { goto error; } return JNI_OK; error: return JNI_ERR; } /* ---------------------------------------------------------------------- JNI_GetCreatedJavaVMs ---------------------------------------------------------------------- */ JNIEXPORT jint JNICALL JNI_GetCreatedJavaVMs (JavaVM **vmBuf, jsize bufLen, jsize *nVMs) { jsize count = 0; _svmt_JavaVM *current; if (_svmf_init () != JNI_OK) { goto error; } /* get lock, then visit list of vms */ _svmm_mutex_lock (_svmv_vm_list_mutex); current = _svmv_vm_list; while (current != NULL && count < bufLen) { vmBuf[count] = _svmf_cast_JavaVM (current); count++; current = current->next; } *nVMs = count; _svmm_mutex_unlock (); return JNI_OK; error: return JNI_ERR; } /* ---------------------------------------------------------------------- JNI_CreateJavaVM ---------------------------------------------------------------------- */ JNIEXPORT jint JNICALL JNI_CreateJavaVM (JavaVM **pvm, void **penv, void *_vm_args) { JavaVMInitArgs *vm_args = (JavaVMInitArgs *) _vm_args; _svmt_JavaVM *vm = NULL; _svmt_JNIEnv *env = NULL; if (_svmf_init () != JNI_OK) { goto error; } /* we only communicate using the 1.2 interface version */ if (vm_args->version != JNI_VERSION_1_2) { goto error; } /* make sure this thread isn't already attached to a vm */ if (_svmf_get_current_env () != NULL) { goto error; } /* allocate vm struct */ if (_svmm_gzalloc_vm_no_exception (vm) != JNI_OK) { goto error; } vm->interface = &_svmv_invoke_interface; _svmm_mutex_init (vm->global_mutex); _svmm_cond_init (vm->requesting_thread_cond); _svmm_cond_init (vm->halted_threads_cond); vm->vfprintf = vfprintf; vm->exit = exit; vm->abort = abort; vm->boot_working_directory = _svmf_get_current_working_directory (); _svmf_heap_init_defaults (vm); _svmf_class_loader_init_defaults (vm); _svmf_stack_init_defaults (vm); if (_svmm_galloc_copy_str_no_exception (vm->class_loading.boot_loader.boot_class_path, BOOT_CLASS_PATH) != JNI_OK) { goto error; } if (_svmm_galloc_copy_str_no_exception (vm->class_loading.boot_loader.boot_library_path, BOOT_LIBRARY_PATH) != JNI_OK) { goto error; } /* allocate initialization struct */ if (_svmm_gzalloc_initialization_no_exception (vm->initialization) != JNI_OK) { goto error; } if (vm_args->nOptions > 0) { vm->class_loading.boot_loader.system_properties.properties = _svmf_calloc (vm_args->nOptions, sizeof (char *)); if (vm->class_loading.boot_loader.system_properties.properties == NULL) { goto error; } } /* process vm_args */ { jint i; jint nOptions = vm_args->nOptions; for (i = 0; i < nOptions; i++) { char *optstr = vm_args->options[i].optionString; #include "vm_args.c" } } /* validate some arguments */ if (_svmm_validate_min_max_increment (vm->stack_min_size, vm->stack_max_size, vm->stack_allocation_increment) != JNI_OK) { goto error; } if (_svmm_validate_min_max_increment (vm->class_loader_min_size, vm->class_loader_max_size, vm->class_loader_allocation_increment) != JNI_OK) { goto error; } if (vm->class_loading.boot_loader.boot_class_path[0] != '/') { goto error; } if (vm->class_loading.boot_loader.boot_library_path[0] != '/') { goto error; } /* allocate JNIEnv struct */ if (_svmm_gzalloc_env_no_exception (env) != JNI_OK) { goto error; } _svmf_set_current_env (env); _svmm_cond_init (vm->threads.vm_destruction_cond); vm->threads.user = env; vm->threads.next_thread_id = 1; /* thread IDs must start at 1 (i.e. no ID == 0) */ env->interface = &_svmv_native_interface; env->vm = vm; env->thread.pthread = pthread_self (); env->thread.id = vm->threads.next_thread_id++; _svmf_initialize_thinlock_id (env); env->thread_status = SVM_THREAD_STATUS_RUNNING_JAVA; env->is_alive = JNI_TRUE; _svmm_mutex_init (env->contention.owner.mutex); _svmm_cond_init (env->contention.requester.cond); if (_svmm_gzmalloc_env_array (env, SVM_MAX_THREAD_ID + 1, vm->threads.array) != JNI_OK) { goto error; } vm->threads.array[env->thread.id] = env; if (_svmm_gzmalloc_fat_lock_array (env, SVM_MAX_FATLOCK_ID, vm->fat_locks.array) != JNI_OK) { goto error; } if (_svmm_gzalloc_native_ref_no_exception (env->native_locals.list) != JNI_OK) { goto error; } env->throwable = _svmf_cast_jobject_nref (env->native_locals.list); if (_svmm_gzalloc_native_ref_no_exception (env->native_locals.list->next) != JNI_OK) { goto error; } env->contention.requester.jobject = _svmf_cast_jobject_nref (env->native_locals.list->next); if (sigsetjmp (vm->initialization->unrecoverable_exception_handler, 1)) { goto error; } /* tell them were're here :-) */ if (vm->verbose_jni) { _svmf_printf (env, stdout, "[verbose jni: JNI_CreateJavaVM]\n"); } /* initialize vm->instructions */ if (_svmm_gzmalloc_instruction_info (env, SVM_INSTRUCTION_COUNT, vm->instructions) != JNI_OK) { goto error; } #ifdef _SABLEVM_SIGNALS_FOR_EXCEPTIONS #ifndef NDEBUG env->sigsegv_expected = JNI_TRUE; #endif #endif if (_svmf_interpreter (env) != JNI_OK) { goto error; } /* initialize special methods */ _svmm_set_flag (vm->stack_bottom_method.access_flags, SVM_ACC_INTERNAL); vm->stack_bottom_method.frame_info = &vm->stack_bottom_method.prepared_info; vm->stack_bottom_method.frame_info->code = &vm->instructions[SVM_INSTRUCTION_ERROR].code; _svmm_set_flag (vm->internal_call_method.access_flags, SVM_ACC_INTERNAL); vm->internal_call_method.frame_info = &vm->internal_call_method.prepared_info; vm->internal_call_method.frame_info->code = &vm->instructions[SVM_INSTRUCTION_INTERNAL_CALL_END].code; _svmm_set_flag (vm->vm_initiated_call_method.access_flags, SVM_ACC_INTERNAL); vm->vm_initiated_call_method.frame_info = &vm->vm_initiated_call_method.prepared_info; vm->vm_initiated_call_method.frame_info->code = &vm->instructions[SVM_INSTRUCTION_INTERNAL_CALL_END].code; /* initialize the heap */ if (_svmf_heap_init (env) != JNI_OK) { goto error; } /* allocate boot class loader */ if (_svmm_gzalloc_class_loader_info (env, vm->class_loading.boot_loader.class_loader_info) != JNI_OK) { goto error; } vm->class_loading.class_loader_list = vm->class_loading.boot_loader.class_loader_info; if (_svmf_init_cl_alloc (env, vm->class_loading.boot_loader.class_loader_info) != JNI_OK) { goto error; } /* initialize the stack */ if (_svmf_stack_init (env) != JNI_OK) { goto error; } /* set vm as first native library */ if (_svmm_cl_zalloc_native_library (env, vm->class_loading.boot_loader.class_loader_info, vm->class_loading.boot_loader.class_loader_info-> native_library_list) != JNI_OK) { goto error; } vm->class_loading.boot_loader.class_loader_info-> native_library_list_tail = &vm->class_loading.boot_loader.class_loader_info->native_library_list-> next; if (_svmm_galloc_copy_str_no_exception (vm->class_loading.boot_loader.class_loader_info-> native_library_list->name, "SableVM internal library") != JNI_OK) { goto error; } vm->class_loading.boot_loader.class_loader_info->native_library_list-> handle = lt_dlopen (NULL); if (vm->class_loading.boot_loader.class_loader_info->native_library_list-> handle == NULL) { goto error; } /* time to bootstrap! */ if (_svmf_bootstrap (env) != JNI_OK) { goto error; } _svmm_gzfree_initialization_no_exception (vm->initialization); *penv = env; *pvm = (JavaVM *) env->vm; _svmf_stopping_java (env); return JNI_OK; error: /* should be freeing resources (memory, locks, dynamic libraries,...) */ return JNI_ERR; } /* ---------------------------------------------------------------------- DestroyJavaVM ---------------------------------------------------------------------- */ static JNIEXPORT jint JNICALL DestroyJavaVM (JavaVM *_vm) { _svmt_JavaVM *vm = (_svmt_JavaVM *) _vm; _svmt_JNIEnv *env = _svmf_get_current_env (); if (env == NULL) { return JNI_ERR; } _svmf_resuming_java (env); _svmm_mutex_lock (vm->global_mutex); /* remove this thread from user thread list */ _svmf_halt_if_requested (env); assert (env->is_alive); env->is_alive = JNI_FALSE; if (env->previous != NULL) { env->previous->next = env->next; } else { if (env->thread.is_daemon) { vm->threads.system = env->next; } else { vm->threads.user = env->next; } } if (env->next != NULL) { env->next->previous = env->previous; } /* wait for all non-deamon threads to die */ while (vm->threads.user != NULL) { _svmm_cond_wait (vm->threads.vm_destruction_cond, vm->global_mutex); } _svmm_mutex_unlock (); #if defined (_SABLEVM_COPY_GC) if (vm->verbose_gc) { _svmf_printf (env, stdout, "[verbose gc: total gc time = %ld sec %ld usec]\n", vm->heap.total_gc_secs, vm->heap.total_gc_usecs); } #endif #ifdef STATISTICS _svmf_print_statistics (env); #endif /* STATISTICS */ /* Just for simplicity... */ return JNI_OK; } /* ---------------------------------------------------------------------- AttachCurrentThread ---------------------------------------------------------------------- */ static JNIEXPORT jint JNICALL AttachCurrentThread (JavaVM *vm, void **penv, void *args) { _svmm_fatal_error ("todo"); return JNI_ERR; } /* ---------------------------------------------------------------------- DetachCurrentThread ---------------------------------------------------------------------- */ static JNIEXPORT jint JNICALL DetachCurrentThread (JavaVM *vm) { _svmm_fatal_error ("todo"); return JNI_ERR; } /* ---------------------------------------------------------------------- GetEnv ---------------------------------------------------------------------- */ /* If the current thread is not attached to the VM, sets *env to NULL, and returns JNI_EDETACHED. If the specified version is not supported, sets *env to NULL, and returns JNI_EVERSION. Otherwise, sets *env to the appropriate interface, and returns JNI_OK. */ static JNIEXPORT jint JNICALL GetEnv (JavaVM *vm, void **penv, jint interface_id) { _svmt_JNIEnv *env; /* find the current thread */ env = _svmf_get_current_env (); if (env == NULL) { /* This thread is not attached to VM */ (*penv) = NULL; return JNI_EDETACHED; } switch (interface_id) { case JNI_VERSION_1_1: case JNI_VERSION_1_2: break; default: (*penv) = NULL; return JNI_EVERSION; } (*penv) = env; return JNI_OK; }