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/05 04:20:10 UTC

svn commit: r294974 [12/25] - in /incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm: ./ jchevm/ jchevm/doc/ jchevm/etc/ jchevm/include/ jchevm/java/ jchevm/java/org/ jchevm/java/org/dellroad/ jchevm/java/org/dellroad/jc/ jchevm/java/org/dellroad...

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/definitions.h
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/definitions.h?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/definitions.h (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/definitions.h Tue Oct  4 19:19:16 2005
@@ -0,0 +1,792 @@
+
+/*
+ * 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.
+ *
+ * $Id: definitions.h,v 1.17 2005/05/24 01:09:38 archiecobbs Exp $
+ */
+
+#ifndef _DEFINITIONS_H_
+#define _DEFINITIONS_H_
+
+/*
+ * We like this definition for NULL because it generates more
+ * gcc compiler warnings than just plain "0" would.
+ */
+#undef NULL
+#define NULL	((void *)0)
+
+/*
+ * Round up 'x' to a multiple of 'y' (must be a power of two).
+ */
+#define _JC_ROUNDUP2(x, y)	(((x) + ((y) - 1)) & ~((y) - 1))
+
+/*
+ * Count how many 'y' required to cover 'x'.
+ */
+#define _JC_HOWMANY(x, y)	(((x) + ((y) - 1)) / (y))
+
+/*
+ * Number of bits in a '_jc_word' type.
+ */
+#define _JC_BITS_PER_WORD	(sizeof(_jc_word) << 3)
+
+/*
+ * Value of a hex digit.
+ */
+#define _JC_HEXVAL(c)	(isdigit(c) ? (c) - '0' : tolower(c) - 'a' + 10)
+
+/*
+ * Name of the system thread group.
+ */
+#define _JC_SYSTEM_THREADGROUP_NAME	"Internal"
+
+/*
+ * Thread status values.
+ *
+ * Each running thread is either running in Java mode or native mode.
+ * In native mode, the thread is not allowed to directly touch any VM state.
+ * In either case, the thread is "halting" if another thread wishes for
+ * it to halt. Once it does halt, it enters the halted state.
+ */
+enum {
+	_JC_THRDSTAT_RUNNING_NORMAL = 1,	/* running in java mode */
+	_JC_THRDSTAT_HALTING_NORMAL,		/* java, halt requested */
+	_JC_THRDSTAT_RUNNING_NONJAVA,		/* running in native mode */
+	_JC_THRDSTAT_HALTING_NONJAVA,		/* native, halt requested */
+	_JC_THRDSTAT_HALTED			/* halted */
+};
+
+/*
+ * Thread interrupt status. These values are used to implement
+ * Thread.interrupt() and friends.
+ */
+enum {
+	_JC_INTERRUPT_CLEAR = 0,	/* not interrupted, not interruptible */
+	_JC_INTERRUPT_INTERRUPTIBLE,	/* sleeping away and interruptible */
+	_JC_INTERRUPT_SET,		/* interrupted, but not handled yet */
+	_JC_INTERRUPT_INTERRUPTED,	/* waking up to handle interruption */
+};
+
+/*
+ * Verbosity flags.
+ */
+enum {
+	_JC_VERBOSE_CLASS,
+	_JC_VERBOSE_GC,
+	_JC_VERBOSE_JNI,
+	_JC_VERBOSE_EXCEPTIONS,
+	_JC_VERBOSE_RESOLUTION,
+	_JC_VERBOSE_INIT,
+	_JC_VERBOSE_GEN,
+	_JC_VERBOSE_JNI_INVOKE,
+	_JC_VERBOSE_OBJ,
+	_JC_VERBOSE_MAX
+};
+
+/*
+ * Exceptions generated by the virtual machine itself.
+ * We have special handling for these to avoid recursively
+ * trying to throw the same exception over and over again.
+ */
+enum {
+	_JC_AbstractMethodError,
+	_JC_ArithmeticException,
+	_JC_ArrayIndexOutOfBoundsException,
+	_JC_ArrayStoreException,
+	_JC_ClassCastException,
+	_JC_ClassCircularityError,
+	_JC_ClassFormatError,
+	_JC_ClassNotFoundException,
+	_JC_CloneNotSupportedException,
+	_JC_ExceptionInInitializerError,
+	_JC_IOException,
+	_JC_IllegalAccessError,
+	_JC_IllegalAccessException,
+	_JC_IllegalArgumentException,
+	_JC_IllegalMonitorStateException,
+	_JC_IllegalThreadStateException,
+	_JC_IncompatibleClassChangeError,
+	_JC_InstantiationError,
+	_JC_InstantiationException,
+	_JC_InternalError,
+	_JC_InterruptedException,
+	_JC_InvocationTargetException,
+	_JC_LinkageError,
+	_JC_NegativeArraySizeException,
+	_JC_NoClassDefFoundError,
+	_JC_NoSuchFieldError,
+	_JC_NoSuchMethodError,
+	_JC_NullPointerException,
+	_JC_OutOfMemoryError,
+	_JC_StackOverflowError,
+	_JC_ThreadDeath,
+	_JC_UnsatisfiedLinkError,
+	_JC_UnsupportedClassVersionError,
+	_JC_VMEXCEPTION_MAX
+};
+
+/*
+ * Macros to convert between splay tree nodes and the larger
+ * structure containing the _jc_splay_node node structure.
+ */
+#define _JC_NODE2ITEM(tree, node)					\
+	((void *)((char *)(node) - (tree)->offset))
+#define _JC_ITEM2NODE(tree, item)					\
+	((_jc_splay_node *)((char *)(item) + (tree)->offset))
+
+/*
+ * Macros to convert between internal and JNI VM and thread pointers.
+ */
+#define _JC_ENV2JNI(env)						\
+	((JNIEnv *)((char *)(env) + _JC_OFFSETOF(_jc_env, jni_interface)))
+#define _JC_JNI2ENV(jni_ptr)						\
+	((_jc_env *)((char *)(jni_ptr) - _JC_OFFSETOF(_jc_env, jni_interface)))
+#define _JC_JVM2JNI(jvm)						\
+	((JavaVM *)((char *)(jvm) + _JC_OFFSETOF(_jc_jvm, jni_interface)))
+#define _JC_JNI2JVM(jni_ptr)						\
+	((_jc_jvm *)((char *)(jni_ptr) - _JC_OFFSETOF(_jc_jvm, jni_interface)))
+
+/*
+ * Some pseudo-bytecodes
+ */
+#define _JC_ldc_string		0xe0
+
+/*
+ * Lockword layout
+ * ---------------
+ *
+ * The lockword is a _jc_word (of which we only use the bottom 32 bits).
+ * The top bits are used for locking, the bottom for misc type info that
+ * helps us avoid dereferencing obj->type.
+ *
+ *   Bits	Meaning
+ *   ----	-------
+ *     31	0 = lock is THIN, 1 = lock is FAT
+ *  16-30	FAT: fat lock ID
+ *  21-30	THIN: owner thread ID (or zero if not locked)
+ *  16-20	THIN: number of times locked - 1
+ *  10-15	Number of reference fields in object (0x3f = overflow)
+ *	9	Finalize bit: object requires finalization (heap objects only)
+ *	9	Visited bit: object seen this GC cycle (stack objects only)
+ *      8	Live bit: object is live (reachable from root set)
+ *      7	Keep bit: don't reclaim object (e.g., finalize() reachable)
+ *      6	Special bit: special GC handling required (e.g., ClassLoader)
+ *	5	0 = non-array, 1 = array
+ *    1-4	Array: element_type->flags & _JC_TYPE_MASK
+ *		Non-array: _JC_TYPE_REFERENCE
+ *      0	Always 1 to distinguish from a reference (aligned pointer)
+ */
+#define _JC_LW_FAT_BIT			0x80000000
+#define _JC_LW_FAT_ID_MASK		0x7fff0000
+#define _JC_LW_FAT_ID_SHIFT		16
+#define _JC_LW_THIN_TID_MASK		0x7fe00000
+#define _JC_LW_THIN_TID_SHIFT		21
+#define _JC_LW_THIN_COUNT_MASK		0x001f0000
+#define _JC_LW_THIN_COUNT_SHIFT		16
+#define _JC_LW_INFO_MASK		0x0000ffff
+#define _JC_LW_INFO_SHIFT		0
+#define _JC_LW_REF_COUNT_MASK		0x0000fc00
+#define _JC_LW_REF_COUNT_SHIFT		10
+#define _JC_LW_FINALIZE_BIT		0x00000200
+#define _JC_LW_VISITED_BIT		0x00000200
+#define _JC_LW_LIVE_BIT			0x00000100
+#define _JC_LW_KEEP_BIT			0x00000080
+#define _JC_LW_SPECIAL_BIT		0x00000040
+#define _JC_LW_ARRAY_BIT		0x00000020
+#define _JC_LW_TYPE_MASK		0x0000001e
+#define _JC_LW_TYPE_SHIFT		1
+#define _JC_LW_ODD_BIT			0x00000001
+
+/* Macros for testing and extracting lockword bits */
+#define _JC_LW_TEST(w, bit)						\
+	(((w) & _JC_LW_ ## bit ## _BIT) != 0)
+#define _JC_LW_EXTRACT(w, fld)						\
+	(((_jc_word)(w) & _JC_LW_ ## fld ## _MASK) >> _JC_LW_ ## fld ## _SHIFT)
+#define _JC_LW_MAX(fld)							\
+	(((_jc_word)_JC_LW_ ## fld ## _MASK >> _JC_LW_ ## fld ## _SHIFT) + 1)
+
+/* Hard limits derived from the sizes of the above bit fields */
+#define _JC_MAX_THREADS			_JC_LW_MAX(THIN_TID)
+#define _JC_MAX_FATLOCKS		_JC_LW_MAX(FAT_ID)
+#define _JC_MAX_THIN_RECURSION		_JC_LW_MAX(THIN_COUNT)
+
+/*
+ * Access to special object fields.
+ */
+#ifndef NDEBUG
+#define _JC_VMFIELD(_vm, _obj, _class, _field, _type)			\
+    ({									\
+	_jc_field *const _f = _vm->boot.fields._class._field;		\
+									\
+	_JC_ASSERT(_jc_subclass_of((_obj), _f->class));			\
+	_JC_ASSERT(!_JC_ACC_TEST(_f, STATIC));				\
+	(_type *)((char *)(_obj) + _f->offset);				\
+    })
+#define _JC_VMSTATICFIELD(_vm, _class, _field, _type)			\
+    ({									\
+	_jc_field *const _f = _vm->boot.fields._class._field;		\
+									\
+	_JC_ASSERT(_JC_ACC_TEST(_f, STATIC));				\
+	(_type *)((char *)_vm->boot.types._class->u.nonarray		\
+	    .class_fields + _vm->boot.fields._class._field->offset);	\
+    })
+#else
+#define _JC_VMFIELD(_vm, _obj, _class, _field, _type)			\
+	((_type *)((char *)(_obj)					\
+	    + _vm->boot.fields._class._field->offset))
+#define _JC_VMSTATICFIELD(_vm, _class, _field, _type)			\
+	((_type *)((char *)_vm->boot.types._class->u.nonarray		\
+	    .class_fields + _vm->boot.fields._class._field->offset))
+#endif
+
+/*
+ * How many references in a native reference frame.
+ *
+ * Do not change this, as the structure of 'struct _jc_native_frame'
+ * depends on it.
+ */
+#define _JC_NATIVE_REFS_PER_FRAME		29
+#define _JC_NATIVE_REFS_MIN_PER_FRAME		16	/* per the JNI spec */
+
+/*
+ * Maximum number of free thread structures to keep around.
+ */
+#define _JC_MAX_FREE_THREADS			128
+
+/*
+ * Length of thread status buffer (used for debugging).
+ */
+#define _JC_MAX_TEXT_STATUS			64
+
+/*
+ * Size of an uni-allocator page header.
+ */
+#define _JC_UNI_HDR_SIZE						\
+	_JC_ROUNDUP2(sizeof(_jc_uni_pages), _JC_FULL_ALIGNMENT)
+
+/*
+ * Minimum number of uni-allocator pages to grab when additional
+ * class loader memory is needed.
+ */
+#define _JC_CL_ALLOC_MIN_PAGES			32
+
+/*
+ * How many class loader implicit references to allocate at a time
+ */
+#define _JC_CL_ALLOC_IMPLICIT_REFS		32
+
+/*
+ * Short name for internal java.lang native library.
+ */
+#define _JC_INTERNAL_NATIVE_LIBRARY		"JC virtual machine"
+
+/*
+ * Number of pages to reserve for low memory situations where
+ * an OutOfMemoryError must be thrown.
+ */
+#define _JC_HEAP_RESERVED_PAGES			10
+
+/*
+ * How many heap pages to initialize at a time
+ */
+#define _JC_HEAP_INIT_PAGES(heap)					\
+	((heap)->num_pages == 0 ?					\
+	    (2 * 1024 * 1024 / _JC_PAGE_SIZE) :				\
+	    (heap)->max_pages / 8)
+
+/*
+ * Minimum number of references an object must contain before we
+ * consider putting in a skip word at the beginning of the heap block.
+ */
+#define _JC_SKIPWORD_MIN_REFS			3
+
+/*
+ * Bits defined for 'flags' field in a native reference frame.
+ * The lower three bits are defined here. The top 29 bits are
+ * used as a free entry bitmap.
+ */
+#define _JC_NATIVE_REF_ODD_BIT			0x00000001
+#define _JC_NATIVE_REF_STACK_ALLOC		0x00000002
+#define _JC_NATIVE_REF_EXTENSION		0x00000004
+#define _JC_NATIVE_REF_FREE_BITS		0xfffffff8
+
+#define _JC_NATIVE_REF_IS_FREE(frame, i)				\
+	(((frame)->flags & (1 << (i + 3))) != 0)
+#define _JC_NATIVE_REF_ANY_FREE(frame)					\
+	(((frame)->flags & _JC_NATIVE_REF_FREE_BITS) != 0)
+#define _JC_NATIVE_REF_ANY_USED(frame)					\
+	(((frame)->flags & _JC_NATIVE_REF_FREE_BITS)			\
+	    != _JC_NATIVE_REF_FREE_BITS)
+#define _JC_NATIVE_REF_MARK_FREE(frame, i)				\
+	((frame)->flags |= (1 << (i + 3)))
+#define _JC_NATIVE_REF_MARK_IN_USE(frame, i)				\
+	((frame)->flags &= ~(1 << (i + 3)))
+
+/*
+ * ELF types (32/64 bit)
+ */
+#undef Elf_Addr
+#undef Elf_Ehdr
+#undef Elf_Off
+#undef Elf_Rel
+#undef Elf_Rela
+#undef Elf_Shdr
+#undef Elf_Word
+#undef Elf_Sym
+#undef ELF_R_TYPE
+#undef ELF_R_SYM
+#if _JC_ELF_CLASS == ELFCLASS32
+#define Elf_Addr Elf32_Addr
+#define Elf_Ehdr Elf32_Ehdr
+#define Elf_Off Elf32_Off
+#define Elf_Rel Elf32_Rel
+#define Elf_Rela Elf32_Rela
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Word Elf32_Word
+#define Elf_Sym Elf32_Sym
+#define ELF_R_TYPE(x) ELF32_R_TYPE(x)
+#define ELF_R_SYM(x) ELF32_R_SYM(x)
+#elif _JC_ELF_CLASS == ELFCLASS64
+#define Elf_Addr Elf64_Addr
+#define Elf_Ehdr Elf64_Ehdr
+#define Elf_Off Elf64_Off
+#define Elf_Rel Elf64_Rel
+#define Elf_Rela Elf64_Rela
+#define Elf_Shdr Elf64_Shdr
+#define Elf_Word Elf64_Word
+#define Elf_Sym Elf64_Sym
+#define ELF_R_TYPE(x) ELF64_R_TYPE(x)
+#define ELF_R_SYM(x) ELF64_R_SYM(x)
+#else
+#error "Invalid value for _JC_ELF_CLASS"
+#endif
+
+/*
+ * Supported ELF line info debug sections supported.
+ */
+enum {
+	_JC_LINE_DEBUG_NONE,
+	_JC_LINE_DEBUG_DWARF1,
+	_JC_LINE_DEBUG_DWARF2,
+	_JC_LINE_DEBUG_STABS,
+};
+
+/* Stabs debugging section entry types */
+#define STAB_FUN		0x24
+#define STAB_SLINE		0x44
+
+/* DWARF 2.0 .debug_line sections definitions (partial list) */
+#define DW_LNE_end_sequence	1
+#define DW_LNE_set_address	2
+#define DW_LNS_copy		1
+#define DW_LNS_advance_pc	2
+#define DW_LNS_advance_line	3
+#define DW_LNS_const_add_pc	8
+#define DW_LNS_fixed_advance_pc	9
+
+/* Size of one page */
+#define _JC_PAGE_SIZE			(1 << _JC_PAGE_SHIFT)
+
+/* Convert page index to _jc_word pointer */
+#define _JC_PAGE_ADDR(ptr, i)						\
+	((_jc_word *)((char *)(ptr) + (i) * _JC_PAGE_SIZE))
+
+/* Convert page pointer to page index */
+#define _JC_PAGE_INDEX(heap, ptr)					\
+	(((char *)(ptr) - (char *)(heap)->pages) / _JC_PAGE_SIZE)
+
+/*
+ * Heap page info layout
+ * ---------------------
+ *
+ * Each page of the heap has an info word at its beginning, except for
+ * pages that are the second or later pages in a multi-page large object.
+ *
+ *   Bits	Meaning
+ *   ----	-------
+ *  30-31	00 = free, 01 = small, 10 = large, 11 = being allocated
+ *  24-29	SMALL: block size index
+ *   0-23	SMALL: next page in list (all ones for end of list)
+ *   0-29	LARGE: number of pages in the range
+ *   0-29	ALLOC: number of pages in the range being allocated
+ */
+#define _JC_HEAP_PTYPE_MASK		0xc0000000
+#define _JC_HEAP_PTYPE_SHIFT		30
+#define _JC_HEAP_NPAGES_MASK		0x3fffffff
+#define _JC_HEAP_NPAGES_SHIFT		0
+#define _JC_HEAP_BSI_MASK		0x3f000000
+#define _JC_HEAP_BSI_SHIFT		24
+#define _JC_HEAP_NEXT_MASK		0x00ffffff
+#define _JC_HEAP_NEXT_SHIFT		0
+
+/*
+ * Heap page types, contained in the 'PTYPE' bits.
+ */
+#define _JC_HEAP_PAGE_FREE		0
+#define _JC_HEAP_PAGE_SMALL		1
+#define _JC_HEAP_PAGE_LARGE		2
+#define _JC_HEAP_PAGE_ALLOC		3
+
+/*
+ * Heap block header/skip word (optional).
+ */
+#define _JC_HEAP_BTYPE_MASK		0x0000001f
+#define _JC_HEAP_BTYPE_SHIFT		0
+#define _JC_HEAP_SKIP_MASK		0xffffffe0
+#define _JC_HEAP_SKIP_SHIFT		5
+
+/*
+ * Values for BTYPE bits in the first word of a heap block.
+ *
+ * In the case of _JC_HEAP_BLOCK_SKIP, the upper 27 bits contain the offset
+ * in words from the start of the heap block to the object header.
+ *
+ * If the value of BTYPE is other than listed here, then the first word
+ * of the block is also the first word of the object.
+ */
+#define _JC_HEAP_BLOCK_FREE		0x00000001	/* free block */
+#define _JC_HEAP_BLOCK_ALLOC		0x00000003	/* being allocated */
+#define _JC_HEAP_BLOCK_SKIP		0x0000001f	/* skipword + object */
+
+/* Macros for extracting heap bits */
+#define _JC_HEAP_EXTRACT(w, fld)					\
+	(((_jc_word)(w) & _JC_HEAP_ ## fld ## _MASK)			\
+	    >> _JC_HEAP_ ## fld ## _SHIFT)
+#define _JC_HEAP_MAX(fld)						\
+	(((_jc_word)_JC_HEAP_ ## fld ## _MASK				\
+		>> _JC_HEAP_ ## fld ## _SHIFT) + 1)
+
+/* Determine if two pointers point within the same page */
+#define _JC_HEAP_SAME_PAGE(ptr1, ptr2)					\
+	((((_jc_word)(ptr1) ^ (_jc_word)(ptr2))				\
+	    & ~(_JC_PAGE_SIZE - 1)) == 0)
+
+/* Determine if an address lies within heap memory */
+#define _JC_IN_HEAP(heap, addr)						\
+	((char *)(addr) >= (char *)(heap)->pages			\
+	    && (char *)(addr) < (char *)(heap)->pages			\
+	      + ((heap)->num_pages * _JC_PAGE_SIZE))
+
+/* Offset from the start of a heap page to the start of the first block */
+#define _JC_HEAP_BLOCK_OFFSET						\
+    (_JC_HOWMANY(sizeof(_jc_word), _JC_FULL_ALIGNMENT) * _JC_FULL_ALIGNMENT)
+
+/*
+ * Random portability fixes.
+ */
+#ifndef ULLONG_MAX
+#define ULLONG_MAX	(~(unsigned long long)0)
+#endif
+#ifndef SIZE_T_MAX
+#define SIZE_T_MAX	(~(size_t)0)
+#endif
+#if HAVE_INTTYPES_H
+#include <inttypes.h>
+#ifdef PRIxFAST64
+#define _JC_JLONG_FMT	PRIxFAST64
+#else
+#define _JC_JLONG_FMT	"llx"		/* a guess */
+#endif
+#endif	/* HAVE_INTTYPES_H */
+
+#define _JC_LIBRARY_PATH	_JC_CLASSPATH_HOME "/lib/classpath"
+#define _JC_INCLUDE_DIR		_AC_INCLUDEDIR "/jc"
+#define _JC_BOOT_SOURCE_DIR	_AC_DATADIR "/jc/src"
+#define _JC_BOOT_OBJECT_DIR	_AC_LIBDIR "/jc/obj"
+
+#define _JC_BOOT_CLASS_PATH						\
+    _AC_DATADIR "/jc/jc.zip"						\
+    _JC_PATH_SEPARATOR _JC_CLASSPATH_HOME "/share/classpath/glibj.zip"	\
+    _JC_PATH_SEPARATOR _AC_DATADIR 					\
+	"/jc/sootclasses-" SOOT_VERSION ".jar"				\
+    _JC_PATH_SEPARATOR _AC_DATADIR					\
+	"/jc/jasminclasses-sable-" JASMIN_VERSION ".jar"		\
+    _JC_PATH_SEPARATOR _AC_DATADIR					\
+	"/jc/polyglot-" POLYGLOT_VERSION ".jar"
+
+/*
+ * Core classes that must be loaded by the boot loader.
+ */
+#define _JC_CORE_CLASS(name)						\
+	(strncmp((name), "java/", 5) == 0				\
+	    || strncmp((name), "gnu/java/", 9) == 0)
+
+/*
+ * Package object file name
+ */
+#define _JC_PACKAGE_OBJECT_NAME		"_package.o"
+
+/*
+ * Class path entry types.
+ */
+#define _JC_CPATH_UNKNOWN		0
+#define _JC_CPATH_DIRECTORY		1
+#define _JC_CPATH_ZIPFILE		2
+#define _JC_CPATH_ERROR			3
+
+/*
+ * Object path entry types.
+ */
+#define _JC_OBJPATH_UNKNOWN		0
+#define _JC_OBJPATH_DIRECTORY		1
+#define _JC_OBJPATH_ELFFILE		2
+#define _JC_OBJPATH_ERROR		3
+
+/*
+ * Macro to check if a PC value lies within a method.
+ */
+#define _JC_INMETHOD(meth, pc)						\
+	((pc) > (meth)->function && (pc) <= (meth)->function_end)
+
+/*
+ * Array bounds check for offset + length. Returns true if bounds are OK.
+ *
+ * We have to be careful because of potential 32-bit overflow.
+ */
+#define _JC_BOUNDS_CHECK(ary, off, len)					\
+    ({									\
+	const jint _alen = (ary)->length;				\
+	const jint _off = (off);					\
+	const jint _len = (len);					\
+	const jint _end = (_off + _len);				\
+									\
+	((_len | _off | _end) >= 0) && _end <= _alen;			\
+    })
+
+/*
+ * _JC_FULL_ALIGNMENT is the minimum alignment that satisfies all alignment
+ * requirements. This is also the aligment guaranteed by malloc().
+ */
+struct _jc_align {
+	char		c;
+	_jc_value	u;
+};
+#define _JC_FULL_ALIGNMENT						\
+	((char *)&((struct _jc_align *)0)->u - (char *)0)
+
+/* Bit mask for page alignment */
+#define _JC_PAGE_MASK	(_JC_PAGE_SIZE - 1)
+
+/*
+ * ELF symbol resolver function type.
+ */
+typedef jint	_jc_elf_resolver(_jc_env *env, void *arg,
+			const char *name, Elf_Addr *result);
+
+/*
+ * Splay tree node comparision function type.
+ */
+typedef int	_jc_splay_cmp_t(const void *item1, const void *item2);
+
+/*
+ * Store exception information in the thread structure.
+ */
+#define _JC_EX_STORE(env, e, fmt, args...)				\
+    do {								\
+	_jc_env *const _env = (env);					\
+									\
+	_env->ex.num = _JC_ ## e;					\
+	snprintf(_env->ex.msg, sizeof(_env->ex.msg), fmt , ## args);	\
+    } while (0)
+
+/*
+ * Allocate some memory on the stack, and throw a StackOverflowError
+ * if that fails. This does not directly check for stack overflow, which
+ * is especially hard to do in native threads. We rely on "reasonable"
+ * values being allocated, within the stack space used by internal code.
+ *
+ * If unsuccessful an exception is stored (not posted).
+ */
+#define _JC_STACK_ALLOC(env, size)					\
+    ({									\
+	_jc_env *const _env = (env);					\
+	void *_mem;							\
+									\
+	if ((_mem = alloca(size)) == NULL) { 				\
+		_env->ex.num = _JC_StackOverflowError;			\
+		*_env->ex.msg = '\0';					\
+	}								\
+	_mem;								\
+    })
+
+/*
+ * Macros for formatting arbitrary strings into stack-allocated buffers.
+ *
+ * If unsuccessful an exception is stored (not posted).
+ */
+#define _JC_FORMAT_STRING(env, fmt, args...)				\
+    ({									\
+	const char *const _fmt = (fmt);					\
+	size_t _len;							\
+	char *_buf;							\
+									\
+	/* Print into nonexistent buffer to compute length */		\
+	_len = snprintf(NULL, 0, _fmt , ## args);			\
+									\
+	/* Allocate buffer, then print into it */			\
+	if ((_buf = _JC_STACK_ALLOC((env), _len + 1)) != NULL)		\
+		sprintf(_buf, _fmt , ## args);				\
+									\
+	/* Return buffer */						\
+	_buf;								\
+    })
+
+#define _JC_FORMAT_STRINGV(env, fmt, args)				\
+    ({									\
+	const char *const _fmt = (fmt);					\
+	const va_list _args = (args);					\
+	size_t _len;							\
+	char *_buf;							\
+									\
+	/* Print into nonexistent buffer to compute length */		\
+	_len = vsnprintf(NULL, 0, _fmt, _args);				\
+									\
+	/* Allocate buffer, then print into it */			\
+	if ((_buf = _JC_STACK_ALLOC((env), _len + 1)) != NULL)		\
+		vsprintf(_buf, _fmt, _args);				\
+									\
+	/* Return buffer */						\
+	_buf;								\
+    })
+
+/*
+ * Macro for testing class, field, or method access flags.
+ */
+#define _JC_ACC_TEST(thing, flag)					\
+	(((thing)->access_flags & _JC_ACC_ ## flag) != 0)
+#define _JC_FLG_TEST(thing, flag)					\
+	(((thing)->flags & _JC_TYPE_ ## flag) != 0)
+
+/*
+ * Assertion macro.
+ */
+#ifndef NDEBUG
+#define _JC_ASSERT(x)							\
+    do {								\
+	if (!(x)) {							\
+		fprintf(stderr, "jc: assertion failure: %s\n", #x);	\
+		fprintf(stderr, "jc: location: file `%s' line %d\n",	\
+		    __FILE__, __LINE__);				\
+		abort();						\
+	}								\
+    } while (0)
+#else
+#define _JC_ASSERT(x)	do { } while (0)
+#endif
+
+/*
+ * Mutex macros, in debugging and normal versions.
+ */
+#ifndef NDEBUG
+#define _JC_MUTEX_LOCK(env, mutex)					\
+    do {								\
+	pthread_mutex_t *const _mutex = &(mutex);			\
+	_jc_env *const _env = (env);					\
+	int _r;								\
+									\
+	_JC_ASSERT(_env == NULL || (mutex ## _owner) != _env);		\
+	_r = pthread_mutex_lock(_mutex);				\
+	_JC_ASSERT(_r == 0);						\
+	(mutex ## _owner) = _env;					\
+    } while (0)
+#define _JC_MUTEX_UNLOCK(env, mutex)					\
+    do {								\
+	pthread_mutex_t *const _mutex = &(mutex);			\
+	_jc_env *const _env = (env);					\
+	int _r;								\
+									\
+	_JC_ASSERT((mutex ## _owner) == _env);				\
+	(mutex ## _owner) = NULL;					\
+	_r = pthread_mutex_unlock(_mutex);				\
+	_JC_ASSERT(_r == 0);						\
+    } while (0)
+#define _JC_MUTEX_ASSERT(env, mutex)					\
+    do {								\
+	_JC_ASSERT((mutex ## _owner) == (env));				\
+    } while (0)
+#define _JC_COND_WAIT(env, cond, mutex)					\
+    do {								\
+	pthread_cond_t *const _cond = &(cond);				\
+	pthread_mutex_t *const _mutex = &(mutex);			\
+	_jc_env *const _env = (env);					\
+	int _r;								\
+									\
+	_JC_ASSERT((mutex ## _owner) == _env);				\
+	(mutex ## _owner) = NULL;					\
+	_r = pthread_cond_wait(_cond, _mutex);				\
+	_JC_ASSERT(_r == 0);						\
+	_JC_ASSERT((mutex ## _owner) == NULL);				\
+	(mutex ## _owner) = _env;					\
+    } while (0)
+#define _JC_COND_TIMEDWAIT(env, cond, mutex, wakeup)			\
+    do {								\
+	pthread_cond_t *const _cond = &(cond);				\
+	pthread_mutex_t *const _mutex = &(mutex);			\
+	_jc_env *const _env = (env);					\
+	int _r;								\
+									\
+	_JC_ASSERT((mutex ## _owner) == _env);				\
+	(mutex ## _owner) = NULL;					\
+	_r = pthread_cond_timedwait(_cond, _mutex, (wakeup));		\
+	_JC_ASSERT(_r == 0 || _r == ETIMEDOUT);				\
+	_JC_ASSERT((mutex ## _owner) == NULL);				\
+	(mutex ## _owner) = _env;					\
+    } while (0)
+#define _JC_COND_SIGNAL(cond)						\
+    do {								\
+	pthread_cond_t *const _cond = &(cond);				\
+	int _r;								\
+									\
+	_r = pthread_cond_signal(_cond);				\
+	_JC_ASSERT(_r == 0);						\
+    } while (0)
+#define _JC_COND_BROADCAST(cond)					\
+    do {								\
+	pthread_cond_t *const _cond = &(cond);				\
+	int _r;								\
+									\
+	_r = pthread_cond_broadcast(_cond);				\
+	_JC_ASSERT(_r == 0);						\
+    } while (0)
+
+#else
+
+#define _JC_MUTEX_LOCK(env, mutex)	pthread_mutex_lock(&(mutex))
+#define _JC_MUTEX_UNLOCK(env, mutex)	pthread_mutex_unlock(&(mutex))
+#define _JC_MUTEX_ASSERT(env, mutex)	do { } while (0)
+#define _JC_COND_WAIT(env, cond, mutex)					\
+	pthread_cond_wait(&(cond), &(mutex))
+#define _JC_COND_TIMEDWAIT(env, cond, mutex, wakeup)			\
+	pthread_cond_timedwait(&(cond), &(mutex), (wakeup))
+#define _JC_COND_SIGNAL(cond)		pthread_cond_signal(&(cond))
+#define _JC_COND_BROADCAST(cond)	pthread_cond_broadcast(&(cond))
+#endif	/* NDEBUG */
+
+/*
+ * Verbosity.
+ */
+#define VERBOSE_INDX(indx, vm, fmt, args...)				\
+    do {								\
+	if (((vm)->verbose_flags & (1 << (indx))) != 0) {		\
+		_jc_printf((vm), "[verbose %s: " fmt "]\n",		\
+		    _jc_verbose_names[indx] , ## args);			\
+	}								\
+    } while (0)
+
+#define VERBOSE(flag, vm, fmt, args...)					\
+	VERBOSE_INDX(_JC_VERBOSE_ ## flag, vm, fmt , ## args)
+
+#endif	/* _DEFINITIONS_H_ */

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/derive.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/derive.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/derive.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/derive.c Tue Oct  4 19:19:16 2005
@@ -0,0 +1,903 @@
+
+/*
+ * 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.
+ *
+ * $Id: derive.c,v 1.20 2005/05/10 14:41:38 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/* Internal functions */
+static jint	_jc_derive_type(_jc_env *env, _jc_type *type,
+			_jc_type_node *node);
+static void	_jc_underive_type(_jc_env *env, _jc_type *type,
+			_jc_type_node *node);
+
+/*
+ * List of types that need to be specially recognized during garbage
+ * collection in order to handle implicit references. All under java.lang.
+ */
+static const char	*const _jc_special_classes[] = {
+	"Class",
+	"ClassLoader",
+	"VMThrowable",
+	"ref/Reference",
+	NULL
+};
+
+/*
+ * Given the bytes of a class file, derive the internal representation
+ * of the corresponding Java run-time type. This assumes the type node
+ * is in the loader's initiating types tree. We try to either find the
+ * type structure in an ELF file (possibly generating it on demand), or
+ * else we create one from the class file.
+ *
+ * If successful, the type is added to both the class loader's
+ * initiated and defined types trees.
+ *
+ * If unsuccessful, an exception is posted.
+ */
+_jc_type *
+_jc_derive_type_from_classfile(_jc_env *env, _jc_class_loader *loader,
+	const char *name, _jc_classbytes *cbytes)
+{
+	_jc_jvm *const vm = env->vm;
+	jboolean deriving_node = JNI_FALSE;
+	_jc_type *const key = (_jc_type *)((char *)&name
+	    - _JC_OFFSETOF(_jc_type, name));
+	_jc_super_info *supers = NULL;
+	_jc_class_node *cnode = NULL;
+	_jc_classfile *cfile;
+	_jc_type_node node;
+	_jc_type *type = NULL;
+	_jc_type *stype;
+	int i;
+
+	/* Parse class file */
+	if ((cfile = _jc_parse_classfile(env, cbytes, 1)) == NULL) {
+		_jc_post_exception_info(env);
+		goto fail;
+	}
+
+	/*
+	 * If name not explicitly supplied, get it from the classfile.
+	 * Otherwise, verify that the name matches what we expect.
+	 */
+	if (name == NULL)
+		name = cfile->name;
+	else if (strcmp(cfile->name, name) != 0) {
+		_jc_post_exception_msg(env, _JC_NoClassDefFoundError,
+		    "class file for `%s' actually defines `%s'",
+		    name, cfile->name);
+		goto fail;
+	}
+
+	/* The bootstrap loader must always be used for core Java types */
+	if (loader != vm->boot.loader && _JC_CORE_CLASS(name)) {
+		_jc_post_exception_msg(env, _JC_LinkageError,
+		    "type `%s' must be defined by the bootstrap loader", name);
+		goto fail;
+	}
+
+	/* Lock VM */
+	_JC_MUTEX_LOCK(env, vm->mutex);
+
+	/* Add class file to VM class file tree */
+	if ((cnode = _jc_ref_class_node(env,
+	    name, cbytes->hash, cbytes)) == NULL) {
+		_JC_MUTEX_UNLOCK(env, vm->mutex);
+		_jc_post_exception_info(env);
+		return NULL;
+	}
+
+	/* Unlock VM */
+	_JC_MUTEX_UNLOCK(env, vm->mutex);
+
+	/* Create a temporary fake type node for the deriving types tree */
+	memset(&node, 0, sizeof(node));
+	node.type = (_jc_type *)((char *)&name - _JC_OFFSETOF(_jc_type, name));
+
+	/* Lock loader */
+	_JC_MUTEX_LOCK(env, loader->mutex);
+
+	/* Has this loader already been recorded as an initiating loader? */
+	if (_jc_splay_find(&loader->initiated_types, &node) != NULL) {
+		_JC_MUTEX_UNLOCK(env, loader->mutex);
+		_jc_post_exception_msg(env, _JC_LinkageError,
+		    "type `%s' has already been defined", name);
+		goto fail;
+	}
+
+	/* Detect attempts to recursively derive the same type */
+	if (_jc_splay_find(&loader->deriving_types, &node) != NULL) {
+		_JC_MUTEX_UNLOCK(env, loader->mutex);
+		_jc_post_exception_msg(env, _JC_ClassCircularityError,
+		    "class `%s'", name);
+		goto fail;
+	}
+
+	/* Sanity check */
+	_JC_ASSERT(_jc_splay_find(&loader->defined_types, node.type) == NULL);
+
+	/* Add node to partially derived types tree */
+	_jc_splay_insert(&loader->deriving_types, &node);
+	deriving_node = JNI_TRUE;
+
+	/* Unlock loader */
+	_JC_MUTEX_UNLOCK(env, loader->mutex);
+
+	/* Allocate structure for temporarily saving super types */
+	if (!vm->loader_enabled || !vm->generation_enabled) {
+		if ((supers = _jc_vm_alloc(env,
+		    sizeof(*supers) + cfile->num_interfaces
+		      * sizeof(*supers->interfaces))) == NULL) {
+			_jc_post_exception_info(env);
+			goto fail;
+		}
+	}
+
+	/* Skip loading superclass for java.lang.Object */
+	if (cfile->superclass == NULL) {
+		stype = NULL;
+		goto no_superclass;
+	}
+
+	/* Load and validate superclass */
+	if ((stype = _jc_load_type(env, loader, cfile->superclass)) == NULL)
+		goto fail;
+	if ((_JC_ACC_TEST(cfile, INTERFACE) && stype != vm->boot.types.Object)
+	    || (stype->access_flags & (_JC_ACC_INTERFACE|_JC_ACC_FINAL)) != 0) {
+		_jc_post_exception_msg(env, _JC_IncompatibleClassChangeError,
+		    "%s `%s' cannot be the superclass of `%s'",
+		    _JC_ACC_TEST(stype, INTERFACE) ?
+		      "interface" : "final class", stype->name, name);
+		goto fail;
+	}
+	if (supers != NULL)
+		supers->superclass = stype;
+
+no_superclass:
+	/* Load and validate superinterfaces */
+	for (i = 0; i < cfile->num_interfaces; i++) {
+		_jc_type *siface;
+
+		if ((siface = _jc_load_type(env,
+		    loader, cfile->interfaces[i])) == NULL)
+			goto fail;
+		if (!_JC_ACC_TEST(siface, INTERFACE)) {
+			_jc_post_exception_msg(env,
+			    _JC_IncompatibleClassChangeError, "non-interface"
+			    " class `%s' cannot be a superinterface of `%s'",
+			    siface->name, name);
+			goto fail;
+		}
+		if (supers != NULL)
+			supers->interfaces[i] = siface;
+	}
+
+	/* Loading supertypes may have loaded ELF object with type as well */
+	_JC_MUTEX_LOCK(env, loader->mutex);
+	type = _jc_splay_find(&loader->defined_types, key);
+	_JC_MUTEX_UNLOCK(env, loader->mutex);
+	if (type != NULL)
+		goto done;
+
+	/* If the ELF loader is disabled, we must interpret */
+	if (!vm->loader_enabled)
+		goto create_type;
+
+	/* Try to load an ELF object containing the type */
+	if (_jc_load_object(env, loader, name) == JNI_OK)
+		goto find_type;
+
+	/* If something unexpected happened, bail out */
+	if (env->ex.num != _JC_LinkageError) {
+		_jc_post_exception_info(env);
+		goto fail;
+	}
+
+	/* If on-demand object generation is disabled, interpret */
+	if (!vm->generation_enabled)
+		goto create_type;
+
+	/* Generate a new ELF object file for this class */
+	if (_jc_generate_object(env, loader, name) != JNI_OK)
+		goto fail;
+
+	/* Try again to load object file containing the type */
+	if (_jc_load_object(env, loader, name) != JNI_OK) {
+		_jc_post_exception_info(env);
+		goto fail;
+	}
+
+find_type:
+	/*
+	 * We've done our best to load the right ELF object.
+	 * Look in the types tree to see if our type is there.
+	 */
+	_JC_MUTEX_LOCK(env, loader->mutex);
+	type = _jc_splay_find(&loader->defined_types, key);
+	_JC_MUTEX_UNLOCK(env, loader->mutex);
+	if (type == NULL) {
+		_jc_post_exception_msg(env, _JC_LinkageError,
+		    "no ELF object found containing `%s'", name);
+		goto fail;
+	}
+
+	/* Save super types (so we can access them before resolution) */
+	type->u.nonarray.supers = supers;
+	supers = NULL;
+
+	/* Done */
+	goto done;
+
+create_type:
+	/*
+	 * We are unable or unwilling to find or create an ELF object.
+	 * We must interpret this Java class.
+	 */
+	if ((type = _jc_derive_type_interp(env, loader, cbytes)) == NULL) {
+		_jc_post_exception_info(env);
+		goto fail;
+	}
+	goto done;
+
+fail:
+	_JC_ASSERT(type == NULL);
+
+done:
+	/* Remove node from the loader's deriving types tree */
+	if (deriving_node) {
+		_JC_MUTEX_LOCK(env, loader->mutex);
+		_jc_splay_remove(&loader->deriving_types, &node);
+		_JC_MUTEX_UNLOCK(env, loader->mutex);
+	}
+
+	/* Unreference class file in VM class file tree */
+	_JC_MUTEX_LOCK(env, vm->mutex);
+	_jc_unref_class_node(vm, &cnode);
+	_JC_MUTEX_UNLOCK(env, vm->mutex);
+
+	/* Destroy parsed class file */
+	_jc_destroy_classfile(&cfile);
+
+	/* If this thread wants to save class file, save it */
+	if (type == NULL) {
+		_jc_class_save *csave;
+
+		for (csave = env->class_save;
+		    csave != NULL; csave = csave->next) {
+			if (strcmp(csave->name, name) == 0) {
+				_JC_ASSERT(csave->bytes == NULL);
+				csave->bytes = _jc_dup_classbytes(cbytes);
+				break;
+			}
+		}
+	}
+
+	/* Free leftover supers info (if any) */
+	_jc_vm_free(&supers);
+
+	/* Done */
+	_JC_ASSERT(type == NULL || _JC_FLG_TEST(type, LOADED));
+	return type;
+}
+
+/*
+ * Given an object file, load all the types defined in that file at once.
+ *
+ * If unsuccessful an exception is stored.
+ */
+jint
+_jc_derive_types_from_object(_jc_env *env, _jc_elf *elf)
+{
+	_jc_jvm *const vm = env->vm;
+	const int num_types = elf->types.size;
+	_jc_class_loader *const loader = elf->loader;
+	_jc_type_node *nodes = NULL;
+	_jc_type **types;
+	int i;
+
+	/* Get the list of types defined in this object */
+	if ((types = _JC_STACK_ALLOC(env, num_types * sizeof(*types))) == NULL)
+		return JNI_ERR;
+	_jc_splay_list(&elf->types, (void **)types);
+
+	/* Point types at ELF file and verify object versions */
+	for (i = 0; i < num_types; i++) {
+		_jc_type *const type = types[i];
+
+		type->u.nonarray.u.elf = elf;
+		if (type->u.nonarray.block_size_index != _JC_LIBJC_VERSION) {
+			_JC_EX_STORE(env, LinkageError,
+			    "type `%s' in ELF object `%s' was created from an"
+			    " incompatible `_jc_defs.h' version 0x%04x !="
+			    " 0x%04x", type->name, elf->pathname,
+			    type->u.nonarray.block_size_index,
+			    _JC_LIBJC_VERSION);
+			return JNI_ERR;
+		}
+	}
+
+	/* Lock loader */
+	_JC_MUTEX_LOCK(env, loader->mutex);
+
+	/* Verify that all types defined in the object are not yet loaded */
+	for (i = 0; i < num_types; i++) {
+		_jc_type *const type = types[i];
+		_jc_type *otype;
+
+		if ((otype = _jc_splay_find(&loader->defined_types,
+		    type)) != NULL) {
+			_JC_EX_STORE(env, LinkageError,
+			    "can't load `%s' because it defines the type `%s'"
+			    " which was already defined by the previously"
+			    " loaded object `%s'", elf->pathname, type->name,
+			    otype->u.nonarray.u.elf->pathname);
+			goto fail;
+		}
+	}
+
+	/* Allocate and initialize type nodes */
+	if ((nodes = _jc_cl_alloc(env, loader,
+	    num_types * sizeof(*nodes))) == NULL)
+		goto fail;
+	for (i = 0; i < num_types; i++) {
+		_jc_type_node *const node = &nodes[i];
+
+		/* Initialize node */
+		node->type = types[i];
+		node->thread = NULL;
+#ifndef NDEBUG
+		memset(&node->node, 0, sizeof(node->node));
+#endif
+	}
+
+	/* Derive all types; if something fails, un-do everything */
+	for (i = 0; i < num_types; i++) {
+		_jc_type_node *const node = &nodes[i];
+		_jc_type *const type = types[i];
+
+		if (_jc_derive_type(env, type, node) != JNI_OK) {
+			while (--i > 0)
+				_jc_underive_type(env, types[i], &nodes[i]);
+			goto fail;
+		}
+	}
+
+	/* Unlock loader */
+	_JC_MUTEX_UNLOCK(env, loader->mutex);
+
+	/* Verbosity */
+	if ((vm->verbose_flags & (1 << _JC_VERBOSE_OBJ)) != 0) {
+		if (num_types == 1) {
+			_jc_printf(vm, "[verbose %s: loaded `%s' from `%s']\n",
+			    _jc_verbose_names[_JC_VERBOSE_OBJ], types[0]->name,
+			    elf->pathname);
+		} else {
+			_jc_printf(vm, "[verbose %s: types loaded from `%s':\n",
+			    _jc_verbose_names[_JC_VERBOSE_OBJ], elf->pathname);
+			for (i = 0; i < num_types; i++) {
+				_jc_type *const type = types[i];
+
+				_jc_printf(vm, "\t%s%s\n", type->name,
+				    i == num_types - 1 ? "]" : "");
+			}
+		}
+	}
+
+	/* Done */
+	return JNI_OK;
+
+fail:
+	/* Attempt to give back class loader memory */
+	_jc_cl_unalloc(loader, &nodes, num_types * sizeof(*nodes));
+
+	/* Done */
+	_JC_MUTEX_UNLOCK(env, loader->mutex);
+	return JNI_ERR;
+}
+
+/*
+ * Derive a non-array type. This fills in all the runtime field of
+ * the _jc_type structure and adds the type to the derived types tree.
+ *
+ * If unsuccessful an exception is stored.
+ *
+ * NOTE: This assumes the type's class loader mutex is locked.
+ */
+static jint
+_jc_derive_type(_jc_env *env, _jc_type *type, _jc_type_node *node)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_nonarray_type *const ntype = &type->u.nonarray;
+	_jc_class_loader *const loader = type->loader;
+	_jc_class_node *cnode;
+	int i;
+
+	/* Sanity check */
+	_JC_ASSERT(!_JC_FLG_TEST(type, ARRAY));
+	_JC_ASSERT(!_JC_FLG_TEST(type, LOADED));
+	_JC_MUTEX_ASSERT(env, loader->mutex);
+
+	/*
+	 * Create the java.lang.Class instance for this type, unless during
+	 * initialization when java.lang.Class hasn't been loaded yet.
+	 */
+	if ((vm->initialization == NULL || vm->initialization->create_class)
+	    && _jc_create_class_instance(env, type) != JNI_OK)
+		return JNI_ERR;
+
+	/* Create mtable if needed (i.e., if interpreter is enabled) */
+	if (!_JC_ACC_TEST(type, INTERFACE)
+	    && (!vm->loader_enabled || !vm->generation_enabled)) {
+
+		/* Allocate mtable */
+		if ((ntype->mtable = _jc_cl_alloc(env, loader,
+		    ntype->num_vmethods * sizeof(*ntype->mtable))) == NULL)
+			return JNI_ERR;
+
+		/* Fill in this class' portion */
+		for (i = 0; i < ntype->num_methods; i++) {
+			_jc_method *const method = ntype->methods[i];
+
+			if (_JC_ACC_TEST(method, STATIC)
+			    || *method->name == '<')
+			    	continue;
+			_JC_ASSERT(method->vtable_index < ntype->num_vmethods);
+			_JC_ASSERT(type->vtable[method->vtable_index]
+			    == method->function);
+			ntype->mtable[method->vtable_index] = method;
+		}
+	}
+
+	/* Lock VM */
+	_JC_MUTEX_LOCK(env, vm->mutex);
+
+	/* Add reference to the type's class file in the VM class file tree */
+	if ((cnode = _jc_ref_class_node(env,
+	    type->name, ntype->hash, NULL)) == NULL) {
+		_JC_MUTEX_UNLOCK(env, vm->mutex);
+		goto fail;
+	}
+
+	/* Add reference to all other class files this type depends on */
+	for (i = 0; i < ntype->num_class_depends; i++) {
+		_jc_class_depend *const dep
+		    = &type->u.nonarray.class_depends[i];
+
+		/* Find/create class file node and add reference to it */
+		if (_jc_ref_class_node(env,
+		    dep->name, dep->hash, NULL) != NULL)
+			continue;
+
+		/* Failed; un-reference previously referenced class nodes */
+		_jc_unref_class_deps(vm, ntype->class_depends, i);
+		_jc_unref_class_node(vm, &cnode);
+
+		/* Bail out */
+		_JC_MUTEX_UNLOCK(env, vm->mutex);
+		goto fail;
+	}
+
+	/* Add this class' methods to the VM method tree */
+	for (i = 0; i < ntype->num_methods; i++) {
+		_jc_method *method = ntype->methods[i];
+
+		/* Add method to the method tree if it exists */
+		if (method->function != NULL)
+			_jc_splay_insert(&vm->method_tree, method);
+	}
+
+	/* Unlock VM */
+	_JC_MUTEX_UNLOCK(env, vm->mutex);
+
+	/* Initialize heap block size index skip word flag */
+	if (!_JC_ACC_TEST(type, ABSTRACT))
+		_jc_initialize_bsi(vm, type);
+
+	/* Add node to the loader's initiated types tree */
+	_jc_splay_insert(&loader->initiated_types, node);
+
+	/* Remove type from the ELF file's unloaded types tree */
+	_jc_splay_remove(&ntype->u.elf->types, type);
+
+	/* Add type to the loader's defined types tree */
+	_jc_splay_insert(&loader->defined_types, type);
+
+	/* Point type node at real type */
+	_JC_ASSERT(strcmp(node->type->name, type->name) == 0);
+	node->type = type;
+
+	/* Add reference to ELF file */
+	_jc_elf_addref(ntype->u.elf);
+
+	/* Set type loaded flag */
+	type->flags |= _JC_TYPE_LOADED;
+
+	/* Done */
+	return JNI_OK;
+
+fail:
+	/* Give back Class object memory */
+	if (vm->initialization == NULL || vm->initialization->create_class) {
+		_jc_cl_unalloc(loader, &type->instance,
+		    vm->boot.types.Class->u.nonarray.instance_size);
+	}
+
+	/* Done */
+	return JNI_ERR;
+}
+
+/*
+ * Reverse the effects of _jc_derive_type().
+ *
+ * NOTE: This assumes the type's class loader mutex is locked.
+ */
+static void
+_jc_underive_type(_jc_env *env, _jc_type *type, _jc_type_node *node)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_nonarray_type *const ntype = &type->u.nonarray;
+	_jc_class_loader *const loader = type->loader;
+	_jc_class_node key;
+	_jc_class_node *cnode;
+	int i;
+
+	/* Sanity check */
+	_JC_ASSERT(!_JC_FLG_TEST(type, ARRAY));
+	_JC_ASSERT(_JC_FLG_TEST(type, LOADED));
+	_JC_ASSERT(type->instance != NULL
+	    || (vm->initialization != NULL
+	      && !vm->initialization->create_class));
+	_JC_MUTEX_ASSERT(env, loader->mutex);
+
+	/* Unset type loaded flag */
+	type->flags &= ~_JC_TYPE_LOADED;
+
+	/* Remove type from the loader's defined types tree */
+	_jc_splay_remove(&loader->defined_types, type);
+
+	/* Put type back in ELF file's unloaded types tree */
+	_jc_splay_insert(&ntype->u.elf->types, type);
+
+	/* Remove type node from the loader's initiated types tree */
+	_jc_splay_remove(&loader->initiated_types, node);
+
+	/* Unreference ELF file */
+	_jc_elf_unref(&ntype->u.elf);
+
+	/* Lock VM */
+	_JC_MUTEX_LOCK(env, vm->mutex);
+
+	/* Unreference class file in VM class file tree */
+	key.name = type->name;
+	cnode = _jc_splay_find(&vm->classfiles, &key);
+	_JC_ASSERT(node != NULL);
+	_jc_unref_class_node(vm, &cnode);
+
+	/* Unreference class file dependencies */
+	_jc_unref_class_deps(vm, ntype->class_depends,
+	    ntype->num_class_depends);
+
+	/* Remove class' methods from the VM method tree */
+	for (i = 0; i < ntype->num_methods; i++) {
+		_jc_method *method = ntype->methods[i];
+
+		/* Add method to the method tree if it exists */
+		if (method->function != NULL)
+			_jc_splay_remove(&vm->method_tree, method);
+	}
+
+	/* Unlock VM */
+	_JC_MUTEX_UNLOCK(env, vm->mutex);
+
+	/* Give back java.lang.Class object memory */
+	if (vm->initialization == NULL || vm->initialization->create_class) {
+		_jc_cl_unalloc(loader, &type->instance,
+		    vm->boot.types.Class->u.nonarray.instance_size);
+	}
+}
+
+/*
+ * Derive an array type using the supplied loader.
+ */
+_jc_type *
+_jc_derive_array_type(_jc_env *env, _jc_class_loader *loader, const char *name)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_type *const obj_type = vm->boot.types.Object;
+	_jc_type *elem_type = NULL;
+	_jc_type *type = NULL;
+	const char *base_name;
+	_jc_type *base_type;
+	_jc_type_node *node;
+	_jc_type_node key;
+	u_char base_ptype;
+	void *mark;
+	int dims;
+
+	/* Sanity check */
+	_JC_ASSERT(vm->boot.types.Object != NULL);
+	_JC_ASSERT(*name == '[');
+
+	/* Count number of dimensions and get base class name */
+	for (base_name = name; *++base_name == '['; );
+	dims = base_name - name;
+
+	/* Check number of dimensions */
+	if (dims < 0 || dims > 255) {
+		_jc_post_exception_msg(env, _JC_NoClassDefFoundError,
+		    "array type has too many (%d) dimensions: %s",
+		    dims, name);
+		return NULL;
+	}
+
+	/* Remaining class name must not contain any '[' characters */
+	if (strchr(base_name, '[') != NULL) {
+		_jc_post_exception_msg(env, _JC_NoClassDefFoundError,
+		    "%s", name);
+		return NULL;
+	}
+
+	/* Recursively load element type if multi-dimensional */
+	if (dims > 1) {
+		if ((elem_type = _jc_load_type(env, loader, name + 1)) == NULL)
+			return NULL;
+		base_type = elem_type->u.array.base_type;
+		goto got_elem_type;
+	}
+
+	/* Create/find base type */
+	base_ptype = _jc_sig_types[(u_char)*base_name];
+	switch (base_ptype) {
+	case _JC_TYPE_BOOLEAN:
+	case _JC_TYPE_BYTE:
+	case _JC_TYPE_CHAR:
+	case _JC_TYPE_SHORT:
+	case _JC_TYPE_INT:
+	case _JC_TYPE_LONG:
+	case _JC_TYPE_FLOAT:
+	case _JC_TYPE_DOUBLE:
+		if (base_name[1] != '\0')
+			goto invalid;
+		base_type = vm->boot.types.prim[base_ptype];
+		_JC_ASSERT(base_type != NULL);
+		break;
+	case _JC_TYPE_REFERENCE:
+	    {
+		const size_t base_name_len = strlen(base_name);
+		char *bname;
+
+		/* Extract base class name */
+		if (base_name[0] != 'L'
+		    || base_name_len < 3
+		    || base_name[base_name_len - 1] != ';')
+			goto invalid;
+		if ((bname = _JC_STACK_ALLOC(env, base_name_len - 1)) == NULL) {
+			_jc_post_exception_info(env);
+			return NULL;
+		}
+		memcpy(bname, base_name + 1, base_name_len - 2);
+		bname[base_name_len - 2] = '\0';
+
+		/* Load/find base class */
+		if ((base_type = _jc_load_type(env, loader, bname)) == NULL)
+			return NULL;
+		break;
+	    }
+	default:
+	invalid:
+		_jc_post_exception_msg(env, _JC_NoClassDefFoundError,
+		    "invalid class name: %s", name);
+		return NULL;
+	}
+	elem_type = base_type;
+
+got_elem_type:
+	/*
+	 * The array type's defining loader is the same as it's base type.
+	 * If this is different from the initiating loader, then load the
+	 * type via the defining loader first. This ensures that the type
+	 * ends up in the defining loader's initiated types tree as required.
+	 */
+	if (base_type->loader != loader) {
+		if ((type = _jc_load_type(env,
+		    base_type->loader, name)) == NULL)
+			return NULL;
+		return type;
+	}
+
+	/* Lock loader and mark memory */
+	_JC_MUTEX_LOCK(env, loader->mutex);
+	mark = _jc_uni_mark(&loader->uni);
+
+	/* Check whether another thread has beaten us to the punch */
+	key.type = (_jc_type *)((char *)&name - _JC_OFFSETOF(_jc_type, name));
+	_JC_ASSERT(_jc_splay_find(&loader->deriving_types, &key) == NULL);
+	if ((type = _jc_splay_find(&loader->defined_types, key.type)) != NULL) {
+		_JC_MUTEX_UNLOCK(env, loader->mutex);
+		return type;
+	}
+
+	/*
+	 * Allocate memory for the new type descriptor plus a copy of
+	 * java.lang.Object's vtable (and mtable if Object is interpreted).
+	 */
+	_JC_ASSERT(obj_type->u.nonarray.num_vmethods != 0);
+	if ((type = _jc_cl_alloc(env, loader,
+	    sizeof(*type) + obj_type->u.nonarray.num_vmethods
+	      * sizeof(*type->vtable))) == NULL)
+		goto fail;
+
+	/* Initialize type */
+	memset(type, 0, sizeof(*type));
+	if ((type->name = _jc_cl_strdup(env, loader, name)) == NULL)
+		goto fail;
+	type->loader = loader;
+	type->superclass = vm->boot.types.Object;
+	type->u.array.dimensions = dims;
+	type->u.array.base_type = base_type;
+	type->u.array.element_type = elem_type;
+	type->access_flags = base_type->access_flags
+	    & (_JC_ACC_PUBLIC|_JC_ACC_PROTECTED|_JC_ACC_PRIVATE);
+	type->access_flags |= _JC_ACC_FINAL | _JC_ACC_ABSTRACT;
+	type->flags = (_JC_TYPE_ARRAY | _JC_TYPE_REFERENCE)
+	    | _JC_TYPE_RESOLVED | _JC_TYPE_VERIFIED | _JC_TYPE_PREPARED
+	    | _JC_TYPE_INITIALIZED | _JC_TYPE_LOADED;
+	type->initial_lockword =
+	    ((elem_type->flags & _JC_TYPE_MASK) << _JC_LW_TYPE_SHIFT)
+	    | _JC_LW_LIVE_BIT | _JC_LW_KEEP_BIT
+	    | _JC_LW_ARRAY_BIT | _JC_LW_ODD_BIT;
+
+	/* Copy Object's vtable */
+	memcpy(type->vtable, obj_type->vtable,
+	    obj_type->u.nonarray.num_vmethods * sizeof(*type->vtable));
+
+	/* Copy java.lang.Object's interface method lookup info */
+	_JC_ASSERT(vm->boot.array.interfaces != NULL);
+	type->num_interfaces = vm->boot.array.num_interfaces;
+	type->interfaces = vm->boot.array.interfaces;
+	type->imethod_hash_table = vm->boot.array.imethod_hash_table;
+	type->imethod_quick_table = vm->boot.array.imethod_quick_table;
+
+	/* Initialize type node */
+	if ((node = _jc_cl_zalloc(env, loader, sizeof(*node))) == NULL)
+		goto fail;
+	memset(node, 0, sizeof(*node));
+	node->type = type;
+
+	/* Create Class instance (unless Class itself is not loaded yet) */
+	if ((vm->initialization == NULL || vm->initialization->create_class)
+	    && _jc_create_class_instance(env, type) != JNI_OK)
+		goto fail;
+
+	/* Add type node to the loader's initiated types tree */
+	_jc_splay_insert(&loader->initiated_types, node);
+
+	/* Add type to the loader's defined types tree */
+	_jc_splay_insert(&loader->defined_types, type);
+
+	/* Unlock loader */
+	_JC_MUTEX_UNLOCK(env, loader->mutex);
+
+	/* Done */
+	return type;
+
+fail:
+	/* Give back loader memory */
+	_jc_uni_reset(&loader->uni, mark);
+
+	/* Unlock loader */
+	_JC_MUTEX_UNLOCK(env, loader->mutex);
+
+	/* Post exception and exit */
+	_jc_post_exception_info(env);
+	return NULL;
+}
+
+/*
+ * Initialize the lockword for a class (i.e., non-array, non-interface) type.
+ * We initialize abstract class lockwords even though they are never directly
+ * used. This is so concrete subclasses can use some of the lockword bits.
+ */
+void
+_jc_initialize_lockword(_jc_env *env, _jc_type *type, _jc_type *stype)
+{
+	_jc_word lockword = 0;
+	int ref_count_field;
+
+	/* Sanity check */
+	_JC_ASSERT(!_JC_FLG_TEST(type, ARRAY));
+	_JC_ASSERT(!_JC_ACC_TEST(type, INTERFACE));
+	_JC_ASSERT(stype == NULL || stype->initial_lockword != 0);
+
+	/* Set number of reference fields */
+	ref_count_field =
+	    type->u.nonarray.num_virtual_refs < _JC_LW_MAX(REF_COUNT) - 1 ?
+	      type->u.nonarray.num_virtual_refs : _JC_LW_MAX(REF_COUNT) - 1;
+	lockword |= ref_count_field << _JC_LW_REF_COUNT_SHIFT;
+
+	/* java.lang.Object gets neither SPECIAL nor FINALIZE bits */
+	if (stype == NULL)
+		goto no_superclass;
+
+	/*
+	 * If superclass is special, then so is this class. All
+	 * top level special classes are in the java.lang package.
+	 */
+	if (_JC_LW_TEST(stype->initial_lockword, SPECIAL))
+		lockword |= _JC_LW_SPECIAL_BIT;
+	else if (strncmp(type->name, "java/lang/", 10) == 0) {
+		const char *const subname = type->name + 10;
+		const char *const *sp;
+
+		/* See if this class is listed as special */
+		for (sp = _jc_special_classes; *sp != NULL; sp++) {
+			if (strcmp(subname, *sp) == 0) {
+				lockword |= _JC_LW_SPECIAL_BIT;
+				break;
+			}
+		}
+	}
+
+	/* Determine if class or a superclass overrides Object.finalize() */
+	if (_JC_LW_TEST(stype->initial_lockword, FINALIZE)
+	    || _jc_get_declared_method(env, type,
+	      "finalize", "()V", _JC_ACC_STATIC, 0) != NULL)
+		lockword |= _JC_LW_FINALIZE_BIT;
+
+no_superclass:
+	/* Set type bits and odd bit */
+	lockword |= (_JC_TYPE_REFERENCE << _JC_LW_TYPE_SHIFT)
+	    | _JC_LW_LIVE_BIT | _JC_LW_KEEP_BIT | _JC_LW_ODD_BIT;
+
+	/* Done */
+	type->initial_lockword = lockword;
+}
+
+/*
+ * Initialize heap block size index for a class and set the
+ * _JC_TYPE_SKIPWORD flag in type->flags if appropriate.
+ */
+void
+_jc_initialize_bsi(_jc_jvm *vm, _jc_type *type)
+{
+	_jc_nonarray_type *const ntype = &type->u.nonarray;
+	int block_size;
+	int bsi;
+
+	/* Sanity check */
+	_JC_ASSERT(!_JC_FLG_TEST(type, ARRAY));
+	_JC_ASSERT(!_JC_ACC_TEST(type, ABSTRACT));
+
+	/* Get block size index */
+	bsi = _jc_heap_block_size(vm, ntype->instance_size);
+
+	/* Reverse-engineer actual block size */
+	block_size = bsi < 0 ?
+	    ((-bsi * _JC_PAGE_SIZE) - _JC_HEAP_BLOCK_OFFSET) :
+	    vm->heap.sizes[bsi].size;
+
+	/* Determine if there's room for a skip word */
+	if (block_size - sizeof(_jc_word) >= ntype->instance_size
+	    && ntype->num_virtual_refs >= _JC_SKIPWORD_MIN_REFS)
+		type->flags |= _JC_TYPE_SKIPWORD;
+
+	/* Done */
+	ntype->block_size_index = bsi;
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/derive2.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/derive2.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/derive2.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/derive2.c Tue Oct  4 19:19:16 2005
@@ -0,0 +1,450 @@
+
+/*
+ * 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.
+ *
+ * $Id: derive2.c,v 1.4 2005/05/08 21:12:07 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/*
+ * This file performs class derivation for interpreted classes.
+ * I.e., it is the non-ELF equivalent of derive.c.
+ */
+
+/* Internal functions */
+static jint	_jc_derive_fields(_jc_env *env, _jc_type *type);
+static jint	_jc_derive_methods(_jc_env *env, _jc_type *type);
+
+/*
+ * Given a class file, create a corresponding internal representation
+ * of the Java run-time type. This is done when there is no ELF object
+ * available, so we have to create the type structure at runtime and
+ * interpret the class' bytecode for method execution.
+ *
+ * If unsuccessful, an exception is stored.
+ */
+_jc_type *
+_jc_derive_type_interp(_jc_env *env,
+	_jc_class_loader *loader, _jc_classbytes *cbytes)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_class_node *cnode = NULL;
+	int num_class_vmethods;
+	int num_super_vmethods;
+	int num_vmethods;
+	_jc_nonarray_type *ntype;
+	_jc_type **interfaces;
+	_jc_type *superclass;
+	_jc_classfile *cfile;
+	_jc_type_node node_key;
+	_jc_type_node *node;
+	size_t virtual_offset;
+	size_t static_offset;
+	int vtable_index;
+	_jc_type *type;
+	void *mark;
+	int i;
+
+	/* Parse class file */
+	if ((cfile = _jc_parse_classfile(env, cbytes, 2)) == NULL)
+		return NULL;
+
+	/* Lock loader */
+	_JC_MUTEX_LOCK(env, loader->mutex);
+
+	/* Mark top of class loader memory */
+	mark = _jc_uni_mark(&loader->uni);
+
+	/* Get superclass (it should already be loaded) */
+	if (cfile->superclass != NULL) {
+		node_key.type = (_jc_type *)((char *)&cfile->superclass
+		    - _JC_OFFSETOF(_jc_type, name));
+		node = _jc_splay_find(&loader->initiated_types, &node_key);
+		_JC_ASSERT(node != NULL && node->type != NULL);
+		superclass = node->type;
+	} else
+		superclass = NULL;
+
+	/* Get interfaces (they should already be loaded) */
+	if (cfile->num_interfaces > 0) {
+
+		/* Allocate array */
+		if ((interfaces = _JC_STACK_ALLOC(env, cfile->num_interfaces
+		    * sizeof(*interfaces))) == NULL)
+			goto fail;
+
+		/* Fill array */
+		for (i = 0; i < cfile->num_interfaces; i++) {
+			node_key.type = (_jc_type *)((char *)&cfile
+			    ->interfaces[i] - _JC_OFFSETOF(_jc_type, name));
+			node = _jc_splay_find(&loader->initiated_types,
+			    &node_key);
+			_JC_ASSERT(node != NULL && node->type != NULL);
+			interfaces[i] = node->type;
+		}
+	} else
+		interfaces = NULL;
+
+	/* Compute the size of this class' vtable */
+	num_class_vmethods = 0;
+	num_super_vmethods = 0;
+	if (!_JC_ACC_TEST(cfile, INTERFACE)) {
+
+		/* Get total virtual methods in all superclasses */
+		if (superclass != NULL) {
+			num_super_vmethods
+			    = superclass->u.nonarray.num_vmethods;
+		}
+
+		/* Count virtual methods in this class */
+		for (i = 0; i < cfile->num_methods; i++) {
+			_jc_cf_method *const method = &cfile->methods[i];
+
+			if (!_JC_ACC_TEST(method, STATIC)
+			    && *method->name != '<')
+				num_class_vmethods++;
+		}
+	}
+	num_vmethods = num_super_vmethods + num_class_vmethods;
+
+	/* Allocate and start building the type structure */
+	if ((type = _jc_cl_alloc(env, loader, sizeof(*type)
+	    + num_vmethods * sizeof(*type->vtable))) == NULL)
+		goto fail;
+	memset(type, 0, sizeof(*type));
+	ntype = &type->u.nonarray;
+	ntype->num_vmethods = num_vmethods;
+	type->superclass = superclass;
+	type->access_flags = cfile->access_flags | _JC_ACC_INTERP;
+	type->flags = _JC_TYPE_REFERENCE | _JC_TYPE_LOADED;
+	type->loader = loader;
+	ntype->u.cfile = cfile;
+	ntype->hash = cbytes->hash;
+
+	/* Allocate memory for mtable */
+	if (num_vmethods > 0
+	    && (ntype->mtable = _jc_cl_alloc(env, loader,
+	      num_vmethods * sizeof(*ntype->mtable))) == NULL)
+		goto fail;
+
+	/* Allocate memory for type name */
+	if ((type->name = _jc_cl_strdup(env, loader, cfile->name)) == NULL)
+		goto fail;
+
+	/*
+	 * Create the java.lang.Class instance for this type, unless during
+	 * initialization when java.lang.Class hasn't been loaded yet.
+	 */
+	if ((vm->initialization == NULL || vm->initialization->create_class)
+	    && _jc_create_class_instance(env, type) != JNI_OK)
+		goto fail;
+
+	/* Populate interface list */
+	type->num_interfaces = cfile->num_interfaces;
+	if (type->num_interfaces > 0
+	    && (type->interfaces = _jc_cl_alloc(env, loader,
+	      type->num_interfaces * sizeof(*type->interfaces))) == NULL)
+		goto fail;
+	for (i = 0; i < type->num_interfaces; i++)
+		*((_jc_type **)type->interfaces + i) = interfaces[i];
+
+	/* Derive fields */
+	if (_jc_derive_fields(env, type) != JNI_OK)
+		goto fail;
+
+	/* Derive methods */
+	if (_jc_derive_methods(env, type) != JNI_OK)
+		goto fail;
+
+	/* Compute field sizes and offsets */
+	ntype->num_virtual_refs = type->superclass != NULL ?
+	    type->superclass->u.nonarray.num_virtual_refs : 0;
+	virtual_offset = type->superclass != NULL ?
+	    (type->superclass->u.nonarray.instance_size
+	      - ntype->num_virtual_refs * sizeof(void *)) : sizeof(_jc_object);
+	static_offset = 0;
+	for (i = 0; i < ntype->num_fields; i++) {
+		_jc_field *const field = ntype->fields[i];
+		const u_char ptype = _jc_sig_types[(u_char)*field->signature];
+		const int align = _jc_type_align[ptype];
+		const int size = _jc_type_sizes[ptype];
+
+		if (_JC_ACC_TEST(field, STATIC)) {
+			while (static_offset % align != 0)
+				static_offset++;
+			field->offset = static_offset;
+			static_offset += size;
+		} else {
+			_JC_ASSERT(!_JC_ACC_TEST(type, INTERFACE));
+			if (ptype == _JC_TYPE_REFERENCE) {
+				field->offset = -++ntype->num_virtual_refs
+				    * sizeof(void *);
+			} else {
+				while (virtual_offset % align != 0)
+					virtual_offset++;
+				field->offset = virtual_offset;
+				virtual_offset += size;
+			}
+		}
+	}
+
+	/* Compute instance size */
+	if (!_JC_ACC_TEST(type, INTERFACE)) {
+		ntype->instance_size = virtual_offset
+		    + ntype->num_virtual_refs * sizeof(void *);
+	}
+
+	/* Initialize heap block size index skip word flag */
+	if (!_JC_ACC_TEST(type, ABSTRACT))
+		_jc_initialize_bsi(vm, type);
+
+	/* Allocate memory for static fields, if any */
+	if (static_offset > 0
+	    && (ntype->class_fields = _jc_cl_zalloc(env,
+	      loader, static_offset)) == NULL)
+		goto fail;
+
+	/* Build trampolines */
+	for (i = 0; i < ntype->num_methods; i++) {
+		_jc_method *const method = ntype->methods[i];
+		u_char rtype = method->param_ptypes[method->num_parameters];
+		u_char *trampoline;
+		const void *func;
+		int len;
+
+		/* Skip interface methods */
+		if (_JC_ACC_TEST(type, INTERFACE)
+		    && !_JC_ACC_TEST(method, STATIC))
+			continue;
+
+		/* Get the appropriate destination function */
+		func = _JC_ACC_TEST(method, NATIVE) ?
+		    _jc_interp_native_funcs[rtype] : _jc_interp_funcs[rtype];
+
+		/* Create trampoline */
+		len = _jc_build_trampoline(NULL, method, func);
+		if ((trampoline = _jc_cl_alloc(env, loader, len)) == NULL)
+			goto fail;
+		_jc_build_trampoline(trampoline, method, func);
+		_jc_iflush(trampoline, len);
+		method->function = trampoline;
+	}
+
+	/* Skip vtable stuff for interfaces */
+	if (_JC_ACC_TEST(type, INTERFACE))
+		goto skip_vtable;
+
+	/*
+	 * Fill in the vtable and mtable portions corresponding to this class.
+	 * We fill in and override the superclass portions during resolution.
+	 */
+	vtable_index = num_super_vmethods;
+	for (i = 0; i < ntype->num_methods; i++) {
+		_jc_method *const method = ntype->methods[i];
+
+		if (_JC_ACC_TEST(method, STATIC) || *method->name == '<')
+			continue;
+		method->vtable_index = vtable_index;
+		type->vtable[vtable_index] = method->function;
+		ntype->mtable[vtable_index] = method;
+		vtable_index++;
+	}
+
+	/* Sanity check */
+	_JC_ASSERT(vtable_index == num_vmethods);
+
+skip_vtable:
+	/*
+	 * Find/create this class' class file node and add a reference to it.
+	 * This also acts as an implicit dependency on the class file.
+	 */
+	_JC_MUTEX_LOCK(env, vm->mutex);
+	if ((cnode = _jc_ref_class_node(env, type->name, ntype->hash,
+	    loader != vm->boot.loader ? cbytes : NULL)) == NULL) {
+		_JC_MUTEX_UNLOCK(env, vm->mutex);
+		goto fail;
+	}
+	_JC_MUTEX_UNLOCK(env, vm->mutex);
+
+	/* Allocate and initialize type node */
+	if ((node = _jc_cl_zalloc(env, loader, sizeof(*node))) == NULL)
+		goto fail;
+	node->type = type;
+
+	/* Add node to the loader's initiated types tree */
+	_jc_splay_insert(&loader->initiated_types, node);
+
+	/* Add type to the loader's defined types tree */
+	_jc_splay_insert(&loader->defined_types, type);
+
+	/* Set type flags */
+	type->flags = _JC_TYPE_REFERENCE | _JC_TYPE_LOADED;
+
+	/* Done */
+	_JC_MUTEX_UNLOCK(env, loader->mutex);
+	return type;
+
+fail:
+	/* Give back class loader memory */
+	_jc_uni_reset(&loader->uni, mark);
+
+	/* Release class file reference */
+	if (cnode != NULL) {
+		_JC_MUTEX_LOCK(env, vm->mutex);
+		_jc_unref_class_node(vm, &cnode);
+		_JC_MUTEX_UNLOCK(env, vm->mutex);
+	}
+
+	/* Free parsed class file */
+	_jc_destroy_classfile(&cfile);
+
+	/* Unlock loader */
+	_JC_MUTEX_UNLOCK(env, loader->mutex);
+	return NULL;
+}
+
+/*
+ * Derive fields.
+ */
+static jint
+_jc_derive_fields(_jc_env *env, _jc_type *type)
+{
+	_jc_nonarray_type *const ntype = &type->u.nonarray;
+	_jc_classfile *const cfile = ntype->u.cfile;
+	int i;
+
+	/* Sanity check */
+	_JC_ASSERT(_JC_ACC_TEST(type, INTERP));
+	_JC_MUTEX_ASSERT(env, type->loader->mutex);
+
+	/* Allocate fields array */
+	ntype->num_fields = cfile->num_fields;
+	if (ntype->num_fields > 0
+	    && (ntype->fields = _jc_cl_alloc(env, type->loader,
+	      ntype->num_fields * sizeof(*ntype->fields))) == NULL)
+		return JNI_ERR;
+
+	/* Create field structures */
+	for (i = 0; i < cfile->num_fields; i++) {
+		_jc_cf_field *const cfield = &cfile->fields[i];
+		_jc_field *field;
+		size_t nlen;
+		size_t slen;
+
+		/* Allocate structure */
+		nlen = strlen(cfield->name) + 1;
+		slen = strlen(cfield->descriptor) + 1;
+		if ((field = _jc_cl_alloc(env, type->loader,
+		    sizeof(*field) + nlen + slen)) == NULL)
+			return JNI_ERR;
+		ntype->fields[i] = field;
+
+		/* Initialize it */
+		memset(field, 0, sizeof(*field));
+		field->name = (char *)(field + 1);
+		memcpy((char *)field->name, cfield->name, nlen);
+		field->signature = field->name + nlen;
+		memcpy((char *)field->signature, cfield->descriptor, slen);
+		field->class = type;
+		field->access_flags = cfield->access_flags | _JC_ACC_INTERP;
+	}
+
+	/* Done */
+	return JNI_OK;
+}
+
+/*
+ * Derive methods.
+ */
+static jint
+_jc_derive_methods(_jc_env *env, _jc_type *type)
+{
+	_jc_nonarray_type *const ntype = &type->u.nonarray;
+	_jc_classfile *const cfile = ntype->u.cfile;
+	int i;
+
+	/* Sanity check */
+	_JC_ASSERT(_JC_ACC_TEST(type, INTERP));
+	_JC_MUTEX_ASSERT(env, type->loader->mutex);
+
+	/* Allocate methods array */
+	ntype->num_methods = cfile->num_methods;
+	if (ntype->num_methods > 0
+	    && (ntype->methods = _jc_cl_alloc(env, type->loader,
+	      ntype->num_methods * sizeof(*ntype->methods))) == NULL)
+		return JNI_ERR;
+
+	/* Create method structures */
+	for (i = 0; i < cfile->num_methods; i++) {
+		_jc_cf_method *const cmethod = &cfile->methods[i];
+		_jc_method *method;
+		size_t mem_size;
+		size_t nlen;
+		size_t slen;
+		int nparam;
+		void *mem;
+
+		/* Allocate structure */
+		nlen = strlen(cmethod->name) + 1;
+		slen = strlen(cmethod->descriptor) + 1;
+		if ((method = _jc_cl_alloc(env, type->loader,
+		    sizeof(*method) + nlen + slen)) == NULL)
+			return JNI_ERR;
+		ntype->methods[i] = method;
+
+		/* Initialize it */
+		memset(method, 0, sizeof(*method));
+		method->name = (char *)(method + 1);
+		memcpy((char *)method->name, cmethod->name, nlen);
+		method->signature = method->name + nlen;
+		memcpy((char *)method->signature, cmethod->descriptor, slen);
+		method->class = type;
+		method->access_flags = cmethod->access_flags | _JC_ACC_INTERP;
+
+		/* Parse signature and count number of parameters */
+		if ((nparam = _jc_resolve_signature(env, method, NULL)) == -1)
+			return JNI_ERR;
+		method->num_parameters = nparam;
+		if (cmethod->exceptions != NULL) {
+			method->num_exceptions
+			    = cmethod->exceptions->num_exceptions;
+		}
+
+		/* Allocate storage for stuff */
+		mem_size = (method->num_exceptions + method->num_parameters)
+		    * sizeof(_jc_type *) + (method->num_parameters + 1);
+		if ((mem = _jc_cl_zalloc(env, type->loader, mem_size)) == NULL)
+			return JNI_ERR;
+
+		/* Initialize pointers */
+		if (method->num_parameters > 0)
+			method->param_types = mem;
+		if (method->num_exceptions > 0) {
+			method->exceptions = (_jc_type **)mem
+			    + method->num_parameters;
+		}
+		method->param_ptypes = (u_char *)((_jc_type **)mem
+		    + method->num_parameters + method->num_exceptions);
+
+		/* Get parameter ptypes */
+		_jc_resolve_signature(env, method, NULL);
+	}
+
+	/* Done */
+	return JNI_OK;
+}
+