Return-Path: Delivered-To: apmail-incubator-harmony-commits-archive@www.apache.org Received: (qmail 12909 invoked from network); 4 Nov 2005 21:36:14 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 4 Nov 2005 21:36:14 -0000 Received: (qmail 69105 invoked by uid 500); 4 Nov 2005 21:36:14 -0000 Delivered-To: apmail-incubator-harmony-commits-archive@incubator.apache.org Received: (qmail 69073 invoked by uid 500); 4 Nov 2005 21:36:14 -0000 Mailing-List: contact harmony-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: harmony-dev@incubator.apache.org Delivered-To: mailing list harmony-commits@incubator.apache.org Received: (qmail 69062 invoked by uid 99); 4 Nov 2005 21:36:13 -0000 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.29) with SMTP; Fri, 04 Nov 2005 13:36:12 -0800 Received: (qmail 12686 invoked by uid 65534); 4 Nov 2005 21:35:52 -0000 Message-ID: <20051104213552.12683.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r330917 - /incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/opcode.c Date: Fri, 04 Nov 2005 21:35:52 -0000 To: harmony-commits@incubator.apache.org From: dlydick@apache.org X-Mailer: svnmailer-1.0.5 X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: dlydick Date: Fri Nov 4 13:35:31 2005 New Revision: 330917 URL: http://svn.apache.org/viewcvs?rev=330917&view=rev Log: Next round of opcodes and misc. changes. Modified: incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/opcode.c Modified: incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/opcode.c URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/opcode.c?rev=330917&r1=330916&r2=330917&view=diff ============================================================================== --- incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/opcode.c (original) +++ incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/opcode.c Fri Nov 4 13:35:31 2005 @@ -320,9 +320,9 @@ * followed by its @c @b \ method with default parameters. * * This function must @e not be called until - * @c @b java.lang.Object , @c @b java.lang.Class, - * @c @b java.lang.String , @c @b java.lang.Throwable - * @c @b java.lang.Error have been loaded and initialized. + * @c @b java.lang.Object , @c @b java.lang.Class , + * @c @b java.lang.String , @c @b java.lang.Throwable , + * and @c @b java.lang.Error have been loaded and initialized. * * There is @e no attempt to enforce which classes may be invoked * by this handler. It is assumed that the caller will @e only @@ -498,7 +498,8 @@ LOCAL_CONSTANT_NO_ARRAY_DIMS, (jint *) rnull, rtrue, - thridx); + thridx, + (CONSTANT_Utf8_info *) rnull); /*! * @internal Both mark and unmark object so it @@ -706,7 +707,7 @@ */ /* - * Set FP lower boundary so Java @c @b return + * Set FP lower boundary so Java @c @b RETURN * instruction does not keep going after handler, check if * @c @b java.lang.ThreadGroup.uncaughtException() * is there, and run it. @@ -764,7 +765,7 @@ else { Code_attribute *pca = (Code_attribute *) - &pcfs->methods[mthidx]->attributes[codeatridx]; + &pcfs->methods[mthidx]->attributes[codeatridx]; PUSH_FRAME(thridx, pca->max_locals); PUT_PC_IMMEDIATE(thridx, clsidx, @@ -838,7 +839,7 @@ * * When loading the error class, process its * @c @b \ on any available thread, but process - * its @C @b \ on @e this thread so thread will be + * its @c @b \ on @e this thread so thread will be * done running after it has been processed (due to FP * change). */ @@ -868,19 +869,21 @@ } /* if nonlocal_rc */ } /* if nonlocal_rc */ - /***************************************************************/ - /***************************************************************/ - /***************************************************************/ - /***************************************************************/ - /***************************************************************/ - /* BEGIN GIANT SWITCH STATEMENT if(){}else{while(){switch()}} **/ - /***************************************************************/ - /***************************************************************/ - /***************************************************************/ - /***************************************************************/ - /***************************************************************/ else { + /**************************************************************/ + /**************************************************************/ + /**************************************************************/ + /**************************************************************/ + /**************************************************************/ + /* BEGIN GIANT SWITCH STATEMENT if(){}else{while(){switch()}} */ + /**************************************************************/ + /**************************************************************/ + /**************************************************************/ + /**************************************************************/ + /**************************************************************/ + + /* * Run inner JVM execution loop. */ @@ -890,8 +893,11 @@ * and its key associations */ jvm_pc *pc = THIS_PC(thridx); - ClassFile *pcfs = THIS_PCFS(thridx); - jvm_virtual_opcode *pcode = DEREFERENCE_PC_CODE_BASE(thridx); + + /* Load new class file context, incl. method context for PC */ + ClassFile *pcfs; + jvm_virtual_opcode *pcode; + LOAD_METHOD_CONTEXT; /* Scratch area for operand resolution */ rboolean iswide; @@ -903,6 +909,8 @@ u4 op1u4; /* Operand 1 as a (u4) */ rboolean rbool1; /* Conditional instruction status */ + u4 *pu4; /* Operand as a (u4 *) */ + jbyte jbtmp; /* Opcode (jbyte) scratch area */ jchar jctmp; /* Opcode (jchar) scratch area */ jshort jstmp; /* Opcode (jshort) scratch area */ @@ -910,6 +918,8 @@ jint jitmp2; /* Opcode (jint) scratch area 2 */ jint jitmp3; /* Opcode (jint) scratch area 3 */ jint jitmp4; /* Opcode (jint) scratch area 4 */ + jint jitmp5; /* Opcode (jint) scratch area 5 */ + jvm_pc_offset jptmp; /* Opcode (jvm_pc_offset) scratch */ jlong jltmp1; /* Opcode (jlong) scratch area 1 */ jlong jltmp2; /* Opcode (jlong) scratch area 2 */ jfloat jftmp1; /* Opcode (jfloat) scratch area 1 */ @@ -930,10 +940,12 @@ field_info *pfld; method_info *pmth; + Code_attribute *pca; ClassFile *pcfsmisc; u2 cpidxmisc; jvm_class_index clsidxmisc; + jvm_class_index clsidxmisc2; jvm_method_index mthidxmisc; jvm_object_hash objhashmisc; jvm_field_lookup_index fluidxmisc; @@ -1053,18 +1065,103 @@ break; case OPCODE_12_LDC: - /*! @todo HARMONY-6-jvm-opcode.c-11 Write this opcode */ - STUB; - break; - case OPCODE_13_LDC_W: - /*! @todo HARMONY-6-jvm-opcode.c-12 Write this opcode */ - STUB; +/*! @todo HARMONY-6-jvm-opcode.c-122 Needs unit testing with real data*/ + switch(opcode) + { + case OPCODE_12_LDC: + GET_U1_OPERAND(op1u1); + jitmp1 = (juint) op1u1; /* Play sign extension games */ + break; + + case OPCODE_13_LDC_W: + GET_U2_OPERAND(op1u2); + jitmp1 = (juint) op1u2; /* Play sign extension games */ + break; + } + + /* Treat all three 32-bit types the same except for constant_pool */ + switch (CP_TAG(pcfs, jitmp1)) + { + case CONSTANT_Integer: + MAKE_PU4(pu4, &PTR_CP_ENTRY_INTEGER(pcfs, jitmp1)->bytes); + jitmp2 = GETRI4(pu4); + PUSH(thridx, jitmp2); + break; + + case CONSTANT_Float: + MAKE_PU4(pu4, &PTR_CP_ENTRY_FLOAT(pcfs, jitmp1)->bytes); + jitmp2 = GETRI4(pu4); /* Don't need to do type conversions*/ + PUSH(thridx, jitmp2); + break; + + case CONSTANT_String: + objhashmisc = + object_instance_new( + OBJECT_STATUS_STRING, + CLASS_OBJECT_LINKAGE(pjvm->class_java_lang_String)->pcfs, + pjvm->class_java_lang_String, + LOCAL_CONSTANT_NO_ARRAY_DIMS, + (rvoid *) rnull, + rfalse, + thridx, + PTR_CP_ENTRY_UTF8(pcfs, + PTR_CP_ENTRY_STRING(pcfs, + jitmp1) + ->string_index)); + PUSH(thridx, (jint) objhashmisc); + break; + + default: + /* No other CP_TAG() is legal for this opcode */ + thread_throw_exception(thridx, + THREAD_STATUS_THREW_ERROR, + JVMCLASS_JAVA_LANG_VERIFYERROR); +/*NOTREACHED*/ + } + break; case OPCODE_14_LDC2_W: - /*! @todo HARMONY-6-jvm-opcode.c-13 Write this opcode */ - STUB; +/*! @todo HARMONY-6-jvm-opcode.c-123 Needs unit testing with real data*/ + GET_U2_OPERAND(op1u2); + jitmp1 = (juint) op1u2; /* Play sign extension games */ + + /* Treat all three 32-bit types the same except for constant_pool */ + switch (CP_TAG(pcfs, jitmp1)) + { + case CONSTANT_Long: + MAKE_PU4(pu4, &PTR_CP_ENTRY_LONG(pcfs, jitmp1)->high_bytes); + jitmp2 = GETRI4(pu4); + MAKE_PU4(pu4, &PTR_CP_ENTRY_LONG(pcfs, jitmp1)->low_bytes); + jitmp3 = GETRI4(pu4); + + /* Just move words around, don't interpret w/ type cnv */ + PUSH(thridx, jitmp2); + PUSH(thridx, jitmp3); + break; + + case CONSTANT_Double: + MAKE_PU4(pu4, &PTR_CP_ENTRY_DOUBLE(pcfs, + jitmp1)->high_bytes); + jitmp2 = GETRI4(pu4); + MAKE_PU4(pu4, &PTR_CP_ENTRY_DOUBLE(pcfs, + jitmp1)->low_bytes); + jitmp3 = GETRI4(pu4); + + /* Just move words around, don't interpret w/ type cnv */ + PUSH(thridx, jitmp2); + PUSH(thridx, jitmp3); + break; + + default: + /* No other CP_TAG() is legal for this opcode */ + thread_throw_exception(thridx, + THREAD_STATUS_THREW_ERROR, + JVMCLASS_JAVA_LANG_VERIFYERROR); +/*NOTREACHED*/ + } + break; case OPCODE_15_ILOAD: @@ -1231,7 +1328,10 @@ VERIFY_OBJECT_HASH(jotmp1); VERIFY_ARRAY_REFERENCE(jotmp1, BASETYPE_CHAR_L, jitmp1); - /*! @internal Careful! Use of 'jotmp1' as both rvalue and lvalue!*/ + /*! + * @internal Careful! Use of 'jotmp1' as both rvalue and lvalue! + * + */ jotmp1 = ((jvm_object_hash *) OBJECT(jotmp1).arraydata)[jitmp1]; jitmp1 = (jint) jotmp1; PUSH(thridx, jitmp1); @@ -2034,20 +2134,23 @@ case OPCODE_95_FCMPL: case OPCODE_96_FCMPG: + /*! @todo HARMONY-6-jvm-opcode.c-117 Needs unit testing w/ real data */ POP(thridx, jftmp2, jfloat); POP(thridx, jftmp1, jfloat); jitmp2 = FORCE_JINT(jftmp2); jitmp1 = FORCE_JINT(jftmp1); if (JFLOAT_IS_NAN(jitmp1) || JFLOAT_IS_NAN(jitmp2)) - { - if (OPCODE_96_FCMPG == opcode) - { - jitmp1 = (jint) 1; - } - else + { + switch(opcode) { - jitmp1 = (jint) -1; + case OPCODE_95_FCMPL: + jitmp1 = (jint) -1; + break; + + case OPCODE_96_FCMPG: + jitmp1 = (jint) 1; + break; } } else @@ -2064,6 +2167,7 @@ case OPCODE_97_DCMPL: case OPCODE_98_DCMPG: + /*! @todo HARMONY-6-jvm-opcode.c-118 Needs unit testing w/ real data */ POP(thridx, jitmp2, jint); POP(thridx, jitmp1, jint); jdtmp2 = bytegames_combine_jdouble(jitmp1, jitmp2); @@ -2076,13 +2180,15 @@ jltmp1 = FORCE_JLONG(jdtmp1); if (JDOUBLE_IS_NAN(jltmp1) || JDOUBLE_IS_NAN(jltmp2)) { - if (OPCODE_98_DCMPG == opcode) - { - jitmp1 = (jint) 1; - } - else + switch(opcode) { + case OPCODE_97_DCMPL: jitmp1 = (jint) -1; + break; + + case OPCODE_98_DCMPG: + jitmp1 = (jint) 1; + break; } } else @@ -2103,6 +2209,7 @@ case OPCODE_9C_IFGE: case OPCODE_9D_IFGT: case OPCODE_9E_IFLE: + /*! @todo HARMONY-6-jvm-opcode.c-119 Needs unit testing w/ real data */ GET_U2_OPERAND(op1u2); POP(thridx, jitmp1, jint); @@ -2138,6 +2245,7 @@ case OPCODE_A2_IF_ICMPGE: case OPCODE_A3_IF_ICMPGT: case OPCODE_A4_IF_ICMPLE: + /*! @todo HARMONY-6-jvm-opcode.c-120 Needs unit testing w/ real data */ GET_U2_OPERAND(op1u2); POP(thridx, jitmp2, jint); @@ -2162,7 +2270,7 @@ if (rtrue == rbool1) { - /* size of opcode size of operand */ + /* size of opcode + size of operand */ LOAD_TARGET_PC_OFFSET(op1u2, sizeof(u1) + sizeof(u2)); } @@ -2170,26 +2278,29 @@ case OPCODE_A5_IF_ACMPEQ: case OPCODE_A6_IF_ACMPNE: + /*! @todo HARMONY-6-jvm-opcode.c-121 Needs unit testing w/ real data */ GET_U2_OPERAND(op1u2); POP(thridx, jotmp2, jvm_object_hash); POP(thridx, jotmp1, jvm_object_hash); - if (OPCODE_A5_IF_ACMPEQ) - { - if (jotmp1 == jotmp2) - { - /* size of opcode size of operand */ - LOAD_TARGET_PC_OFFSET(op1u2, sizeof(u1) + sizeof(u2)); - } - } - else + switch(opcode) { - if (jotmp1 != jotmp2) - { - /* size of opcode size of operand */ - LOAD_TARGET_PC_OFFSET(op1u2, sizeof(u1) + sizeof(u2)); - } + case OPCODE_A5_IF_ACMPEQ: + if (jotmp1 == jotmp2) + { + /* size of opcode + operand*/ + LOAD_TARGET_PC_OFFSET(op1u2, sizeof(u1) + sizeof(u2)); + } + break; + + case OPCODE_A6_IF_ACMPNE: + if (jotmp1 != jotmp2) + { + /* size of opcode + operand*/ + LOAD_TARGET_PC_OFFSET(op1u2, sizeof(u1) + sizeof(u2)); + } + break; } break; @@ -2197,7 +2308,7 @@ case OPCODE_A7_GOTO: GET_U2_OPERAND(op1u2); - /* size of opcode size of operand */ + /* size of opcode + size of operand */ LOAD_TARGET_PC_OFFSET(op1u2, sizeof(u1) + sizeof(u2)); break; @@ -2230,46 +2341,127 @@ break; case OPCODE_AA_TABLESWITCH: - STUB; + /*! @todo HARMONY-6-jvm-opcode.c-124 Needs unit testing w/ real data */ + SWITCH_PAD_PC; + + /* Retrieve 'default' table switch value */ + MAKE_PU4(pu4, &pcode[pc->offset]); + jitmp1 = GETRI4(pu4); + pu4++; + + /* Retrieve 'low' table switch value */ + jitmp2 = GETRI4(pu4); + pu4++; + + /* Retrieve 'high' table switch value */ + jitmp3 = GETRI4(pu4); + pu4++; + + /* Retrieve switch table 'index' operand */ + POP(thridx, jitmp5, jint); + + /* + * If operand out of range, select default offset + * (currently in 'jitmp1'), else index the table + * for target offset. + */ + if ((jitmp5 >= jitmp2) && (jitmp5 <= jitmp3)) + { + /* 'pu4' now points to 'jump offsets' area of opcode */ + jitmp1 = pu4[jitmp5 - jitmp2]; + MACHINE_JINT_SWAP(jitmp1); + } + pc->offset = jptmp + jitmp1; break; case OPCODE_AB_LOOKUPSWITCH: - /*! @todo HARMONY-6-jvm-opcode.c-53 Write this opcode */ - STUB; - break; + /*! @todo HARMONY-6-jvm-opcode.c-125 Needs unit testing w/ real data */ + SWITCH_PAD_PC; -case OPCODE_AC_IRETURN: - /*! @todo HARMONY-6-jvm-opcode.c-54 Write this opcode */ - STUB; - opcode_end_thread_test(thridx, &opcode_end_thread_nonlocal_return); - break; + /* Retrieve 'default' table switch value */ + MAKE_PU4(pu4, &pcode[pc->offset]); + jitmp1 = GETRI4(pu4); + pu4++; + + /* Retrieve 'npairs' table switch value */ + jitmp2 = GETRI4(pu4); + pu4++; - /*! @todo HARMONY-6-jvm-opcode.c-55 Write this opcode */ -case OPCODE_AD_LRETURN: - STUB; - opcode_end_thread_test(thridx, &opcode_end_thread_nonlocal_return); - break; - /*! @todo HARMONY-6-jvm-opcode.c-56 Write this opcode */ + /* Retrieve lookup table 'key' operand */ + POP(thridx, jitmp5, jint); -case OPCODE_AE_FRETURN: - STUB; - opcode_end_thread_test(thridx, &opcode_end_thread_nonlocal_return); - /*! @todo HARMONY-6-jvm-opcode.c-57 Write this opcode */ - break; + /* 'pu4' now points to 'match-offset pairs' area of opcode */ -case OPCODE_AF_DRETURN: - STUB; - /*! @todo HARMONY-6-jvm-opcode.c-58 Write this opcode */ - opcode_end_thread_test(thridx, &opcode_end_thread_nonlocal_return); - break; + /*! + * @todo HARMONY-6-jvm-opcode.c-126 On the @b ASSUMPTION that + * the 'match-offset pairs' are stored with the 'match' + * as the @e first @link #u4 u4@endlink value and the + * 'offset' as the @e second @link #u4 u4@endlink value, + * then the following @c @b for() loop should be correct. + * If these values are stored the other way around, + * then the @c @b pu4[] indices need to be swapped. + * + */ +#define LOOKUPSWITCH_MATCH_INDEX 0 +#define LOOKUPSWITCH_OFFSET_INDEX 1 -case OPCODE_B0_ARETURN: - /*! @todo HARMONY-6-jvm-opcode.c-59 Write this opcode */ - STUB; - opcode_end_thread_test(thridx, &opcode_end_thread_nonlocal_return); + /* Scan lookup table (if 'npairs' is 0, no for() loop iterations) */ + rbool1 = rfalse; + for (jitmp3 = 0; jitmp3 < jitmp2; jitmp3++) + { + /* Compare against 'match' value */ + + /* 2 = 1 match (u4) + 1 offset (u4), 0+ means first word */ + jitmp4 = pu4[LOOKUPSWITCH_MATCH_INDEX + 2 * jitmp3]; + MACHINE_JINT_SWAP(jitmp4); + + /* Done if match found */ + if (jitmp4 == jitmp5) + { + /* 2 = 1 match (u4) + 1 offset (u4), 1+ means second word */ + jitmp4 = pu4[LOOKUPSWITCH_OFFSET_INDEX + 2 * jitmp3]; + MACHINE_JINT_SWAP(jitmp4); + + /* Match found, new PC offset loaded */ + pc->offset = jptmp + jitmp4; + rbool1 = rtrue; + break; + } + } + + /* Select default if match with 'key' operand not found */ + if (rfalse == rbool1) + { + pc->offset = jptmp + jitmp1; + } break; +case OPCODE_AC_IRETURN: +case OPCODE_AD_LRETURN: +case OPCODE_AE_FRETURN: +case OPCODE_AF_DRETURN: +case OPCODE_B0_ARETURN: case OPCODE_B1_RETURN: + /*! @todo HARMONY-6-jvm-opcode.c-128 Needs unit testing w/ real data */ + + /* Pop return code from this method's operand stack */ + switch(opcode) + { + case OPCODE_AC_IRETURN: + case OPCODE_AE_FRETURN: + case OPCODE_B0_ARETURN: + POP(thridx, jitmp1, jint); + break; + + case OPCODE_AD_LRETURN: + case OPCODE_AF_DRETURN: + POP(thridx, jitmp1, jint); + POP(thridx, jitmp2, jint); + break; + + case OPCODE_B1_RETURN: + break; + } CALCULATE_METHOD_INFO_FROM_PC; @@ -2286,18 +2478,44 @@ /*! * @todo HARMONY-6-jvm-opcode.c-60 Implement test for same * number of locks/unlocks per JVM spec section 8.13. + * This applies to @e all of the @c @b xRETURN opcodes. */ POP_FRAME(thridx); -/* -... Don't forget to set these to old method: - pcfs = THIS_PCFS(thridx); - pcode = DEREFERENCE_PC_CODE_BASE(thridx); -*/ + + /*! + * @todo HARMONY-6-jvm-opcode.c-127 Value set conversion is + * @e not performed on floating point values at return time. + */ + + /* Push return code onto calling method's operand stack */ + switch(opcode) + { + case OPCODE_AC_IRETURN: + case OPCODE_AE_FRETURN: + case OPCODE_B0_ARETURN: + PUSH(thridx, jitmp1); + break; + + case OPCODE_AD_LRETURN: + case OPCODE_AF_DRETURN: + PUSH(thridx, jitmp2); + PUSH(thridx, jitmp1); + break; + + case OPCODE_B1_RETURN: + break; + } + opcode_end_thread_test(thridx, &opcode_end_thread_nonlocal_return); + + /* Restore class and method context of old method */ + LOAD_METHOD_CONTEXT; + break; case OPCODE_B2_GETSTATIC: + case_opcode_b4_getfield: /* Retrieve the @c @b constant_pool (u2) operand */ GET_U2_OPERAND(op1u2); @@ -2308,21 +2526,46 @@ /* calc clsidxmisc and pcpd and pcpd_Fieldref */ CALCULATE_FIELD_INFO_FROM_FIELD_REFERENCE(op1u2); - /* Must be a valid reference to a method */ + /* Must be a valid reference to a field */ CHECK_VALID_FIELDLOOKUPIDX(fluidxmisc); - /* Must be a static field */ - CHECK_STATIC_FIELD; + switch (opcode) + { + case OPCODE_B2_GETSTATIC: + /* 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; + /*! + * @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? + */ - /* Retrieve data from the static field now */ - GETSTATIC; + /* 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 */ + GETSTATIC; + break; + + case OPCODE_B4_GETFIELD: + /*! + * @todo HARMONY-6-jvm-opcode.c-132 Needs unit + * testing w/ real data + */ + + /* Must be an object instance field */ + CHECK_INSTANCE_FIELD; + + /* Retrieve data from the object instance field now */ + POP(thridx, jotmp1, jvm_object_hash); + GETFIELD(jotmp1); + break; + } break; case OPCODE_B3_PUTSTATIC: + case_opcode_b5_putfield: /* Retrieve the @c @b constant_pool (u2) operand */ GET_U2_OPERAND(op1u2); @@ -2333,29 +2576,49 @@ /* calc clsidxmisc and pcpd and pcpd_Fieldref */ CALCULATE_FIELD_INFO_FROM_FIELD_REFERENCE(op1u2); - /* Must be a valid reference to a method */ + /* Must be a valid reference to a field */ CHECK_VALID_FIELDLOOKUPIDX(fluidxmisc); - /* Must be a static field */ - CHECK_STATIC_FIELD; + switch (opcode) + { + case OPCODE_B3_PUTSTATIC: + /* Must be a static field */ + CHECK_STATIC_FIELD; + + /*! + * @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? + */ + + /* 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 */ + PUTSTATIC; + break; - /* Store data into the static field now */ - PUTSTATIC; + case OPCODE_B5_PUTFIELD: + /*! + * @todo HARMONY-6-jvm-opcode.c-134 Needs unit + * testing w/ real data + */ + /* Must be an object instance field */ + CHECK_INSTANCE_FIELD; + + /* Store data into the object instance field now */ + POP(thridx, jotmp1, jvm_object_hash); + PUTFIELD(jotmp1); + break; + } break; case OPCODE_B4_GETFIELD: - /*! @todo HARMONY-6-jvm-opcode.c-61 Write this opcode */ - STUB; - break; + goto case_opcode_b4_getfield; case OPCODE_B5_PUTFIELD: - /*! @todo HARMONY-6-jvm-opcode.c-62 Write this opcode */ - STUB; - break; + goto case_opcode_b5_putfield; case OPCODE_B6_INVOKEVIRTUAL: /*! @todo HARMONY-6-jvm-opcode.c-63 Write this opcode */ @@ -2401,18 +2664,18 @@ CLASS(clsidxmisc).class_objhash, CURRENT_THREAD)) { - /* size of opcode size of operand */ - pc->offset -= sizeof(u1) + sizeof(u2); + /* size of opcode + size of operand */ + pc->offset -= ( sizeof(u1) + sizeof(u2) ); break; } } + cpidxmisc = pcpd_Methodref->name_and_type_index; + pcpd = pcfs->constant_pool[cpidxmisc]; + pcpd_NameAndType = PTR_THIS_CP_NameAndType(pcpd); + if (ACC_NATIVE & pmth->access_flags) { - cpidxmisc = pcpd_Methodref->name_and_type_index; - pcpd = pcfs->constant_pool[cpidxmisc]; - pcpd_NameAndType = PTR_THIS_CP_NameAndType(pcpd); - native_run_method(CURRENT_THREAD, pcpd_Methodref ->LOCAL_Methodref_binding @@ -2423,12 +2686,58 @@ } else { - ; /* Start up Java code */ -/* -... Don't forget to set these to new method: - pcfs = THIS_PCFS(thridx); - pcode = DEREFERENCE_PC_CODE_BASE(thridx); -*/ + /*! + * @internal Start up Java code. Instead of using POP() to + * retrieve parameters and load them into the stack + * frame of the invoked method, simply reference + * the first parameter (bottom of the operand stack) + * as local variable 0 and build a stack frame above + * the pushed parameters. (This will entail changing + * 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.) + * + */ + jitmp1 = method_parm_size(clsidxmisc, + pcpd_NameAndType->descriptor_index, + pmth->access_flags); + + 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) + { + thread_throw_exception(thridx, + THREAD_STATUS_THREW_ERROR, + JVMCLASS_JAVA_LANG_VERIFYERROR); +/*NOTREACHED*/ + } + + /* Build stack frame with parameters in place as local vars */ + PUSH_FRAME(thridx, pca->max_locals - jitmp1); + + /* Load target program counter */ + PUT_PC_IMMEDIATE(thridx, + clsidxmisc, + mthidxmisc, + codeatridx, + pcfsmisc + ->methods[mthidxmisc] + ->LOCAL_method_binding.excpatridxJVM, + CODE_CONSTRAINT_START_PC); + + /* Store proper local var size now */ + PUT_FP_WORD(thridx, JVMREG_STACK_LS_OFFSET, pca->max_locals); + + /* Set class and method context to point to new method */ + LOAD_METHOD_CONTEXT; } break; @@ -2458,6 +2767,19 @@ /* Create new object from this class */ special_obj_misc = OBJECT_STATUS_EMPTY; + if (0 == utf_prchar_classname_strcmp(JVMCLASS_JAVA_LANG_STRING, + pcfsmisc, + pcfsmisc->this_class)) + { + special_obj_misc |= OBJECT_STATUS_STRING; + + /* + * @internal Notice that 'utf8string' parameter will + * be unused here since the @c @b \ method + * will be used to set them later. + */ + } + else if (0 == utf_prchar_classname_strcmp(JVMCLASS_JAVA_LANG_THREAD, pcfsmisc, pcfsmisc->this_class)) @@ -2469,10 +2791,11 @@ object_instance_new(special_obj_misc, pcfsmisc, clsidxmisc, - 0, + LOCAL_CONSTANT_NO_ARRAY_DIMS, (rvoid *) rnull, rfalse, - thridx); + thridx, + (CONSTANT_Utf8_info *) rnull); /* Store result to stack */ PUSH(thridx, (jint) objhashmisc); @@ -2503,7 +2826,7 @@ CALCULATE_CLASS_INFO_FROM_CLASS_REFERENCE(op1u2); /* Retrieve 'count' operand from TOS */ - POP(thridx, jitmp1, jint ); + POP(thridx, jitmp1, jint); /* Cannot have negative number of array elements (zero is okay) */ if (0 > jitmp1) @@ -2519,7 +2842,7 @@ /*! * @todo HARMONY-6-jvm-opcode.c-68 Should this be simply * the unconditional clause only? or is - * the 'if' statement needed? + * the @c @b if statement needed? */ #if 1 special_obj_misc = OBJECT_STATUS_ARRAY; @@ -2556,13 +2879,15 @@ /*! * @todo: HARMONY-6-jvm-opcode.c-70 Is * 'rfalse' correct? Probably, - * because \ is typically - * called after object creation, - * but this needs to be verified. + * because @c @b \ is + * typically called after object + * creation, but this needs to be + * verified. */ rfalse, - thridx); + thridx, + (CONSTANT_Utf8_info *) rnull); /* Store result to stack */ PUSH(thridx, (jint) objhashmisc); @@ -2580,29 +2905,266 @@ break; case OPCODE_C0_CHECKCAST: - /*! @todo HARMONY-6-jvm-opcode.c-73 Write this opcode */ - STUB; - break; - case OPCODE_C1_INSTANCEOF: - /*! @todo HARMONY-6-jvm-opcode.c-74 Write this opcode */ - STUB; + /*! @todo HARMONY-6-jvm-opcode.c-130 Needs unit testing w/ real data */ + + /* + * Retrieve the @c @b constant_pool (u2) operand. + * The spec refers to this as an 'objectref' of type 'S' + */ + GET_U2_OPERAND(op1u2); + + /* + * Locate or load class being requested. + * The spec refers to this as type 'T' + */ + clsidxmisc2 = + class_load_from_cp_entry_utf(pcfs->constant_pool[op1u2], + rfalse, + (jint *) rnull); + + /* Retrieve object reference to examine */ + POP(thridx, jotmp1, jvm_object_hash); + + /* Initialize result code, then go test INSTANCEOF conditions */ + jitmp2 = 0; + + if (jvm_object_hash_null == jotmp1) + { + + switch(opcode) + { + case OPCODE_C0_CHECKCAST: + + jitmp2 = 1; /* No failure */ + break; + + case OPCODE_C1_INSTANCEOF: + + /* Nothing to do, just PUSH() result below*/ + break; + } + } + else + if (OBJECT(jotmp1).status & + (OBJECT_STATUS_NULL | OBJECT_STATUS_GCREQ)) + { + /* Sorry, this is not a valie object */ + thread_throw_exception(thridx, + THREAD_STATUS_THREW_ERROR, + JVMCLASS_JAVA_LANG_VERIFYERROR); +/*NOTREACHED*/ + } + else + { + clsidxmisc = OBJECT_CLASS_LINKAGE(jotmp1)->clsidx; + + pcfsmisc = OBJECT_CLASS_LINKAGE(jotmp1)->pcfs; + + /* + * If S is a class representing the array type SC[], that is, + * an array of components of type SC, then: + */ + if (CLASS(clsidxmisc).status & CLASS_STATUS_ARRAY) + { + pcfsmisc = CLASS_OBJECT_LINKAGE(clsidxmisc2)->pcfs; + + /* + * If T is an array type TC[], that is, an array of + * components of type TC, then one of the following + * must be true: + */ + if (CLASS(clsidxmisc2).status & CLASS_STATUS_ARRAY) + { + /* + * TC and SC are the same primative type (sec 2.4.1). + */ + if ((CLASS(clsidxmisc).status & CLASS_STATUS_PRIMATIVE) + && + (CLASS(clsidxmisc2).status & CLASS_STATUS_PRIMATIVE) + && + (clsidxmisc2 == clsidxmisc)) + { + jitmp2 = 1; + } + else + /*! + * @todo HARMONY-6-jvm-opcode.c-129 Resolve the + * VM spec language differences and change + * code for conformity if needed. + * + * @internal Slightly different spec statements here. + * It is @e assumed that they mean the same + * thing since @e all other algorithmic + * comments are identical on these two + * operation code: + * + *
  • @b CHECKCAST opcode: + * TC and SC are reference types (sec 2.4.6), and + * type SC can be cast to TC by recursive application + * of these rules. + * + *
  • + * + *
  • @b INSTANCEOF opcode: + * TC and SC are reference types (sec 2.4.6), and + * type SC can be cast to TC by these runtime rules. + * + *
+ * + */ + if ( + (!(CLASS(clsidxmisc).status & CLASS_STATUS_PRIMATIVE)) + && + (!(CLASS(clsidxmisc2).status & CLASS_STATUS_PRIMATIVE))) + { + /* class S is a T */ + if ((rtrue == + classutil_subclass_of(clsidxmisc,clsidxmisc2)) + || + /* class S implements interface T */ + (rtrue == + classutil_implements_interface(clsidxmisc, + clsidxmisc2)) + || + /* interface T is a superinterface of S */ + (rtrue == + classutil_superinterface_of(clsidxmisc2, + clsidxmisc))) + { + jitmp2 = 1; + } + } + } + else + /* + * If T is an interface type, T must be one of the + * interfaces implemented by arrays (sec 2.15) + */ + if (pcfsmisc->access_flags & ACC_INTERFACE) + { + if (rtrue == + classutil_interface_implemented_by_arrays(clsidxmisc)) + { + jitmp2 = 1; + } + } + else + /* + * If T is a class type, then T must be java.lang.Object + * (sec 2.4.7) + */ + { + if (clsidxmisc2 == pjvm->class_java_lang_Object) + { + jitmp2 = 1; + } + } + } + else + /* + * If S is an interface type, then: + */ + if (pcfsmisc->access_flags & ACC_INTERFACE) + { + pcfsmisc = CLASS_OBJECT_LINKAGE(clsidxmisc2)->pcfs; + + /* + * If T is an interface type, then T must be the same + * interface as S, or a super interface of S (sec 2.13.2). + */ + if (pcfsmisc->access_flags & ACC_INTERFACE) + { + if (rtrue == classutil_superinterface_of(clsidxmisc2, + clsidxmisc)) + { + jitmp2 = 1; + } + } + else + /* + * If T is a class type, then T must be java.lang.Object + * (sec 2.4.7). + */ + { + if (clsidxmisc2 == pjvm->class_java_lang_Object) + { + jitmp2 = 1; + } + } + } + else + /* + * If S is an ordinary (noarray) class, then: + */ + { + pcfsmisc = CLASS_OBJECT_LINKAGE(clsidxmisc2)->pcfs; + + /* + * If T is an interface type, then S must implement + * (sec 2.13) interface T. + */ + if (pcfsmisc->access_flags & ACC_INTERFACE) + { + if (rtrue == + classutil_implements_interface(clsidxmisc, + clsidxmisc2)) + { + jitmp2 = 1; + } + } + else + /* + * If T is a class type, then S must be the same class + * (sec 2.8.1) as T or a subclass of T. + */ + { + if (rtrue == + classutil_subclass_of(clsidxmisc, clsidxmisc2)) + { + jitmp2 = 1; + } + } + } + } + + /* Process the result differently for each opcode */ + switch(opcode) + { + case OPCODE_C0_CHECKCAST: + /* Throw exception if 'objectref' is not an instance of T */ + if (0 == jitmp2) + { + thread_throw_exception(thridx, + THREAD_STATUS_THREW_EXCEPTION, + JVMCLASS_JAVA_LANG_CLASSCASTEXCEPTION); +/*NOTREACHED*/ + } + break; + + case OPCODE_C1_INSTANCEOF: + /* Push result code onto stack */ + PUSH(thridx, jitmp2); + break; + } break; case OPCODE_C2_MONITORENTER: - /*! @todo HARMONY-6-jvm-opcode.c-75 Write this opcode */ - STUB; + POP(thridx, jotmp1, jvm_object_hash); + + (rvoid) objectutil_synchronize(jotmp1, CURRENT_THREAD); break; case OPCODE_C3_MONITOREXIT: - /*! @todo HARMONY-6-jvm-opcode.c-76 Write this opcode */ - STUB; + POP(thridx, jotmp1, jvm_object_hash); + + (rvoid) objectutil_unsynchronize(jotmp1, CURRENT_THREAD); break; case OPCODE_C4_WIDE: /*! * @todo HARMONY-6-jvm-opcode.c-77 Test this opcode and - * those that reference @c @b iswide + * those that reference @c @b iswide for operand size. */ iswide = rtrue; /* Will be read then cleared by other opcodes */ break; @@ -2622,7 +3184,7 @@ { if (jvm_object_hash_null == jotmp1) { - /* size of opcode size of operand */ + /* size of opcode + size of operand */ LOAD_TARGET_PC_OFFSET(op1u2, sizeof(u1) + sizeof(u2)); } } @@ -2630,7 +3192,7 @@ { if (jvm_object_hash_null != jotmp1) { - /* size of opcode size of operand */ + /* size of opcode + size of operand */ LOAD_TARGET_PC_OFFSET(op1u2, sizeof(u1) + sizeof(u2)); } } @@ -2640,7 +3202,7 @@ case OPCODE_C8_GOTO_W: GET_U4_OPERAND(op1u4); - /* size of opcode size of operand */ + /* size of opcode + size of operand */ LOAD_TARGET_PC_OFFSET(op1u4, sizeof(u1) + sizeof(u4)); break; @@ -2758,21 +3320,22 @@ /* Renew indentation... */ } /* while ... */ + } /* if nonlocal_thread_return else */ - } /* if nonlocal_rc else */ + /**************************************************************/ + /**************************************************************/ + /**************************************************************/ + /**************************************************************/ + /**************************************************************/ + /* END OF GIANT SWITCH STATEMENT if(){}else{while(){switch()}}*/ + /**************************************************************/ + /**************************************************************/ + /**************************************************************/ + /**************************************************************/ + /**************************************************************/ - /***************************************************************/ - /***************************************************************/ - /***************************************************************/ - /***************************************************************/ - /***************************************************************/ - /* END OF GIANT SWITCH STATEMENT if(){}else{while(){switch()}}**/ - /***************************************************************/ - /***************************************************************/ - /***************************************************************/ - /***************************************************************/ - /***************************************************************/ + } /* if nonlocal_rc else */ /* If the timer ticked, clear flag and process next thread */ if((rtrue == check_timeslice) && (rtrue == pjvm->timeslice_expired)) @@ -2783,7 +3346,7 @@ /* * If frame is empty, thread is done running, but if * @link #rthread.fp_end_program fp_end_program@endlink is being - * used to control, say, a \ of a + * used to control, say, a \ of a * @link #LATE_CLASS_LOAD() LATE_CLASS_LOAD@endlink, the thread is * still doing something even when the end-of-program indication * has occurred. See also @@ -2830,8 +3393,8 @@ } /* - * Move unhandled condition (@b nonlocal_rc) - * and "thread is finished running" (@b nonlocal_thread_return) + * Move unhandled condition (@c @b nonlocal_rc) + * and "thread is finished running" (@c @b nonlocal_thread_return) * conditions to the @b COMPLETE state, otherwise everything * ran fine and thread is still in the @b RUNNING state. */