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 [10/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.h
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/class.h?rev=307257&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/class.h (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/class.h Fri Oct 7 21:27:56 2005
@@ -0,0 +1,297 @@
+#ifndef _class_h_included_
+#define _class_h_included_
+
+/*!
+ * @file class.h
+ *
+ * @brief Definition of the @c @b java.lang.Class structure in
+ * this real machine implementation.
+ *
+ * The definition of a class index is found here, as is the
+ * definition of a class. When initializing an class,
+ * the following activities happen in the class array:
+ *
+ * <b>(1)</b> Its class index is used to address an empty slot in
+ * the class storage area.
+ *
+ * <b>(2)</b> Since it is not a
+ @link #jvm_class_index_null jvm_class_index_null@endlink
+ * value, its
+ * @link rclass#status status@endlink is set to
+ * @link #CLASS_STATUS_INUSE CLASS_STATUS_INUSE@endlink,
+ * with an @c @b |
+ @link #OBJECT_STATUS_ARRAY OBJECT_STATUS_ARRAY@endlink
+ * if it is an array type. All other bits are clear.
+ *
+ * <b>(3)</b> Allocate an object table slot that references this class
+ * table slot. This a class definition can be references
+ * using an object hash.
+ *
+ * <b>(4)</b> Recursively define array class types.
+ *
+ *
+ * @section Control
+ *
+ * \$URL: https://svn.apache.org/path/name/class.h $ \$Id: class.h 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
+ *
+ */
+
+ARCH_COPYRIGHT_APACHE(class, h, "$URL: https://svn.apache.org/path/name/class.h $ $Id: class.h 0 09/28/2005 dlydick $");
+
+
+#include "object.h"
+
+/*!
+ * @def CLASS
+ * @brief Access structures of class table at certain index.
+ *
+ * The class table, being an array of slots, provides space for
+ * one class definition per slot. This macro references one of
+ * them using the @p @b clsidx index.
+ *
+ * @param clsidx Class table index into the global
+ * @link #rjvm.class rjvm.class[]@endlink array (via
+ * @link #pjvm pjvm->class[]@endlink).
+ *
+ * @returns pointer to a class slot
+ */
+#define CLASS(clsidx) pjvm->class[clsidx]
+
+/*!
+ * @brief General class slot definition.
+ */
+typedef struct
+{
+ rushort status; /*!< Runtime status of class, bitwise */
+
+
+/*!
+ * @name Class status bits
+ *
+ * @brief Bitwise status bits for the status of a class slot.
+ *
+ * These class status bits have direct
+ * @link #OBJECT_STATUS_EMPTY OBJECT_STATUS_xxx@endlink equivalents and
+ * a few @link #THREAD_STATUS_EMPTY THREAD_STATUS_xxx@endlink
+ * equivalents also. There are no overloaded bit positions between them
+ * (for ease of diagnostics).
+ */
+
+/*@{ */ /* Begin grouped definitions */
+
+/****** First 3 bits same for class, object, and thread ***********/
+#define CLASS_STATUS_EMPTY 0x0000 /**< This slot is available for
+ use*/
+#define CLASS_STATUS_INUSE 0x0001 /**< This slot contains a class */
+#define CLASS_STATUS_NULL 0x0002 /**< NULL class slot.
+ * <em>Exactly on</em> exists
+ * in normal use, any else besides
+ * the @link #JVMCFG_NULL_CLASS
+ JVMCFG_NULL_CLASS@endlink
+ * is a class slot now
+ * being initialized. */
+/******************************************************************/
+
+/****** Next 2 bits same for class and object *********************/
+#define CLASS_STATUS_GCREQ 0x0004 /**< Class may be garbage
+ collected. */
+#define CLASS_STATUS_ARRAY 0x0008 /**< Class is an array type where
+ @p @b arraydims contains
+ number of dimensions */
+/******************************************************************/
+
+/****** Next 5 bits unique between class and object except: *******/
+
+#define CLASS_STATUS_REFERENCE 0x0080 /**< Class variable is a
+ * reference. This is the
+ * @e same definition as for
+ * @link #OBJECT_STATUS_REFERENCE
+ OBJECT_STATUS_REFERENCE@endlink
+ * and for
+ * @link #LOCAL_STATUS_REFERENCE
+ LOCAL_STATUS_REFERENCE@endlink,
+ * the local variable reference
+ * bit for variables on the stack
+ * frame, where the GC algorithm
+ * implements it.
+ */
+
+/******************************************************************/
+
+/****** Next 4 bits unique between class and object ***************/
+#define CLASS_STATUS_PRIMATIVE 0x0200 /**< Primative for
+ @c @b java.lang.Class */
+#define CLASS_STATUS_LINKED 0x0400 /**< Class linkages completed */
+#define CLASS_STATUS_DOCLINIT 0x0800 /**< Class loaded,
+ * needs @c @b \<clinit\> */
+#define CLASS_STATUS_CLINIT 0x1000 /**< Class loaded, initialized,
+ * and ready to allocate
+ * instances */
+/******************************************************************/
+
+/****** Last 3 bits not used by class or object *******************/
+#define CLASS_STATUS_2000 0x2000 /**< not used */
+#define CLASS_STATUS_4000 0x4000 /**< not used */
+#define CLASS_STATUS_8000 0x8000 /**< not used */
+/******************************************************************/
+
+/*@} */ /* End of grouped definitions */
+
+ u1 unused1; /**< Not used, keep 2-byte alignment */
+
+ jvm_array_dim arraydims; /**< Number of array dimensions,
+ * meaningful only when @link
+ #CLASS_STATUS_ARRAY CLASS_STATUS_ARRAY@endlink
+ * is set */
+
+
+ jint *arraylength; /**< Array of length @p @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} */
+
+ jvm_class_index lower_dim_array; /**< Class table index of
+ * version of this class with one fewer array
+ * dimensions, meaningful only when @link
+ #CLASS_STATUS_ARRAY CLASS_STATUS_ARRAY@endlink
+ * is set. */
+
+ jvm_object_hash class_objhash; /**< Object table hash used to
+ find this slot */
+
+ u2 num_class_static_field_lookups; /**< size of
+ * @p @b class_static_field_lookup
+ * field lookup array[] for class static fields
+ */
+
+ jvm_field_index *class_static_field_lookup; /**< field lookup
+ * array[] for class static fields.
+ * Indexed by @link #jvm_field_lookup_index
+ jvm_field_lookup_index@endlink
+ */
+
+ jvalue *class_static_field_data; /**< field lookup array[] for
+ * class static fields.
+ * Indexed by @link #jvm_field_lookup_index
+ jvm_field_lookup_index@endlink
+ */
+
+
+
+ u2 num_object_instance_field_lookups; /**< size of
+ * @p @b object_instance_field_lookup
+ * field lookup array[] for object instance
+ * fields */
+
+ jvm_field_index *object_instance_field_lookup; /**< field lookup
+ * array[] for object instance fields.
+ * The jvalue array[] for each object may
+ * be found in @link
+ #robject.object_instance_field_data
+ robject.object_instance_field_data@endlink
+ * instead of here in order to have unique
+ * values for each and every object. (This is
+ * over and against the class static field
+ * array[] here in this structure.)
+ * Indexed by @link #jvm_field_lookup_index
+ jvm_field_lookup_index@endlink
+ */
+
+
+ jvm_class_index initiating_ClassLoader; /**<Object table hash
+ * of initiating @c @b ClassLoader */
+
+ jvm_class_index defining_ClassLoader; /**< Object table hash
+ * of defining @c @b ClassLoader */
+
+ rvoid *pgarbage; /**< Garbage collection profile of
+ * this class. An @link #rvoid rvoid@endlink
+ * pointer is used here to avoid linking this
+ * structure to any particular GC
+ * implementation.
+ */
+
+} rclass;
+
+/* Prototypes for functions in 'class.c' */
+extern rvoid class_init(rvoid);
+extern rvoid class_shutdown_1(rvoid);
+extern rvoid class_shutdown_2(rvoid);
+extern jvm_class_index class_static_new(rushort status_req,
+ ClassFile *pcfs,
+ jvm_array_dim arraydims,
+ jint *arraylength,
+ jvm_class_index lower_dim_array);
+extern jvm_class_index class_reload(jvm_class_index clsidxOLD);
+extern jvm_class_index class_static_delete(jvm_class_index clsidx,
+ rboolean rmref);
+extern jvm_class_index class_find_by_cp_entry(cp_info_dup *clsname);
+extern jvm_class_index class_find_by_prchar(rchar *clsname);
+extern jvm_class_index class_load_primative(u1 basetype);
+extern jvm_class_index class_load_from_prchar(rchar *clsname,
+ rboolean
+ find_registerNatives,
+ jint *arraylength);
+extern jvm_class_index class_load_from_cp_entry_utf(
+ cp_info_dup *clsname,
+ rboolean
+ find_registerNatives,
+ jint *arraylength);
+
+extern jvm_class_index class_load_resolve_clinit(
+ rchar *clsname,
+ jvm_thread_index thridx,
+ rboolean usesystemthread,
+ rboolean find_registerNatives);
+
+extern u2 class_get_num_static_fields(ClassFile *pcfs);
+extern jvm_class_index *class_get_static_field_lookups(
+ ClassFile *pcfs);
+extern jvalue *class_get_static_field_data(
+ jvm_class_index clsidx,
+ ClassFile *pcfs);
+
+extern u2 class_get_num_object_instance_fields(
+ ClassFile *pcfs);
+extern jvm_class_index *class_get_object_instance_field_lookups(
+ ClassFile *pcfs);
+extern jvalue *class_get_object_instance_field_data(
+ jvm_class_index clsidx,
+ jvm_object_hash objhash,
+ ClassFile *pcfs);
+
+/* Prototypes for functions in 'classutil.c' */
+extern jvm_class_index classutil_jobject2clsidx(jvm_object_hash
+ objhash);
+#endif /* _class_h_included_ */
+
+
+/* EOF */
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/classfile.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/classfile.c?rev=307257&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/classfile.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/bootjvm/bootJVM/jvm/src/classfile.c Fri Oct 7 21:27:56 2005
@@ -0,0 +1,1822 @@
+/*!
+ * @file classfile.c
+ *
+ * @brief Implementation of <em>The Java Virtual Machine Specification,
+ * version 2 Chapter 4, The Class File Format</em>.
+ *
+ * Manipulation of attributes is performed in
+ * @link jvm/src/cfattrib.c cfattrib.c@endlink.
+ * All other work is done here.
+ *
+ * The JVM specification is available from Sun Microsystems' web site
+ * at http://java.sun.com/docs/books/vmspec/index.html and
+ * may be read online at
+http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html
+ *
+ * The Java 5 class file format is available as a PDF file separately at
+http://java.sun.com/docs/books/vmspec/2nd-edition/ClassFileFormat-final-draft.pdf
+ * and was the basis for the ClassFile structure of this implementation.
+ *
+ *
+ * @todo Per spec section 5.4.1, need to verify the contents of
+ * the file read in before initializing the class, else
+ * throw @b VerifyError.
+ *
+ * @todo Need to verify which web document for the
+ * Java 5 class file definition is either "official",
+ * actually correct, or is the <em>de facto</em> standard.
+ *
+ *
+ * @section Control
+ *
+ * \$URL: https://svn.apache.org/path/name/classfile.c $ \$Id: classfile.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(classfile, c, "$URL: https://svn.apache.org/path/name/classfile.c $ $Id: classfile.c 0 09/28/2005 dlydick $");
+
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "jvmcfg.h"
+#include "cfmacros.h"
+#include "classfile.h"
+#include "classpath.h"
+#include "exit.h"
+#include "jvm.h"
+#include "native.h"
+#include "util.h"
+
+
+/*!
+ * @brief Build up empty JVM class file structure for use
+ * by Java primative data types.
+ *
+ * Each primative data type needs a minimal class definition
+ * to avoid having special cases for class processing logic.
+ * Also, treating primatives like classes can provide convenient
+ * information on data size types, like @b (jlong) versus @b (jint).
+ * This can be provided by the base type information, which is
+ * passed in here when creating these minimal classes.
+ *
+ * The constant pool for such a minima class looks like this:
+ *
+ * <ul>
+ * <li><b>CP[0]</b>: Not represented, per spec. Implies
+ * @c @b java.lang.Object .
+ * </li>
+ * <li><b>CP[1]</b>: CONSTANT_Utf8_info string of one character, the
+ * @link #BASETYPE_CHAR_B basetype@endlink letter.
+ * </li>
+ * <li><b>CP[2]</b>: CONSTANT_Class_info class definition of this
+ * primative, with @link
+ CONSTANT_Class_info#name_index name_index@endlink
+ * pointing to UTF8 string at index 1.
+ * </li>
+ * </ul>
+ *
+ * @todo Need to take a hard look at the requirements
+ * for @c @b java.lang.Class and see if this is sufficient
+ * or even accurately implemented.
+ *
+ *
+ * @param basetype One of the primative base types BASETYPE_CHAR_x
+ *
+ *
+ * @returns (ClassFile *) to heap-allocated area, used throughtout life
+ * of JVM, then released.
+ *
+ */
+ClassFile *classfile_allocate_primative(jvm_basetype basetype)
+{
+ /*!
+ * @internal INITIALIZE TO ZEROES all fields so there are
+ * automatic @link #rnull rnull@endlink pointers in case of
+ * failure along the way.
+ */
+ ClassFile *pcfs = HEAP_GET_DATA(sizeof(ClassFile), rtrue);
+
+
+ pcfs->magic = CLASSFILE_MAGIC; /* "This is a Java class" */
+ /* Look like -r1.2 source file*/
+ pcfs->major_version = VERSION_MAJOR_JDK2;
+ pcfs->minor_version = VERSION_MINOR_DEFAULT;
+
+ pcfs->constant_pool_count = 3; /* 1 class, 1 string, + j/l/Object */
+ pcfs->constant_pool = HEAP_GET_DATA(pcfs->constant_pool_count *
+ sizeof(cp_info_dup *), rfalse);
+
+
+ /*!
+ * @internal Since @c @b java.lang.Object is implied,
+ * don't need this slot.
+ */
+ pcfs->constant_pool[0] = (cp_info_dup *) rnull;
+
+
+ /* Allocate CONSTANT_Utf8_info member. Default of u1[1] okay */
+ pcfs->constant_pool[1] = HEAP_GET_DATA(sizeof(cp_info_dup) +
+ sizeof(CONSTANT_Utf8_info) -
+ sizeof(cp_info), rtrue);
+ CONSTANT_Utf8_info *putf =PTR_THIS_CP_Utf8(pcfs->constant_pool[1]);
+ putf->tag = CONSTANT_Utf8;
+ putf->length = sizeof(u1); /* Primatives have a single char name */
+ putf->bytes[0] = basetype; /* single (u1) character */
+
+ /* Allocate CONSTANT_Class_info member */
+ pcfs->constant_pool[2] = HEAP_GET_DATA(sizeof(cp_info_dup) +
+ sizeof(CONSTANT_Class_info) -
+ sizeof(cp_info), rfalse);
+ CONSTANT_Class_info *pci =PTR_THIS_CP_Class(pcfs->constant_pool[2]);
+ pci->tag = CONSTANT_Class;
+ pci->name_index = 1; /* Index of Utf8 string of primative desc. */
+
+
+ pcfs->access_flags = ACC_SYNTHETIC; /*! @todo Needs more thought */
+ pcfs->this_class = 2; /* Index to class entry */
+
+ /*! @todo Is this assumption
+ valid/meaningful? */
+ pcfs->super_class = 0; /* No superclass, imply java.lang.Object */
+
+ pcfs->interfaces_count = 0;
+ pcfs->interfaces = (u2 *) rnull;
+
+ pcfs->fields_count = 0;
+ pcfs->fields = (field_info **) rnull;
+
+ pcfs->methods_count = 0;
+ pcfs->methods = (method_info **) rnull;
+
+ pcfs->attributes_count = 0;
+ pcfs->attributes = (attribute_info_dup **) rnull;
+
+ return(pcfs);
+
+} /* END of classfile_allocate_primative() */
+
+
+/*!
+ * @def ALLOC_CP_INFO()
+ *
+ * @brief Allocate a cp_info_dup structure containing any generic
+ * type of constant_pool entry.
+ *
+ * Allocate space from heap, populate from class file data,
+ * and fill in initial pad bytes.
+ *
+ *
+ * @param spec_typedef Structure @link #CONSTANT_Class_info
+ CONSTANT_xxx_info@endlink type definition
+ * of one of the constant_pool types.
+ *
+ *
+ * @param binding_struct Name of local binding structure @link
+ #CONSTANT_Class_info.LOCAL_Class_binding
+ LOCAL_xxx_binding@endlink associated with
+ * @b spec_typedef
+ *
+ *
+ * @returns @link #rvoid rvoid@endlink
+ *
+ */
+
+#define ALLOC_CP_INFO(spec_typedef, binding_struct) \
+ misc_adj = sizeof(u1) * CP_INFO_NUM_EMPTIES; \
+ \
+ cf_item_size = sizeof(spec_typedef)-sizeof(struct binding_struct); \
+ pcpd = HEAP_GET_METHOD(misc_adj + sizeof(spec_typedef), rfalse); \
+ memcpy(((rbyte *) pcpd) + misc_adj,pcpbytes,cf_item_size); \
+ \
+ pcpd->empty[0] = FILL_INFO_DUP0; \
+ pcpd->empty[1] = FILL_INFO_DUP1; \
+ pcpd->empty[2] = FILL_INFO_DUP2; /* Extra ; */
+
+
+/*!
+ * @def ALLOC_CF_ITEM()
+ *
+ * @brief Allocate either a field_info or method_info structure.
+ *
+ * Allocate space from heap and populate from class file data,
+ *
+ *
+ * @param spec_typedef Structure field_info or method_info type
+ * definition.
+ *
+ * @param pbytes Name <b><code>(jbyte *)</code></b> pointer into
+ * class file data being parsed pointing to
+ * where this structure is found.
+
+ * @param pcfsi <b><code>(spec_typedef *)</code></b> array[]
+ * pointer to the field_info or method_info table
+ * slot where the parsed data will be stored.
+ *
+ * @param binding_struct Structure LOCAL_field_binding or
+ * LOCAL_method_binding for appropriate
+ * @b spec_typedef type definition.
+ */
+
+#define ALLOC_CF_ITEM(spec_typedef, pbytes, pcfsi, binding_struct) \
+ cf_item_size = sizeof(spec_typedef) - \
+ sizeof(struct binding_struct) - \
+ sizeof(attribute_info_dup **); \
+ pcfsi = HEAP_GET_METHOD(sizeof(spec_typedef), rfalse); \
+ memcpy(((rbyte *) pcfsi),pbytes,cf_item_size);/*Extra ;*/
+
+/*!
+ * @name Range check of constant_pool indices.
+ *
+ * @brief Range check constant_pool @b cpidx against max index,
+ * with/without typed pointer.
+ *
+ * (Testing <b><code>cpidx < 0</code></b> is not checked,
+ * since @p @b cpidx is an unsigned integer.)
+ *
+ *
+ * @param type @link #CONSTANT_Class_info CONSTANT_xxx_info@endlink
+ * pointer of data type to be checked
+ *
+ * @param pcfs ClassFile area to be checked
+ *
+ * @param cpidx constant_pool index to be checked
+ *
+ * @param msg Error message to display at failure
+ *
+ *
+ * @returns @link #rvoid rvoid@endlink
+ *
+ */
+
+/*@{ */ /* Begin grouped definitions */
+
+/*!
+ * @brief Range check a typed pointer against the
+ * @link #ClassFile.constant_pool_count constant_pool_count@endlink
+ * value
+ */
+#define CPTYPEIDX_RANGE_CHECK(type, pcfs, cpidx, msg) \
+ LOAD_SYSCALL_FAILURE(( /* ((((type *) &pcpd->cp)->cpidx) < 0) || */\
+ ((((type *) &pcpd->cp)->cpidx) >= \
+ pcfs->constant_pool_count)), \
+ msg, \
+ rnull, \
+ rnull); /* Extra ; */
+
+/*!
+ * @brief Range check a simple index against the
+ * @link #ClassFile.constant_pool_count constant_pool_count@endlink
+ * value
+ */
+#define CPIDX_RANGE_CHECK(pcfs, cpidx, msg) \
+ LOAD_SYSCALL_FAILURE((/* (cpidx < 0) || */ \
+ (cpidx >= pcfs->constant_pool_count)), \
+ msg, \
+ rnull, \
+ rnull); /* Extra ; */
+
+/*@} */ /* End of grouped definitions */
+
+/*!
+ * @brief Parse an in-memory JVM class file, create structures to point
+ * to various parts of it, per JVM spec pseuco-code structures.
+ *
+ * Interpret the class file data and load up the data structures
+ * which access it, such as the fully qualified class names,
+ * the code area, etc.
+ *
+ * @todo Need a @e much better way to free partially built class
+ * structure when an error occurs. The current scheme is
+ * only piecemeal and @e will leave orphaned memory blocks
+ * lying around when something is freed that has @e the
+ * pointer to it, case in point, the constant_pool[] table
+ * when freeing the main ClassFile structure block on error.
+ * The partial solutions of adding heap pointer parameters to
+ * LOAD_SYSCALL_FAILURE() and GENERIC_FAILURExxx() macros
+ * is not useful here since so @e many allocations are done
+ * in this function.
+ *
+ * @param pclassfile_image Null-terminated ASCII string,
+ * pathname of file.
+ *
+ *
+ * @returns Complete class file structure, fully loaded with the
+ * real instantiation of the JVM spec pseudo-code structures.
+ * If error detected, @link #rnull rnull@endlink is returned
+ * and perror("msg") may be called to report the system call
+ * problem that caused the particular failure more. Status
+ * of heap areas will be undefined since a failure like this
+ * should be fatal to program execution.
+ *
+ */
+
+ClassFile *classfile_loadclassdata(u1 *pclassfile_image)
+{
+ rint misc_adj; /* For ALLOC_xxx macros */
+
+
+ u2 tmplenutf;
+
+ /* Needed for CP_ITEM_SWAP_Ux() macros */
+#ifdef CONFIG_LITTLE_ENDIAN
+ u2 *pcpu2;
+ u4 *pcpu4;
+#endif
+
+ /* Generic data pointers, loaded via MAKE_Ux() macros above */
+ u2 *pu2;
+ u4 *pu4;
+
+ /*
+ * First things first: Need to sequentially access class file data
+ * (Data SOURCE into which *pcfs structure pointers will point)
+ */
+ u1 *pcfd = (u1 *) pclassfile_image;
+
+ /*
+ * Also need to access class file structures
+ * (Data INDEX area that holds pointers to class file data in *pcfd)
+ */
+ ClassFile *pcfs = (ClassFile *) HEAP_GET_METHOD(sizeof(ClassFile),
+ rtrue);
+
+ /*
+ * Need default value until field is loaded. Set default
+ * to "no class". Spec also says that this constant_pool
+ * index implies <code>java.lang.Object<code>.
+ */
+ pcfs->this_class = jvm_class_index_null;
+
+ /*****************************************************************/
+ /* Get magic number-- an easy exercise in using generic pointers */
+ /*****************************************************************/
+ MAKE_PU4(pu4, pcfd); /* Allocate next class file data pointer */
+ /* Byte swap 2 & 4 byte areas */
+
+ /*
+ * Copy into class file structure area.
+ *
+ * ALWAYS use GETRxx() macros for multi-byte accesses
+ * in *pclassfile_image since they are NEVER guaranteed
+ * to be 2-byte aligned! (See getrs2() in
+ * @link jvm/src/bytegames.c bytegames.c@endlink
+ * and ARCH_ODD_ADDRESS_SIGSEGV in
+ * @link jvm/src/arch.h arch.h@endlink
+ * for details.)
+ */
+ pcfs->magic = GETRI4(pu4);
+
+ /*
+ * Perform little-endian byte swapping,
+ * where appropriate (NOP otherwise)
+ */
+ MACHINE_JINT_SWAP(pcfs->magic);
+
+ sysDbgMsg(DMLNORM,
+ "classfile_loadclassdata",
+ "magic=%08x",
+ pcfs->magic);
+
+ /*
+ * Perform integrity checking as needed for each data type.
+ */
+ LOAD_SYSCALL_FAILURE((CLASSFILE_MAGIC != pcfs->magic),
+ "magic",
+ rnull,
+ rnull);
+
+ /* calculate offset to next field in file data */
+ pu4++;
+
+
+ /*****************************************************************/
+ /* Get minor class file version */
+ /*****************************************************************/
+ MAKE_PU2(pu2, pu4);
+
+ pcfs->minor_version = GETRS2(pu2);
+
+ MACHINE_JSHORT_SWAP(pcfs->minor_version);
+
+ /* LOAD_SYSCALL_FAILURE( what needs checking here?, "minor"); */
+
+ sysDbgMsg(DMLNORM,
+ "classfile_loadclassdata",
+ "minor=%d",
+ pcfs->minor_version);
+
+ pu2++; /* calc offset to next field in file data*/
+
+
+ /*****************************************************************/
+ /* Get major class file version */
+ /*****************************************************************/
+
+ /* Can optimize along the way-- pu2 already points here */
+ /* MAKE_PU2(pu2, pu2); */
+
+ pcfs->major_version = GETRS2(pu2++);
+
+ MACHINE_JSHORT_SWAP(pcfs->major_version);
+
+ sysDbgMsg(DMLNORM,
+ "classfile_loadclassdata",
+ "major=%d",
+ pcfs->major_version);
+
+ /* Range check against spec (footnote to field definition in spec)*/
+ LOAD_SYSCALL_FAILURE(((pcfs->major_version < VERSION_MAJOR_LOW) ||
+ (pcfs->major_version > VERSION_MAJOR_HIGH)),
+ "major",
+ rnull,
+ rnull);
+
+ LOAD_SYSCALL_FAILURE(((pcfs->major_version == VERSION_MAJOR_LOW)
+ /* &&
+ (pcfs->minor_version < VERSION_MINOR_LOW) */
+ ),
+ "low minor",
+ rnull,
+ rnull);
+
+ LOAD_SYSCALL_FAILURE(((pcfs->major_version == VERSION_MAJOR_HIGH) &&
+ (pcfs->minor_version > VERSION_MINOR_HIGH)),
+ "high minor",
+ rnull,
+ rnull);
+
+
+ /*! @todo Throw @b UnsupportedClassVersionError for bad versions */
+
+ /*****************************************************************/
+ /* Get constant_pool_count */
+ /*****************************************************************/
+ pcfs->constant_pool_count = GETRS2(pu2++);
+
+ MACHINE_JSHORT_SWAP(pcfs->constant_pool_count);
+
+ sysDbgMsg(DMLNORM,
+ "classfile_loadclassdata",
+ "cp count=%d",
+ pcfs->constant_pool_count);
+
+ /* In reality a NOP, but theoretically possible for empty file */
+ /* LOAD_SYSCALL_FAILURE((0 > pcfs->constant_pool_count), "CP index");*/
+
+
+ /*****************************************************************/
+ /* Create constant pool index, then load up constant pool */
+ /*****************************************************************/
+
+ jvm_constant_pool_index cpidx;
+ rint cf_item_size;
+ jbyte *pcpbytes = (jbyte *) pu2;
+
+ /*
+ * Map the indices in the class file to point to actual
+ * constant pool enties via a pointer lookup table.
+ *
+ * Make constant_pool[] large enough for 0th element as well
+ * as defined element (the @c @b java.lang.Object per spec).
+ * This is simply a convenience for future access without doing
+ * an <b><code>x - 1</code></b> calculation. Therefore, fill
+ * in 0th element with @link #rnull rnull@endlink info as it
+ * should never be used. Any access SHOULD produce @b SIGSEGV
+ * because the proper class info should be accessed instead.
+ */
+ pcfs->constant_pool = HEAP_GET_METHOD(pcfs->constant_pool_count *
+ sizeof(cp_info_dup *),
+ rfalse);
+
+ /*
+ * Dummy entry for @c @b java.lang.Object constant pool
+ * references (0th element)
+ */
+ pcfs->constant_pool[CONSTANT_CP_DEFAULT_INDEX] =
+ (cp_info_dup *) rnull;
+
+ /*
+ * Iterate through class file's constant_pool and fill in
+ * the constant_pool[] pointer array for normal use.
+ */
+ for (cpidx = CONSTANT_CP_START_INDEX;
+ cpidx < pcfs->constant_pool_count + CONSTANT_CP_START_INDEX -1;
+ cpidx++)
+ {
+ cp_info_dup *pcpd;
+
+ pu2 = (u2 *) pcpbytes;
+
+ /*
+ * Look up structure size, perform in-place byte swap
+ * for little-endian architectures.
+ */
+ switch (((cp_info *) pcpbytes)->tag)
+ {
+ case CONSTANT_Class:
+ ALLOC_CP_INFO(CONSTANT_Class_info,
+ LOCAL_Class_binding);
+
+ CP_ITEM_SWAP_U2(CONSTANT_Class_info, name_index);
+
+ CPTYPEIDX_RANGE_CHECK(CONSTANT_Class_info,
+ pcfs,
+ name_index,
+ "CP name index");
+
+ /* Initialize late binding extension */
+ PTR_THIS_CP_Class(pcpd)->LOCAL_Class_binding.clsidxJVM =
+ jvm_class_index_null;
+
+ break;
+
+ case CONSTANT_Fieldref:
+ ALLOC_CP_INFO(CONSTANT_Fieldref_info,
+ LOCAL_Fieldref_binding);
+
+ CP_ITEM_SWAP_U2(CONSTANT_Fieldref_info,class_index);
+
+ CP_ITEM_SWAP_U2(CONSTANT_Fieldref_info,
+ name_and_type_index);
+
+ CPTYPEIDX_RANGE_CHECK(CONSTANT_Fieldref_info,
+ pcfs,
+ class_index,
+ "CP class index");
+
+ /* Initialize late binding extension */
+ PTR_THIS_CP_Fieldref(pcpd)
+ ->LOCAL_Fieldref_binding.clsidxJVM =
+ jvm_class_index_null;
+
+ PTR_THIS_CP_Fieldref(pcpd)
+ ->LOCAL_Fieldref_binding.fluidxJVM =
+ jvm_field_index_bad;
+
+ PTR_THIS_CP_Fieldref(pcpd)
+ ->LOCAL_Fieldref_binding.oiflagJVM =
+ rneither_true_nor_false;
+
+ PTR_THIS_CP_Fieldref(pcpd)
+ ->LOCAL_Fieldref_binding.jvaluetypeJVM =
+ LOCAL_BASETYPE_ERROR;
+
+ break;
+
+ case CONSTANT_Methodref:
+ ALLOC_CP_INFO(CONSTANT_Methodref_info,
+ LOCAL_Methodref_binding);
+
+ CP_ITEM_SWAP_U2(CONSTANT_Methodref_info, class_index);
+
+ CP_ITEM_SWAP_U2(CONSTANT_Methodref_info,
+ name_and_type_index);
+
+ CPTYPEIDX_RANGE_CHECK(CONSTANT_Methodref_info,
+ pcfs,
+ class_index,
+ "CP method class index");
+
+ CPTYPEIDX_RANGE_CHECK(CONSTANT_Methodref_info,
+ pcfs,
+ name_and_type_index,
+ "CP method name and type index");
+
+ /* Initialize late binding extension */
+ PTR_THIS_CP_Methodref(pcpd)
+ ->LOCAL_Methodref_binding.clsidxJVM =
+ jvm_class_index_null;
+
+ PTR_THIS_CP_Methodref(pcpd)
+ ->LOCAL_Methodref_binding.mthidxJVM =
+ jvm_method_index_bad;
+
+ PTR_THIS_CP_Methodref(pcpd)
+ ->LOCAL_Methodref_binding.codeatridxJVM =
+ jvm_attribute_index_bad;
+
+ PTR_THIS_CP_Methodref(pcpd)
+ ->LOCAL_Methodref_binding.excpatridxJVM =
+ jvm_attribute_index_bad;
+
+ PTR_THIS_CP_Methodref(pcpd)
+ ->LOCAL_Methodref_binding.nmordJVM =
+ jvm_native_method_ordinal_null;
+
+ break;
+
+ case CONSTANT_InterfaceMethodref:
+ ALLOC_CP_INFO(CONSTANT_InterfaceMethodref_info,
+ LOCAL_InterfaceMethodref_binding);
+
+ CP_ITEM_SWAP_U2(CONSTANT_InterfaceMethodref_info,
+ class_index);
+
+ CP_ITEM_SWAP_U2(CONSTANT_InterfaceMethodref_info,
+ name_and_type_index);
+
+ CPTYPEIDX_RANGE_CHECK(CONSTANT_InterfaceMethodref_info,
+ pcfs,
+ class_index,
+ "CP interface method class index");
+
+ CPTYPEIDX_RANGE_CHECK(CONSTANT_InterfaceMethodref_info,
+ pcfs,
+ name_and_type_index,
+ "CP interface method name and type index");
+
+ /* Initialize late binding extension */
+ PTR_THIS_CP_InterfaceMethodref(pcpd)
+ ->LOCAL_InterfaceMethodref_binding.clsidxJVM =
+ jvm_class_index_null;
+
+ PTR_THIS_CP_InterfaceMethodref(pcpd)
+ ->LOCAL_InterfaceMethodref_binding.mthidxJVM =
+ jvm_method_index_bad;
+
+ PTR_THIS_CP_InterfaceMethodref(pcpd)
+ ->LOCAL_InterfaceMethodref_binding.codeatridxJVM =
+ jvm_attribute_index_bad;
+
+ PTR_THIS_CP_InterfaceMethodref(pcpd)
+ ->LOCAL_InterfaceMethodref_binding.excpatridxJVM =
+ jvm_attribute_index_bad;
+
+ PTR_THIS_CP_InterfaceMethodref(pcpd)
+ ->LOCAL_InterfaceMethodref_binding.nmordJVM =
+ jvm_native_method_ordinal_null;
+
+ break;
+
+ case CONSTANT_String:
+ ALLOC_CP_INFO(CONSTANT_String_info,
+ LOCAL_String_binding);
+
+ CP_ITEM_SWAP_U2(CONSTANT_String_info, string_index);
+
+ CPTYPEIDX_RANGE_CHECK(CONSTANT_String_info,
+ pcfs,
+ string_index,
+ "CP string index");
+ break;
+
+ case CONSTANT_Integer:
+ ALLOC_CP_INFO(CONSTANT_Integer_info,
+ LOCAL_Integer_binding);
+
+ CP_ITEM_SWAP_U4(CONSTANT_Integer_info, bytes);
+
+ break;
+
+ case CONSTANT_Float:
+ ALLOC_CP_INFO(CONSTANT_Float_info,
+ LOCAL_Float_binding);
+
+ CP_ITEM_SWAP_U4(CONSTANT_Float_info, bytes);
+
+ break;
+
+ case CONSTANT_Long:
+ ALLOC_CP_INFO(CONSTANT_Long_info,
+ LOCAL_Long_binding);
+
+ CP_ITEM_SWAP_U4(CONSTANT_Long_info, high_bytes);
+
+ CP_ITEM_SWAP_U4(CONSTANT_Long_info, low_bytes);
+
+ /*
+ * Make both slots point to the same place-- see
+ * assignment below for value at [cpidx]. This is
+ * a simple way to have something meaningful in
+ * the unused slot. Ignore this second slot, but
+ * make sure it does not contain garbage.
+ */
+ pcfs->constant_pool[cpidx] = pcpd;
+ cpidx++;
+
+ break;
+
+ case CONSTANT_Double:
+ ALLOC_CP_INFO(CONSTANT_Double_info,
+ LOCAL_Double_binding);
+
+ CP_ITEM_SWAP_U4(CONSTANT_Double_info, high_bytes);
+
+ CP_ITEM_SWAP_U4(CONSTANT_Double_info, low_bytes);
+
+ /*
+ * Make both slots point to the same place-- see
+ * assignment below for value at [cpidx]. This is
+ * a simple way to have something meaningful in
+ * the unused slot. Ignore this second slot, but
+ * make sure it does not contain garbage.
+ */
+ pcfs->constant_pool[cpidx] = pcpd;
+ cpidx++;
+
+ break;
+
+ case CONSTANT_NameAndType:
+ ALLOC_CP_INFO(CONSTANT_NameAndType_info,
+ LOCAL_NameAndType_binding);
+ CP_ITEM_SWAP_U2(CONSTANT_NameAndType_info, name_index);
+ CP_ITEM_SWAP_U2(CONSTANT_NameAndType_info,
+ descriptor_index);
+ CPTYPEIDX_RANGE_CHECK(CONSTANT_NameAndType_info,
+ pcfs,
+ name_index,
+ "CP name and type name index");
+ CPTYPEIDX_RANGE_CHECK(CONSTANT_NameAndType_info,
+ pcfs,
+ descriptor_index,
+ "CP name and type descriptor index");
+
+ /* Initialize late binding extension */
+
+ /* (There is no late binding associated with this tag)*/
+ break;
+
+ case CONSTANT_Utf8:
+
+ tmplenutf = ((CONSTANT_Utf8_info *) pcpbytes)->length;
+ MACHINE_JSHORT_SWAP(tmplenutf);
+
+ /*
+ * Explicitly unroll the ALLOC_CP_INFO() macro
+ * due to the variable length string area. Adjust
+ * also for the dummy item
+ * @link CONSTANT_Utf8_info#bytes bytes@endlink,
+ * namely @c @b sizeof(info[1]), or 1 byte.
+ *
+ * The segment below copies each piece of the buffer
+ * from @c @b *pcpbytes to @c @b *pcpd .
+ */
+
+ /* Size of structure to copy */
+ cf_item_size = sizeof(CONSTANT_Utf8_info) -
+ sizeof(struct LOCAL_Utf8_binding) -
+ sizeof(u1);
+
+ /* Allocate heap for structure */
+ pcpd = HEAP_GET_METHOD(sizeof(u1) * CP_INFO_NUM_EMPTIES+
+ tmplenutf + cf_item_size,
+ rfalse);
+
+ /* Copy structure, including @b empty bytes */
+ memcpy(((rbyte *)pcpd) +
+ sizeof(u1) * CP_INFO_NUM_EMPTIES,
+ pcpbytes,
+ cf_item_size);
+ pcpd->empty[0] = FILL_INFO_DUP0;
+ pcpd->empty[1] = FILL_INFO_DUP1;
+ pcpd->empty[2] = FILL_INFO_DUP2;
+
+ /*
+ * Byte swap contents of
+ * @link CONSTANT_Utf8_info#length length@endlink
+ * field (only multi-byte field in structure)
+ */
+ CP_ITEM_SWAP_U2(CONSTANT_Utf8_info, length);
+
+ /* Copy UTF string itself (No byte reversal needed.) */
+ memcpy(PTR_THIS_CP_Utf8(pcpd)->bytes,
+ ((CONSTANT_Utf8_info *) pcpbytes)->bytes,
+ tmplenutf);
+
+ /*
+ * Adjust for variable length UTF8 string in source bfr
+ */
+ cf_item_size += tmplenutf;
+
+ /* Initialize late binding extension */
+
+ /* (There is no late binding associated with this tag)*/
+
+ break;
+
+ default:
+ /*!
+ * @todo Need better and more complete heap free here
+ */
+
+ /* This pointer came from HEAP_GET_METHOD() */
+ HEAP_FREE_METHOD(pcfs);
+
+ GENERIC_FAILURE1_PTR(rtrue,
+ DMLNORM,
+ "classfile_loadclassdata",
+ "Invalid CP tag %d",
+ (((cp_info *) pcpbytes)->tag),
+ ClassFile,
+ rnull,
+ rnull);
+
+ } /* switch ... */
+
+ /* Point to storage area for this constant_pool[] item */
+ pcfs->constant_pool[cpidx] = pcpd;
+
+ /* Now point past this CONSTANT_Xxxxxx_info area */
+ pcpbytes += cf_item_size;
+
+ } /* for (cpidx) */
+
+
+ /*****************************************************************/
+ /* Get access_flags */
+ /*****************************************************************/
+
+ /* Point past the constant_pool[] area */
+ MAKE_PU2(pu2, pcpbytes);
+
+ pcfs->access_flags = GETRS2(pu2++);
+ /*
+ * Strip out all other @link #ACC_PUBLIC ACC_xxx@endlink bits, per
+ * spec
+ */
+ pcfs->access_flags &= (ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
+ ACC_INTERFACE | ACC_ABSTRACT | ACC_SYNTHETIC | ACC_ANNOTATION |
+ ACC_ENUM);
+
+ MACHINE_JSHORT_SWAP(pcfs->access_flags);
+
+ /* LOAD_SYSCALL_FAILURE(what needs checking here?,"access flags");*/
+
+ sysDbgMsg(DMLNORM,
+ "classfile_loadclassdata",
+ "access %04x",
+ pcfs->access_flags);
+
+
+ /*****************************************************************/
+ /* Get this_class */
+ /*****************************************************************/
+ pcfs->this_class = GETRS2(pu2++);
+
+ MACHINE_JSHORT_SWAP(pcfs->this_class);
+
+ /*!
+ * @todo Need to free constant_pool[0..n] also if failure
+ */
+ CPIDX_RANGE_CHECK(pcfs, pcfs->this_class, "this class");
+
+ cfmsgs_typemsg("this", pcfs, pcfs->this_class);
+
+ cfmsgs_show_constant_pool(pcfs);
+
+
+ /*****************************************************************/
+ /* Get super_class */
+ /*****************************************************************/
+ pcfs->super_class = GETRS2(pu2++);
+
+ MACHINE_JSHORT_SWAP(pcfs->super_class);
+
+ /* LOAD_SYSCALL_FAILURE(what needs checking here?,"access flags");*/
+
+ cfmsgs_typemsg("super", pcfs, pcfs->super_class);
+
+ /*****************************************************************/
+ /* Create interfaces index, then load up interfaces array */
+ /*****************************************************************/
+ pcfs->interfaces_count = GETRS2(pu2++);
+
+ MACHINE_JSHORT_SWAP(pcfs->interfaces_count);
+
+ sysDbgMsg(DMLNORM,
+ "classfile_loadclassdata",
+ "intfc count=%d",
+ pcfs->interfaces_count);
+
+ /*
+ LOAD_SYSCALL_FAILURE(what needs checking here?,"interfaces_count");
+ */
+
+ if (0 == pcfs->interfaces_count)
+ {
+ /* Quite possible, and theoretically okay */
+ pcfs->interfaces = (u2 *) rnull;
+ }
+ else
+ {
+ /*
+ * Map the indices in the class file to point to actual
+ * constant pool enties via a pointer lookup table.
+ */
+ pcfs->interfaces = HEAP_GET_METHOD(pcfs->interfaces_count *
+ sizeof(u2 *),
+ rfalse);
+
+ /*
+ * Iterate through class file's interfaces[] array and
+ * fill in the constant_pool[] references for normal use.
+ */
+ jvm_interface_index ifidx;
+ for (ifidx = 0; ifidx < pcfs->interfaces_count; ifidx++)
+ {
+ /* Retrieve next interface index from class file area */
+ jvm_interface_index cfifidx = GETRS2(pu2++);
+
+ /* Range check the index value */
+ CPIDX_RANGE_CHECK(pcfs,
+ cfifidx,
+ "interface index");
+
+ /*
+ * Can't free in GENERIC_FAILURE1_PTR() because
+ * these pointer came from HEAP_GET_METHOD(),
+ * not from HEAP_GET_DATA()
+ */
+ if (CONSTANT_Class != CP_TAG(pcfs, cfifidx))
+ {
+ HEAP_FREE_METHOD(pcfs->interfaces);
+ /*!
+ * @todo HEAP_FREE_METHOD(pcfs->constan_pool[0..n]);
+ */
+ HEAP_FREE_METHOD(pcfs);
+ }
+
+ GENERIC_FAILURE1_PTR((CONSTANT_Class !=
+ CP_TAG(pcfs,cfifidx)),
+ DMLNORM,
+ "classfile_loadclassdata",
+ "Invalid interface tag %d",
+ CP_TAG(pcfs, cfifidx),
+ ClassFile,
+ rnull,
+ rnull);
+
+ /* Finally store valid constant pool entry index */
+ pcfs->interfaces[ifidx] = cfifidx;
+
+ cfmsgs_typemsg("intfc", pcfs, cfifidx);
+
+ } /* for (ifidx) */
+
+ /*
+ * Point past the interfaces[] area
+ * (done above by autoincrement)
+ */
+
+ /* pu2 += pcfs->interfaces_count; */
+
+ }
+
+
+ /*****************************************************************/
+ /* Get field_count */
+ /*****************************************************************/
+ pcfs->fields_count = GETRS2(pu2++);
+
+ MACHINE_JSHORT_SWAP(pcfs->fields_count);
+
+ /* LOAD_SYSCALL_FAILURE(what needs checking here?,"fields_count");*/
+
+ sysDbgMsg(DMLNORM,
+ "classfile_loadclassdata",
+ "flds count=%d",
+ pcfs->fields_count);
+
+
+ /*****************************************************************/
+ /* Create constant pool index, then load up fields[] array */
+ /*****************************************************************/
+ jbyte *pfbytes = (jbyte *) pu2;
+
+ if (0 == pcfs->fields_count)
+ {
+ /* Quite possible, and theoretically okay */
+ pcfs->fields = (field_info **) rnull;
+ }
+ else
+ {
+ jvm_field_index fldidx;
+
+ /*
+ * Map the indices in the class file to point to actual
+ * constant pool enties via a pointer lookup table.
+ */
+ pcfs->fields = HEAP_GET_METHOD(pcfs->fields_count *
+ sizeof(field_info *),
+ rtrue);
+
+
+ /*
+ * Iterate through class file's fields and fill in
+ * the attributes[] pointer array for normal use.
+ */
+ for (fldidx = 0; fldidx < pcfs->fields_count; fldidx++)
+ {
+ /* Allocate a heap area for each fields[] entry */
+ ALLOC_CF_ITEM(field_info,
+ pfbytes,
+ pcfs->fields[fldidx],
+ LOCAL_field_binding);
+
+ MACHINE_JSHORT_SWAP(pcfs->fields[fldidx]->access_flags);
+ MACHINE_JSHORT_SWAP(pcfs->fields[fldidx]->name_index);
+ MACHINE_JSHORT_SWAP(pcfs->fields[fldidx]->descriptor_index);
+ MACHINE_JSHORT_SWAP(pcfs->fields[fldidx]->attributes_count);
+
+ /* Strip out unused access flags, per spec */
+ pcfs->fields[fldidx]->access_flags &=
+ (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
+ ACC_STATIC | ACC_FINAL | ACC_VOLATILE | ACC_TRANSIENT |
+ ACC_SYNTHETIC | ACC_ENUM);
+
+ /* Range check the indices */
+ CPIDX_RANGE_CHECK(pcfs,
+ pcfs->fields[fldidx]->name_index,
+ "field name index");
+ CPIDX_RANGE_CHECK(pcfs,
+ pcfs->fields[fldidx]->descriptor_index,
+ "field descriptor index");
+
+ cfmsgs_typemsg("fld name",
+ pcfs,
+ pcfs->fields[fldidx]->name_index);
+ cfmsgs_typemsg("fld desc",
+ pcfs,
+ pcfs->fields[fldidx]->descriptor_index);
+
+ /* Skip past above items to attributes area */
+ pfbytes = (jbyte *) &((method_info *) pfbytes)->attributes;
+
+
+ /*
+ * Map the indices in the class file to point to actual
+ * constant pool enties via a pointer lookup table.
+ */
+ if (0 == pcfs->fields[fldidx]->attributes_count)
+ {
+ /* Quite possible for small objects */
+ pcfs->fields[fldidx]->attributes =
+ (attribute_info_dup **) rnull;
+ }
+ else
+ {
+ pcfs->fields[fldidx]->attributes =
+ HEAP_GET_METHOD(
+ pcfs->fields[fldidx]->attributes_count *
+ sizeof(attribute_info *),
+ rtrue);
+
+ /*
+ * Load up each attribute in this attribute area
+ */
+ jvm_attribute_index atridx;
+ for (atridx = 0;
+ atridx < pcfs->fields[fldidx]->attributes_count;
+ atridx++)
+ {
+ /*
+ * Load an attribute and verify that it is either
+ * a valid (or an ignored) attribute, then point to
+ * next attribute in class file image.
+ */
+
+ pfbytes =
+ cfattrib_loadattribute(
+ pcfs,
+ &pcfs->fields[fldidx]->attributes[atridx],
+ (attribute_info *) pfbytes);
+
+ LOAD_SYSCALL_FAILURE((rnull == pfbytes),
+ "load field attribute",
+ rnull,
+ rnull);
+
+ } /* for (atridx) */
+
+ } /* if attributes_count else */
+
+ /* Finally, Initialize the late binding extension */
+ pcfs->fields[fldidx]->LOCAL_field_binding.fluidxJVM =
+ jvm_field_index_bad;
+
+ } /* for (fldidx) */
+
+ } /* if pcfs->fields */
+
+
+ /*****************************************************************/
+ /* Get method_count */
+ /*****************************************************************/
+
+ /* Point past end of fields area */
+ MAKE_PU2(pu2, pfbytes);
+
+ /*LOAD_SYSCALL_FAILURE(what needs checking here?,"methods count");*/
+ MACHINE_JSHORT_SWAP(pu2);
+ pcfs->methods_count = GETRS2(pu2++);
+
+ sysDbgMsg(DMLNORM,
+ "classfile_loadclassdata",
+ "meth count=%d",
+ pcfs->methods_count);
+
+ /*****************************************************************/
+ /* Create constant pool index, then load up methods[] array */
+ /*****************************************************************/
+ jbyte *pmbytes = (jbyte *) pu2;
+
+ if (0 == pcfs->methods_count)
+ {
+ /* Quite possible, and theoretically okay */
+ pcfs->methods = (method_info **) rnull;
+ }
+ else
+ {
+ jvm_method_index mthidx;
+
+ /*
+ * Map the indices in the class file to point to actual
+ * constant pool enties via a pointer lookup table.
+ */
+ pcfs->methods = HEAP_GET_METHOD(pcfs->methods_count *
+ sizeof(method_info *),
+ rtrue);
+
+ /*
+ * Iterate through class file's methods and fill in
+ * the attributes[] pointer array for normal use.
+ */
+ for (mthidx = 0; mthidx < pcfs->methods_count; mthidx++)
+ {
+ /* Allocate a heap area for each methods[] entry */
+ ALLOC_CF_ITEM(method_info,
+ pmbytes,
+ pcfs->methods[mthidx],
+ LOCAL_method_binding);
+
+ MACHINE_JSHORT_SWAP(pcfs->methods[mthidx]->access_flags);
+ MACHINE_JSHORT_SWAP(pcfs->methods[mthidx]->name_index);
+ MACHINE_JSHORT_SWAP(pcfs->methods[mthidx]->descriptor_index);
+ MACHINE_JSHORT_SWAP(pcfs->methods[mthidx]->attributes_count);
+
+ /* Strip out unused access flags, per spec */
+ pcfs->methods[mthidx]->access_flags &=
+ (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
+ ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
+ ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE| ACC_ABSTRACT |
+ ACC_STRICT | ACC_SYNTHETIC);
+
+ /* Range check the indices */
+ CPIDX_RANGE_CHECK(pcfs,
+ pcfs->methods[mthidx]->name_index,
+ "method name index");
+ CPIDX_RANGE_CHECK(pcfs,
+ pcfs->methods[mthidx]->descriptor_index,
+ "method descriptor index");
+
+ cfmsgs_typemsg("meth name",
+ pcfs,
+ pcfs->methods[mthidx]->name_index);
+ cfmsgs_typemsg("meth desc",
+ pcfs,
+ pcfs->methods[mthidx]->descriptor_index);
+
+
+ /* Skip past above items to attributes area */
+ pmbytes = (jbyte *) &((method_info *) pmbytes)->attributes;
+
+ /*
+ * Initialize the late binding extension.
+ * These values will get overwritten when a
+ * code attribute is found and when an optional
+ * exception attribute is found.
+ */
+ pcfs->methods[mthidx]
+ ->LOCAL_method_binding.codeatridxJVM =
+ jvm_attribute_index_bad;
+
+ pcfs->methods[mthidx]
+ ->LOCAL_method_binding.excpatridxJVM =
+ jvm_attribute_index_bad;
+
+ pcfs->methods[mthidx]
+ ->LOCAL_method_binding.nmordJVM =
+ jvm_native_method_ordinal_null;
+
+
+ /*
+ * Map the indices in the class file to point to actual
+ * constant pool enties via a pointer lookup table.
+ */
+ if (0 == pcfs->methods[mthidx]->attributes_count)
+ {
+ /* Quite possible for small objects */
+ pcfs->methods[mthidx]->attributes =
+ (attribute_info_dup **) rnull;
+ }
+ else
+ {
+ /*
+ * Allocate the attribute area for this method
+ */
+ pcfs->methods[mthidx]->attributes =
+ HEAP_GET_METHOD(
+ pcfs->methods[mthidx]->attributes_count *
+ sizeof(attribute_info_dup *),
+ rtrue);
+
+ /*
+ * Load up each attribute in this attribute area
+ */
+ jvm_attribute_index atridx;
+ for (atridx = 0;
+ atridx < pcfs->methods[mthidx]->attributes_count;
+ atridx++)
+ {
+ /*
+ * Load an attribute and verify that it is either
+ * a valid (or an ignored) attribute, then point to
+ * next attribute in class file image.
+ */
+
+ pmbytes =
+ cfattrib_loadattribute(
+ pcfs,
+ &pcfs->methods[mthidx]->attributes[atridx],
+ (attribute_info *) pmbytes);
+
+ LOAD_SYSCALL_FAILURE((rnull == pmbytes),
+ "verify member attribute",
+ rnull,
+ rnull);
+
+ /*
+ * Load Code_attribute and Exceptions_attribute
+ * atridx
+ */
+ switch (cfattrib_atr2enum(pcfs,
+ pcfs->methods[mthidx]->attributes[atridx]
+ ->ai.attribute_name_index))
+ {
+ case LOCAL_CODE_ATTRIBUTE:
+ pcfs
+ ->methods[mthidx]
+ ->LOCAL_method_binding.codeatridxJVM =
+ atridx;
+ break;
+
+ case LOCAL_EXCEPTIONS_ATTRIBUTE:
+
+ pcfs
+ ->methods[mthidx]
+ ->LOCAL_method_binding.excpatridxJVM =
+ atridx;
+ break;
+
+ /* Satisfy compiler that all cases are handled*/
+ case LOCAL_UNKNOWN_ATTRIBUTE:
+ case LOCAL_CONSTANTVALUE_ATTRIBUTE:
+ case LOCAL_INNERCLASSES_ATTRIBUTE:
+ case LOCAL_ENCLOSINGMETHOD_ATTRIBUTE:
+ case LOCAL_SYNTHETIC_ATTRIBUTE:
+ case LOCAL_SIGNATURE_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) */
+
+ } /* if attributes_count else */
+
+ } /* for (mthidx) */
+
+ } /* if pcfs->methods */
+
+ /*****************************************************************/
+ /* Get attributes_count */
+ /*****************************************************************/
+
+ /* Point past end of methods area */
+ MAKE_PU2(pu2, pmbytes);
+
+ /*LOAD_SYSCALL_FAILURE(what needs checking here?,"methods count");*/
+ MACHINE_JSHORT_SWAP(pu2);
+ pcfs->attributes_count = GETRS2(pu2++);
+
+ sysDbgMsg(DMLNORM,
+ "classfile_loadclassdata",
+ "att cnt=%d",
+ pcfs->attributes_count);
+
+ /*****************************************************************/
+ /* Create constant pool index, then load up attributes[] array */
+ /*****************************************************************/
+
+ if (0 == pcfs->attributes_count)
+ {
+ /* Not really possible, and theoretically faulty */
+ pcfs->attributes = (attribute_info_dup **) rnull;
+ }
+ else
+ {
+ /*
+ * Map the indices in the class file to point to actual
+ * constant pool enties via a pointer lookup table.
+ */
+ pcfs->attributes = HEAP_GET_METHOD(pcfs->attributes_count *
+ sizeof(attribute_info *),
+ rtrue);
+
+ /*
+ * Load up each attribute in the class file attribute area
+ */
+ jvm_attribute_index atridx;
+ jbyte *pcbytes = (jbyte *) pu2;
+
+ for (atridx = 0; atridx < pcfs->attributes_count; atridx++)
+ {
+ /*
+ * Load an attribute and verify that it is either
+ * a valid (or an ignored) attribute, then point to
+ * next attribute in class file image.
+ */
+
+ pcbytes =
+ cfattrib_loadattribute(
+ pcfs,
+ &pcfs->attributes[atridx],
+ (attribute_info *) pcbytes);
+
+ LOAD_SYSCALL_FAILURE((rnull == pcbytes),
+ "verify file attribute",
+ rnull,
+ rnull);
+
+ } /* for (atridx) */
+
+ } /* if pcfs->methods_count else */
+
+
+ /*! @todo Throw @b VerifyError for classes w/ questionable contents*/
+
+ /* Class file structures are now fully loaded from class file data*/
+
+ return(pcfs);
+
+} /* END of classfile_loadclassdata() */
+
+
+/*!
+ * @brief Release all heap allocated to a fully loaded
+ * ClassFile structure
+ *
+ * @param pcfs Pointer to a ClassFile structure with all its pieces
+ *
+ * @returns @link #rvoid rvoid@endlink Whether it succeeds or fails,
+ * returning anything does not make much sense. This is
+ * similar to @c @b free(3) not returning anything even
+ * when a bad pointer was passed in.
+ */
+rvoid classfile_unloadclassdata(ClassFile *pcfs)
+{
+ if (rnull == pcfs)
+ {
+ return; /* Nothing to do if @link #rnull rnull@endlink pointer*/
+ }
+
+ jvm_constant_pool_index cpidx;
+ jvm_field_index fldidx;
+ jvm_method_index mthidx;
+ jvm_attribute_index atridx;
+
+ /*
+ * Deallocate in the reverse order of allocation to eliminate
+ * @e any chance for @link #rnull rnull@endlink pointer. Do
+ * file attributes first (last entry to first), then method
+ * attributes, methods, field attributes, fields, and constant_pool.
+ */
+
+ if ((0 < pcfs->attributes_count) && (rnull != pcfs->attributes))
+ {
+ for (atridx = pcfs->attributes_count - 1;
+ atridx != JVMCFG_BAD_ATTRIBUTE; /* wrap-around when done */
+ atridx--)
+ {
+ /*
+ * Skip any @link #rnull rnull@endlink entries
+ * (should NEVER happen)
+ */
+ if (rnull == pcfs->attributes[atridx])
+ {
+ continue;
+ }
+
+ cfattrib_unloadattribute(pcfs, pcfs->attributes[atridx]);
+ }
+ }
+
+
+ if ((0 < pcfs->methods_count) && (rnull != pcfs->methods))
+ {
+ for (mthidx = pcfs->methods_count - 1;
+ mthidx != JVMCFG_BAD_METHOD; /* wrap-around when done */
+ mthidx--)
+ {
+ /*
+ * Skip any @link #rnull rnull@endlink entries
+ * (should NEVER happen)
+ */
+ if (rnull == pcfs->methods[mthidx])
+ {
+ continue;
+ }
+
+ if (0 < pcfs->methods[mthidx]->attributes_count)
+ {
+ for (atridx = pcfs->methods[mthidx]->attributes_count-1;
+ /* wrap-around when done */
+ atridx != JVMCFG_BAD_ATTRIBUTE;
+ atridx--)
+ {
+ /*
+ * Skip any @link #rnull rnull@endlink entries
+ * (should NEVER happen)
+ */
+ if (rnull ==
+ pcfs->methods[mthidx]->attributes[atridx])
+ {
+ continue;
+ }
+
+ cfattrib_unloadattribute(pcfs,
+ pcfs->methods[mthidx]->attributes[atridx]);
+ }
+ }
+
+ HEAP_FREE_METHOD(pcfs->methods[mthidx]->attributes);
+ HEAP_FREE_METHOD(pcfs->methods[mthidx]);
+ }
+ }
+
+
+ if ((0 < pcfs->fields_count) && (rnull != pcfs->fields))
+ {
+ for (fldidx = pcfs->fields_count - 1;
+ fldidx != JVMCFG_BAD_FIELD; /* wrap-around when done */
+ fldidx--)
+ {
+ /*
+ * Skip any @link #rnull rnull@endlink entries
+ * (should NEVER happen)
+ */
+ if (rnull == pcfs->fields[fldidx])
+ {
+ continue;
+ }
+
+ if (0 < pcfs->fields[fldidx]->attributes_count)
+ {
+ for (atridx = pcfs->fields[fldidx]->attributes_count -1;
+ /* wrap-around when done */
+ atridx != JVMCFG_BAD_ATTRIBUTE;
+ atridx--)
+ {
+ /*
+ * Skip any @link #rnull rnull@endlink entries
+ * (should NEVER happen)
+ */
+ if (rnull ==
+ pcfs->fields[fldidx]->attributes[atridx])
+ {
+ continue;
+ }
+
+ cfattrib_unloadattribute(pcfs,
+ pcfs->fields[fldidx]->attributes[atridx]);
+ }
+ }
+
+ HEAP_FREE_METHOD(pcfs->fields[fldidx]->attributes);
+ HEAP_FREE_METHOD(pcfs->fields[fldidx]);
+ }
+ }
+
+
+ if ((0 < pcfs->constant_pool_count)&&(rnull != pcfs->constant_pool))
+ {
+ for (cpidx = pcfs->constant_pool_count - 1;
+ cpidx > CONSTANT_CP_DEFAULT_INDEX;
+ cpidx--)
+ {
+ /*
+ * Skip any @link #rnull rnull@endlink entries
+ * (should NEVER happen)
+ */
+ if (rnull == pcfs->constant_pool[cpidx])
+ {
+ continue;
+ }
+
+ HEAP_FREE_METHOD(pcfs->constant_pool[cpidx]);
+ }
+ }
+
+ HEAP_FREE_METHOD(pcfs->constant_pool);
+ HEAP_FREE_METHOD(pcfs);
+
+ return;
+
+} /* end of classfile_unloadclassdata() */
+
+
+/*******************************************************************/
+/*!
+ *
+ * @brief Report an error @link #rnull rnull@endlink pointer if
+ * a system call fails
+ *
+ *
+ * @param expr Any logical expression that returns
+ * @link #rtrue rtrue@endlink or
+ * @link #rfalse rfalse@endlink.
+ *
+ * @param msg Text to display to sysDbgMsg() upon failure
+ *
+ *
+ * @returns If @b expr is @link #rtrue rtrue@endlink, return a
+ * @link #rnull rnull@endlink pointer to the
+ * calling function, cast as <b><code>(rvoid *)</code></b>,
+ * else continue with inline code.
+ *
+ */
+#define READ_SYSCALL_FAILURE(expr, msg) \
+ GENERIC_FAILURE_PTR((expr), \
+ DMLMIN, \
+ "classfile_readclassfile", \
+ msg, \
+ rvoid, \
+ rnull, \
+ rnull)
+
+/*!
+ * @name Read Java object code (class data) from disk files.
+ *
+ *
+ * @param filename Null-terminated ASCII string, pathname
+ * of JAR file or class file.
+ *
+ *
+ * @returns Pointer to memory area containing class file data.
+ * If error detected, @link #rnull rnull@endlink is
+ * returned and perror("msg") may be called to report
+ * the system call problem that caused the
+ * particular failure more.
+ *
+ */
+
+/*@{ */ /* Begin grouped definitions */
+
+/*!
+ * @brief Read a JVM class file.
+ *
+ * If a valid class file is read, return pointer to memory area
+ * containing its Java class image.
+ *
+ */
+u1 *classfile_readclassfile(rchar *filename)
+{
+ off_t filesize = 0;
+
+ struct stat statbfr;
+
+ rvoid *pclassfile_image;
+
+ int fd;
+
+ /*
+ * Chk if file is available and read its stat info, esp file size
+ */
+ int rc = stat(filename, &statbfr);
+ READ_SYSCALL_FAILURE(0 > rc, "statbfr");
+
+ /*
+ * Allocate enough space for entire class file to be
+ * Read into memory at once.
+ */
+
+ pclassfile_image = (rvoid *) HEAP_GET_DATA(statbfr.st_size, rfalse);
+
+ /* Now go open the file and read it */
+ fd = open(filename, O_RDONLY);
+ READ_SYSCALL_FAILURE(0 > fd, "file open");
+
+ /* Read the whole file in at once and close it. */
+ filesize = read(fd, pclassfile_image, statbfr.st_size);
+ READ_SYSCALL_FAILURE(0 > filesize, "file read");
+
+ close(fd);
+
+ /* Make sure stat() and read() have the same size */
+ GENERIC_FAILURE_PTR((filesize != statbfr.st_size),
+ DMLNORM,
+ "classfile_readclassfile",
+ "Incomplete file read",
+ rvoid,
+ pclassfile_image,
+ rnull);
+
+ /* Proper completion when entire file is read in */
+ return(pclassfile_image);
+
+} /* END of classfile_readclassfile() */
+
+
+/*!
+ * @brief Read an entire JAR file into temporary disk area and
+ * load up one class file from it.
+ *
+ * If a valid JAR file is read, return pointer to memory area containing
+ * the JAva class image of the startup class that was specified in Jar
+ * Manifest file. In the future, all classes in the JAR file will
+ * be available for loading from the temporary disk area via
+ * @b CLASSPATH.
+ *
+ */
+u1 *classfile_readjarfile(rchar *filename)
+{
+ struct stat statbfr;
+
+ rchar *jarparm = HEAP_GET_DATA(JVMCFG_SCRIPT_MAX, rfalse);
+
+ rchar *pwd = HEAP_GET_DATA(JVMCFG_SCRIPT_MAX, rfalse);
+
+ rchar *jarscript = HEAP_GET_DATA(JVMCFG_SCRIPT_MAX, rfalse);
+
+ /*! @todo Need a version of this that works on MS Windows */
+
+ /*
+ * Make sure to have an @e absolute path name to @b filename
+ * since it may be relative and the @c @b jar command
+ * used @c @b chdir
+ */
+ if (JVMCFG_PATHNAME_DELIMITER_CHAR == filename[0])
+ {
+ strcpy(jarparm, filename);
+ }
+ else
+ {
+ /*!
+ * @todo Check `pwd` overflow and @link #rnull rnull@endlink
+ * returned
+ */
+ getwd(pwd);
+
+ sprintfLocal(jarparm,
+ "%s%c%s",
+ pwd,
+ JVMCFG_PATHNAME_DELIMITER_CHAR,
+ filename);
+ }
+
+ /* Convert input parm to internal form, append suffix */
+
+ /*
+ * Build up JAR command using internal class name w/suffix. Make
+ * @e sure all files are writeable for final <code>rm -rf<code>.
+ */
+ sprintfLocal(jarscript,
+ JVMCFG_JARFILE_MANIFEST_EXTRACT_SCRIPT,
+ tmparea_get(),
+ pjvm->java_home,
+ jarparm);
+
+ int rc = system(jarscript);
+
+ if (0 != rc)
+ {
+ sysErrMsg("classfile_readjarfile",
+ "Cannot extract data from JAR file %s",
+ jarparm);
+ exit_jvm(EXIT_CLASSPATH_JAR);
+/*NOTREACHED*/
+ }
+
+ /* Verify extraction of manifest file */
+ sprintfLocal(jarscript, /* Reuse unneeded buffer */
+ "%s%c%s",
+ tmparea_get(),
+ JVMCFG_PATHNAME_DELIMITER_CHAR,
+ JVMCFG_JARFILE_MANIFEST_FILENAME);
+
+ rc = stat(jarscript, &statbfr);
+
+
+ /* Read manifest file and locate starting class name */
+ rchar *mnfstartclass = manifest_get_main(jarscript);
+
+ if (rnull == mnfstartclass)
+ {
+ sysErrMsg("classfile_readjarfile",
+ "Cannot locate start class in JAR file %s",
+ jarparm);
+ exit_jvm(EXIT_CLASSPATH_JAR);
+/*NOTREACHED*/
+ }
+
+ /* Reuse unneeded bfr w/ descriptive name */
+ rchar *start_class_tmpfile = pwd;
+
+ /* Verify existence of start class in JAR file */
+ sprintfLocal(start_class_tmpfile,
+ "%s%c",
+ tmparea_get(),
+ JVMCFG_PATHNAME_DELIMITER_CHAR);
+
+ int dirlen = strlen(start_class_tmpfile);
+ strcat(pwd, mnfstartclass);
+
+ (rvoid) classpath_external2internal_classname_inplace(&pwd[dirlen]);
+
+ int alllen = strlen(start_class_tmpfile);
+ start_class_tmpfile[alllen] = JVMCFG_EXTENSION_DELIMITER_CHAR;
+ start_class_tmpfile[alllen + 1] = '\0';
+ strcat(pwd, CLASSFILE_EXTENSION_DEFAULT);
+
+ rc = stat(start_class_tmpfile, &statbfr);
+
+ /* Complain if class in manifest was not found in JAR file */
+ if (0 != rc)
+ {
+ sysErrMsg("classfile_readjarfile",
+ "Cannot locate start class '%s' in manifest for JAR file %s",
+ mnfstartclass,
+ jarparm);
+
+ HEAP_FREE_DATA(mnfstartclass);
+ HEAP_FREE_DATA(jarparm);
+ HEAP_FREE_DATA(start_class_tmpfile);
+ HEAP_FREE_DATA(jarscript);
+
+ exit_jvm(EXIT_CLASSPATH_JAR);
+ }
+
+ /* Clean up for return */
+ HEAP_FREE_DATA(jarparm);
+ HEAP_FREE_DATA(mnfstartclass);
+ HEAP_FREE_DATA(jarscript);
+
+ /*
+ * If starting class file was extracted, report result
+ * in heap-allocated bfr
+ */
+
+ rvoid *pvrc = classfile_readclassfile(start_class_tmpfile);
+
+ HEAP_FREE_DATA(start_class_tmpfile);
+
+ return(pvrc);
+
+} /* END of classfile_readjarfile() */
+
+/*@} */ /* End of grouped definitions */
+
+
+/* EOF */