You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ge...@apache.org on 2005/10/08 06:29:29 UTC
svn commit: r307257 [9/24] - in
/incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm: ./ bootJVM/
bootJVM/jni/ bootJVM/jni/src/ bootJVM/jni/src/gnu/
bootJVM/jni/src/gnu/classpath/ bootJVM/jni/src/gnu/classpath/0.16/
bootJVM/jni/src/gnu/classpath/...
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/class.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/class.c?rev=307257&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/class.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/class.c Fri Oct 7 21:27:56 2005
@@ -0,0 +1,2176 @@
+/*!
+ * @file class.c
+ *
+ * @brief Create and manage real machine Java class data structures.
+ *
+ *
+ * @section Control
+ *
+ * \$URL: https://svn.apache.org/path/name/class.c $ \$Id: class.c 0 09/28/2005 dlydick $
+ *
+ * Copyright 2005 The Apache Software Foundation
+ * or its licensors, as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 ("the License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied.
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * @version \$LastChangedRevision: 0 $
+ *
+ * @date \$LastChangedDate: 09/28/2005 $
+ *
+ * @author \$LastChangedBy: dlydick $
+ * Original code contributed by Daniel Lydick on 09/28/2005.
+ *
+ * @section Reference
+ *
+ */
+
+#include "arch.h"
+ARCH_COPYRIGHT_APACHE(class, c, "$URL: https://svn.apache.org/path/name/class.c $ $Id: class.c 0 09/28/2005 dlydick $");
+
+
+#include <string.h>
+
+#include "jvmcfg.h"
+#include "cfmacros.h"
+#include "classfile.h"
+#include "classfile.h"
+#include "classpath.h"
+#include "exit.h"
+#include "field.h"
+#include "gc.h"
+#include "jvm.h"
+#include "jvmclass.h"
+#include "linkage.h"
+#include "method.h"
+#include "nts.h"
+#include "utf.h"
+#include "util.h"
+
+
+/*!
+ * @brief Set up an empty class in a given class table slot.
+ *
+ * The @b clsidx of JVMCFG_NULL_CLASS has special
+ * properties in that it can ALWAYS be allocated and
+ * is NEVER garbage collected! Part of the purpose
+ * for this is the JVMCFG_NULL_CLASS is of value zero,
+ * which is widely used throughout the code as a special
+ * value. This this slot is not available for @e anything
+ * else.
+ *
+ *
+ * @param clsidx Class table index of slot to set up.
+ *
+ *
+ * @returns @link #rvoid rvoid@endlink
+ *
+ */
+rvoid class_static_setup(jvm_class_index clsidx)
+{
+ /*
+ * Declare slot in use, but not initialized.
+ * (Redundant for most situations where
+ * class_allocate_slot() was called, but needed
+ * for initializing classes like JVMCFG_NULL_CLASS
+ * with an absolute slot number that was not
+ * searched for by the allocator.)
+ */
+ CLASS(clsidx).status = CLASS_STATUS_INUSE | CLASS_STATUS_NULL;
+
+ /*
+ * Start out with no array allocation and no array dimensions
+ */
+ CLASS(clsidx).arraydims = LOCAL_CONSTANT_NO_ARRAY_DIMS;
+ CLASS(clsidx).arraylength = (jint *) rnull;
+ CLASS(clsidx).lower_dim_array = jvm_class_index_null;
+
+ /* Start out with no object hash */
+ CLASS(clsidx).class_objhash = jvm_object_hash_null;
+
+ /* Start out with no class static field lookups */
+ CLASS(clsidx).num_class_static_field_lookups = 0;
+ CLASS(clsidx).class_static_field_lookup = (jvm_class_index *) rnull;
+ CLASS(clsidx).class_static_field_data = (jvalue *) rnull;
+
+ /* Start out with no object instance field lookups */
+ CLASS(clsidx).num_object_instance_field_lookups = 0;
+ CLASS(clsidx).object_instance_field_lookup =
+ (jvm_field_index *) rnull;
+
+ /*
+ * Report which @c @b java.lang.ClassLoader initiated
+ * and defined this class. The bootstrap ClassLoader always
+ * reports @link #jvm_class_index_null jvm_class_index_null@endlink
+ * for both of these items.
+ */
+ CLASS(clsidx).initiating_ClassLoader = jvm_class_index_null;
+ CLASS(clsidx).defining_ClassLoader = jvm_class_index_null;
+
+ /*
+ * Garbage collection @e initialization is performed by
+ * @link #GC_CLASS_NEW GC_CLASS_NEW()@endlink.
+ *
+ * Garbage collection @e finalization is performed by
+ * @link #GC_CLASS_DELETE GC_CLASS_DELETE()@endlink.
+ */
+ CLASS(clsidx).pgarbage = (rvoid *) rnull;
+
+ /*
+ * Do not set up GC_CLASS_NEW() unless there is
+ * a real class with the possibility of real fields.
+ */
+
+ return;
+
+} /* END of class_static_setup() */
+
+
+/*!
+ * @brief Initialize the class area of the JVM model
+ *
+ *
+ * @b Parameters: @link #rvoid rvoid@endlink
+ *
+ *
+ * @returns @link #rvoid rvoid@endlink
+ *
+ */
+rvoid class_init()
+{
+ class_static_setup(jvm_class_index_null);
+
+ pjvm->class_allocate_last = jvm_class_index_null;
+
+ /* Declare this module initialized */
+ jvm_class_initialized = rtrue;
+
+ return;
+
+} /* END of class_init() */
+
+
+/*!
+ * @brief Locate and reserve an unused class table slot for a new class.
+ *
+ *
+ * @param tryagain If @link #rtrue rtrue@endlink, run garbage
+ * collection @e once if no empty slots are
+ * available so as to try and free up something.
+ * Typically, invoke as
+ * @link #rtrue rtrue@endlink, and
+ * let recursion call it with
+ * @link #rfalse rfalse@endlink.
+ *
+ *
+ * @returns Class table index of an empty slot. Throw error if no
+ * slots.
+ *
+ * @throws JVMCLASS_JAVA_LANG_OUTOFMEMORYERROR
+ * @link #JVMCLASS_JAVA_LANG_OUTOFMEMORYERROR
+ * if no slots are available.@endlink.
+ *
+ */
+static jvm_class_index class_allocate_slot(rboolean tryagain)
+{
+ /* Search for a free class table slot */
+ jvm_class_index clsidx =
+ (JVMCFG_MAX_CLASSES == (1 + pjvm->class_allocate_last))
+ ? JVMCFG_FIRST_CLASS
+ : 1 + pjvm->class_allocate_last;
+
+ /* Count allocated slots in all slots are full */
+ jvm_class_index count = 0;
+
+ while(rtrue)
+ {
+ if (CLASS(clsidx).status & CLASS_STATUS_INUSE)
+ {
+ /* Point to next slot, wrap around at end */
+ clsidx++;
+
+ if (clsidx == JVMCFG_MAX_CLASSES - 1)
+ {
+ clsidx = JVMCFG_FIRST_CLASS;
+ }
+
+ /* Limit high value to end of table */
+ if (pjvm->class_allocate_last == JVMCFG_MAX_CLASSES - 1)
+ {
+ pjvm->class_allocate_last = JVMCFG_FIRST_CLASS - 1;
+ }
+
+ /* Count this attempt and keep looking */
+ count++;
+
+ if (count == (JVMCFG_MAX_CLASSES - JVMCFG_FIRST_CLASS))
+ {
+ /* Try again (with rfalse) if requested */
+ if (rtrue == tryagain)
+ {
+ GC_RUN(rtrue); /* Try to free up some space */
+
+ /* Now try to locate a free slot */
+
+ /* WARNING!!! Recursive call-- but only 1 deep */
+ return(class_allocate_slot(rfalse));
+ }
+
+ /* No more slots, cannot continue */
+ exit_throw_exception(EXIT_JVM_CLASS,
+ JVMCLASS_JAVA_LANG_OUTOFMEMORYERROR);
+/*NOTREACHED*/
+ }
+ }
+
+ /* Declare slot in use, but not initialized */
+ CLASS(clsidx).status = CLASS_STATUS_INUSE | CLASS_STATUS_NULL;
+
+ /* Report where this allocation was performed */
+ pjvm->class_allocate_last = clsidx;
+
+ return(clsidx);
+ }
+/*NOTREACHED*/
+ return(jvm_class_index_null); /* Satisfy compiler */
+
+} /* END of class_allocate_slot() */
+
+
+/*!
+ * @brief Load a class into ad class table slot and load up its
+ * associated class definition object.
+ *
+ * Create a Java class itself (and NOT a @c @b new instance
+ * of a class!). The following three mutially exclusive variations
+ * are available using the @b special_cls modifier:
+ *
+ * <ul>
+ * <li>(1) @b CLASS_STATUS_EMPTY: Normal class, no special
+ * treatment.
+ * </li>
+ *
+ * <li>(2) @b CLASS_STATUS_ARRAY: Treat class instance creation
+ * as a dimension of an array
+ * instead of as a normal class
+ * load. The recursion will
+ * eventually load its base
+ * class and superclasses.
+ * When allocating an array
+ * class, DO NOT EVER INVOKE
+ * THIS FUNCTION FOR A PRIMATIVE
+ * ARRAY!
+ * </li>
+ *
+ * <li>(3) @b CLASS_STATUS_PRIMATIVE: Treat class instance creation
+ * as loading a primative
+ * pseudo-class for use by
+ * @c @b java.lang.Class.
+ * A related Classfile structure
+ * will be generated for this
+ * pseudo-class.
+ * </li></ul>
+ *
+ * No verification of @b special_cls is performed, only these values
+ * are assumed.
+ *
+ * Use a simple circular slot allocation mechanism to report where
+ * most recent class was allocated. The search for the next slot
+ * will begin from here and go all the way around the array to this
+ * same slot. If not successful, throw error, but do @e not return.
+ *
+ *
+ * @param special_cls Bit-mapped request for various special
+ * considerations for class construction. If not
+ * needed, use @b CLASS_STATUS_EMPTY. If used, the
+ * values are:
+ *
+ * <ul><li>
+ * @b CLASS_STATUS_ARRAY create new array class
+ * instead of class instance
+ * </li>
+ *
+ * <li>
+ * @b CLASS_STATUS_PRIMATIVE create special class
+ * instance of a Java
+ * primative for use by
+ * @c @b java.lang.Class
+ * </li>
+ * </ul>
+ *
+ * @param pcfs Pointer to ClassFile area which contains this
+ * class, @link #rnull rnull@endlink for
+ * @b CLASS_STATUS_PRIMATIVE requests.
+ *
+ * @param arraydims Number of array dimensions for this class,
+ * or zero if not an array class.
+ *
+ * @param arraylength Array of length @b arraydims containing the
+ * length of array in each of those dimensions.
+ * E.g., @b arraydims is 4 for new X[7][3][9][2]
+ * so this parameter will be a 4-element array
+ * containing the numbers {7, 3, 9, 2}
+ *
+ * @param lower_dim_array Class index of this array class' next
+ * lower dimension, e.g. if this is a 3-dim
+ * array @c @b [[[L then need index
+ * it as @c @b [[L .
+ *
+ *
+ * @returns Class index value of allocation. Throw error if no slots.
+ *
+ *
+ * @throws JVMCLASS_JAVA_LANG_OUTOFMEMORYERROR
+ * @link #JVMCLASS_JAVA_LANG_OUTOFMEMORYERROR
+ * if no slots are available.@endlink.
+ *
+ */
+
+jvm_class_index class_static_new(rushort special_cls,
+ ClassFile *pcfs,
+ jvm_array_dim arraydims,
+ jint *arraylength,
+ jvm_class_index lower_dim_array)
+{
+ jvm_class_index clsidx;
+
+ /* Locate an empty slot */
+ clsidx = class_allocate_slot(rtrue);
+
+ /* Abort if no more class table slots */
+ if(jvm_class_index_null == clsidx)
+ {
+ return(jvm_class_index_null);
+ }
+
+ /* Initialize class structures */
+ class_static_setup(clsidx);
+
+
+
+ /*
+ * Set up empty class static field lookup table
+ * and object instance lookup table now
+ * instead of later so that GC_CLASS_NEW()
+ * and GC_OBJECT_NEW() know how many fields
+ * to anticipate for primative and array classes,
+ * namely zero.
+ */
+ CLASS(clsidx).num_class_static_field_lookups = 0;
+ CLASS(clsidx).num_object_instance_field_lookups = 0;
+
+
+ /*
+ * Start GC references on new and valid class.
+ * Unlike for objects, this must be done @e immediately
+ * so that object_instance_new() can add references to
+ * it from @link table_linkage#clsidx table_linkage.clsidx@endlink
+ * and write to an initialized structure.
+ *
+ * GC_CLASS_NEW(clsidx);
+ *
+ * ... but not until after num_XXX_field_lookups() is known.
+ *
+ */
+
+
+ /* Check for special class instances, then normal ones */
+ jvm_object_hash objhash;
+ if (CLASS_STATUS_PRIMATIVE & special_cls)
+ {
+ /* Start GC tracking for class */
+ (rvoid) GC_CLASS_NEW(clsidx);
+
+ /*
+ * Allocate a primative class
+ */
+
+ objhash = object_instance_new(OBJECT_STATUS_EMPTY,
+ pcfs,
+ clsidx,
+ arraydims,
+ arraylength,
+ rfalse,
+ jvm_thread_index_null);
+
+ /*
+ * Mark as a primative class, @c @b \<clinit\> done
+ * (not applicable)
+ */
+ CLASS(clsidx).status |= CLASS_STATUS_PRIMATIVE |
+ CLASS_STATUS_CLINIT;
+ }
+ else
+ if (special_cls & CLASS_STATUS_ARRAY)
+ {
+ /* Start GC tracking for class */
+ (rvoid) GC_CLASS_NEW(clsidx);
+
+ /*
+ * Allocate an array class-- but treat object as a class object
+ * lest it try to initialize the array dimensions, which is
+ * @e only something that an array @e instance object can do.
+ */
+
+ objhash = object_instance_new(OBJECT_STATUS_CLASS,
+ pcfs,
+ clsidx,
+ arraydims,
+ arraylength,
+ rfalse,
+ jvm_thread_index_null);
+
+ CLASS(clsidx).status |= CLASS_STATUS_ARRAY;
+
+ CLASS(clsidx).arraydims = arraydims;
+ CLASS(clsidx).arraylength = arraylength;
+ CLASS(clsidx).lower_dim_array = lower_dim_array;
+
+ /*! @todo Where is this mkref's GC_CLASS_RMREF() ??? */
+ (rvoid) GC_CLASS_MKREF_FROM_CLASS(clsidx,
+ CLASS(clsidx).lower_dim_array);
+ }
+ else
+ {
+ /*
+ * Allocate a normal class
+ */
+ CLASS(clsidx).num_class_static_field_lookups =
+ class_get_num_static_fields(pcfs);
+ CLASS(clsidx).class_static_field_lookup =
+ class_get_static_field_lookups(pcfs);
+
+ CLASS(clsidx).num_object_instance_field_lookups =
+ class_get_num_object_instance_fields(pcfs);
+ CLASS(clsidx).object_instance_field_lookup =
+ class_get_object_instance_field_lookups(pcfs);
+
+ /*
+ * Start GC tracking for class, now that actual
+ * number and type of fields is known
+ */
+ (rvoid) GC_CLASS_NEW(clsidx);
+
+
+ objhash = object_instance_new(OBJECT_STATUS_EMPTY,
+ pcfs,
+ clsidx,
+ arraydims,
+ arraylength,
+ rfalse,
+ jvm_thread_index_null);
+
+ /* Delay loading field data until after @b objhash is known */
+ CLASS(clsidx).class_static_field_data =
+ class_get_static_field_data(clsidx, pcfs);
+ }
+
+ /*
+ * Declare this class instance as being
+ * referenced by a class object
+ */
+ CLASS(clsidx).class_objhash = objhash;
+ (rvoid) GC_OBJECT_MKREF_FROM_CLASS(clsidx, objhash);
+
+ /* normal class definition */
+ CLASS(clsidx).status &= ~CLASS_STATUS_NULL;
+
+ /*
+ * Declare this class as being referenced, but not here.
+ * The calling function must perform this task.
+ */
+ /* GC_CLASS_MKREF(clsidx); */
+
+ return(clsidx);
+
+} /* END of class_static_new() */
+
+
+/*!
+ * @brief Reload a class in the class table after
+ * @c @b java.lang.String has become available.
+ *
+ * This process does @e not re-read the class file, only redoes
+ * class initialization. The @b class_objhash does not get deleted.
+ *
+ *
+ * @param clsidxOLD Class table index of slot to tear down.
+ *
+ * @returns New class index of rebuilt class slot. Throw error if
+ * no slots.
+ *
+ * @throws JVMCLASS_JAVA_LANG_OUTOFMEMORYERROR
+ * @link #JVMCLASS_JAVA_LANG_OUTOFMEMORYERROR
+ * if no slots are available.@endlink.
+ *
+ *
+ * @todo This function needs more testing. Also, is it @e really
+ * needed in the implementation?
+ */
+
+jvm_class_index class_reload(jvm_class_index clsidxOLD)
+{
+
+ if (CLASS(clsidxOLD).status & CLASS_STATUS_INUSE)
+ {
+ /* Locate an empty slot */
+ jvm_class_index clsidxNEW = class_allocate_slot(rtrue);
+
+ /*
+ * Save image of class slot to be copied into new slot
+ */
+ rclass *dupslot = HEAP_GET_METHOD(sizeof(rclass), rfalse);
+
+ memcpy(dupslot, &CLASS(clsidxOLD), sizeof(rclass));
+
+
+ /* Mark old slot as partially initialized */
+ CLASS(clsidxOLD).status |= CLASS_STATUS_NULL;
+
+ /* Should @e always be true */
+ if (jvm_object_hash_null != CLASS(clsidxOLD).class_objhash)
+ {
+ /* Replace old class slot ref with new class slot ref. */
+ OBJECT(dupslot->class_objhash).table_linkage.clsidx =
+ clsidxNEW;
+
+ /* Make SURE there is at least 1 class object reference */
+ (rvoid) GC_OBJECT_MKREF_FROM_CLASS(
+ clsidxOLD,
+ dupslot->class_objhash);
+ (rvoid) GC_CLASS_MKREF_FROM_CLASS(
+ clsidxOLD,
+ dupslot->lower_dim_array);
+ (rvoid) GC_CLASS_MKREF_FROM_OBJECT(
+ dupslot->class_objhash,
+ OBJECT(dupslot->class_objhash)
+ .table_linkage
+ .clsidx);
+
+ /* Unwind real class object reference */
+ (rvoid) GC_OBJECT_RMREF_FROM_CLASS(
+ clsidxOLD,
+ CLASS(clsidxOLD).class_objhash);
+ (rvoid) GC_CLASS_RMREF_FROM_CLASS(
+ clsidxOLD,
+ CLASS(clsidxOLD).lower_dim_array);
+ (rvoid) GC_CLASS_RMREF_FROM_OBJECT(
+ CLASS(clsidxOLD).class_objhash,
+ OBJECT(CLASS(clsidxOLD).class_objhash)
+ .table_linkage
+ .clsidx);
+
+ /* DO NOT DO THIS-- use same object, incl. class file
+ * object_instance_delete(CLASS(clsidxOLD)
+ * .class_objhash);
+ */
+
+ CLASS(clsidxOLD).class_objhash = jvm_object_hash_null;
+ }
+
+ /* Unhook class object's class ref, then all unhook class refs*/
+ (rvoid) GC_CLASS_RMREF_FROM_CLASS(
+ clsidxOLD,
+ CLASS(clsidxOLD).lower_dim_array);
+ (rvoid) GC_CLASS_RMREF_FROM_CLASS(jvm_class_index_null,
+ clsidxOLD);
+ (rvoid) linkage_unresolve_class(clsidxOLD);
+
+ /*
+ * Finalize garbage collection status of this class instance,
+ * but DO NOT do class_static_delete()!
+ */
+ (rvoid) GC_CLASS_DELETE(clsidxOLD, rfalse);
+
+ /*
+ * Wipe out old structures, see similar in class_static_delete()
+ */
+ CLASS(clsidxOLD).class_static_field_lookup =
+ (jvm_class_index *) rnull;
+ CLASS(clsidxOLD).num_class_static_field_lookups = 0;
+
+ CLASS(clsidxOLD).object_instance_field_lookup =
+ (jvm_class_index *) rnull;
+ CLASS(clsidxOLD).num_object_instance_field_lookups = 0;
+
+
+ CLASS(clsidxOLD).status = CLASS_STATUS_EMPTY;
+
+ /*
+ * Copy slot image into new slot
+ */
+ dupslot->status |= CLASS_STATUS_NULL; /* Partial init */
+
+ memcpy(&CLASS(clsidxNEW), dupslot, sizeof(rclass));
+
+ /* Reverse of first pair of mkref/rmref */
+ (rvoid) GC_OBJECT_MKREF_FROM_CLASS(
+ clsidxNEW,
+ CLASS(clsidxNEW).class_objhash);
+ (rvoid) GC_CLASS_MKREF_FROM_CLASS(
+ clsidxNEW,
+ CLASS(clsidxNEW).lower_dim_array);
+ (rvoid) GC_CLASS_MKREF_FROM_OBJECT(
+ CLASS(clsidxNEW).class_objhash,
+ OBJECT(CLASS(clsidxNEW).class_objhash)
+ .table_linkage
+ .clsidx);
+
+ (rvoid) GC_OBJECT_RMREF_FROM_CLASS(
+ clsidxOLD,
+ dupslot->class_objhash);
+ (rvoid) GC_CLASS_RMREF_FROM_CLASS(
+ clsidxOLD,
+ dupslot->lower_dim_array);
+ (rvoid) GC_CLASS_RMREF_FROM_OBJECT(
+ dupslot->class_objhash,
+ OBJECT(dupslot->class_objhash)
+ .table_linkage
+ .clsidx);
+
+ /* Unwind real class object reference */
+ HEAP_FREE_METHOD(&dupslot);
+
+ return(clsidxNEW);
+ }
+ else
+ {
+ /* Error-- slot was already free */
+ return(jvm_class_index_null);
+ }
+
+} /* END of class_reload() */
+
+
+/*!
+ * @brief Un-reserve a slot from the class table.
+ *
+ * This is the reverse of the process of class_static_new() above.
+ * Only tear down the heap allocations and mark the slot as empty.
+ * Leave the rest of the data in place for post-mortem. When the
+ * slot gets allocated again, any zeroing out of values will just
+ * get overwritten again, so don't bother.
+ *
+ * @todo Make @e sure all objects of this class type have been
+ * destroyed @e before destroying this class itself!
+ *
+ * @todo This function may be used to declutter the class table when
+ * a class has not been used for some period of time (including
+ * any static methods and fields, watch out for static final
+ * constants), so as to free up its slot for other purposes.
+ *
+ *
+ * @param clsidx Class index value of allocation.
+ *
+ * @param rmref @link #rtrue rtrue@endlink if @e class references
+ * should be removed, which is NOT SO during JVM
+ * shutdown. Regardless of this value, @e object
+ * references are always removed.
+ *
+ *
+ * @returns Same class index as input if slot was freed, else
+ * @link #jvm_class_index_null jvm_class_index_null@endlink
+ * if slot was already free.
+ *
+ */
+
+jvm_class_index class_static_delete(jvm_class_index clsidx,
+ rboolean rmref)
+{
+ if (CLASS(clsidx).status & CLASS_STATUS_INUSE)
+ {
+ /*!
+ * @todo Determine what to do, if anything, when rfalse is
+ * returned from linkage_unresolve_class(). Is the
+ * class slot unusable? Should class_static_delete()
+ * proceed?
+ */
+ (rvoid) linkage_unresolve_class(clsidx);
+
+ /*!
+ * @todo Is there anything equivalent to calling
+ * @c @b java.lang.Object.finalize() for an object
+ * that must be invoked before unloading a class?
+ */
+
+ if (jvm_object_hash_null != CLASS(clsidx).class_objhash)
+ {
+ (rvoid) GC_OBJECT_RMREF_FROM_CLASS(
+ clsidx,
+ CLASS(clsidx).class_objhash);
+
+ object_instance_finalize(CLASS(clsidx).class_objhash,
+ JVMCFG_GC_THREAD);
+
+ (rvoid) object_instance_delete(
+ CLASS(clsidx).class_objhash,
+ rtrue);
+
+ /* CLASS(clsidx).class_objhash = jvm_object_hash_null;*/
+ }
+
+ /* Finalize garbage collection status of this class instance */
+ if (rtrue == rmref)
+ {
+ (rvoid) GC_CLASS_RMREF_FROM_CLASS(clsidx,
+ CLASS(clsidx).lower_dim_array);
+ }
+ (rvoid) GC_CLASS_DELETE(clsidx, rfalse);
+
+ if (rnull != CLASS(clsidx).class_static_field_data)
+ {
+ /* Remove class static field reference markings */
+ u2 ncsfl = CLASS(clsidx).num_class_static_field_lookups;
+ jvm_field_lookup_index csflidx;
+ for (csflidx = 0; csflidx < ncsfl; csflidx++)
+ {
+ (rvoid) GC_CLASS_FIELD_RMREF(clsidx, csflidx);
+ }
+
+ HEAP_FREE_DATA(CLASS(clsidx).class_static_field_data);
+ }
+
+ if (rnull != CLASS(clsidx).class_static_field_lookup)
+ {
+ HEAP_FREE_DATA(CLASS(clsidx).class_static_field_lookup);
+ }
+ /* CLASS(clsidx).class_static_field_lookup =
+ (jvm_class_index *) rnull; */
+ /* CLASS(clsidx).num_class_static_field_lookups = 0; */
+
+ if (rnull != CLASS(clsidx).object_instance_field_lookup)
+ {
+ HEAP_FREE_DATA(CLASS(clsidx).object_instance_field_lookup);
+ }
+ /* CLASS(clsidx).object_instance_field_lookup =
+ (jvm_class_index *) rnull; */
+ /* CLASS(clsidx).num_object_instance_field_lookups = 0; */
+
+
+ /* CLASS(clsidx).status = CLASS_STATUS_EMPTY; */
+
+ CLASS(clsidx).status &= ~CLASS_STATUS_INUSE;
+
+ return(clsidx);
+ }
+ else
+ {
+ /* Error-- slot was already free */
+ return(jvm_class_index_null);
+ }
+
+} /* END of class_static_delete() */
+
+
+/*!
+ * @brief Scan class table using CP table entry for presence of a class
+ * of specific name and number of dimensions.
+ *
+ *
+ * @param clsname UTF8 string pointer to a class
+ * name, possibly with array dimensions:
+ * @c @b [[Lsome/class/path/SomeClassname;
+ * has two array dimensions. Can also
+ * accept classes that are null-terminated
+ * strings @e without class formatting.
+ * Such strings @e may start with @c @b L
+ * but will @e not end with @c @b ; .
+ *
+ *
+ * @returns its index in pjvm->class if present, else
+ * @link #jvm_class_index_null jvm_class_index_null@endlink.
+ *
+ */
+jvm_class_index class_find_by_cp_entry(cp_info_dup *clsname)
+{
+ jvm_class_index clsidx;
+
+ jvm_array_dim arraydims =
+ utf_get_utf_arraydims(PTR_THIS_CP_Utf8(clsname));
+
+ for (clsidx = JVMCFG_FIRST_CLASS;
+ clsidx < JVMCFG_MAX_CLASSES;
+ clsidx++)
+ {
+ if ( (CLASS_STATUS_INUSE & CLASS(clsidx).status) &&
+ !(CLASS_STATUS_NULL & CLASS(clsidx).status))
+ {
+ ClassFile *pcfs = CLASS_OBJECT_LINKAGE(clsidx)->pcfs;
+ u2 cpidx = pcfs->this_class;
+
+ /*
+ * Check if this slot's class name matches input request.
+ * Must match BOTH @b arraydims and string name.
+ */
+ if (arraydims != CLASS(clsidx).arraydims)
+ {
+ continue;
+ }
+
+ if (0 == utf_classname_strcmp(
+ PTR_THIS_CP_Utf8(clsname),
+ pcfs,
+ cpidx))
+ {
+ return(clsidx);
+ }
+ }
+ }
+
+ /* Return NULL if entry not found */
+ return(jvm_class_index_null);
+
+} /* END of class_find_by_cp_entry() */
+
+
+/*!
+ * @brief Retrieve by (rchar *) name a class index to a class.
+ *
+ *
+ * @param clsname Null-terminated string of name of class.
+ *
+ *
+ * @returns class index of located class, otherwise
+ * @link #jvm_class_index_null jvm_class_index_null@endlink.
+ *
+ */
+jvm_class_index class_find_by_prchar(rchar *clsname)
+{
+ cp_info_dup *pcip_clsname = nts_prchar2utf(clsname);
+
+ jvm_method_index rc =
+ class_find_by_cp_entry(pcip_clsname);
+
+ HEAP_FREE_DATA(pcip_clsname);
+
+ return(rc);
+
+} /* END of class_find_by_prchar() */
+
+
+/*!
+ * @brief Load primative classes for @c @b java.lang.Class
+ *
+ * Load primative classes as opposed to a real class
+ * @c @b LSome/Package/Name/SomeClassName; .
+ * These will be known by their primative types: @c @b I
+ * for "integer", @c @b S for "short", etc.
+ *
+ * Classes loaded with this method will typically @e never have any
+ * references to them except from their class object created
+ * within class_static_new(), yet are completely valid and are used
+ * intensively by class type processing. Because they never have
+ * references @e removed, they will never be marked for garbage
+ * collection, either. In this way, they are permanently available
+ * to the JVM for class type processing.
+ *
+ * @param basetype One of the primative base types BASETYPE_CHAR_x
+ *
+ *
+ * @returns class table index to loaded primative [pseudo-]class,
+ * ready for use. Throw error if could not load.
+ *
+ *
+ * @throws JVMCLASS_JAVA_LANG_OUTOFMEMORYERROR
+ * @link #JVMCLASS_JAVA_LANG_OUTOFMEMORYERROR
+ * if no slots are available.@endlink.
+ *
+ */
+jvm_class_index class_load_primative(u1 basetype)
+{
+ ClassFile *pcfs = classfile_allocate_primative(basetype);
+
+ return(class_static_new(CLASS_STATUS_PRIMATIVE,
+ pcfs,
+ LOCAL_CONSTANT_NO_ARRAY_DIMS,
+ (jint *) rnull,
+ jvm_class_index_null));
+
+} /* END of class_load_primative() */
+
+
+/*!
+ * @name DEFAULT SYSTEM CLASS LOADER:
+ *
+ * @brief perform the duties of @c @b java.lang.ClassLoader
+
+ * Using either null-terminated strings or UTF strings from
+ * @link #CONSTANT_Utf8_info CONSTANT_Utf8_info@endlink or
+ * @link #CONSTANT_Class_info CONSTANT_Class_info@endlink
+ * constant_pool entries, the following three functions function
+ * as the system default class loader that can be invoked three
+ * different ways. It searches @b CLASSPATH, reads in a class
+ * file, parses its contents, and loads it into the class table
+ * and object table, and performs static initialization.
+ *
+ * Notice that the array formatting @e must already be included in
+ * @b clsname (if this is an array class), and that the @b arraylength
+ * array must contain the same number of integers as described
+ * in @b clsname. No checking is done for this in this function.
+ *
+ * @attention This function performs the task of the method
+ *
+ * @verbatim
+ ClassLoader.defineClass(String name, byte[] b, int off, int len)
+ @endverbatim
+ *
+ * but combines the operands effectively into,
+ *
+ * @verbatim
+ ClassLoader.defineClass(String name)
+ @endverbatim
+ *
+ * where @b name is a null-terminated string passed as the only parm,
+ * and @b b is the byte array read in by classfile_readclassfile()
+ * or classfile_readjarfile(), and @b off is zero, and @b len being
+ * discovered by classfile_read_XXXfile().
+ *
+ * @todo Spec section 5.3.4 <b>Loading Constraints</b> has not been
+ * considered in this implementation. It needs to be looked at.
+ *
+ * @todo Convert this function from recursive (easy to write) into
+ * iterative (easier to run and maintain).
+ *
+ *
+ * @param clsname This parameter may be one of three styles:
+ *
+ * <ul>
+ * <li> for class_load_from_cp_entry_utf() only: a
+ * CONSTANT_Utf8_info constant_pool entry string
+ * containing unqualified class name:
+ *
+ * @c @b Lsome/class/path/SomeClassname;
+ *
+ * with possible array specification:
+ *
+ * @c @b [[[Lsome/class/path/SomeClassname;
+ *
+ * This example has three array dimensions.
+ * </li>
+ *
+ * <li> for class_load_from_prchar() only: a null-terminated string
+ * containing unqualified class name.
+ * See above for further comments.
+ * </li>
+ *
+ * <li> for class_load_from_cp_entry_class() only: a
+ * CONSTANT_Class_info constant_pool entry containing
+ * constant_pool entry to unqualified class name.
+ * See above for further comments.
+ * </li>
+ * </ul>
+ *
+ * @param find_registerNatives When @link #rtrue rtrue@endlink,
+ * will return the ordinal for
+ * @link #JVMCFG_JLOBJECT_NMO_REGISTER
+ JVMCFG_JLOBJECT_NMO_REGISTER@endlink and
+ * @link #JVMCFG_JLOBJECT_NMO_UNREGISTER
+ JVMCFG_JLOBJECT_NMO_UNREGISTER@endlink
+ * as well as the other ordinals. Once JVM
+ * initialization is complete, this should always
+ * be @link #rfalse rfalse@endlink because all future
+ * classes should @e never have local ordinals.
+ *
+ * @param arraylength Array of number of elements in @e each array
+ * dimension. If not needed, set to
+ * @link #rnull rnull@endlink.
+ * Notice that @b clsname will determine how many
+ * array dimensions are needed. In the above
+ * example of 3 dimensions, an array of 3 numbers
+ * must be passed here. If the declaration was,
+ * <b><code>new SomeClassname[4][7][8]</code></b>,
+ * then the array {4, 7, 8} must be passed here.
+ *
+ *
+ * @returns class table index to loaded class, ready for use, or
+ * @link #jvm_class_index_null jvm_class_index_null@endlink
+ * if could not load.
+ *
+ *
+ * @throws JVMCLASS_JAVA_LANG_OUTOFMEMORYERROR
+ * @link #JVMCLASS_JAVA_LANG_OUTOFMEMORYERROR
+ * if no slots are available.@endlink.
+ *
+ * @throws JVMCLASS_JAVA_LANG_INTERNALERROR
+ * @link #JVMCLASS_JAVA_LANG_INTERNALERROR
+ * with bad clsname constant_pool entry type@endlink.
+ * Meaninful only for
+ * @link #class_load_from_cp_entry_utf()
+ class_load_from_cp_entry_utf()@endlink
+ *
+ */
+/* and @link #@class_load_from_cp_entry_class()
+ class_load_from_cp_entry_class()@endlink only. */
+
+/*@{ */ /* Begin grouped definitions */
+
+jvm_class_index
+ class_load_from_cp_entry_utf(cp_info_dup *clsname,
+ rboolean find_registerNatives,
+ jint *arraylength)
+{
+ /* Disallow all but UTF8 constant_pool entries */
+ if (CONSTANT_Utf8 != PTR_THIS_CP_Utf8(clsname)->tag)
+ {
+ /* Somebody goofed */
+ exit_throw_exception(EXIT_JVM_INTERNAL,
+ JVMCLASS_JAVA_LANG_INTERNALERROR);
+/*NOTREACHED*/
+ }
+
+ /*
+ * Be @e VERY conservative about local var allocation
+ * due to upcoming deep recursion.
+ */
+ jvm_class_index rc;
+
+ /*
+ * Ignore this request if class already loaded, but distinguish
+ * between array and non-array classes
+ */
+ rc = class_find_by_cp_entry(clsname);
+
+ /* If class already loaded, then do nothing */
+ if (jvm_class_index_null != rc)
+ {
+ return(rc);
+ }
+
+ /* Inquire if this is an array class */
+ jvm_array_dim arraydims =
+ utf_get_utf_arraydims(PTR_THIS_CP_Utf8(clsname));
+
+ /*
+ * If an array class, load array class of 1 lower dimension,
+ * or non-array version if this is array dimension 1.
+ */
+ if (LOCAL_CONSTANT_NO_ARRAY_DIMS < arraydims)
+ {
+ rchar *pnextdim = utf_utf2prchar(PTR_THIS_CP_Utf8(clsname));
+
+ /*
+ * WARNING! RECURSIVE CALL! This call goes 1 level per
+ * array dimension.
+ */
+ rc = class_load_from_prchar(&pnextdim[1 * sizeof(u1)],
+ find_registerNatives,
+ (rnull == arraylength)
+ ? (jint *) rnull
+ : &arraylength[1]);
+
+ HEAP_FREE_DATA(pnextdim);
+ }
+
+ /*
+ * Be conservative about number of local variables above
+ * due to possibility of deep recursion (avert stack overflow).
+ * Now that recursion is over, can allocate locals more freely.
+ */
+ {
+ /* Use name more descriptive of new role. Known non-zero. */
+ jvm_class_index lower_dim_clsidx = rc;
+
+ /*
+ * For an array, locate class file structure of non-array
+ * version and mark class as being an array class (through
+ * agency of class_static_new(,,arraydims,)). If not an
+ * array class, load the class file. This will be
+ * known to array classes as the "non-array version" of
+ * the class. All array class file pointers will point
+ * to this class file structure.
+ */
+ u1 *pcfd;
+ ClassFile *pcfs;
+ rchar *pcname;
+ jvm_class_index clsidx;
+
+ if (LOCAL_CONSTANT_NO_ARRAY_DIMS < arraydims)
+ {
+ /* Locate non-array version of class in class table */
+ jvm_class_index next_clsidx = lower_dim_clsidx;
+
+ while(jvm_class_index_null !=
+ CLASS(next_clsidx).lower_dim_array)
+ {
+ next_clsidx =
+ CLASS(CLASS_OBJECT_LINKAGE(next_clsidx)->clsidx)
+ .lower_dim_array;
+ }
+
+ /* Having traversed the indices, found non-array version */
+ ClassFile *pcfs = CLASS_OBJECT_LINKAGE(next_clsidx)->pcfs;
+
+ /* Load into class and object tables */
+ clsidx =
+ class_static_new(((LOCAL_CONSTANT_NO_ARRAY_DIMS ==
+ arraydims)
+ ? CLASS_STATUS_EMPTY
+ : CLASS_STATUS_ARRAY),
+ pcfs,
+ arraydims,
+ arraylength,
+ lower_dim_clsidx);
+
+ } /* if arraydims */
+ else
+ {
+ cp_info_dup *pnofmt =
+ utf_utf2utf_unformatted_classname(clsname);
+
+ pcname = classpath_get_from_cp_entry_utf(pnofmt);
+
+ HEAP_FREE_DATA(pnofmt);
+
+ GENERIC_FAILURE1_THROWERROR((rnull == pcname),
+ DMLNORM,
+ "class_load_from_prchar",
+ "Cannot locate class %s",
+ clsname,
+ EXIT_JVM_CLASS,
+ JVMCLASS_JAVA_LANG_NOCLASSDEFFOUNDERROR,
+ pcname,
+ rnull);
+
+ /*
+ * Check if JAR file or class file and read in the class
+ * file data stream as a simple binary image.
+ */
+ if (rtrue == classpath_isjar(pcname))
+ {
+ pcfd = classfile_readjarfile(pcname);
+ }
+ else
+ {
+ pcfd = classfile_readclassfile(pcname);
+ }
+
+ GENERIC_FAILURE1_THROWERROR((rnull == pcfd),
+ DMLNORM,
+ "class_load_from_prchar",
+ "Cannot read file %s",
+ pcname,
+ EXIT_JVM_CLASS,
+ JVMCLASS_JAVA_LANG_CLASSFORMATERROR,
+ pcfd,
+ pcname);
+
+ /*! @todo Throw @b UnsupportedClassVersionError */
+
+ /* Parse out the class file input stream */
+ pcfs = classfile_loadclassdata(pcfd);
+
+ /* Load into class and object tables */
+ clsidx = class_static_new(CLASS_STATUS_EMPTY,
+ pcfs,
+ LOCAL_CONSTANT_NO_ARRAY_DIMS,
+ (jint *) rnull,
+ jvm_class_index_null);
+
+ /* Don't need file image any more */
+ HEAP_FREE_DATA(pcfd);
+
+ GENERIC_FAILURE1_THROWERROR((rnull == pcfs),
+ DMLNORM,
+ "class_load_from_prchar",
+ "Invalid class file %s",
+ pcname,
+ EXIT_JVM_CLASS,
+ JVMCLASS_JAVA_LANG_CLASSFORMATERROR,
+ pcname,
+ rnull);
+
+ /* Don't need absolute path name any more, either */
+ HEAP_FREE_DATA(pcname);
+
+ /*!
+ * @internal Load superclass
+ *
+ * @todo (The @c @b \<clinit\> procedure is run when the
+ * JVM virtual machine execution engine moves
+ * a new class from the START state into the
+ * RUNNABLE state.)
+ */
+ if (jvm_class_index_null != pcfs->super_class)
+ {
+ CONSTANT_Utf8_info *name = PTR_CP1_CLASS_NAME(pcfs,
+ pcfs->super_class);
+
+ rchar *super_name = utf_utf2prchar_classname(name);
+
+ /*!
+ * @internal WATCH OUT! RECURSIVE CALL! This will
+ * recurse until super_class is a
+ * @c @b java.lang.Object, where
+ * @link ClassFile.super_class
+ ClassFile.super_class@endlink is 0 (per JVM spec.
+ * Throw error if could not load superclass.
+ * Don't care about its class index, as
+ * that is also available in other places.
+ *
+ * @todo Make @e sure that this superclass and all of
+ * its superclasses are not only loaded, but also
+ * linked and have @c @b \<clinit\> run also.
+ *
+ */
+ (rvoid) class_load_from_prchar(super_name,
+ find_registerNatives,
+ (jint *) rnull);
+
+ /*
+ * If error above, neither HEAP_FREE_DATA(super_name)
+ * nor classfile_unloadclassdata(pcfs) will be called.
+ */
+ }
+
+ /* Mark as needing @c @b \<clinit\> in JVM class startup */
+ CLASS(clsidx).status |= CLASS_STATUS_DOCLINIT;
+
+ } /* if arraydims else */
+
+ /* Make a pass at resolving constant_pool linkages */
+ (rvoid) linkage_resolve_class(clsidx, find_registerNatives);
+
+ /*
+ * Class is ready for JVM execution.
+ */
+ return(clsidx);
+
+ } /* local block */
+
+} /* END of class_load_from_cp_entry_utf() */
+
+
+jvm_class_index class_load_from_prchar(rchar *clsname,
+ rboolean find_registerNatives,
+ jint *arraylength)
+{
+ cp_info_dup *cp_clsname = nts_prchar2utf(clsname);
+
+ jvm_class_index clsidx =
+ class_load_from_cp_entry_utf(cp_clsname,
+ find_registerNatives,
+ arraylength);
+
+ HEAP_FREE_DATA(cp_clsname);
+
+ return(clsidx);
+
+} /* END of class_load_from_prchar() */
+
+
+#if 0
+/* Can use if want to add @b pcfs to parm list or some such */
+jvm_class_index
+ class_load_from_cp_entry_class(cp_info_dup *clsname,
+ rboolean find_registerNatives,
+ jint *arraylength)
+{
+ /* Disallow all but CLASS constant_pool entries */
+ if (CONSTANT_Class != PTR_THIS_CP_Class(clsname)->tag)
+ {
+ /* Somebody goofed */
+ exit_throw_exception(EXIT_JVM_INTERNAL,
+ JVMCLASS_JAVA_LANG_INTERNALERROR);
+/*NOTREACHED*/
+ }
+
+ rchar *prchar_clsname =
+ utf_utf2prchar(
+ PTR_THIS_CP_Utf8(
+ &pcfs->constant_pool
+ [PTR_THIS_CP_Class(clsname)->name_index]));
+
+ jvm_class_index clsidx = class_load_from_prchar(prchar_clsname,
+ find_registerNatives,
+ arraylength);
+
+ HEAP_FREE_DATA(prchar_clsname);
+
+ return(clsidx);
+
+} /* END of class_load_from_cp_entry_class() */
+#endif
+
+/*@} */ /* End of grouped definitions */
+
+
+/*!
+ * @brief All-purpose class loading, load, resolve, @c @b \<clinit\> ,
+ * each step only run if needed.
+ *
+ * Load a class into the JVM, resolve its linkages, and run its
+ * @c @b \<clinit\> method, if any, typically on the system thread.
+ * All three steps are optional and will be invoked @e only if needed.
+ * Therefore it is possible that @e none of the steps will be run.
+ * However, if @e any step needs to performed, that step will be run.
+ *
+ *
+ * @param clsname Null-terminated string of unformatted
+ * class name.(Formatting is okay, but don't
+ * pass an array class)
+ *
+ * @param thridx If a non-null thread index is passed in,
+ * use the current state of that thread to
+ * load the class and run its
+ * @c @b \<clinit\> .
+ * If null thread index is passed in, use
+ * the @b usesystemthread parameter to
+ * further clarify which thread to load up
+ * with class @c @b \<clinit\> .
+ *
+ * @param usesystemthread Load onto system thread when
+ * @link #rtrue rtrue@endlink, use
+ * an available thread otherwise.
+ *
+ * @param find_registerNatives When @link #rtrue rtrue@endlink,
+ * will return the ordinal for
+ * @link #JVMCFG_JLOBJECT_NMO_REGISTER
+ JVMCFG_JLOBJECT_NMO_REGISTER@endlink and
+ * @link #JVMCFG_JLOBJECT_NMO_UNREGISTER
+ JVMCFG_JLOBJECT_NMO_UNREGISTER@endlink
+ * as well as the other ordinals. Once JVM
+ * initialization is complete, this should always
+ * be @link #rfalse rfalse@endlink because all
+ * future classes should @e never have local
+ * ordinals.
+ *
+ *
+ * @returns class index of loaded class, whether or not a
+ * @c @b \<clinit\> method was available. Throw
+ * error if not slots available.
+ *
+ *
+ * @throws JVMCLASS_JAVA_LANG_OUTOFMEMORYERROR
+ * @link #JVMCLASS_JAVA_LANG_OUTOFMEMORYERROR
+ * if no slots are available.@endlink.
+ *
+ * @throws JVMCLASS_JAVA_LANG_INTERNALERROR
+ * @link #JVMCLASS_JAVA_LANG_INTERNALERROR
+ if invalid clsidx@endlink
+ *
+ * @throws JVMCLASS_JAVA_LANG_NOSUCHFIELDERROR
+ * @link #JVMCLASS_JAVA_LANG_NOSUCHFIELDERROR
+ if invalid field linked by class@endlink
+ *
+ * @throws JVMCLASS_JAVA_LANG_NOSUCHMETHODERROR
+ * @link #JVMCLASS_JAVA_LANG_NOSUCHMETHODERROR
+ if invalid method linked by class@endlink
+ *
+ * @todo Any JAR file passed in here that has a @c @b [ in its
+ * first one or more characters may be interpreted as an array
+ * class. I have not tested this, and it is an oddball,
+ * but somebody needs to make sure that either, (a) such
+ * a name is @e never passed in, which is preferred due to
+ * standard industry file naming practices, and/or (b) that
+ * no array processing happens in the lower levels.
+ *
+ */
+
+
+jvm_class_index class_load_resolve_clinit(rchar *clsname,
+ jvm_thread_index thridx,
+ rboolean usesystemthread,
+ rboolean find_registerNatives)
+{
+ jvm_class_index clsidx = class_load_from_prchar(clsname,
+ find_registerNatives,
+ (jint *) rnull);
+
+ /*
+ * Make another pass at class linkage (if completely linked,
+ * request is ignored).
+ */
+ (rvoid) linkage_resolve_class(clsidx, find_registerNatives);
+
+ /*
+ * If @c @b \<clinit\> has been run due to previous class load,
+ * done
+ */
+ if (CLASS_STATUS_CLINIT & CLASS(clsidx).status)
+ {
+ return(clsidx);
+ }
+
+ /*
+ * Need to explicitly run @c @b \<clinit\> since not
+ * in main JVM loop
+ */
+ jvm_method_index mthidx =
+ method_find_by_prchar(clsidx,
+ LOCAL_CONSTANT_UTF8_CLASS_CONSTRUCTOR,
+ LOCAL_CONSTANT_UTF8_CLASS_CONSTRUCTOR_PARMS);
+ if (jvm_method_index_bad == mthidx)
+ {
+ /*
+ * Return valid class index even if no @c @b \<clinit\>
+ * was available
+ */
+ return(clsidx);
+ }
+ else
+ {
+ jvm_thread_index thridxLOAD;
+
+ if (jvm_thread_index_null != thridx)
+ {
+ thridxLOAD = thridx;
+
+ /*!
+ * @internal see similar logic for loading a new stack
+ * frame and PC in thread_new_common()
+ *
+ */
+
+ ClassFile *pcfs = CLASS_OBJECT_LINKAGE(clsidx)->pcfs;
+
+ jvm_attribute_index codeatridx =
+ pcfs
+ ->methods[mthidx]
+ ->LOCAL_method_binding
+ .codeatridxJVM;
+
+ if (jvm_attribute_index_bad == codeatridx)
+ {
+ /*!
+ * @todo Currently, return valid class index even
+ * if no @c @b \<clinit\> was available. Is this
+ * correct? Or should it throw a @b VerifyError since
+ * a method was declared, yet had no code area? Take
+ * the easy way out for now, evaluate and maybe fix
+ * later.
+ */
+ return(clsidx);
+ }
+
+ jvm_attribute_index excpatridx =
+ pcfs
+ ->methods[mthidx]
+ ->LOCAL_method_binding
+ .excpatridxJVM;
+
+ Code_attribute *pca =
+ (Code_attribute *)
+ &pcfs->methods[mthidx]->attributes[codeatridx]->ai;
+
+ /* Check for stack overflow if this frame is loaded */
+ if (JVMCFG_MAX_SP <= GET_SP(thridx) +
+ JVMREG_STACK_MIN_FRAME_HEIGHT +
+ JVMREG_STACK_PC_HEIGHT +
+ pca->max_stack +
+ pca->max_locals)
+ {
+ exit_throw_exception(EXIT_JVM_CLASS,
+ JVMCLASS_JAVA_LANG_OUTOFMEMORYERROR);
+/*NOTLOADED*/
+ }
+
+ /*
+ * Save old stack frame for @b RETURN from @c b \<clinit\>
+ */
+ PUSH_FRAME(thridx, pca->max_locals);
+
+ /* Load PC of @c @b \<clinit\> method */
+ PUT_PC_IMMEDIATE(thridx,
+ clsidx,
+ mthidx,
+ codeatridx,
+ excpatridx,
+ CODE_CONSTRAINT_START_PC);
+ }
+ else
+ {
+ /*
+ * Class is now known to be available,
+ * so start it on the system thread.
+ *
+ * There is no old stack frame to save for @b RETURN
+ * from @c @b \<clinit\> because this a new thread. The
+ * starting stack frame is set up by thread_class_load()
+ * and returning to it will @b COMPLETE the thread.
+ */
+ thridxLOAD =
+ thread_class_load(clsname,
+ LOCAL_CONSTANT_UTF8_CLASS_CONSTRUCTOR,
+ LOCAL_CONSTANT_UTF8_CLASS_CONSTRUCTOR_PARMS,
+ THREAD_PRIORITY_MAX,
+ rfalse,
+ usesystemthread,
+ find_registerNatives);
+ }
+
+ jvm_manual_thread_run(thridxLOAD,
+ ((rtrue == usesystemthread) ||
+ (jvm_thread_index_null == thridx))
+ ? rtrue /* Die if not prev @b RUN */
+ : rfalse,
+ clsname,
+ LOCAL_CONSTANT_UTF8_CLASS_CONSTRUCTOR,
+ LOCAL_CONSTANT_UTF8_CLASS_CONSTRUCTOR_PARMS);
+
+ /* Class @c @b \<clinit\> has been completed (manually) */
+ CLASS(clsidx).status &= ~CLASS_STATUS_DOCLINIT;
+ CLASS(clsidx).status |= CLASS_STATUS_CLINIT;
+
+
+ /*Return class index of class loaded,resolved,and ready to use*/
+ return(clsidx);
+ }
+
+} /* END of class_load_resolve_clinit() */
+
+
+/*!
+ * @brief Retrieve data from a @link #CONSTANT_Class_info
+ CONSTANT_xxx_info@endlink structure and insert it
+ * into a slot in the field data table. Also implements table 4.6.
+ *
+ *
+ * @param clsidx Class table index of slot having class loaded
+ *
+ * @param pcfs Pointer to ClassFile area
+ *
+ * @param fldidx Class file field info table index
+ *
+ * @param field_data Field data tbl in class tbl entry(on the heap)
+ *
+ * @param fluidx Field lookup index into field_data table
+ *
+ * @param staticmark If @link #rtrue rtrue@endlink, this
+ * invocation is for a class static field lookup
+ * table, so call
+ * GC_CLASS_FIELD_MKREF(clsidx, fluidx) for
+ * reference types (namely CONSTANT_String
+ * types). When @link #rfalse rfalse@endlink,
+ * call instead
+ * GC_OBJECT_FIELD_MKREF(objhash, fluidx) for
+ * reference types. It is for this @e specific
+ * purpose that @b objhash is supplied below:
+ *
+ * @param objhash If @b staticmark is
+ * @link #rfalse rfalse@endlink,
+ * this is the object
+ * hash of the field lookup table whose reference
+ * types should be GC marked, otherwise ignored.
+ * See @b staticmark above for details.
+ *
+ *
+ * @returns @link #rvoid rvoid@endlink
+ *
+ */
+static
+ rvoid class_get_constant_field_attribute(jvm_class_index clsidx,
+ ClassFile *pcfs,
+ jvm_field_index fldidx,
+ jvalue *field_data,
+ jvm_field_lookup_index fluidx,
+ rboolean staticmark,
+ jvm_object_hash objhash)
+{
+ /* Check for an initial value for each field */
+ jvm_attribute_index atridx;
+ for (atridx = 0;
+ atridx < pcfs->fields[fldidx]->attributes_count;
+ atridx++)
+ {
+ rulong *prl8;
+ rdouble *prd8;
+
+ u4 *pu4, *pu4h, *pu4l;
+ jint vali;
+ jlong vall;
+ jfloat valf;
+ jdouble vald;
+
+ jvalue val;
+
+ jvm_constant_pool_index constantvalue_index;
+
+ switch (cfattrib_atr2enum(pcfs,
+ pcfs->fields[fldidx]
+ ->attributes[atridx]
+ ->ai.attribute_name_index))
+ {
+ case LOCAL_SIGNATURE_ATTRIBUTE:
+ /*! @todo Need to recognize signatures */
+ break;
+
+ case LOCAL_CONSTANTVALUE_ATTRIBUTE:
+ constantvalue_index =
+ ((ConstantValue_attribute *)
+ &pcfs->fields[fldidx]->attributes[atridx]->ai)
+ ->constantvalue_index;
+
+ /* Spec table 4.6 implementation */
+ switch(CP_TAG(pcfs, constantvalue_index))
+ {
+ case CONSTANT_Long:
+ pu4h = &PTR_CP_ENTRY_TYPE(
+ CONSTANT_Long_info,
+ pcfs,
+ constantvalue_index)->high_bytes;
+
+ pu4l = &PTR_CP_ENTRY_TYPE(
+ CONSTANT_Long_info,
+ pcfs,
+ constantvalue_index)->low_bytes;
+
+ /*
+ * if WORDSIZE/32/64 mismatches -m32/-m64,
+ * the <code>JBITS * sizeof(u4)<code>
+ * calculation @e will cause a runtime-visible
+ * compiler warning!
+ */
+/*
+ * vall = (jlong)
+ * ((((julong) *pu4h) << (JBITS * sizeof(u4)))|
+ * ((julong) *pu4l));
+ */
+
+/*! @todo Above logic works, 64-bit logic below needs testing: */
+ /* LS word always follows MS word */
+ prl8 = (rulong *) pu4h;
+ vall = (jlong) GETRL8(prl8);
+
+ val._jlong = vall;
+ break;
+
+ case CONSTANT_Float:
+ pu4 = &PTR_CP_ENTRY_TYPE(
+ CONSTANT_Float_info,
+ pcfs,
+ constantvalue_index)
+ ->bytes;
+
+ valf = (jfloat) (jint) *pu4;
+
+ val._jfloat = valf;
+ break;
+
+ case CONSTANT_Double:
+ pu4h = &PTR_CP_ENTRY_TYPE(
+ CONSTANT_Long_info,
+ pcfs,
+ constantvalue_index)->high_bytes;
+ pu4l = &PTR_CP_ENTRY_TYPE(
+ CONSTANT_Long_info,
+ pcfs,
+ constantvalue_index)->low_bytes;
+
+ /*
+ * if WORDSIZE/32/64 mismatches -m32/-m64,
+ * the <code>JBITS * sizeof(u4)<code>
+ * calculation @e will cause a runtime-visible
+ * compiler warning!
+ */
+/*
+ * vald = (jdouble)
+ * ((((julong) *pu4h) << (JBITS * sizeof(u4)))|
+ * ((julong) *pu4l));
+ */
+
+/*! @todo Above logic works, 64-bit logic below needs testing: */
+ /* LS word always follows MS word */
+ prd8 = (rdouble *) pu4h;
+ vald = (jdouble) GETRL8((rulong *) prd8);
+
+
+ val._jdouble = vald;
+ break;
+
+ case CONSTANT_Integer:
+ pu4 = &PTR_CP_ENTRY_TYPE(
+ CONSTANT_Integer_info,
+ pcfs,
+ constantvalue_index)
+ ->bytes;
+
+ vali = (jint) *pu4;
+
+ /*
+ * Casting to shorter types, namely
+ * (jshort), (jchar), (jbyte), and
+ * (jboolean), is done during field
+ * access, not here.
+ */
+ val._jint = vali;
+
+ break;
+
+
+ case CONSTANT_String:
+ /*!
+ * @todo Load up this string into a
+ * @c @b java.lang.String using the
+ * source from
+ *
+ * <b><code> pcfs->constant_pool
+ [PTR_CP_ENTRY_TYPE(
+ CONSTANT_String_info,
+ pcfs,
+ constantvalue_index)
+ ->string_index]</code></b>
+ *
+ * But do not store directly into,
+ *
+ * <b><code>val._jstring = ... </code></b>
+ *
+ * Instead, store the resulting object
+ * hash from the algorithm shown in
+ * @link #jvm_init() jvm_init()@endlink
+ * where the @link #main() main()@endlink
+ * parameter @c @b argv[] array is loaded
+ * into the Java edition of the same.
+ * The pseudocode for this operation is
+ * shown there.
+ *
+ * <em>DO NOT</em> do this until the class
+ * initialization is complete for
+ * @c @b java.lang.String or the results
+ * may be arbitrary or even fatal. A
+ * well-formed class library will not
+ * attempt such an operation.
+ *
+ */
+
+
+ /*
+ * DO NOT do GC_OBJECT_MKREF(val._jstring)
+ * since it is part of this class
+ * definition, that is, self-referential.
+ */
+
+
+
+ /*
+ * Since strings are constant, this is the
+ * only opportunity to mark this field.
+ */
+ if (rtrue == staticmark)
+ {
+ GC_CLASS_FIELD_MKREF(clsidx, fluidx);
+ }
+ else
+ {
+ /*
+ * Rearranged higher level logic to
+ * make sure that @b objhash was valid
+ * by the time this call occurs here:
+ */
+ GC_OBJECT_FIELD_MKREF(objhash, fluidx);
+ }
+ break;
+
+ } /* switch constantvalue_index */
+
+
+ /* Copy constant value into result array */
+ memcpy(&field_data[fluidx++], &val, sizeof(jvalue));
+ break;
+
+ /* Satisfy compiler that all cases are handled */
+ case LOCAL_UNKNOWN_ATTRIBUTE:
+ case LOCAL_CODE_ATTRIBUTE:
+ case LOCAL_EXCEPTIONS_ATTRIBUTE:
+ case LOCAL_INNERCLASSES_ATTRIBUTE:
+ case LOCAL_ENCLOSINGMETHOD_ATTRIBUTE:
+ case LOCAL_SYNTHETIC_ATTRIBUTE:
+ case LOCAL_SOURCEFILE_ATTRIBUTE:
+ case LOCAL_LINENUMBERTABLE_ATTRIBUTE:
+ case LOCAL_LOCALVARIABLETABLE_ATTRIBUTE:
+ case LOCAL_LOCALVARIABLETYPETABLE_ATTRIBUTE:
+ case LOCAL_DEPRECATED_ATTRIBUTE:
+ case LOCAL_RUNTIMEVISIBLEANNOTATIONS_ATTRIBUTE:
+ case LOCAL_RUNTIMEINVISIBLEANNOTATIONS_ATTRIBUTE:
+ case LOCAL_RUNTIMEVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE:
+ case LOCAL_RUNTIMEINVISIBLEPARAMETERANNOTATIONS_ATTRIBUTE:
+ case LOCAL_ANNOTATIONDEFAULT_ATTRIBUTE:
+ break;
+ } /* switch cfattrib_atr2enum() */
+
+ } /* for atridx */
+
+ return;
+
+} /* END of class_get_constant_field_attribute() */
+
+
+/*!
+ * @brief Report number of class static fields are in a class file.
+ *
+ *
+ * @param pcfs Pointer to ClassFile area
+ *
+ *
+ * @returns number of fields marked ACC_STATIC.
+ *
+ */
+u2 class_get_num_static_fields(ClassFile *pcfs)
+{
+ jvm_field_index fldidx;
+ u2 rc = 0;
+
+ for (fldidx = 0; fldidx < pcfs->fields_count; fldidx++)
+ {
+ if (ACC_STATIC & pcfs->fields[fldidx]->access_flags)
+ {
+ rc++;
+ }
+ }
+
+ return(rc);
+
+} /* END of class_get_num_static_fields() */
+
+
+/*!
+ * @brief Load the field lookup table for class static fields in
+ * this class.
+ *
+ *
+ * @param pcfs Pointer to ClassFile area
+ *
+ *
+ * @returns array of field indices in ClassFile @b fields table
+ * for all static fields in this class or
+ * @link #rnull rnull@endlink if no values
+ * to initialize or heap allocation error. The
+ * size of the array is determined by the result
+ * of class_get_num_static_fields().
+ *
+ */
+jvm_field_index *class_get_static_field_lookups(ClassFile *pcfs)
+{
+ u2 num_static_fields = class_get_num_static_fields(pcfs);
+
+ /* Done if no static fields to initialize */
+ if (0 == num_static_fields)
+ {
+ return((u2 *) rnull);
+ }
+
+ u2 fldidx;
+ u2 fluidx = 0;
+ jvm_field_index *rc =
+ HEAP_GET_DATA(sizeof(jvm_field_index) * num_static_fields,
+ rfalse);
+
+ for (fldidx = 0; fldidx < pcfs->fields_count; fldidx++)
+ {
+ if (ACC_STATIC & pcfs->fields[fldidx]->access_flags)
+ {
+ rc[fluidx++] = fldidx;
+ }
+ }
+
+ return(rc);
+
+} /* END of class_get_static_field_lookups() */
+
+
+/*!
+ * @brief Load the field data table for class static fields in
+ * this class
+ *
+ *
+ * @param clsidx Class table index of slot having class loaded
+ *
+ * @param pcfs Pointer to ClassFile area
+ *
+ *
+ * @returns array of data values corresponding to each field index
+ * as returned from class_get_static_field_lookups() or
+ * @link #rnull rnull@endlink if no values to initialize
+ * or heap allocation error.
+ * The size of the array is determined by the result of
+ * class_get_num_static_fields().
+ *
+ */
+jvalue *class_get_static_field_data(jvm_class_index clsidx,
+ ClassFile *pcfs)
+{
+ u2 num_static_fields = class_get_num_static_fields(pcfs);
+
+ /* Done if no static fields to initialize */
+ if (0 == num_static_fields)
+ {
+ return((jvalue *) rnull);
+ }
+
+ u2 fldidx;
+ u2 fluidx = 0;
+
+ /*
+ * Allocate heap are for data table, SET ALL VALUES TO ZERO.
+ * This will accomplish the intention of clearing all primative
+ * data types.
+ */
+ jvalue *rc =HEAP_GET_DATA(sizeof(jvalue) * num_static_fields,rtrue);
+
+ for (fldidx = 0; fldidx < pcfs->fields_count; fldidx++)
+ {
+ if (ACC_STATIC & pcfs->fields[fldidx]->access_flags)
+ {
+ class_get_constant_field_attribute(clsidx,
+ pcfs,
+ fldidx,
+ rc,
+ fluidx,
+ rtrue,
+ jvm_object_hash_null);
+
+ fluidx++;
+ }
+ }
+
+ return(rc);
+
+} /* END of class_get_static_field_data() */
+
+
+/*!
+ * @brief Report number of object instance fields are in a class file.
+ *
+ *
+ * @param pcfs Pointer to ClassFile area
+ *
+ *
+ * @returns number of fields @e not marked ACC_STATIC.
+ *
+ */
+u2 class_get_num_object_instance_fields(ClassFile *pcfs)
+{
+ jvm_field_index fldidx;
+ u2 rc = 0;
+
+ for (fldidx = 0; fldidx < pcfs->fields_count; fldidx++)
+ {
+ if (!(ACC_STATIC & pcfs->fields[fldidx]->access_flags))
+ {
+ rc++;
+ }
+ }
+
+ return(rc);
+
+} /* END of class_get_num_object_instance_fields() */
+
+
+/*!
+ * @brief Load the field lookup table for object instance fields in
+ * this class
+ *
+ *
+ * @param pcfs Pointer to ClassFile area
+ *
+ *
+ * @returns array of field indices in ClassFile @b fields table
+ * for all object instance fields in this class or
+ * @link #rnull rnull@endlink if no values to initialize
+ * or heap allocation error. The size of the array is
+ * determined by the result of
+ * class_get_num_object_instance_fields().
+ *
+ */
+jvm_field_index
+ *class_get_object_instance_field_lookups(ClassFile *pcfs)
+{
+ u2 num_instance_fields = class_get_num_object_instance_fields(pcfs);
+
+ /* Done if no object instance fields to initialize */
+ if (0 == num_instance_fields)
+ {
+ return((u2 *) rnull);
+ }
+
+ u2 fldidx;
+ u2 fluidx = 0;
+ jvm_field_index *rc =
+ HEAP_GET_DATA(sizeof(jvm_field_index) * num_instance_fields,
+ rfalse);
+
+ for (fldidx = 0; fldidx < pcfs->fields_count; fldidx++)
+ {
+ if (!(ACC_STATIC & pcfs->fields[fldidx]->access_flags))
+ {
+ rc[fluidx++] = fldidx;
+ }
+ }
+
+ return(rc);
+
+} /* END of class_get_object_instance_field_lookups() */
+
+
+/*!
+ * @brief Load the field data table for object instance fields in
+ * this class.
+ *
+ * This initialization is the same for all objects of this class,
+ * so this function is still naturally a part of class processing
+ * instead of object processing.
+ *
+ *
+ * @param clsidx Class table index of slot having class loaded
+ *
+ * @param objhash Object hash of object slot being loaded.
+ * This is supplied @e expressly to mark
+ * reference types (that is, CONSTANT_String)
+ * during field loading from the class file,
+ * otherwise not needed.
+ *
+ * @param pcfs Pointer to ClassFile area
+ *
+ *
+ * @returns array of data values corresponding to each field index
+ * as returned from class_get_static_field_lookups() or
+ * @link #rnull rnull@endlink if no values to initialize
+ * or heap allocation error. The size of the array is
+ * determined by the result of
+ * class_get_num_object_instance_fields().
+ */
+jvalue *class_get_object_instance_field_data(jvm_class_index clsidx,
+ jvm_object_hash objhash,
+ ClassFile *pcfs)
+{
+ u2 num_object_instance_fields =
+ class_get_num_object_instance_fields(pcfs);
+
+ /* Done if no object instance fields to initialize */
+ if (0 == num_object_instance_fields)
+ {
+ return((jvalue *) rnull);
+ }
+
+ u2 fldidx;
+ u2 fluidx = 0;
+
+ /*
+ * Allocate heap are for data table, SET ALL VALUES TO ZERO.
+ * This will accomplish the intention of clearing all primative
+ * data types.
+ */
+ jvalue *rc =
+ HEAP_GET_DATA(sizeof(jvalue) * num_object_instance_fields,rtrue);
+
+ for (fldidx = 0; fldidx < pcfs->fields_count; fldidx++)
+ {
+ if (!(ACC_STATIC & pcfs->fields[fldidx]->access_flags))
+ {
+ class_get_constant_field_attribute(clsidx,
+ pcfs,
+ fldidx,
+ rc,
+ fluidx,
+ rfalse,
+ objhash);
+ fluidx++;
+ }
+ }
+
+ return(rc);
+
+} /* END of class_get_object_instance_field_data() */
+
+
+/*!
+ * @brief Shut down the class area of the JVM model after JVM execution
+ * in two stages.
+ *
+ * In between these two stages will be object_shutdown()
+ * which performs related reference cleanup from the object side:
+ *
+ * Stage 1-- remove class object references and class array
+ * references.
+ *
+ * object_shutdown()-- remove @e class references from @e objects
+ * here.
+ *
+ * Stage 2-- all remaining cleanup. Notice that references are
+ * removed here @e also except during this shutdown process.
+ *
+ *
+ * @b Parameters: @link #rvoid rvoid@endlink
+ *
+ *
+ * @returns @link #rvoid rvoid@endlink
+ *
+ */
+rvoid class_shutdown_1()
+{
+ jvm_class_index clsidx;
+
+ for (clsidx = jvm_class_index_null;
+ clsidx < JVMCFG_MAX_CLASSES;
+ clsidx++)
+ {
+ if (CLASS(clsidx).status & CLASS_STATUS_INUSE)
+ {
+ if (!(CLASS(clsidx).status & CLASS_STATUS_NULL))
+ {
+ (rvoid) GC_CLASS_RMREF_FROM_CLASS(
+ clsidx,
+ CLASS(clsidx).lower_dim_array);
+
+ (rvoid) GC_OBJECT_RMREF_FROM_CLASS(
+ clsidx,
+ CLASS(clsidx).class_objhash);
+
+ (rvoid) GC_CLASS_RMREF_FROM_CLASS(
+ clsidx,
+ CLASS(clsidx).initiating_ClassLoader);
+
+ (rvoid) GC_CLASS_RMREF_FROM_CLASS(
+ clsidx,
+ CLASS(clsidx).defining_ClassLoader);
+ }
+
+ (rvoid) GC_CLASS_RMREF_FROM_CLASS(jvm_class_index_null,
+ clsidx);
+ }
+ }
+
+ /* This may result in a @e large garbage collection */
+ GC_RUN(rfalse);
+
+ return;
+
+} /* END of class_shutdown_1() */
+
+
+rvoid class_shutdown_2()
+{
+ jvm_class_index clsidx;
+
+ for (clsidx = jvm_class_index_null;
+ clsidx < JVMCFG_MAX_CLASSES;
+ clsidx++)
+ {
+ if (CLASS(clsidx).status & CLASS_STATUS_INUSE)
+ {
+ (rvoid) class_static_delete(clsidx, rfalse);
+ }
+ }
+
+ /* Declare this module uninitialized */
+ jvm_class_initialized = rfalse;
+
+ /* This may result in a @e large garbage collection */
+ GC_RUN(rfalse);
+
+ return;
+
+} /* END of class_shutdown_2() */
+
+
+/* EOF */