Return-Path: Delivered-To: apmail-harmony-commits-archive@www.apache.org Received: (qmail 70154 invoked from network); 12 Aug 2007 22:18:58 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 12 Aug 2007 22:18:58 -0000 Received: (qmail 90433 invoked by uid 500); 12 Aug 2007 22:18:56 -0000 Delivered-To: apmail-harmony-commits-archive@harmony.apache.org Received: (qmail 90415 invoked by uid 500); 12 Aug 2007 22:18:56 -0000 Mailing-List: contact commits-help@harmony.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@harmony.apache.org Delivered-To: mailing list commits@harmony.apache.org Received: (qmail 90406 invoked by uid 99); 12 Aug 2007 22:18:56 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 12 Aug 2007 15:18:56 -0700 X-ASF-Spam-Status: No, hits=-100.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 12 Aug 2007 22:18:56 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 6F2831A981A; Sun, 12 Aug 2007 15:18:36 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r565178 - /harmony/enhanced/sandbox/bootjvm/bootJVM/jvm/src/opcode.c Date: Sun, 12 Aug 2007 22:18:36 -0000 To: commits@harmony.apache.org From: dlydick@apache.org X-Mailer: svnmailer-1.1.0 Message-Id: <20070812221836.6F2831A981A@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: dlydick Date: Sun Aug 12 15:18:34 2007 New Revision: 565178 URL: http://svn.apache.org/viewvc?view=rev&rev=565178 Log: Trying to set up logic for finding out what is going on with trashed 'thridx' on longjmp() return. Check abstract method index in longjmp() recovery logic as well as bad method index. Broke up group of GETSTATIC, GETFIELD, PUTSTATIC, PUTFIELD. Instead, use the various macros to explicitly define each one instead of trying to maximize common code. This will run faster and be simpler to maintain at the expense of some small memory premium. Then finished out GETFIELD and PUTFIELD, including adding OO tests in classutil_xxx() functions Adjusted grouping of common code for INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, and INVOKEINTERFACE opcodes. Keep commonality since there is so much overlap, including adding OO tests in classutil_xxx() functions. Modified: harmony/enhanced/sandbox/bootjvm/bootJVM/jvm/src/opcode.c Modified: harmony/enhanced/sandbox/bootjvm/bootJVM/jvm/src/opcode.c URL: http://svn.apache.org/viewvc/harmony/enhanced/sandbox/bootjvm/bootJVM/jvm/src/opcode.c?view=diff&rev=565178&r1=565177&r2=565178 ============================================================================== --- harmony/enhanced/sandbox/bootjvm/bootJVM/jvm/src/opcode.c (original) +++ harmony/enhanced/sandbox/bootjvm/bootJVM/jvm/src/opcode.c Sun Aug 12 15:18:34 2007 @@ -196,6 +196,7 @@ #define PORTABLE_JMP_BUF_VISIBLE #include "jvmcfg.h" +#include "attribute.h" #include "cfmacros.h" #include "classfile.h" #include "exit.h" @@ -578,6 +579,20 @@ ARCH_FUNCTION_NAME(opcode_run); /*! + * @internal Keep a copy of @b thridx of compiler optimizes it out + * somehow at the @b longjmp(3) return via + * @link #THREAD_EXCEPTION_SETUP() + THREAD_EXCEPTION_SETUP()@endlink . + * + * @todo: HARMONY-6-jvm-opcode.c-159 There is something fishy here + * that produces the zeroed-out 'thridx' below. What is it? + * It is _not_ a compile optimization problem. + * A to-do item below uses 'keep_thridx' defined here. + */ + auto jvm_thread_index keep_thridx = thridx; + +#warning Need to redesign this mechanism to use Java exception mechanism + /*! * @internal Handler linkage for end of thread detection. * This structure is @e horrible. It is @e ugly. See * @link jvm/src/portable_jmp_buf.c portable_jmp_buf.c@endlink @@ -616,6 +631,7 @@ int nonlocal_rc = THREAD_EXCEPTION_SETUP(thridx); /* Show error case first due to @e long switch() following */ +#warning Look into why 'thridx' is trashed upon longjmp() here if (THREAD_STATUS_EMPTY != nonlocal_rc) { /* @@ -628,10 +644,16 @@ THREAD_STATUS_THREW_THROWABLE | THREAD_STATUS_THREW_UNCAUGHT); - /* - * Local copy of @link rthread#pThrowable pThrowable@endlink - * for use below + /*! + * @internal Local copy of + * @link rthread#pThrowableEvent pThrowableEvent@endlink + * for use below. Notice that @b keep_thridx is used here + * to restore @b thridx also per above comments. + * + * @todo: HARMONY-6-jvm-opcode.c-160 This is the other half + * of a to-do item above that defines 'keep_thridx'. */ + thridx = keep_thridx; rchar *pThrowableEvent = THREAD(thridx).pThrowableEvent; /* @@ -751,6 +773,13 @@ /*NOTREACHED*/ } + if (jvm_attribute_index_abstract == codeatridx) + { + exit_throw_exception(EXIT_JVM_ATTRIBUTE, + JVMCLASS_JAVA_LANG_ABSTRACTMETHODERROR); +/*NOTREACHED*/ + } + if (jvm_attribute_index_native == codeatridx) { /* Pass parameters for both local method and JNI call */ @@ -770,8 +799,8 @@ } else { - Code_attribute *pca = (Code_attribute *) - &pmthidx->attributes[codeatridx]; + Code_attribute *pca = + ATR_CODE_AI(pmthidx->attributes[codeatridx]); PUSH_FRAME(thridx, pca->max_locals); PUT_PC_IMMEDIATE(thridx, clsidx, @@ -914,6 +943,7 @@ u1 op2u1; /* Operand 2 as a (u1) */ u1 op3u1; /* Operand 3 as a (u1) */ rboolean rbool1; /* Conditional instruction status */ + rboolean rbool2; /* INVOKESPECIAL method selection */ u4 *pu4; /* Operand as a (u4 *) */ @@ -938,11 +968,13 @@ /* Scratch area for Fieldref and Methodref navigation */ - cp_info_mem_align *pcpma; - CONSTANT_Class_info *pcpma_Class; - CONSTANT_Fieldref_info *pcpma_Fieldref; - CONSTANT_Methodref_info *pcpma_Methodref; - CONSTANT_Utf8_info *pcpma_Utf8; + cp_info_mem_align *pcpma; + CONSTANT_Class_info *pcpma_Class; + CONSTANT_Fieldref_info *pcpma_Fieldref; + CONSTANT_Methodref_info *pcpma_Methodref; + CONSTANT_InterfaceMethodref_info *pcpma_InterfaceMethodref; + CONSTANT_NameAndType_info *pcpma_NameAndType; + CONSTANT_Utf8_info *pcpma_Utf8; field_info *pfld; method_info *pmth; @@ -953,11 +985,13 @@ jvm_class_index clsidxmisc; jvm_class_index clsidxmisc2; jvm_method_index mthidxmisc; + jvm_attribute_index codeatridxmisc; jvm_object_hash objhashmisc; jvm_field_lookup_index fluidxmisc; rchar *prchar_clsname; rushort special_obj_misc; jvm_sp fptmp; + class_resolve_member resolve_objhashmisc; /* Calls @c @b setjmp(3) to arm handler */ @@ -965,7 +999,7 @@ nonlocal_thread_return = OPCODE_END_THREAD_SETUP( &opcode_end_thread_nonlocal_return); - /* Show error case first due to @e long switch() following */ + /* Show longjmp() case first due to @e long switch() following*/ if (EXIT_MAIN_OKAY != nonlocal_thread_return) { ; /* Nothing to do since this is not an error. */ @@ -989,7 +1023,7 @@ #if 1 if (DBGMSG_PRINT(DMLNORM - 1)) { - opcode_disassemble(DMLNORM - 1, + opcode_disassemble(DML4, arch_function_name, thridx, pcode, @@ -2536,7 +2570,6 @@ break; case OPCODE_B2_GETSTATIC: - case_opcode_b4_getfield: /* Retrieve the @c @b constant_pool (u2) operand */ GET_U2_OPERAND(op1u2); @@ -2544,54 +2577,111 @@ /* Must reference a field */ CHECK_CP_TAG(op1u2, CONSTANT_Fieldref); - /* calc clsidxmisc and pcpma and pcpma_Fieldref */ + /* calc clsidxmisc and pcpma and pcpma_Fieldref and pfld */ CALCULATE_FIELD_INFO_FROM_FIELD_REFERENCE(op1u2); /* Must be a valid reference to a field */ CHECK_VALID_FIELDLOOKUPIDX(fluidxmisc); - switch (opcode) - { - case OPCODE_B2_GETSTATIC: - /* Must be a static field */ - CHECK_STATIC_FIELD; + /* Must be a static field */ + CHECK_STATIC_FIELD; - /*! - * @todo HARMONY-6-jvm-opcode.c-131 Does this check for - * final field also apply to an object instance - * field, or is it for class static fields only? - */ + /*! + * @todo HARMONY-6-jvm-opcode.c-131 Does this check for + * final field also apply to an object instance + * field, or is it for class static fields only? + */ - /* If it is a final field, it must be in the current class*/ - CHECK_FINAL_FIELD_CURRENT_CLASS; + /* If it is a final field, it must be in the current class*/ + CHECK_FINAL_FIELD_CURRENT_CLASS; - /* Retrieve data from the class static field now */ - GETDATA(CLASS(pcpma_Fieldref - ->LOCAL_Fieldref_binding - .clsidxJVM) - .class_static_field_data[fluidxmisc]); - break; + /* Retrieve data from the class static field now */ + GETDATA(CLASS(pcpma_Fieldref->LOCAL_Fieldref_binding.clsidxJVM) + .class_static_field_data[fluidxmisc]); - case OPCODE_B4_GETFIELD: - /*! - * @todo HARMONY-6-jvm-opcode.c-132 Needs unit - * testing w/ real data - */ + break; - /* Must be an object instance field */ - CHECK_INSTANCE_FIELD; +case OPCODE_B3_PUTSTATIC: - /* Retrieve data from the object instance field now */ - POP(thridx, jotmp1, jvm_object_hash); - VERIFY_OBJECT_HASH(jotmp1); - GETDATA(OBJECT(jotmp1) - .object_instance_field_data[fluidxmisc]); - break; + /* Retrieve the @c @b constant_pool (u2) operand */ + GET_U2_OPERAND(op1u2); + + /* Must reference a field */ + CHECK_CP_TAG(op1u2, CONSTANT_Fieldref); + + /* calc clsidxmisc and pcpma and pcpma_Fieldref and pfld */ + CALCULATE_FIELD_INFO_FROM_FIELD_REFERENCE(op1u2); + + /* Must be a valid reference to a field */ + CHECK_VALID_FIELDLOOKUPIDX(fluidxmisc); + + /* Must be a static field */ + CHECK_STATIC_FIELD; + + /* If it is a final field, it must be in the current class*/ + CHECK_FINAL_FIELD_CURRENT_CLASS; + + /* Store data into the static field now */ + PUTDATA(CLASS(pcpma_Fieldref->LOCAL_Fieldref_binding.clsidxJVM) + .class_static_field_data[fluidxmisc]); + + break; + +case OPCODE_B4_GETFIELD: + /* Retrieve the @c @b constant_pool (u2) operand */ + GET_U2_OPERAND(op1u2); + + /* Must reference a field */ + CHECK_CP_TAG(op1u2, CONSTANT_Fieldref); + + /* calc clsidxmisc and pcpma and pcpma_Fieldref and pfld */ + CALCULATE_FIELD_INFO_FROM_FIELD_REFERENCE(op1u2); + + /* Must be a valid reference to a field */ + CHECK_VALID_FIELDLOOKUPIDX(fluidxmisc); + + /*! + * @todo HARMONY-6-jvm-opcode.c-132 Needs unit + * testing w/ real data + */ + + /* Must be an object instance field */ + CHECK_INSTANCE_FIELD; + + /* Retrieve and validate object reference */ + POP(thridx, objhashmisc, jvm_object_hash); + VERIFY_OBJECT_HASH(objhashmisc); + + /* Must not be an array object */ + CHECK_NOT_ARRAY_OBJECT; + +#warning When tested below, test here + /* Validate requested field if it is protected */ + clsidxmisc2 = GET_PC_FIELD_IMMEDIATE(thridx, clsidx); + CHECK_PROTECTED_FIELD_IS_ACCESSIBLE; + + /* Locate object hash of class containing field */ + objhashmisc = + classutil_direct_superclass_parent_object_of(clsidxmisc, + objhashmisc); + + if (jvm_object_hash_null == objhashmisc) + { + thread_throw_exception(thridx, + THREAD_STATUS_THREW_ERROR, + JVMCLASS_JAVA_LANG_ILLEGALACCESSERROR); +/*NOTREACHED*/ } + + /* + * Retrieve data from the object instance field now + * and push it onto the stack. + */ + GETDATA(OBJECT(objhashmisc).object_instance_field_data[fluidxmisc]); + break; -case OPCODE_B3_PUTSTATIC: - case_opcode_b5_putfield: +case OPCODE_B5_PUTFIELD: /* Retrieve the @c @b constant_pool (u2) operand */ GET_U2_OPERAND(op1u2); @@ -2599,160 +2689,408 @@ /* Must reference a field */ CHECK_CP_TAG(op1u2, CONSTANT_Fieldref); - /* calc clsidxmisc and pcpma and pcpma_Fieldref */ + /* calc clsidxmisc and pcpma and pcpma_Fieldref and pfld */ CALCULATE_FIELD_INFO_FROM_FIELD_REFERENCE(op1u2); /* Must be a valid reference to a field */ CHECK_VALID_FIELDLOOKUPIDX(fluidxmisc); - switch (opcode) - { - case OPCODE_B3_PUTSTATIC: - /* Must be a static field */ - CHECK_STATIC_FIELD; + /*! + * @todo HARMONY-6-jvm-opcode.c-134 Needs unit + * testing w/ real data + */ - /*! - * @todo HARMONY-6-jvm-opcode.c-133 Does this check for - * final field also apply to an object instance - * field, or is it for class static fields only? - */ + /* Must be an object instance field */ + CHECK_INSTANCE_FIELD; - /* If it is a final field, it must be in the current class*/ - CHECK_FINAL_FIELD_CURRENT_CLASS; + /* If it is a final field, it must be in the current class*/ + CHECK_FINAL_FIELD_CURRENT_CLASS; - /* Store data into the static field now */ - PUTDATA(CLASS(pcpma_Fieldref - ->LOCAL_Fieldref_binding.clsidxJVM) - .class_static_field_data[fluidxmisc]); + /* + * Retrieve and validate object reference, located either + * 1 stack 'value' below value to be stored, being either + * 1 or 2 stack words, depending on sizeof(value). + */ + switch (pcpma_Fieldref->LOCAL_Fieldref_binding.jvaluetypeJVM) + { + case BASETYPE_CHAR_D: + objhashmisc = + GET_SP_WORD(thridx, + sizeof(jdouble) / sizeof(jint), + jvm_object_hash); + break; + case BASETYPE_CHAR_J: + objhashmisc = + GET_SP_WORD(thridx, + sizeof(jlong) / sizeof(jint), + jvm_object_hash); + break; + case BASETYPE_CHAR_F: + objhashmisc = + GET_SP_WORD(thridx, + sizeof(jfloat) / sizeof(jint), + jvm_object_hash); break; + case BASETYPE_CHAR_L: + objhashmisc = + GET_SP_WORD(thridx, + sizeof(jvm_object_hash) / sizeof(jint), + jvm_object_hash); + break; + default: + objhashmisc = + GET_SP_WORD(thridx, + sizeof(jint) / sizeof(jint), + jvm_object_hash); + break; + } + VERIFY_OBJECT_HASH(objhashmisc); - case OPCODE_B5_PUTFIELD: - /*! - * @todo HARMONY-6-jvm-opcode.c-134 Needs unit - * testing w/ real data - */ + /* Must not be an array object */ + CHECK_NOT_ARRAY_OBJECT; - /* Must be an object instance field */ - CHECK_INSTANCE_FIELD; + /* Validate requested field if it is protected */ + clsidxmisc2 = GET_PC_FIELD_IMMEDIATE(thridx, clsidx); + CHECK_PROTECTED_FIELD_IS_ACCESSIBLE; - /* Store data into the object instance field now */ - POP(thridx, jotmp1, jvm_object_hash); - VERIFY_OBJECT_HASH(jotmp1); - PUTDATA(OBJECT(jotmp1) - .object_instance_field_data[fluidxmisc]); - break; + /* Locate object hash of class containing field */ + objhashmisc = + classutil_direct_superclass_parent_object_of(clsidxmisc, + objhashmisc); + + if (jvm_object_hash_null == objhashmisc) + { + thread_throw_exception(thridx, + THREAD_STATUS_THREW_ERROR, + JVMCLASS_JAVA_LANG_ILLEGALACCESSERROR); +/*NOTREACHED*/ } - break; -case OPCODE_B4_GETFIELD: - goto case_opcode_b4_getfield; + /* + * Pop data from the stack and store it into the + * object instance field + */ + PUTDATA(OBJECT(objhashmisc).object_instance_field_data[fluidxmisc]); -case OPCODE_B5_PUTFIELD: - goto case_opcode_b5_putfield; + /* Strip object hash from stack (retrieved above) */ + DEC_SP(thridx, 1); + + break; case OPCODE_B6_INVOKEVIRTUAL: /* Retrieve the @c @b constant_pool (u2) operand */ GET_U2_OPERAND(op1u2); + /* Must reference a method */ + CHECK_CP_TAG(op1u2, CONSTANT_Methodref); + + /* calc clsidxmisc and pcpma and pcpma_Methodref and pmth */ + CALCULATE_METHOD_INFO_FROM_METHOD_REFERENCE(op1u2,Methodref); + goto case_opcode_b6_invokevirtual; case OPCODE_B7_INVOKESPECIAL: /* Retrieve the @c @b constant_pool (u2) operand */ GET_U2_OPERAND(op1u2); + /* Must reference a method */ + CHECK_CP_TAG(op1u2, CONSTANT_Methodref); + + /* calc clsidxmisc and pcpma and pcpma_Methodref and pmth */ + CALCULATE_METHOD_INFO_FROM_METHOD_REFERENCE(op1u2,Methodref); + goto case_opcode_b7_invokespecial; case OPCODE_B8_INVOKESTATIC: /* Retrieve the @c @b constant_pool (u2) operand */ GET_U2_OPERAND(op1u2); - case_opcode_b6_invokevirtual: - case_opcode_b7_invokespecial: - case_opcode_b9_invokeinterface: - /* Must reference a method */ CHECK_CP_TAG(op1u2, CONSTANT_Methodref); - /* - * Calc clsidxmisc and pcpma and pcpma_Methodref. If class - * has not yet been loaded, do so now. The spec says to - * do it following the check for an abstract method, but - * in this implementation, the loading has to be done - * before the testing in case the method is not in this - * class but in a superclass or superinterface. - */ - pcpma = pcfs->constant_pool[op1u2]; - pcpma_Methodref = PTR_THIS_CP_Methodref(pcpma); - clsidxmisc =pcpma_Methodref->LOCAL_Methodref_binding.clsidxJVM; + /* calc clsidxmisc and pcpma and pcpma_Methodref and pmth */ + CALCULATE_METHOD_INFO_FROM_METHOD_REFERENCE(op1u2,Methodref); + + case_opcode_b6_invokevirtual: + case_opcode_b7_invokespecial: + case_opcode_b9_invokeinterface: + + /*! + * @internal Calculate length of argument list in stack frame + * and whether or not there is a @c @b this object hash + * beyond it. + */ + jitmp1 = method_parm_size(clsidxmisc, pmth->descriptor_index); + + jitmp2 = (ACC_STATIC & pmth->access_flags) + ? (((0 * sizeof(jvm_object_hash)) / sizeof(jint))) + : (((1 * sizeof(jvm_object_hash)) / sizeof(jint))); /* - * Try to resolve this class before attempting to load. - * It could be that it has been loaded but is not yet - * resolved enough. + * Resolve method to use, except INVOKESTATIC already knows this. */ - if (jvm_class_index_null == clsidxmisc) + switch(opcode) { - (rvoid) linkage_resolve_class(GET_PC_FIELD_IMMEDIATE(thridx, - clsidx), - rfalse); + case OPCODE_B6_INVOKEVIRTUAL: + case OPCODE_B7_INVOKESPECIAL: + case OPCODE_B9_INVOKEINTERFACE: + /*! + * @internal The object reference for @c @b this object + * is located immediately past the argument + * list for the invoked method. + */ + objhashmisc = GET_SP_WORD(thridx, + (jitmp1 + jitmp2 - 1), + jvm_object_hash); - clsidxmisc = pcpma_Methodref->LOCAL_Methodref_binding.clsidxJVM; + /*! + * @internal The null reference and access_flags logic + * is also implemented in the macro + * @link #POP_THIS_OBJHASH POP_THIS_OBJHASH@endlink + * in the file + * @link jvm/src/native.c native.c@endlink + * for native methods. + * + * @todo HARMONY-6-jvm-opcode.c-139 The spec is unclear + * as to what happens in the case that the object + * reference is not of the current class or one + * of its subclasses. It is @e assumed that + * @b VerifyError should be thrown. Is this + * a valid assumption? + * + */ + + /* Test for reasonable contents and non-null in object */ + VERIFY_OBJECT_HASH(objhashmisc); - if (jvm_class_index_null == clsidxmisc) - { - /* If class is not loaded, retrieve it by UTF8 class name */ - LATE_CLASS_LOAD(pcpma_Methodref->class_index); + /* Retrieve class of current PC */ + clsidxmisc2 = GET_PC_FIELD_IMMEDIATE(thridx, clsidx); - /* Check if method exists in loaded class */ - clsidxmisc = pcpma_Methodref - ->LOCAL_Methodref_binding.clsidxJVM; - if (jvm_class_index_null == clsidxmisc) + /*! + * @todo: HARMONY-6-jvm-opcode.c-162 Is the following test + * really needed? Is it the wrong test? Or should + * there be no test at all? + */ +#if 0 + /*! + * @internal Perform rudimentary check to see + * if OO hierarchy is sane before performing @e any + * other kinds of tests. (Not needed for INVOKESTATIC + * because compiler takes care of that case.) + */ + if (rfalse == + classutil_class_is_a(clsidxmisc2, + OBJECT_CLASS_LINKAGE(objhashmisc)->clsidx)) { - thread_throw_exception(thridx, - THREAD_STATUS_THREW_ERROR, - JVMCLASS_JAVA_LANG_ABSTRACTMETHODERROR); + thread_throw_exception( + thridx, + THREAD_STATUS_THREW_ERROR, + JVMCLASS_JAVA_LANG_ABSTRACTMETHODERROR); /*NOTREACHED*/ } - } - } +#endif + + /*! + * @internal Validate class structure for requested method + * if it is a protected method. This check is done here + * instead of in the @e exact sequence listed in the spec + * because the class structure must be known before the + * presence of members within that class can be discovered. + * + */ + CHECK_PROTECTED_METHOD_IS_ACCESSIBLE; - mthidxmisc = pcpma_Methodref->LOCAL_Methodref_binding.mthidxJVM; + /* Look up name & type of method in objhashmisc reference */ + rbool2 = rtrue; /* Normally perform second method lookup */ + switch(opcode) + { + case OPCODE_B6_INVOKEVIRTUAL: + classutil_class_has_a_method(&resolve_objhashmisc, + objhashmisc, + pcfsmisc, + pcpma_Methodref, + rtrue); + break; - if (jvm_method_index_bad == mthidxmisc) - { - thread_throw_exception(thridx, - THREAD_STATUS_THREW_ERROR, - JVMCLASS_JAVA_LANG_NOSUCHMETHODERROR); + case OPCODE_B7_INVOKESPECIAL: + /* Special tests for INVOKESPECIAL */ + + /* + * Check whether this is a instance initialization + * method or not + */ + rbool1 = IS_INIT_METHOD(pcfsmisc, pmth->name_index); + + /* Treat superclass methods specially */ + if ((ACC_SUPER & + CLASS_OBJECT_LINKAGE(clsidxmisc2) + ->pcfs->access_flags) && + + /* + * resolved method's class is a + * superclass of the current class + */ + (rtrue == + classutil_class_is_a(clsidxmisc2, + clsidxmisc)) && + + /* + * resolved method is not an + * instance initialization method + */ + (rtrue != rbool1)) + { + /* + * If all conditions are met, then override + * the "selected method" (per spec phrasing) + * and use the following to derive the "actual + * method": + */ + + /* + * Can't locate superclass if at + * top of hierarchy + */ + if (jvm_constant_pool_index_null == + pcfsmisc->super_class) + { + exit_throw_exception(EXIT_JVM_CLASS, + JVMCLASS_JAVA_LANG_ABSTRACTMETHODERROR); /*NOTREACHED*/ - } + } - pcfsmisc = CLASS_OBJECT_LINKAGE(clsidxmisc)->pcfs; - pmth = pcfsmisc->methods[mthidxmisc]; + /* Normally,however, this is not a problem */ - rbool1 = IS_INIT_METHOD(pcfsmisc, pmth->name_index); + /*! + * @todo: HARMONY-6-jvm-opcode.c-156 Notice that + * the definition of INVOKESPECIAL does + * @e not say anything about + * accessibility! This is probably not a + * concern except for INVOKEVIRTUAL where + * the current class may vary from that + * of the requested object resolution, + * but watch out for errors in this + * regard. Is the check for + * accessibility not needed here? + */ + classutil_class_has_a_method( + &resolve_objhashmisc, + OBJECT(CLASS(clsidxmisc2).class_objhash) + .objhash_super_class, + pcfsmisc, + pcpma_Methodref, + rfalse); + } + else + { + /* + * If any condition is not met, DO NOT perform + * method lookup based on the "resolved method". + * Instead, use the "resolved method" as it + * stands for the "actual method". + */ + rbool2 = rfalse; + } - /* Must be a valid reference to a method */ - if (jvm_attribute_index_bad == - pcpma_Methodref->LOCAL_Methodref_binding.codeatridxJVM) - { - thread_throw_exception(thridx, - THREAD_STATUS_THREW_ERROR, - JVMCLASS_JAVA_LANG_NOSUCHMETHODERROR); + break; + + case OPCODE_B8_INVOKESTATIC: + /* Outer switch() stmt precludes this situation */ /*NOTREACHED*/ - } + break; + + case OPCODE_B9_INVOKEINTERFACE: + if (rfalse == + classutil_class_implements_interface( + OBJECT_CLASS_LINKAGE(objhashmisc)->clsidx, + clsidxmisc)) + { + thread_throw_exception( + thridx, + THREAD_STATUS_THREW_ERROR, + JVMCLASS_JAVA_LANG_INCOMPATIBLECLASSCHANGEERROR); +/*NOTREACHED*/ + } + + /*! + * @todo: HARMONY-6-jvm-opcode.c-157 Notice that + * the definition of INVOKEINTERFACE does + * @e not say anything about accessibility! + * This is probably not a concern except + * for INVOKEVIRTUAL where the current class + * may vary from that of the requested + * object resolution, but watch out for + * errors in this regard. Is the check for + * accessibility not needed here? + */ + classutil_class_has_an_interface_method( + &resolve_objhashmisc, + objhashmisc, + pcfsmisc, + pcpma_InterfaceMethodref); + break; + } + + /* If second method lookup was needed, pick up results */ + if (rtrue == rbool2) + { + /* Check if found reference to a valid method */ + if ((jvm_class_index_null==resolve_objhashmisc.clsidx)|| + (jvm_method_index_bad==resolve_objhashmisc.mthidx)) + { + exit_throw_exception(EXIT_JVM_OBJECT, + JVMCLASS_JAVA_LANG_ABSTRACTMETHODERROR); +/*NOTREACHED*/ + } + + /* Point to the so-called "actual method" to invoke */ + clsidxmisc = resolve_objhashmisc.clsidx; + mthidxmisc = resolve_objhashmisc.mthidx; + pcfsmisc = CLASS_OBJECT_LINKAGE(clsidxmisc)->pcfs; + pmth = pcfsmisc->methods[mthidxmisc]; + } + + break; + + case OPCODE_B8_INVOKESTATIC: + /* Nothing to do since no object on stack to evaluate */ + /*! + * @internal There not any mention in the spec of checking + * for a protected static method because this is + * discovered at compile time. + */ +#if 0 + /* Validate requested method if it is protected */ + clsidxmisc2 = GET_PC_FIELD_IMMEDIATE(thridx, clsidx); + CHECK_PROTECTED_METHOD_IS_ACCESSIBLE; +#endif + break; + + } /* switch opcode */ + + /* + * Method is now fully resolved. The _exact_ method is known. + */ switch(opcode) { case OPCODE_B6_INVOKEVIRTUAL: - /* Must not be a class initialization method */ + /* Must not be a class or instance initialization method */ CHECK_NOT_CLINIT_METHOD; CHECK_NOT_INIT_METHOD; - /* Must be an instance method */ + /* Report this is not instance initialization method */ + rbool1 = rfalse; + + /* + * Must be an instance method (This implies that + * it is not a class initialization method) + */ CHECK_INSTANCE_METHOD; /* Must not be an abstract method */ CHECK_NOT_ABSTRACT_METHOD; + break; case OPCODE_B7_INVOKESPECIAL: @@ -2769,16 +3107,28 @@ /* Must be an instance method */ CHECK_INSTANCE_METHOD; + /* + * Instance initialization method status is already known + */ + /* rbool1 = ... */ + /* Must not be an abstract method */ CHECK_NOT_ABSTRACT_METHOD; break; case OPCODE_B8_INVOKESTATIC: + /* Must not be a class or instance initialization method */ CHECK_NOT_CLINIT_METHOD; CHECK_NOT_INIT_METHOD; - /* Must be a static method */ + /* Report this is not instance initialization method */ + rbool1 = rfalse; + + /* + * Must be a static method (This also implies that + * it is not an instance initialization method.) + */ CHECK_STATIC_METHOD; /* Must not be an abstract method */ @@ -2790,16 +3140,18 @@ CHECK_NOT_CLINIT_METHOD; CHECK_NOT_INIT_METHOD; + /* Report this is not instance initialization method */ + rbool1 = rfalse; + /* @c @b count must be non-zero */ /*! - * @todo HARMONY-6-jvm-opcode.c-145 What is the purpose of - * the 'count' operand besides taking space in the - * code area that must be parsed? Ths spec says - * nothing beyond the fact that it is an unsigned - * byte that must not be zero. There is something - * written out there somewhere about this, but what - * it is apparently is not that important. (?) + * @internal The purpose of the 'count' operand is to + * store the number of arguments on the stack for the + * forthcoming INVOKEINTERFACE execution. It is apparently + * a legacy implementation item. For more info, see the + * notes section of the opcode specification. + * */ if (0 == op2u1) { @@ -2824,11 +3176,13 @@ /*NOTREACHED*/ } - /* Must a public method */ + /* Must a public method (implied for an interface method) */ CHECK_PUBLIC_METHOD; break; - } + } /* switch opcode */ + + /* Start either native method or Java method */ if (ACC_NATIVE & pmth->access_flags) { /*! @@ -2836,23 +3190,34 @@ * w/ real data */ - /* - * Make SURE a native method relinquishes after execution, - * especially when SYNCHRONIZE_METHOD_INVOCATION breaks out. - * This way the opcode will not re-execute while waiting on - * an event that will not take place in this thread. + /*! + * @internal Make SURE a native method relinquishes after + * execution, especially when SYNCHRONIZE_METHOD_INVOCATION + * breaks out. This way the opcode will not re-execute while + * waiting on an event that will not take place in this thread. */ pjvm->timeslice_expired = rtrue; /* This macro conditionally uses 'break' to exit the switch() */ SYNCHRONIZE_METHOD_INVOCATION; + /*! + * @internal If you got here, either the method is not a + * synchronized method or the method is now synchronized + * and the thread is still in the @b RUNNING state. + */ + /* Return code, if any, is pushed in the JNI processing code */ native_run_method(thridx, clsidxmisc, +#warning Use method_info ordinal since Methodref is pre-object resolve? +#if 1 + pmth->LOCAL_method_binding.nmordJVM, +#else pcpma_Methodref ->LOCAL_Methodref_binding .nmordJVM, +#endif pmth->name_index, pmth->descriptor_index, pmth->access_flags, @@ -2877,6 +3242,35 @@ } else { + codeatridxmisc = pcfsmisc + ->methods[mthidxmisc] + ->LOCAL_method_binding.codeatridxJVM; + + /*! + * @todo HARMONY-6-jvm-opcode.c-161 Is this test redundant + * by this point in loading? + */ + if (jvm_attribute_index_bad == codeatridxmisc) + { + (rvoid) linkage_resolve_class(clsidxmisc, rfalse); + + codeatridxmisc = pcfsmisc + ->methods[mthidxmisc] + ->LOCAL_method_binding.codeatridxJVM; + + if (jvm_attribute_index_bad == codeatridxmisc) + { + thread_throw_exception(thridx, + THREAD_STATUS_THREW_ERROR, + JVMCLASS_JAVA_LANG_NOSUCHMETHODERROR); +/*NOTREACHED*/ + } + } + + pca = ATR_CODE_AI(pcfsmisc + ->methods[mthidxmisc] + ->attributes[codeatridxmisc]); + /*! * @internal Start up Java code. Instead of using POP() to * retrieve parameters and load them into the stack @@ -2887,23 +3281,10 @@ * the size of the requested frame by this block size * followed by a simple adjustment to the number of * local variables that are reported in the stack - * frame.) + * frame.) Use of @b jitmp1 and @b jitmp2 supports + * this setup, which will not be done for native code. * */ - jitmp1 = method_parm_size(clsidxmisc, - pmth->descriptor_index); - - jitmp2 = (ACC_STATIC & pmth->access_flags) - ? (((0 * sizeof(jvm_object_hash)) / sizeof(jint))) - : (((1 * sizeof(jvm_object_hash)) / sizeof(jint))); - - jvm_attribute_index codeatridx = - pcfsmisc - ->methods[mthidxmisc] - ->LOCAL_method_binding.codeatridxJVM; - - pca = (Code_attribute *) - &pcfsmisc->methods[mthidxmisc]->attributes[codeatridx]; /* If less local storage than parameters, somebody goofed */ if (pca->max_locals < jitmp1) @@ -2929,7 +3310,7 @@ PUT_PC_IMMEDIATE(thridx, clsidxmisc, mthidxmisc, - codeatridx, + codeatridxmisc, pcfsmisc ->methods[mthidxmisc] ->LOCAL_method_binding.excpatridxJVM, @@ -2943,65 +3324,6 @@ /* Set class and method context to point to new method */ LOAD_METHOD_CONTEXT; - switch(opcode) - { - case OPCODE_B6_INVOKEVIRTUAL: - case OPCODE_B7_INVOKESPECIAL: - /*! - * Local variable 0 is the object reference - * for @c @b this object. - */ - objhashmisc = GET_LOCAL_VAR(thridx,0); - - /*! - * @internal The null reference and access_flags logic - * is also implemented in the macro @link - #POP_THIS_OBJHASH POP_THIS_OBJHASH@endlink - * in the file - * @link jvm/src/native.c native.c@endlink - * for native methods. - * - * @todo HARMONY-6-jvm-opcode.c-139 The spec is unclear - * as to what happens in the case that the object - * reference is not of the current class or one - * of its subclasses. It is @e assumed that - * @b VerifyError should be thrown. Is this - * a valid assumption? - * - */ - - /* Test for reasonable contents and non-null in object*/ - VERIFY_OBJECT_HASH(objhashmisc); - - if ((ACC_PROTECTED & pmth->access_flags) && - (rtrue == - classutil_class_is_a( - GET_PC_FIELD_IMMEDIATE(thridx, clsidx), - clsidxmisc))) - { - if (rfalse == - classutil_class_is_a( - OBJECT_CLASS_LINKAGE(objhashmisc)->clsidx, - GET_PC_FIELD_IMMEDIATE(thridx, clsidx))) - { - /* Somebody goofed */ - thread_throw_exception(thridx, - THREAD_STATUS_THREW_ERROR, - JVMCLASS_JAVA_LANG_VERIFYERROR); -/*NOTREACHED*/ - } - } - break; - - case OPCODE_B8_INVOKESTATIC: - break; - - case OPCODE_B9_INVOKEINTERFACE: - break; - } - - CHECK_OBJECT_CLASS_STRUCTURE(clsidxmisc, objhashmisc, rbool1); - /*! * @todo HARMONY-6-jvm-opcode.c-137 Needs unit testing * w/ real data @@ -3009,6 +3331,12 @@ /* This macro conditionally uses 'break' to exit the switch() */ SYNCHRONIZE_METHOD_INVOCATION; + + /*! + * @internal If you got here, either the method is not a + * synchronized method or the method is now synchronized + * and the thread is still in the @b RUNNING state. + */ } break; @@ -3024,10 +3352,17 @@ GET_U1_OPERAND(op2u1); GET_U1_OPERAND(op3u1); + /* Must reference a method */ + CHECK_CP_TAG(op1u2, CONSTANT_InterfaceMethodref); + + /* calc clsidxmisc and pcpma and pcpma_InterfaceMethodref and pmth*/ + CALCULATE_METHOD_INFO_FROM_METHOD_REFERENCE(op1u2,InterfaceMethodref); + goto case_opcode_b9_invokeinterface; case OPCODE_BA_XXXUNUSEDXXX1: - /* Don't like 'goto', but makes sense */ + + /* Don't like 'goto', but it makes sense here */ goto case_opcode_ba_xxxunusedxxx1; case OPCODE_BB_NEW: @@ -3035,15 +3370,26 @@ /* Retrieve the @c @b constant_pool (u2) operand */ GET_U2_OPERAND(op1u2); - /* Must reference a normal class, not an array or interface class */ + /* Must reference a class */ CHECK_CP_TAG(op1u2, CONSTANT_Class); - CHECK_NOT_ABSTRACT_CLASS; - CHECK_NOT_ARRAY_OBJECT; - CHECK_NOT_INTERFACE_CLASS; /* calc clsidxmisc and pcpma and pcpma_Class and pcfsmisc */ CALCULATE_CLASS_INFO_FROM_CLASS_REFERENCE(op1u2); + /* + * Must not be from an abstract class, nor an interface class, + * nor an array object. + */ + if ((ACC_ABSTRACT & pcfsmisc->access_flags) || + (ACC_INTERFACE & pcfsmisc->access_flags) || + (OBJECT_STATUS_ARRAY & CLASS(clsidxmisc).status)) + { + thread_throw_exception(thridx, + THREAD_STATUS_THREW_ERROR, + JVMCLASS_JAVA_LANG_INSTANTIATIONERROR); +/*NOTREACHED*/ + } + /* Create new object from this class */ special_obj_misc = OBJECT_STATUS_EMPTY; @@ -3298,6 +3644,84 @@ /*! @todo HARMONY-6-jvm-opcode.c-150 Needs unit testing w/ real data */ #warning Need to test the ATHROW code with real stack frame data... + /*! + * @todo: HARMONY-6-jvm-opcode.c-158 Need to examine closely the + * carefully constructed narrative concerning @c @b finally + * clauses to make sure they are properly implemented by + * the @b ATHROW opcode. From the second comment from + * section 3.10, it seems that the @b ATHROW opcode is + * @e not responsible for dealing with the semantics of + * @c @b catch and @c @b finally clauses, but the compiler + * does this. + * + * @internal Such relevant narrative from the JVM spec include: + * + *
    + *
  • + * Section 6 on @c ATHROW opcode: + * "Otherwise [if a valid object reference is on the stack], if the + * method of the current frame is a @c @b synchronized method and + * the current thread is not the owner of the monitor acquired + * or reentered on invocation of the method, @c @b athrow throws + * an @c @b IllegalMonitorStateException instead of the object + * previously being thrown. This can happen, for example, if an + * abruptly completing @c @b synchronized method contains a + * @c @b monitorexit instruction, but no @c @b monitorenter + * instruction, on the object on which the method is synchronized." + *
  • + * + *
  • + * Section 3.10: + * "In cases where a @c @b finally clause (section 2.16.2) is used, + * the @c @b finally clause is executed during the propagation of an + * exception thrown from the associated @c @b try block and any + * associated @c @b catch block, even if no @c @b catch clause that + * handles the thrown exception may be found." + *
  • + * + *
  • + * Section 3.10, later on: + * "Because @c @b try statements are structured, a compiler for the + * Java programming language can always order the entries of the + * exception handler table such that, for any thrown exception and + * any program counter value in that method, the first exception + * handler that matches the thrown exception corresponds to the + * innermost matching @c @b catch or @c @b finally clause." + *
  • + * + *
  • + * Section 2.16.2: + * "The control transfer that occurs when an exception is thrown + * causes abrupt completion of expressions and statements until a + * @c @b catch clause is encountered that can handle the exception; + * execution then continues by executing the block of that + * @c @b catch clause. The code that caused the exception is + * never resumed. + * + * "If no catch clause handling an exception can be found, then + * the current thread (the thread that encountered the exception) + * is terminated, but only after all @c @b finally clauses have + * been executed and the method @c @b uncaughtException has been + * invoked for the @c @b ThreadGroup that is the parent of the + * current thread. + * + * "In situations where it is desirable to ensure that one block + * of code is always executed after another, even if that other + * block of code completes abruptly, a @c @b try statement with + * a @c @b finally clause may be used. If a @c @b try or @c @b catch + * block in a @c @b try-finally or @c @b try-catch-finally statement + * completes abruptly, then the @c @b finally clause is executed + * during propagation of the exception, even if no matching + * @c @b catch clause is ultimately found. If a @c @b finally clause + * is executed because of abrupt completion of a @c @b try block + * and the @c @b finally clause itself completes abruptly, then the + * reason for the abrupt completion of the @c @b try block is + * discarded and the new reason for abrupt completion is propagated + * from there." + *
  • + *
+ */ + /* Retrieve object reference to examine */ POP(thridx, jotmp1, jvm_object_hash); @@ -3358,8 +3782,9 @@ */ fptmp = GET_FP(thridx); pcfsmisc = CLASS_OBJECT_LINKAGE(pc->clsidx)->pcfs; - pca = (Code_attribute *) - &pcfsmisc->methods[pc->mthidx]->attributes[pc->codeatridx]; + pca = ATR_CODE_AI(pcfsmisc + ->methods[pc->mthidx] + ->attributes[pc->codeatridx]); pet = pca->exception_table; #define GET_FPTMP_PC_WORD(thridx, idx) \ @@ -3461,9 +3886,9 @@ CLASS_OBJECT_LINKAGE(GET_FPTMP_PC_WORD(thridx, CLSIDX)) ->pcfs; - pca = (Code_attribute *) - &pcfsmisc->methods[GET_FPTMP_PC_WORD(thridx, MTHIDX)] - ->attributes[GET_FPTMP_PC_WORD(thridx, CODEATRIDX)]; + pca = ATR_CODE_AI(pcfsmisc + ->methods[GET_FPTMP_PC_WORD(thridx, MTHIDX)] + ->attributes[GET_FPTMP_PC_WORD(thridx, CODEATRIDX)]); pet = pca->exception_table; } /* while (rtrue) */ @@ -4098,7 +4523,7 @@ * @link #opcode_end_thread_test() opcode_end_thread_test()@endlink * for use of this same logic. * - * Notice that this check does _not_ look for the fp-end-program + * Notice that this check does @e not look for the fp-end-program * condition per @link #opcode_end_thread_test() opcode_end_thread_test()@endlink. This means that the next * time this thread runs, execution will pick up with the next