/* * Get Method Declaring Class * * For the method indicated by method, return the class that * defined it via declaring_class_ptr. * * REQUIRED Functionality. */ jvmtiError JNICALL jvmtiGetMethodDeclaringClass(jvmtiEnv* env, jmethodID method, jclass* declaring_class_ptr) { TRACE("GetMethodDeclaringClass called for " << method); SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_START, JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); if( !method ) return JVMTI_ERROR_INVALID_FIELDID; if( !declaring_class_ptr ) return JVMTI_ERROR_NULL_POINTER; Method* mtd = (Method*)method; Class* cls = mtd->get_class(); ObjectHandle hclss = struct_Class_to_java_lang_Class_Handle(cls); ObjectHandle newH = NewLocalRef(p_TLS_vmthread->jni_env, hclss); *declaring_class_ptr = (jclass)newH; return JVMTI_ERROR_NONE; }
// // resolve constant pool reference to a method // used for invokespecial // Method* resolve_special_method_env(Global_Env *env, Class_Handle curr_clss, unsigned index, bool raise_exn) { ASSERT_RAISE_AREA; Method* method = curr_clss->_resolve_method(env, index); if(!method) { assert(curr_clss->get_constant_pool().is_entry_in_error(index)); if (raise_exn) { exn_raise_object(curr_clss->get_constant_pool().get_error_cause(index)); } return NULL; } if(curr_clss->is_super() && is_class_extended_class(curr_clss->get_super_class(), method->get_class()) && method->get_name() != env->Init_String) { Method* result_meth; for(Class* clss = curr_clss->get_super_class(); clss; clss = clss->get_super_class()) { result_meth = clss->lookup_method(method->get_name(), method->get_descriptor()); if(result_meth) { method = result_meth; break; } } } if(method && !method_can_link_special(curr_clss, index, method, raise_exn)) return NULL; return method; } //resolve_special_method_env
static Class_Handle method_get_return_type_class(Method_Handle m) { assert(hythread_is_suspend_enabled()); Method *method = (Method *)m; Global_Env *env = VM_Global_State::loader_env; Java_Type UNUSED t = method->get_return_java_type(); assert(t == JAVA_TYPE_CLASS || t == JAVA_TYPE_ARRAY); const char *descr = method->get_descriptor()->bytes; while(*descr != ')') descr++; descr++; String *n; if(descr[0] == 'L') { descr++; size_t len = strlen(descr); n = env->string_pool.lookup(descr, len-1); } else { n = env->string_pool.lookup(descr); } Class *clss = method->get_class(); Class *c = clss->get_class_loader()->LoadVerifyAndPrepareClass(env, n); return c; } //method_get_return_type_class
void Method::_set_nop() { bool verbose = false; Global_Env *env = VM_Global_State::loader_env; if (get_name() != env->Init_String || get_descriptor() != env->VoidVoidDescriptor_String) { return; } if(is_native()) { return; } unsigned len = _byte_code_length; if(!len) { return; } U_8* bc = _byte_codes; Nop_Stack_State stack_state = NS_StackEmpty; if(verbose) { printf("=========== nop[%d]: %s.%s%s\n", len, get_class()->get_name()->bytes, get_name()->bytes, get_descriptor()->bytes); } for (unsigned idx = 0; idx < len; idx++) { U_8 b = bc[idx]; if(verbose) { printf("\tbc[%d]=%d, state=%d\n", idx, b, stack_state); } if(b == 0xb1) { // return if(verbose) { printf("+++++++ nop: %s.%s%s\n", get_class()->get_name()->bytes, get_name()->bytes, get_descriptor()->bytes); } _flags.is_nop = TRUE; return; } switch(stack_state) { case NS_StackEmpty: switch(b) { case 0x2a: // aload_0 stack_state = NS_ThisPushed; break; default: return; } break; case NS_ThisPushed: switch(b) { case 0x01: // aconst_null case 0x03: // iconst_0 stack_state = NS_ThisAndZeroPushed; break; case 0xb7: // invokespecial { unsigned index = (bc[idx + 1] << 8) + bc[idx + 2]; if(verbose) { printf("\tinvokespecial, index=%d\n", index); } Method_Handle mh = resolve_special_method_env(VM_Global_State::loader_env, get_class(), index, false); Method *callee = (Method *)mh; if(!callee) { if(verbose) { printf("\tinvokespecial, callee==null\n"); } return; } if(callee == this) { return; } if(verbose) { printf("invokespecial: %s.%s%s\n", callee->get_class()->get_name()->bytes, callee->get_name()->bytes, callee->get_descriptor()->bytes); } if(!callee->is_nop()) { return; } const char *descr = callee->get_descriptor()->bytes; if(descr[1] != ')') { return; } if(verbose) { printf("invokespecial nop: %s.%s%s\n", callee->get_class()->get_name()->bytes, callee->get_name()->bytes, callee->get_descriptor()->bytes); } } stack_state = NS_StackEmpty; idx += 2; break; default: return; } break; case NS_ThisAndZeroPushed: switch(b) { case 0xb5: // putfield stack_state = NS_StackEmpty; if(verbose) { printf("\tputfield\n"); } idx += 2; break; default: return; } break; default: LDIE(57, "Unexpected stack state"); return; } } LDIE(56, "should'nt get here"); } //Method::_set_nop
void JIT_execute_method_default(JIT_Handle jit, jmethodID methodID, jvalue *return_value, jvalue *args) { // Detecting errors with object headears on stack when using destructive // unwinding. void *lastFrame = p_TLS_vmthread->lastFrame; p_TLS_vmthread->lastFrame = (void*)&lastFrame; //printf("execute: push: prev = 0x%p, curr=0x%p\n", lastFrame, &lastFrame); // fprintf(stderr, "Not implemented\n"); Method *method = (Method*) methodID; TRACE("enter method " << method->get_class()->get_name()->bytes << " " << method->get_name()->bytes << " " << method->get_descriptor()->bytes); int sz = method->get_num_arg_slots(); void *meth_addr = method->get_code_addr(); U_32 *arg_words = (U_32*) STD_ALLOCA(sz * sizeof(U_32)); int argId = sz; int pos = 0; assert(!hythread_is_suspend_enabled()); if (!method->is_static()) { ObjectHandle handle = (ObjectHandle) args[pos++].l; assert(handle); arg_words[--argId] = (unsigned) handle->object; } const char *mtype = method->get_descriptor()->bytes + 1; assert(mtype != 0); for(; *mtype != ')'; mtype++) { switch(*mtype) { case JAVA_TYPE_CLASS: case JAVA_TYPE_ARRAY: { ObjectHandle handle = (ObjectHandle) args[pos++].l; arg_words[--argId] = (unsigned) (handle ? handle->object : 0); while(*mtype == '[') mtype++; if (*mtype == 'L') while(*mtype != ';') mtype++; } break; case JAVA_TYPE_SHORT: // sign extend arg_words[--argId] = (U_32)(I_32) args[pos++].s; break; case JAVA_TYPE_BYTE: // sign extend arg_words[--argId] = (U_32)(I_32) args[pos++].b; break; case JAVA_TYPE_INT: // sign extend arg_words[--argId] = (U_32)(I_32) args[pos++].i; break; case JAVA_TYPE_FLOAT: arg_words[--argId] = (I_32) args[pos++].i; break; case JAVA_TYPE_BOOLEAN: arg_words[--argId] = (I_32) args[pos++].z; break; case JAVA_TYPE_CHAR: // zero extend arg_words[--argId] = (I_32) args[pos++].c; break; case JAVA_TYPE_LONG: case JAVA_TYPE_DOUBLE: *(jlong*)&arg_words[argId-2] = args[pos++].j; argId -= 2; break; default: LDIE(53, "Unexpected java type"); } } assert(argId >= 0); jvalue *resultPtr = (jvalue*) return_value; Java_Type ret_type = method->get_return_java_type(); arg_words += argId; argId = sz - argId; static const IntFuncPtr invoke_managed_func = gen_invoke_int_managed_func(); static const FloatFuncPtr invoke_float_managed_func = gen_invoke_float_managed_func(); static const DoubleFuncPtr invoke_double_managed_func = gen_invoke_double_managed_func(); switch(ret_type) { case JAVA_TYPE_VOID: invoke_managed_func(arg_words, argId, meth_addr); break; case JAVA_TYPE_CLASS: case JAVA_TYPE_ARRAY: case JAVA_TYPE_STRING: { ManagedObject *ref = ((RefFuncPtr)invoke_managed_func)(arg_words, argId, meth_addr); ObjectHandle h = oh_allocate_local_handle(); if (ref != NULL) { h->object = ref; resultPtr->l = h; } else { resultPtr->l = NULL; } } break; case JAVA_TYPE_BOOLEAN: case JAVA_TYPE_BYTE: case JAVA_TYPE_CHAR: case JAVA_TYPE_SHORT: case JAVA_TYPE_INT: resultPtr->i = invoke_managed_func(arg_words, argId, meth_addr); break; case JAVA_TYPE_FLOAT: resultPtr->f = invoke_float_managed_func(arg_words, argId, meth_addr); break; case JAVA_TYPE_LONG: resultPtr->j = ((LongFuncPtr)invoke_managed_func)(arg_words, argId, meth_addr); break; case JAVA_TYPE_DOUBLE: resultPtr->d = invoke_double_managed_func(arg_words, argId, meth_addr); break; default: LDIE(53, "Unexpected java type"); } if (exn_raised()) { TRACE("Exception occured: " << exn_get_name()); if ((resultPtr != NULL) && (ret_type != JAVA_TYPE_VOID)) { resultPtr->l = 0; //clear result } } TRACE("exit method " << method->get_class()->get_name()->bytes << " " << method->get_name()->bytes << " " << method->get_descriptor()->bytes); // Detecting errors with object headears on stack when using destructive // unwinding. //printf("execute: pop: prev = 0x%p, curr=0x%p\n", &lastFrame, lastFrame); p_TLS_vmthread->lastFrame = lastFrame; }
void JIT_execute_method_default(JIT_Handle jh, jmethodID methodID, jvalue *return_value, jvalue *args) { //assert(("Doesn't compile", 0)); //abort(); #if 1 Method *meth = (Method*) methodID; assert(!hythread_is_suspend_enabled()); void *entry_point = meth->get_code_addr(); int nargs = meth->get_num_args(); uint64 arg_words[255]; int double_nargs = 0; double double_args[8]; int num_arg_words = 0; int arg_num = 0; int num_ref_args = 0; Arg_List_Iterator iter = meth->get_argument_list(); uint64 i64; Java_Type typ; char msg[300]; if(!meth->is_static()) { ObjectHandle h = (ObjectHandle) args[arg_num++].l; // this pointer i64 = 0; if (h) i64 = (uint64) h->object; if (VM_Global_State::loader_env->compress_references) { // 20030318 We are in unmanaged code where null is represented by 0/NULL. Convert a null reference // to the representation of null in managed code (heap_base). if (i64 == 0) { i64 = (uint64)VM_Global_State::loader_env->heap_base; } } arg_words[num_arg_words++] = i64; num_ref_args++; } while((typ = curr_arg(iter)) != JAVA_TYPE_END) { ObjectHandle h; *msg = '\0'; switch(typ) { case JAVA_TYPE_LONG: i64 = args[arg_num++].j; arg_words[num_arg_words++] = i64; break; case JAVA_TYPE_CLASS: case JAVA_TYPE_ARRAY: h = (ObjectHandle) args[arg_num++].l; i64 = 0; if (h) i64 = (uint64) h->object; if (VM_Global_State::loader_env->compress_references) { // 20030318 We are in unmanaged code where null is represented by 0/NULL. Convert a null reference // to the representation of null in managed code (heap_base). if (i64 == 0) { i64 = (uint64)VM_Global_State::loader_env->heap_base; } } arg_words[num_arg_words++] = i64; num_ref_args++; #ifdef _DEBUG { if (! VM_Global_State::loader_env->compress_references || i64 != (uint64)VM_Global_State::loader_env->heap_base) { ManagedObject *object = (ManagedObject *)i64; if(object) { Class *clss = object->vt()->clss; sprintf(msg, " of class '%s'", clss->get_name()->bytes); } } } #endif break; case JAVA_TYPE_SHORT: i64 = (uint64)args[arg_num++].s; arg_words[num_arg_words++] = i64; break; case JAVA_TYPE_CHAR: i64 = (uint64)args[arg_num++].c; arg_words[num_arg_words++] = i64; break; case JAVA_TYPE_BYTE: i64 = (uint64)args[arg_num++].b; arg_words[num_arg_words++] = i64; break; case JAVA_TYPE_BOOLEAN: i64 = (uint64)args[arg_num++].z; arg_words[num_arg_words++] = i64; break; case JAVA_TYPE_DOUBLE: double_args[double_nargs] = args[arg_num++].d; double_nargs++; break; case JAVA_TYPE_FLOAT: double_args[double_nargs] = (double)args[arg_num++].f; double_nargs++; break; default: i64 = (uint64)args[arg_num++].i; arg_words[num_arg_words++] = i64; break; } iter = advance_arg_iterator(iter); } // assert(nargs <= 8); double double_result; static void* addr_execute = get_vm_execute_java_method(); struct{ void* fun; void* gp; } fptr; fptr.fun = addr_execute; fptr.gp = get_vm_gp_value(); // gashiman - changed _cdecl to __cdecl to work on linux uint64 (__cdecl *fpp_exec)(void *entry_point, int nargs, uint64 args[], double *double_result_addr, int double_nargs, double double_args[], void *thread_pointer, uint64 tid) = (uint64 (__cdecl * )(void *entry_point, int nargs, uint64 args[], double *double_result_addr, int double_nargs, double double_args[], void *thread_pointer, uint64 tid))&fptr; IDATA id = hythread_get_self_id(); uint64 int_result = (uint64)fpp_exec(entry_point, nargs, arg_words, &double_result, double_nargs, double_args, p_TLS_vmthread, id); // Save the result Java_Type ret_type = meth->get_return_java_type(); switch(ret_type) { case JAVA_TYPE_VOID: break; case JAVA_TYPE_ARRAY: case JAVA_TYPE_CLASS: { ObjectHandle h = 0; if (VM_Global_State::loader_env->compress_references) { // 20030318 Convert a null reference in managed code (represented by heap_base) // to the representation of null in unmanaged code (0 or NULL). if ((uint64)int_result == (uint64)VM_Global_State::loader_env->heap_base) { int_result = 0; } } if (int_result) { h = oh_allocate_local_handle(); h->object = (ManagedObject*) int_result; } return_value->l = h; } break; case JAVA_TYPE_LONG: return_value->j = int_result; break; case JAVA_TYPE_INT: *((I_32 *)return_value) = (I_32) int_result; break; case JAVA_TYPE_SHORT: *((int16 *)return_value) = (int16) int_result; break; case JAVA_TYPE_CHAR: *((uint16 *)return_value) = (uint16) int_result; break; case JAVA_TYPE_BYTE: *((I_8 *)return_value) = (I_8) int_result; break; case JAVA_TYPE_BOOLEAN: *((U_8 *)return_value) = (U_8) int_result; break; case JAVA_TYPE_DOUBLE: *((double *)return_value) = double_result; break; case JAVA_TYPE_FLOAT: *((float *)return_value) = (float) double_result; break; default: #ifdef _DEBUG std::clog << "Returned to C from " << meth->get_class()->get_name()->bytes << "." << meth->get_name()->bytes << meth->get_descriptor()->bytes << "\n"; #endif //DIE("Return type ");// << (int)ret_type << " is not implemented\n"); std::clog << "Return type " << (int)ret_type << " is not implemented\n"; } #endif } //vm_execute_java_method_array