/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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 and 1.4 interface versions */ if (! (vm_args->version == JNI_VERSION_1_2 || vm_args->version == JNI_VERSION_1_4)) { 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 and 1.4 interface versions */ if (! (vm_args->version == JNI_VERSION_1_2 || vm_args->version == JNI_VERSION_1_4)) { 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; } vm->class_loading.boot_loader.boot_class_path_entries = NULL; 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, stderr, "[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 = NULL; /* initialize splay_tree of internal methods */ if (_svmf_initialize_internal_method_tree (env) != JNI_OK) { 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; #ifdef _SABLEVM_INLINABILITY_TESTING _svmf_inlined_testing_initialize (env); #endif _svmf_stopping_java (env); return JNI_OK; error: /* should be freeing resources (memory, locks, dynamic libraries,...) */ return JNI_ERR; } /* ---------------------------------------------------------------------- DestroyJavaVM ---------------------------------------------------------------------- */ void DumpStats(){ printf("Dead Contexts %d\n",deadContextCount); printf("Live Contexts %d\n",liveContextCount); printf("Max Contexts %d\n",maxContextCount); printf("Dead Correlations %d\n",deadCorrelationCount); printf("Live Correlations %d\n",liveCorrelationCount); printf("Max Correlations %d\n",maxCorrelationCount); #ifdef PROBABLECOUNTER { int i; long long total=0; float sum=0.0; for(i=0;i<10000;i++){ if(probableSum[i]>1){ sum+=probableSum[i]/(i+1); total+=probableSum[i]; if(probableSum[i]>9){ printf("Value %d %lld\n",i+1,probableSum[i]); } } } printf("\n Probable Sum %f %f \n",sum/total, (sum-probableSum[0])/(total-probableSum[0])); } #endif #ifdef METHOD_CALL_PROFILING printf("Method Calls %d\n",totalMethodCalls); #endif #ifdef BRANCH_CORRELATION_PROFILING_STATS long long total=0; long long total2=0; printf("Destroyed VM now\n"); printf("MissCounter %lld\n",missCounter); int i; printf("Accounted Instructions %lld ", myInstCounter); for(i=0;i<4;i++){ printf("%lld / %lld ",executedInstructions[i],predictedInstructions[i]); } printf("\n"); printf("Warm Correlations %d \n", warmCorrelations->count); printf("Found %d hotContexts\n",hotCodeCount); printf("hot byteCodes %d \n", hotByteCodeTable->count); printf("hot Branch Merges %d \n", hotBranchMerges->count); printf("hot Branching Contexts %d \n", hotBranchingContexts->count); printf("hot Branch Correlations %d \n", hotCorrelations->count); printf("byteCodes found %d \n", byteCodeTable->count); printf("Branch Merges %d \n", branchMerges->count); printf("Branching Contexts %d \n", branchingContexts->count); printf("Branch Correlation Targets %d \n", branchCorrelationTargets->count); printf("Branch Contexts Created %d\n",branCounter); printf("Branch Correlations Created %d\n",branCorrer); printf("total Signals %d\n",signalCallsCounter); printf("total Scansize %lld\n",scanCounter); printf("total blockSize %lld\n",blockSizeCounter); printf("total loops %lld\n",loopCounter); printf("total weited loops %lld\n",weitLoopCounter); printf("total block entry points %lld\n",blockEntryPointCounter); printf("total entry points %lld\n",entryPointCounter); printf("Strong Correlations %d \n", strongCorrelations->count); printf("Strong Contexts %d \n", strongContexts->count); printf("Strong BytesCodes %d \n", strongBytes->count); printf("new %d size %d matches %d total %d: collisions %d\n",newCounter,totalCached, matchCounter,newCounter+matchCounter,collisionCounter); #ifdef DUMP_TRACES printf("Traced BytesCodes %d \n", blocksLister->count); printf("total %f total instr %f\n blocks %lld instr %f\n length1 %f length2 %f\n", (float)totalCount, totalInstr/10000000.0f, instCount, instr/10000000.0f, (instCount - oldCount2)/(myCount +0.01f - oldCount3) , (counter - oldCount)/(traceCount +.01f - oldCount4)); printf("traces %lld frames %lld ratio %f\n", myCount, traceCount, (traceCount) / (float)(myCount)); printf(" %f frameblocks %lld %lld\n finstr %f %f %f\n", (instCount - oldCount2) / 100000.0f, frameBlocks, counter, finstr/100000000.0f, (counter-oldCount)/100000.0f, (finstr-localFinstr)/(counter-oldCount+0.001f)); printf("trace coverage %f frame coverage %f frame instruction coverage %f\n", (float)(instCount)/(float)(totalCount), (float)(counter)/(float)(totalCount), (float)(finstr)/(float)totalInstr); printf("trace instructions %f, frame instructions %f\n", (float)(instCount)/(float)(myCount), (float)(finstr)/(float)(traceCount)); printf("trace dispatches %f, frame dispatches %f \n", (float)totalCount/(float)((myCount)+(totalCount-(instCount))), (float)totalCount/(float)((totalCount-finstr)+(traceCount))); #endif #ifdef DUMP_BLOCKS { int i; printf("Start Block Distribution Dump\n"); for(i=0;itable->size;i++){ HashUnit *h=blocksLister->table->units[i]; while(h){ printf("%d \n",h->data); h=h->next; } } } #endif /* printf("Start Distribution Dump\n"); while(contextList){ Branch_Context *bc=(Branch_Context *)popList(&contextList); long long current=bc->counter; printf("%lld\n",current); total+=current; } printf("%lld\n",total); */ #ifdef DUMP_TRACES printf("Start Trace Dump\n"); while(traceLister){ Trace *bc=(Trace *)popList(&traceLister); long long current=bc->counter; total2+=bc->blocks; printf("%lld %d\n",current, bc->blocks); total+=current; } printf("%lld %lld\n",total,total2); #endif #endif } JNIEXPORT static jint JNICALL DestroyJavaVM (JavaVM *_vm) { _svmt_JavaVM *vm = (_svmt_JavaVM *) (void *) _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, stderr, "[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 */ #ifdef _SABLEVM_INLINABILITY_TESTING _svmf_print_inlined_testing_results (env); #endif DumpStats(); /* Just for simplicity... */ return JNI_OK; } /* ---------------------------------------------------------------------- AttachCurrentThread ---------------------------------------------------------------------- */ JNIEXPORT static jint JNICALL AttachCurrentThread (JavaVM *vm SVM_UNUSED, void **penv SVM_UNUSED, void *args SVM_UNUSED) { _svmm_fatal_error ("todo"); return JNI_ERR; } /* ---------------------------------------------------------------------- DetachCurrentThread ---------------------------------------------------------------------- */ JNIEXPORT static jint JNICALL DetachCurrentThread (JavaVM *vm SVM_UNUSED) { _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. */ JNIEXPORT static 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 || _svmf_cast_JavaVM (env->vm) != vm) { /* This thread is not attached to VM */ (*penv) = NULL; return JNI_EDETACHED; } switch (interface_id) { case JNI_VERSION_1_4: case JNI_VERSION_1_2: case JNI_VERSION_1_1: break; default: _svmf_printf (env, stderr, "*** Warning: JNI version requested in GetEnv() is unavailable.\n" "*** Only JNI 1.4, 1.2, and 1.1 are supported here."); (*penv) = NULL; return JNI_EVERSION; } (*penv) = env; return JNI_OK; }