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 [11/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/cf_parse.h
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/cf_parse.h?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/cf_parse.h (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/cf_parse.h Tue Oct  4 19:19:16 2005
@@ -0,0 +1,544 @@
+
+/*
+ * 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: cf_parse.h,v 1.2 2005/02/27 23:29:44 archiecobbs Exp $
+ */
+
+#ifndef _CF_PARSE_H_
+#define _CF_PARSE_H_
+
+/************************************************************************
+ *			Class file structures				*
+ ************************************************************************/
+
+/*
+ * Forward structure declarations and typedef's
+ */
+typedef struct _jc_cf_anewarray _jc_cf_anewarray;
+typedef struct _jc_cf_attr _jc_cf_attr;
+typedef struct _jc_cf_branch _jc_cf_branch;
+typedef struct _jc_cf_bytecode _jc_cf_bytecode;
+typedef struct _jc_cf_code _jc_cf_code;
+typedef struct _jc_cf_constant _jc_cf_constant;
+typedef struct _jc_cf_exceptions _jc_cf_exceptions;
+typedef struct _jc_cf_field _jc_cf_field;
+typedef struct _jc_cf_fieldref _jc_cf_fieldref;
+typedef struct _jc_cf_iinc _jc_cf_iinc;
+typedef struct _jc_cf_immediate _jc_cf_immediate;
+typedef struct _jc_cf_inner_class _jc_cf_inner_class;
+typedef struct _jc_cf_inner_classes _jc_cf_inner_classes;
+typedef struct _jc_cf_insn _jc_cf_insn;
+typedef struct _jc_cf_invoke _jc_cf_invoke;
+typedef struct _jc_cf_linemap _jc_cf_linemap;
+typedef struct _jc_cf_linenum _jc_cf_linenum;
+typedef struct _jc_cf_linenums _jc_cf_linenums;
+typedef struct _jc_cf_local _jc_cf_local;
+typedef struct _jc_cf_lookup _jc_cf_lookup;
+typedef struct _jc_cf_lookupswitch _jc_cf_lookupswitch;
+typedef struct _jc_cf_method _jc_cf_method;
+typedef struct _jc_cf_multianewarray _jc_cf_multianewarray;
+typedef struct _jc_cf_name_type _jc_cf_name_type;
+typedef struct _jc_cf_new _jc_cf_new;
+typedef struct _jc_cf_newarray _jc_cf_newarray;
+typedef struct _jc_cf_parse_state _jc_cf_parse_state;
+typedef struct _jc_cf_ref _jc_cf_ref;
+typedef struct _jc_cf_switch _jc_cf_switch;
+typedef struct _jc_cf_tableswitch _jc_cf_tableswitch;
+typedef struct _jc_cf_trap _jc_cf_trap;
+typedef struct _jc_cf_type _jc_cf_type;
+
+/************************************************************************
+ *			Bytecode information				*
+ ************************************************************************/
+
+/*
+ * Bytecode definitions
+ */
+enum {
+	_JC_aaload		=0x32,
+	_JC_aastore		=0x53,
+	_JC_aconst_null		=0x01,
+	_JC_aload		=0x19,
+	_JC_aload_0		=0x2a,
+	_JC_aload_1		=0x2b,
+	_JC_aload_2		=0x2c,
+	_JC_aload_3		=0x2d,
+	_JC_anewarray		=0xbd,
+	_JC_areturn		=0xb0,
+	_JC_arraylength		=0xbe,
+	_JC_astore		=0x3a,
+	_JC_astore_0		=0x4b,
+	_JC_astore_1		=0x4c,
+	_JC_astore_2		=0x4d,
+	_JC_astore_3		=0x4e,
+	_JC_athrow		=0xbf,
+	_JC_baload		=0x33,
+	_JC_bastore		=0x54,
+	_JC_bipush		=0x10,
+	_JC_caload		=0x34,
+	_JC_castore		=0x55,
+	_JC_checkcast		=0xc0,
+	_JC_d2f			=0x90,
+	_JC_d2i			=0x8e,
+	_JC_d2l			=0x8f,
+	_JC_dadd		=0x63,
+	_JC_daload		=0x31,
+	_JC_dastore		=0x52,
+	_JC_dcmpg		=0x98,
+	_JC_dcmpl		=0x97,
+	_JC_dconst_0		=0x0e,
+	_JC_dconst_1		=0x0f,
+	_JC_ddiv		=0x6f,
+	_JC_dload		=0x18,
+	_JC_dload_0		=0x26,
+	_JC_dload_1		=0x27,
+	_JC_dload_2		=0x28,
+	_JC_dload_3		=0x29,
+	_JC_dmul		=0x6b,
+	_JC_dneg		=0x77,
+	_JC_drem		=0x73,
+	_JC_dreturn		=0xaf,
+	_JC_dstore		=0x39,
+	_JC_dstore_0		=0x47,
+	_JC_dstore_1		=0x48,
+	_JC_dstore_2		=0x49,
+	_JC_dstore_3		=0x4a,
+	_JC_dsub		=0x67,
+	_JC_dup			=0x59,
+	_JC_dup_x1		=0x5a,
+	_JC_dup_x2		=0x5b,
+	_JC_dup2		=0x5c,
+	_JC_dup2_x1		=0x5d,
+	_JC_dup2_x2		=0x5e,
+	_JC_f2d			=0x8d,
+	_JC_f2i			=0x8b,
+	_JC_f2l			=0x8c,
+	_JC_fadd		=0x62,
+	_JC_faload		=0x30,
+	_JC_fastore		=0x51,
+	_JC_fcmpg		=0x96,
+	_JC_fcmpl		=0x95,
+	_JC_fconst_0		=0x0b,
+	_JC_fconst_1		=0x0c,
+	_JC_fconst_2		=0x0d,
+	_JC_fdiv		=0x6e,
+	_JC_fload		=0x17,
+	_JC_fload_0		=0x22,
+	_JC_fload_1		=0x23,
+	_JC_fload_2		=0x24,
+	_JC_fload_3		=0x25,
+	_JC_fmul		=0x6a,
+	_JC_fneg		=0x76,
+	_JC_frem		=0x72,
+	_JC_freturn		=0xae,
+	_JC_fstore		=0x38,
+	_JC_fstore_0		=0x43,
+	_JC_fstore_1		=0x44,
+	_JC_fstore_2		=0x45,
+	_JC_fstore_3		=0x46,
+	_JC_fsub		=0x66,
+	_JC_getfield		=0xb4,
+	_JC_getstatic		=0xb2,
+	_JC_goto		=0xa7,
+	_JC_goto_w		=0xc8,
+	_JC_i2b			=0x91,
+	_JC_i2c			=0x92,
+	_JC_i2d			=0x87,
+	_JC_i2f			=0x86,
+	_JC_i2l			=0x85,
+	_JC_i2s			=0x93,
+	_JC_iadd		=0x60,
+	_JC_iaload		=0x2e,
+	_JC_iand		=0x7e,
+	_JC_iastore		=0x4f,
+	_JC_iconst_m1		=0x02,
+	_JC_iconst_0		=0x03,
+	_JC_iconst_1		=0x04,
+	_JC_iconst_2		=0x05,
+	_JC_iconst_3		=0x06,
+	_JC_iconst_4		=0x07,
+	_JC_iconst_5		=0x08,
+	_JC_idiv		=0x6c,
+	_JC_if_acmpeq		=0xa5,
+	_JC_if_acmpne		=0xa6,
+	_JC_if_icmpeq		=0x9f,
+	_JC_if_icmpne		=0xa0,
+	_JC_if_icmplt		=0xa1,
+	_JC_if_icmpge		=0xa2,
+	_JC_if_icmpgt		=0xa3,
+	_JC_if_icmple		=0xa4,
+	_JC_ifeq		=0x99,
+	_JC_ifne		=0x9a,
+	_JC_iflt		=0x9b,
+	_JC_ifge		=0x9c,
+	_JC_ifgt		=0x9d,
+	_JC_ifle		=0x9e,
+	_JC_ifnonnull		=0xc7,
+	_JC_ifnull		=0xc6,
+	_JC_iinc		=0x84,
+	_JC_iload		=0x15,
+	_JC_iload_0		=0x1a,
+	_JC_iload_1		=0x1b,
+	_JC_iload_2		=0x1c,
+	_JC_iload_3		=0x1d,
+	_JC_imul		=0x68,
+	_JC_ineg		=0x74,
+	_JC_instanceof		=0xc1,
+	_JC_invokeinterface	=0xb9,
+	_JC_invokespecial	=0xb7,
+	_JC_invokestatic	=0xb8,
+	_JC_invokevirtual	=0xb6,
+	_JC_ior			=0x80,
+	_JC_irem		=0x70,
+	_JC_ireturn		=0xac,
+	_JC_ishl		=0x78,
+	_JC_ishr		=0x7a,
+	_JC_istore		=0x36,
+	_JC_istore_0		=0x3b,
+	_JC_istore_1		=0x3c,
+	_JC_istore_2		=0x3d,
+	_JC_istore_3		=0x3e,
+	_JC_isub		=0x64,
+	_JC_iushr		=0x7c,
+	_JC_ixor		=0x82,
+	_JC_jsr			=0xa8,
+	_JC_jsr_w		=0xc9,
+	_JC_l2d			=0x8a,
+	_JC_l2f			=0x89,
+	_JC_l2i			=0x88,
+	_JC_ladd		=0x61,
+	_JC_laload		=0x2f,
+	_JC_land		=0x7f,
+	_JC_lastore		=0x50,
+	_JC_lcmp		=0x94,
+	_JC_lconst_0		=0x09,
+	_JC_lconst_1		=0x0a,
+	_JC_ldc			=0x12,
+	_JC_ldc_w		=0x13,
+	_JC_ldc2_w		=0x14,
+	_JC_ldiv		=0x6d,
+	_JC_lload		=0x16,
+	_JC_lload_0		=0x1e,
+	_JC_lload_1		=0x1f,
+	_JC_lload_2		=0x20,
+	_JC_lload_3		=0x21,
+	_JC_lmul		=0x69,
+	_JC_lneg		=0x75,
+	_JC_lookupswitch	=0xab,
+	_JC_lor			=0x81,
+	_JC_lrem		=0x71,
+	_JC_lreturn		=0xad,
+	_JC_lshl		=0x79,
+	_JC_lshr		=0x7b,
+	_JC_lstore		=0x37,
+	_JC_lstore_0		=0x3f,
+	_JC_lstore_1		=0x40,
+	_JC_lstore_2		=0x41,
+	_JC_lstore_3		=0x42,
+	_JC_lsub		=0x65,
+	_JC_lushr		=0x7d,
+	_JC_lxor		=0x83,
+	_JC_monitorenter	=0xc2,
+	_JC_monitorexit		=0xc3,
+	_JC_multianewarray	=0xc5,
+	_JC_new			=0xbb,
+	_JC_newarray		=0xbc,
+	_JC_nop			=0x00,
+	_JC_pop			=0x57,
+	_JC_pop2		=0x58,
+	_JC_putfield		=0xb5,
+	_JC_putstatic		=0xb3,
+	_JC_ret			=0xa9,
+	_JC_return		=0xb1,
+	_JC_saload		=0x35,
+	_JC_sastore		=0x56,
+	_JC_sipush		=0x11,
+	_JC_swap		=0x5f,
+	_JC_tableswitch		=0xaa,
+	_JC_wide		=0xc4,
+};
+
+/*
+ * Primitive type definitions used by 'newarray'
+ */
+enum {
+	_JC_boolean		=4,
+	_JC_char		=5,
+	_JC_float		=6,
+	_JC_double		=7,
+	_JC_byte		=8,
+	_JC_short		=9,
+	_JC_int			=10,
+	_JC_long		=11,
+};
+
+/*
+ * Class file constant pool tags.
+ */
+enum {
+	CONSTANT_Utf8			=1,
+	CONSTANT_Integer		=3,
+	CONSTANT_Float			=4,
+	CONSTANT_Long			=5,
+	CONSTANT_Double			=6,
+	CONSTANT_Class			=7,
+	CONSTANT_String			=8,
+	CONSTANT_Fieldref		=9,
+	CONSTANT_Methodref		=10,
+	CONSTANT_InterfaceMethodref	=11,
+	CONSTANT_NameAndType		=12,
+};
+
+/*
+ * Extra information associated with certain bytecodes. The "target"
+ * fields are indexes into the _jc_cf_insn array, not bytecode offsets.
+ */
+struct _jc_cf_fieldref {
+	_jc_cf_ref	*field;
+};
+struct _jc_cf_iinc {
+	uint16_t	index;
+	jshort		value;
+};
+struct _jc_cf_invoke {
+	_jc_cf_ref	*method;
+};
+struct _jc_cf_lookup {
+	jint		match;
+	jint		target;
+};
+struct _jc_cf_lookupswitch {
+	jint		default_target;
+	jint		num_pairs;
+	_jc_cf_lookup	pairs[0];
+};
+struct _jc_cf_multianewarray {
+	const char	*type;
+	u_char		dims;
+};
+struct _jc_cf_newarray {
+	u_char		type;		/* _JC_TYPE_XXX */
+};
+struct _jc_cf_tableswitch {
+	jint		default_target;
+	jint		low;
+	jint		high;
+	jint		targets[0];
+};
+struct _jc_cf_branch {
+	jint		target;
+};
+struct _jc_cf_local {
+	uint16_t	index;
+};
+struct _jc_cf_immediate {
+	jint		value;
+};
+struct _jc_cf_type {
+	const char	*name;
+};
+
+/* Parsed instruction information */
+struct _jc_cf_insn {
+	union {
+		_jc_cf_fieldref		fieldref;
+		_jc_cf_iinc		iinc;
+		_jc_cf_invoke		invoke;
+		_jc_cf_multianewarray	multianewarray;
+		_jc_cf_newarray		newarray;
+		_jc_cf_lookupswitch	*lookupswitch;
+		_jc_cf_tableswitch	*tableswitch;
+		_jc_cf_branch		branch;
+		_jc_cf_local		local;
+		_jc_cf_immediate	immediate;
+		_jc_cf_type		type;
+		_jc_cf_constant		*constant;
+	}		u;
+	u_char		opcode;
+};
+
+/* LineNumberTable attribute */
+struct _jc_cf_linenums {
+	uint16_t	length;
+	_jc_cf_linenum	*linenums;
+};
+
+struct _jc_cf_linenum {
+	uint16_t	offset;			/* bytecode offset */
+	uint16_t	line;
+};
+
+struct _jc_cf_linemap {
+	jint		index;			/* instruction index */
+	uint16_t	line;
+};
+
+/* Parsed method trap */
+struct _jc_cf_trap {
+	jint		start;			/* instruction index */
+	jint		end;			/* instruction index */
+	jint		target;			/* instruction index */
+	const char	*type;
+};
+
+/* Unparsed method bytecode */
+struct _jc_cf_bytecode {
+	u_char		*bytecode;
+	size_t		length;
+	_jc_cf_linenums	*linenums;
+};
+
+/* Parsed method bytecode */
+struct _jc_cf_code {
+	uint16_t	max_stack;
+	uint16_t	max_locals;
+	uint16_t	num_traps;
+	uint16_t	num_linemaps;
+	jint		num_insns;
+	_jc_cf_insn	*insns;
+	_jc_cf_trap	*traps;
+	_jc_cf_linemap	*linemaps;
+};
+
+/************************************************************************
+ *			Non-bytecode information			*
+ ************************************************************************/
+
+/* Fieldref, Methodref, or InterfaceMethodref constant */
+struct _jc_cf_ref {
+	const char	*class;
+	const char	*name;
+	const char	*descriptor;
+};
+
+/* NameAndType constant */
+struct _jc_cf_name_type {
+	const char	*name;
+	const char	*descriptor;
+};
+
+/* Constant pool entry */
+struct _jc_cf_constant {
+	u_char		type;
+	union {
+	    const char		*Class;
+	    _jc_cf_ref		Ref;
+	    _jc_cf_name_type	NameAndType;
+	    const char		*String;
+	    jint		Integer;
+	    jlong		Long;
+	    jfloat		Float;
+	    jdouble		Double;
+	    const char		*Utf8;
+	}		u;
+};
+
+/* Field info */
+struct _jc_cf_field {
+	uint16_t	access_flags;
+	const char	*name;
+	const char	*descriptor;
+	uint16_t	num_attributes;
+	_jc_cf_attr	*attributes;
+	_jc_cf_constant	*initial_value;
+};
+
+/* Method info */
+struct _jc_cf_method {
+	uint16_t		access_flags;
+	const char		*name;
+	const char		*descriptor;
+	uint16_t		num_attributes;
+	_jc_cf_attr		*attributes;
+	_jc_cf_exceptions	*exceptions;
+	_jc_cf_bytecode		*code;
+};
+
+/* Exceptions attribute */
+struct _jc_cf_exceptions {
+	uint16_t	num_exceptions;
+	const char	**exceptions;
+};
+
+/* InnerClasses attribute */
+struct _jc_cf_inner_class {
+	const char	*inner;
+	const char	*outer;
+	const char	*name;
+	uint16_t	access_flags;
+};
+
+struct _jc_cf_inner_classes {
+	uint16_t		num_classes;
+	_jc_cf_inner_class	*classes;
+};
+
+/* Attribute (only some are explicitly supported) */
+struct _jc_cf_attr {
+	const char	*name;
+	uint32_t	length;
+	const u_char	*bytes;
+	union {
+	    _jc_cf_constant		*ConstantValue;
+	    const char			*SourceFile;
+	    _jc_cf_exceptions		Exceptions;
+	    _jc_cf_inner_classes	InnerClasses;
+	    _jc_cf_bytecode		Code;
+	    _jc_cf_linenums		LineNumberTable;
+	}		u;
+};
+
+/* Parsed classfile */
+struct _jc_classfile {
+	uint16_t		minor_version;
+	uint16_t		major_version;
+	uint16_t		access_flags;
+	uint16_t		num_constants;
+	_jc_cf_constant		*constants;
+	const char		*name;
+	const char		*superclass;
+	uint16_t		num_interfaces;
+	const char		**interfaces;
+	uint16_t		num_fields;
+	_jc_cf_field		*fields;
+	uint16_t		num_methods;
+	_jc_cf_method		*methods;
+	uint16_t		num_attributes;
+	_jc_cf_attr		*attributes;
+	_jc_cf_inner_classes	*inner_classes;
+	const char		*source_file;
+	char			*string_mem;	/* nul-terminated utf strings */
+};
+
+/* Internal parsing state */
+struct _jc_cf_parse_state {
+	_jc_env		*env;
+	_jc_classfile	*cfile;
+	const u_char	*bytes;
+	size_t		length;
+	size_t		pos;
+};
+
+/* cf_parse.c */
+extern _jc_classfile	*_jc_parse_classfile(_jc_env *env,
+				_jc_classbytes *bytes, int howmuch);
+extern void		_jc_destroy_classfile(_jc_classfile **cfilep);
+extern int		_jc_parse_code(_jc_env *env, _jc_classfile *cfile,
+				_jc_cf_bytecode *bytecode, _jc_cf_code *code);
+extern void		_jc_destroy_code(_jc_cf_code *code);
+
+#endif	/* _CF_PARSE_H_ */

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/cl_alloc.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/cl_alloc.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/cl_alloc.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/cl_alloc.c Tue Oct  4 19:19:16 2005
@@ -0,0 +1,358 @@
+
+/*
+ * 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: cl_alloc.c,v 1.6 2005/03/12 04:24:17 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/*
+ * "Uni-alloc" memory allocator used for class loaders.
+ *
+ * Class loader memory blocks are assumed to be allocated once and never
+ * reallocated or freed, until all memory associated with a class loader
+ * is freed at once when the class loader is unloaded.
+ *
+ * As a special exception, we allow memory blocks to be freed in the
+ * reverse order in which they were allocated, to support "undoing"
+ * in the case of certain errors.
+ *
+ * Note also that class loader memory is always manipulated while the
+ * loader's lock is held, so synchronization is not an issue here.
+ *
+ * We provide this same functionality for other users besides class
+ * loaders using the "uni" functions.
+ */
+
+/* Internal functions */
+static jint	_jc_uni_avail_alloc(_jc_uni_mem *uni, int num_pages);
+
+/*
+ * Initialize memory associated with a uni-allocator.
+ */
+void
+_jc_uni_alloc_init(_jc_uni_mem *uni, int min_pages,
+	volatile _jc_word *avail_pages)
+{
+	TAILQ_INIT(&uni->pages);
+	uni->min_pages = min_pages;
+	uni->avail_pages = avail_pages;
+}
+
+/*
+ * Free all memory associated with a uni-allocator.
+ */
+void
+_jc_uni_alloc_free(_jc_uni_mem *uni)
+{
+	int num_pages = 0;
+
+	/* Free all pages of memory */
+	while (!TAILQ_EMPTY(&uni->pages)) {
+		_jc_uni_pages *pages = TAILQ_FIRST(&uni->pages);
+
+		num_pages += pages->num_pages;
+		TAILQ_REMOVE(&uni->pages, pages, link);
+		_jc_vm_free(&pages);
+	}
+
+	/* Update available pages */
+	_jc_uni_avail_alloc(uni, -num_pages);
+}
+
+/*
+ * Extend memory in an uni-allocator.
+ *
+ * If unsuccessful an exception is stored.
+ */
+static jint
+_jc_uni_ensure(_jc_env *env, _jc_uni_mem *uni, size_t size)
+{
+	jboolean reserved = JNI_FALSE;
+	_jc_uni_pages *pages;
+	size_t num_pages;
+	int try;
+
+	/* Get current page set */
+	pages = TAILQ_LAST(&uni->pages, _jc_uni_page_list);
+
+	/* Is there enough room? */
+	if (!TAILQ_EMPTY(&uni->pages)
+	    && size < (pages->num_pages * _JC_PAGE_SIZE) - pages->offset)
+		return JNI_OK;
+
+	/* Compute how many new pages to allocate */
+	num_pages = _JC_HOWMANY(_JC_UNI_HDR_SIZE + size, _JC_PAGE_SIZE);
+	if (num_pages < uni->min_pages)
+		num_pages = uni->min_pages;
+
+	/* Try hard to find memory */
+	for (try = 1; JNI_TRUE; try++) {
+
+		/* Try to reserve pages */
+		if (_jc_uni_avail_alloc(uni, num_pages) == JNI_OK) {
+			reserved = JNI_TRUE;
+			break;
+		}
+
+		/* Give up after three tries */
+		if (try == 3)
+			break;
+
+		/* Try a GC cycle to unload some classes */
+		if (_jc_gc(env, JNI_TRUE) != JNI_OK)
+			return JNI_ERR;
+
+		/* Yield so the finalizer thread can run */
+		sched_yield();
+	}
+
+	/* Did we successfully reserve? */
+	if (!reserved) {
+		_JC_EX_STORE(env, OutOfMemoryError,
+		    "reached limit of %u pages allocated"
+		    " by class loaders", (int)*uni->avail_pages);
+		return JNI_ERR;
+	}
+
+	/* Get pages */
+	pages = _jc_vm_alloc(env, num_pages * _JC_PAGE_SIZE);
+
+	/* Un-reserve (for class loaders) on error */
+	if (pages == NULL) {
+		_jc_uni_avail_alloc(uni, -num_pages);
+		return JNI_ERR;
+	}
+
+	/* Initialize new chunk */
+	memset(pages, 0, sizeof(*pages));
+	pages->num_pages = num_pages;
+	pages->offset = _JC_UNI_HDR_SIZE;
+
+	/* Link it into our list */
+	TAILQ_INSERT_TAIL(&uni->pages, pages, link);
+
+	/* Done */
+	return JNI_OK;
+}
+
+/*
+ * Allocate a chunk of memory from an uni-allocator's page list.
+ * Grab more pages as necessary.
+ *
+ * If unsuccessful an exception is stored.
+ */
+void *
+_jc_uni_alloc(_jc_env *env, _jc_uni_mem *uni, size_t size)
+{
+	_jc_uni_pages *pages;
+	void *ptr;
+
+	/* Stay aligned */
+	size = _JC_ROUNDUP2(size, _JC_FULL_ALIGNMENT);
+
+	/* Ensure we have room */
+	if (_jc_uni_ensure(env, uni, size) != JNI_OK)
+		return NULL;
+
+	/* Grab some more memory */
+	pages = TAILQ_LAST(&uni->pages, _jc_uni_page_list);
+	ptr = (char *)pages + pages->offset;
+	pages->offset += size;
+
+	/* Done */
+	return ptr;
+}
+
+/*
+ * If the most recently allocated memory that was not subsequently
+ * unallocated was address '*pp' with size 'size', then free it.
+ * Otherwise, just leak it.
+ *
+ * In other words, you can free uni-allocated memory if freed in the
+ * reverse order in which it was allocated.
+ */
+void
+_jc_uni_unalloc(_jc_uni_mem *uni, void *pp, size_t size)
+{
+	void **const ptrp = pp;
+	void *const ptr = *ptrp;
+	_jc_uni_pages *pages;
+
+	/* Sanity check */
+	if (ptr == NULL)
+		return;
+	*ptrp = NULL;
+
+	/* Can we un-do? */
+	if (TAILQ_EMPTY(&uni->pages))
+		return;
+	pages = TAILQ_LAST(&uni->pages, _jc_uni_page_list);
+	size = _JC_ROUNDUP2(size, _JC_FULL_ALIGNMENT);
+	if ((char *)ptr + size != (char *)pages + pages->offset)
+		return;
+
+	/* Un-do the previous allocation */
+	pages->offset -= size;
+
+	/* Free the page if empty */
+	if (pages->offset == _JC_UNI_HDR_SIZE) {
+		TAILQ_REMOVE(&uni->pages, pages, link);
+		_jc_uni_avail_alloc(uni, -pages->num_pages);
+		_jc_vm_free(&pages);
+	}
+}
+
+/*
+ * Allocate and clear a chunk of memory from the uni-allocator memory.
+ */
+void *
+_jc_uni_zalloc(_jc_env *env, _jc_uni_mem *uni, size_t size)
+{
+	void *mem;
+
+	/* Alloc mem and zero it */
+	if ((mem = _jc_uni_alloc(env, uni, size)) != NULL)
+		memset(mem, 0, size);
+	return mem;
+}
+
+/*
+ * Copy a string into memory allocated from an uni-allocator.
+ */
+char *
+_jc_uni_strdup(_jc_env *env, _jc_uni_mem *uni, const char *s)
+{
+	const size_t slen = strlen(s);
+	void *mem;
+
+	/* Alloc mem and copy string */
+	if ((mem = _jc_uni_alloc(env, uni, slen + 1)) == NULL)
+		return NULL;
+	memcpy(mem, s, slen + 1);
+	return mem;
+}
+
+/*
+ * Determine if a pointer points into uni-allocator allocated memory.
+ */
+jboolean
+_jc_uni_contains(_jc_uni_mem *uni, const void *ptr)
+{
+	_jc_uni_pages *pages;
+
+	TAILQ_FOREACH(pages, &uni->pages, link) {
+		const char *const start = (char *)pages + _JC_UNI_HDR_SIZE;
+		const char *const end = (char *)pages
+		    + (pages->num_pages * _JC_PAGE_SIZE);
+
+		if ((char *)ptr >= start && (char *)ptr < end)
+		    	return JNI_TRUE;
+	}
+	return JNI_FALSE;
+}
+
+/*
+ * Atomically update available pages, but don't let them go negative.
+ */
+static jint
+_jc_uni_avail_alloc(_jc_uni_mem *uni, int num_pages)
+{
+	_jc_word old_avail_pages;
+
+	if (uni->avail_pages == NULL)
+		return JNI_OK;
+	do {
+		old_avail_pages = *uni->avail_pages;
+		if (num_pages > 0 && num_pages > old_avail_pages)
+			return JNI_ERR;
+	} while (!_jc_compare_and_swap(uni->avail_pages,
+	    old_avail_pages, old_avail_pages - num_pages));
+	return JNI_OK;
+}
+
+/*
+ * Mark the current top of the allocation stack.
+ */
+void *
+_jc_uni_mark(_jc_uni_mem *uni)
+{
+	_jc_uni_pages *pages;
+
+	pages = TAILQ_LAST(&uni->pages, _jc_uni_page_list);
+	return pages != NULL ? (char *)pages + pages->offset : NULL;
+}
+
+/*
+ * Reset the current top of the allocation stack to 'mem'.
+ */
+void
+_jc_uni_reset(_jc_uni_mem *uni, void *mem)
+{
+	_jc_uni_pages *pages;
+
+	if (mem == NULL) {
+		_jc_uni_alloc_free(uni);
+		return;
+	}
+	while (JNI_TRUE) {
+		_JC_ASSERT(!TAILQ_EMPTY(&uni->pages));
+		pages = TAILQ_LAST(&uni->pages, _jc_uni_page_list);
+		if ((char *)mem >= (char *)pages + _JC_UNI_HDR_SIZE
+		    && (char *)mem < (char *)pages
+		      + pages->num_pages * _JC_PAGE_SIZE) {
+			pages->offset = (char *)mem - (char *)pages;
+			break;
+		}
+		TAILQ_REMOVE(&uni->pages, pages, link);
+		_jc_uni_avail_alloc(uni, -pages->num_pages);
+		_jc_vm_free(&pages);
+	}
+}
+
+/************************************************************************
+ *		Class loader equivalents with assertions		*
+ ************************************************************************/
+
+void *
+_jc_cl_alloc(_jc_env *env, _jc_class_loader *loader, size_t size)
+{
+	_JC_MUTEX_ASSERT(env, loader->mutex);
+	return _jc_uni_alloc(env, &loader->uni, size);
+}
+
+void
+_jc_cl_unalloc(_jc_class_loader *loader, void *pp, size_t size)
+{
+	_JC_MUTEX_ASSERT(_jc_get_current_env(), loader->mutex);
+	_jc_uni_unalloc(&loader->uni, pp, size);
+}
+
+void *
+_jc_cl_zalloc(_jc_env *env, _jc_class_loader *loader, size_t size)
+{
+	_JC_MUTEX_ASSERT(env, loader->mutex);
+	return _jc_uni_zalloc(env, &loader->uni, size);
+}
+
+char *
+_jc_cl_strdup(_jc_env *env, _jc_class_loader *loader, const char *s)
+{
+	_JC_MUTEX_ASSERT(env, loader->mutex);
+	return _jc_uni_strdup(env, &loader->uni, s);
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_bytes.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_bytes.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_bytes.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_bytes.c Tue Oct  4 19:19:16 2005
@@ -0,0 +1,380 @@
+
+/*
+ * 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: class_bytes.c,v 1.5 2005/03/18 23:16:28 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/* Internal functions */
+static void		_jc_hash_classbytes(_jc_classbytes *bytes);
+static void		_jc_munmap_freer(_jc_classbytes *bytes);
+static void		_jc_free_freer(_jc_classbytes *bytes);
+
+/*
+ * Search for a class file in the filesystem using the bootstrap
+ * class loader directory search path, and load it into memory.
+ * This is used for the bootstrap loader to find classfiles.
+ *
+ * If not found, NULL is returned and a NoClassDefFoundError is stored.
+ */
+_jc_classbytes *
+_jc_bootcl_find_classbytes(_jc_env *env, const char *name, int *indexp)
+{
+	_jc_jvm *const vm = env->vm;
+	int i;
+
+	/* Search for file in each class path component */
+	for (i = 0; i < vm->boot.class_path_len; i++) {
+		_jc_cpath_entry *const ent = &vm->boot.class_path[i];
+		_jc_classbytes *bytes = NULL;
+
+try_again:
+		/* Look for class in this class path component */
+		switch (ent->type) {
+		case _JC_CPATH_DIRECTORY:
+			_JC_ASSERT(ent->zip == NULL);
+			if (_jc_read_classbytes_dir(env,
+			    ent, name, &bytes) != JNI_OK)
+				return NULL;
+			break;
+		case _JC_CPATH_ZIPFILE:
+			_JC_ASSERT(ent->zip != NULL);
+			if (_jc_read_classbytes_zip(env,
+			    ent, name, &bytes) != JNI_OK) {
+				if (env->ex.num == _JC_IOException)
+					ent->type = _JC_CPATH_ERROR;
+				return NULL;
+			}
+			break;
+		case _JC_CPATH_ERROR:
+			break;
+		case _JC_CPATH_UNKNOWN:
+		    {
+			struct stat info;
+			_jc_zip *zip;
+
+			/* Examine file */
+			_JC_ASSERT(ent->zip == NULL);
+			if (stat(ent->pathname, &info) == -1) {
+				_JC_MUTEX_LOCK(env, vm->mutex);
+				if (ent->type == _JC_CPATH_UNKNOWN)
+					ent->type = _JC_CPATH_ERROR;
+				_JC_MUTEX_UNLOCK(env, vm->mutex);
+				goto try_again;
+			}
+
+			/* If it's a directory, change type and try again */
+			if ((info.st_mode & S_IFMT) == S_IFDIR) {
+				_JC_MUTEX_LOCK(env, vm->mutex);
+				if (ent->type == _JC_CPATH_UNKNOWN)
+					ent->type = _JC_CPATH_DIRECTORY;
+				_JC_MUTEX_UNLOCK(env, vm->mutex);
+				goto try_again;
+			}
+
+			/* Otherwise, try to open it as a ZIP file */
+			if ((zip = _jc_zip_open(env, ent->pathname)) == NULL) {
+				if (env->ex.num != _JC_IOException)
+					return NULL;
+				_JC_MUTEX_LOCK(env, vm->mutex);
+				if (ent->type == _JC_CPATH_UNKNOWN)
+					ent->type = _JC_CPATH_ERROR;
+				_JC_MUTEX_UNLOCK(env, vm->mutex);
+				goto try_again;
+			}
+
+			/* That worked, so change type and try again */
+			_JC_MUTEX_LOCK(env, vm->mutex);
+			if (ent->type == _JC_CPATH_UNKNOWN) {
+				_JC_ASSERT(ent->zip == NULL);
+				ent->type = _JC_CPATH_ZIPFILE;
+				ent->zip = zip;
+				zip = NULL;
+			}
+			_JC_MUTEX_UNLOCK(env, vm->mutex);
+			_jc_zip_close(&zip);
+			goto try_again;
+		    }
+		default:
+			_JC_ASSERT(JNI_FALSE);
+		}
+
+		/* If found, return them */
+		if (bytes != NULL) {
+			if (indexp != NULL)
+				*indexp = i;
+			return bytes;
+		}
+	}
+
+	/* Not found */
+	_JC_EX_STORE(env, NoClassDefFoundError, "%s", name);
+	for (i = 0; env->ex.msg[i] != '\0'; i++) {
+		if (env->ex.msg[i] == '/')
+			env->ex.msg[i] = '.';
+	}
+	return NULL;
+}
+
+/*
+ * Read a class file from the given directory hierarchy.
+ *
+ * Sets *bytesp to the class file bytes, or NULL if not found.
+ * An exception is stored only if something else bad happens.
+ */
+jint
+_jc_read_classbytes_dir(_jc_env *env, _jc_cpath_entry *ent,
+	const char *name, _jc_classbytes **bytesp)
+{
+	_jc_classbytes *bytes;
+	struct stat info;
+	char *path;
+	void *addr;
+	int fd = -1;
+	char *s;
+
+	/* Sanity check */
+	_JC_ASSERT(ent->type == _JC_CPATH_DIRECTORY);
+
+	/* Sanity check name to avoid reading arbitrary files */
+	if (*name == '/')
+		goto not_found;
+
+	/* Concatenate directory and class name to get filename */
+	if ((path = _JC_FORMAT_STRING(env,
+	    "%s/%s.class", ent->pathname, name)) == NULL)
+		return JNI_ERR;
+
+	/* Convert Java "/" separator to directory path separator */
+	for (s = path; *s != '\0'; s++) {
+		if (*s == '/')
+			*s = _JC_FILE_SEPARATOR[0];
+	}
+
+	/* Open file */
+	if ((fd = open(path, O_RDONLY)) == -1) {
+		if (errno == ENOENT)
+			goto not_found;
+		_JC_EX_STORE(env, IOException, "can't read `%s': %s",
+		    name, strerror(errno));
+		goto fail;
+	}
+	(void)fcntl(fd, F_SETFD, 1);
+	if (fstat(fd, &info) == -1) {
+		_JC_EX_STORE(env, IOException, "can't stat `%s': %s",
+		    name, strerror(errno));
+		goto fail;
+	}
+
+	/* Memory map in the file */
+	if ((addr = mmap(NULL, info.st_size, PROT_READ,
+	    MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
+		_JC_EX_STORE(env, IOException, "can't map `%s': %s",
+		    name, strerror(errno));
+		goto fail;
+	}
+
+	/* Create _jc_classbytes object */
+	if ((bytes = _jc_vm_zalloc(env, sizeof(*bytes))) == NULL) {
+		munmap(addr, info.st_size);
+		goto fail;
+	}
+	bytes->bytes = addr;
+	bytes->length = info.st_size;
+	bytes->refs = 1;
+	bytes->freer = _jc_munmap_freer;
+
+	/* Compute hash */
+	_jc_hash_classbytes(bytes);
+
+	/* Set return value to the bytes found */
+	*bytesp = bytes;
+
+not_found:
+	/* No error, just not found */
+	if (fd != -1)
+		close(fd);
+	return JNI_OK;
+
+fail:
+	/* Clean up after error */
+	if (fd != -1)
+		close(fd);
+	return JNI_ERR;
+}
+
+/*
+ * Read a class file from the given ZIP file.
+ *
+ * Sets *bytesp to the class file bytes, or NULL if not found.
+ * An exception is stored only if something else bad happens.
+ */
+jint
+_jc_read_classbytes_zip(_jc_env *env, _jc_cpath_entry *ent,
+	const char *name, _jc_classbytes **bytesp)
+{
+	_jc_classbytes *bytes = NULL;
+	_jc_zip *const zip = ent->zip;
+	_jc_zip_entry *zent;
+	char *zent_name;
+	int indx;
+
+	/* Sanity check */
+	_JC_ASSERT(ent->type == _JC_CPATH_ZIPFILE);
+	_JC_ASSERT(ent->zip != NULL);
+
+	/* Append '.class' suffix to class name */
+	if ((zent_name = _JC_FORMAT_STRING(env, "%s.class", name)) == NULL)
+		return JNI_ERR;
+
+	/* Get file index */
+	if ((indx = _jc_zip_search(ent->zip, zent_name)) == -1)
+		return JNI_OK;				/* not found */
+	zent = &zip->entries[indx];
+
+	/* Create _jc_classbytes object */
+	if ((bytes = _jc_vm_alloc(env,
+	    sizeof(*bytes) + zent->uncomp_len)) == NULL)
+		return JNI_ERR;
+	memset(bytes, 0, sizeof(*bytes));
+	bytes->bytes = (u_char *)bytes + sizeof(*bytes);
+	bytes->length = zent->uncomp_len;
+	bytes->refs = 1;
+	bytes->freer = _jc_free_freer;
+
+	/* Extract file contents from ZIP file */
+	if (_jc_zip_read(env, zip, indx, bytes->bytes) != JNI_OK) {
+		_jc_free_classbytes(&bytes);
+		return JNI_ERR;
+	}
+
+	/* Compute hash */
+	_jc_hash_classbytes(bytes);
+
+	/* Set return value to the bytes found */
+	*bytesp = bytes;
+	return JNI_OK;
+}
+
+/*
+ * Create a _jc_classbytes structure from an array of bytes.
+ *
+ * If there is an error an exception is stored and NULL returned.
+ */
+_jc_classbytes *
+_jc_copy_classbytes(_jc_env *env, const void *data, size_t len)
+{
+	_jc_classbytes *bytes;
+
+	/* Create classbytes object */
+	if ((bytes = _jc_vm_alloc(env, sizeof(*bytes) + len)) == NULL)
+		return NULL;
+	memset(bytes, 0, sizeof(*bytes));
+	bytes->bytes = (u_char *)bytes + sizeof(*bytes);
+	bytes->length = len;
+	bytes->refs = 1;
+	bytes->freer = _jc_free_freer;
+
+	/* Copy bytes */
+	memcpy(bytes->bytes, data, len);
+
+	/* Compute hash */
+	_jc_hash_classbytes(bytes);
+
+	/* Done */
+	return bytes;
+}
+
+/*
+ * Add a reference to a _jc_classbytes structure.
+ */
+_jc_classbytes *
+_jc_dup_classbytes(_jc_classbytes *bytes)
+{
+	_jc_word old_refs;
+
+	_JC_ASSERT(bytes->refs > 0);
+	do
+		old_refs = bytes->refs;
+	while (!_jc_compare_and_swap(&bytes->refs, old_refs, old_refs + 1));
+	return bytes;
+}
+
+/*
+ * Unreference a _jc_classbytes structure.
+ */
+void
+_jc_free_classbytes(_jc_classbytes **bytesp)
+{
+	_jc_classbytes *bytes = *bytesp;
+	_jc_word old_refs;
+
+	/* Sanity check */
+	if (bytes == NULL)
+		return;
+	*bytesp = NULL;
+
+	/* Decrement ref count */
+	_JC_ASSERT(bytes->refs > 0);
+	do
+		old_refs = bytes->refs;
+	while (!_jc_compare_and_swap(&bytes->refs, old_refs, old_refs - 1));
+
+	/* Free structure if that was the last reference */
+	if (bytes->refs == 0)
+		(*bytes->freer)(bytes);
+}
+
+/*
+ * Compute the hash value of a class' bytes.
+ */
+static void
+_jc_hash_classbytes(_jc_classbytes *bytes)
+{
+	u_char md5[MD5_DIGEST_LENGTH];
+	MD5_CTX ctx;
+	int i;
+
+	MD5_Init(&ctx);
+	MD5_Update(&ctx, bytes->bytes, bytes->length);
+	MD5_Final(md5, &ctx);
+	for (bytes->hash = i = 0; i < 8; i++) {
+		bytes->hash = (bytes->hash << 8)
+		    | md5[MD5_DIGEST_LENGTH - 8 + i];
+	}
+}
+
+/*
+ * Free a class file that was memory mapped.
+ */
+static void
+_jc_munmap_freer(_jc_classbytes *bytes)
+{
+	munmap(bytes->bytes, bytes->length);
+	_jc_vm_free(&bytes);
+}
+
+/*
+ * Free a class file that was allocated from the system heap.
+ */
+static void
+_jc_free_freer(_jc_classbytes *bytes)
+{
+	_jc_vm_free(&bytes);
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_file.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_file.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_file.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_file.c Tue Oct  4 19:19:16 2005
@@ -0,0 +1,300 @@
+
+/*
+ * 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: class_file.c,v 1.3 2005/03/18 04:17:48 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/*
+ * The VM class file table contains a node for each class file we've
+ * seen. Each node has a reference count. Every loaded class counts
+ * and each type dependency counts for one reference.
+ */
+
+/*
+ * Search for a class file node in the VM class file tree. If not found,
+ * actively retrieve it by trying to load it with the supplied class loader.
+ *
+ * Because user class loaders control finding and loading their classes,
+ * the only way for us to force the acquisition of a classfile is to try to
+ * load the type. In general this may cause ClassCircularityErrors, but we
+ * don't care about them because by the time one is thrown, the class file
+ * has already been seen by us and its node stored in the class file tree.
+ *
+ * If successful, the node is returned with an extra reference.
+ *
+ * This function is used only if vm->without_classfiles is false.
+ */
+_jc_class_node *
+_jc_get_class_node(_jc_env *env, _jc_class_loader *loader, const char *name)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_class_save class_save;
+	_jc_class_node *node;
+	_jc_class_node key;
+	_jc_type *type;
+
+	/* Sanity check */
+	_JC_ASSERT(name[0] != '[');
+	_JC_ASSERT(!vm->without_classfiles);
+
+	/* Lock VM */
+	_JC_MUTEX_LOCK(env, vm->mutex);
+
+	/* Search for existing class file node */
+	key.name = name;
+	if ((node = _jc_splay_find(&vm->classfiles, &key)) != NULL
+	    && node->bytes != NULL) {
+		node->refs++;
+		_JC_MUTEX_UNLOCK(env, vm->mutex);
+		return node;
+	}
+	node = NULL;
+
+	/* Unlock VM */
+	_JC_MUTEX_UNLOCK(env, vm->mutex);
+
+	/* If loader is the boot loader, we can get the class file directly */
+	if (loader == vm->boot.loader) {
+		_jc_classbytes *cbytes;
+
+		/* Find the class file bytes in the filesystem */
+		if ((cbytes = _jc_bootcl_find_classbytes(env,
+		    name, NULL)) == NULL) {
+			_jc_post_exception_info(env);
+			goto done;
+		}
+
+		/* Try to add class file to class file tree */
+		_JC_MUTEX_LOCK(env, vm->mutex);
+		node = _jc_ref_class_node(env, name, cbytes->hash, cbytes);
+		_JC_MUTEX_UNLOCK(env, vm->mutex);
+
+		/* Free class file bytes */
+		_jc_free_classbytes(&cbytes);
+
+		/* Post stored exception if failed */
+		if (node == NULL)
+			_jc_post_exception_info(env);
+
+		/* Done */
+		goto done;
+	}
+
+	/* Initialize our class file save structure */
+	class_save.name = name;
+	class_save.bytes = NULL;
+	class_save.next = env->class_save;
+	env->class_save = &class_save;
+
+	/*
+	 * Attempt to load the type in order to acquire the class file.
+	 * If we succeeded, then the class file node must have been added.
+	 */
+	if ((type = _jc_load_type(env, loader, name)) != NULL) {
+
+		/* Lock VM */
+		_JC_MUTEX_LOCK(env, vm->mutex);
+
+		/* Find node and add reference */
+		node = _jc_splay_find(&vm->classfiles, &key);
+		_JC_ASSERT(node != NULL);
+		node->refs++;
+
+		/* Unlock VM */
+		_JC_MUTEX_UNLOCK(env, vm->mutex);
+
+		/* Done */
+		goto done;
+	}
+
+	/* Ignore LinkageError's but bail out if any other exception */
+	if (!_jc_unpost_exception(env, _JC_LinkageError))
+		goto done;
+
+	/* Lock VM */
+	_JC_MUTEX_LOCK(env, vm->mutex);
+
+	/*
+	 * Look for class file in our class file save structure; if found,
+	 * copy its info to VM tree and grab a reference to the new node.
+	 */
+	if (class_save.bytes != NULL) {
+
+		/* Add node */
+		node = _jc_ref_class_node(env, name,
+		    class_save.bytes->hash, class_save.bytes);
+		_JC_MUTEX_UNLOCK(env, vm->mutex);
+
+		/* Post exception if failed */
+		if (node == NULL)
+			_jc_post_exception_info(env);
+
+		/* Done */
+		goto done;
+	}
+
+	/* Unlock VM */
+	_JC_MUTEX_UNLOCK(env, vm->mutex);
+
+done:
+	/* Destroy class save structure if we added one */
+	if (env->class_save == &class_save) {
+		_jc_free_classbytes(&class_save.bytes);
+		env->class_save = class_save.next;
+	}
+
+	/* Done */
+	return node;
+}
+
+/*
+ * Find/create a class file node in the VM's class file table.
+ *
+ * If the class already exists, the hash must be the same, otherwise
+ * a LinkageError is stored. Bump the reference count on the existing node.
+ *
+ * If no class by this name exists, add a new node with reference count 1.
+ *
+ * 'cbytes' should be NULL unless object generation is enabled and the
+ * classfile was loaded by a user-defined class loader. If successful,
+ * it will be copied to any newly created node.
+ *
+ * Stores an exception if unsuccessful.
+ *
+ * NOTE: This assumes the VM global mutex is locked.
+ */
+_jc_class_node *
+_jc_ref_class_node(_jc_env *env, const char *name,
+	jlong hash, _jc_classbytes *cbytes)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_class_node *node;
+	_jc_class_node key;
+	size_t nlen;
+
+	/* Sanity check */
+	_JC_MUTEX_ASSERT(env, vm->mutex);
+	_JC_ASSERT(cbytes == NULL || cbytes->hash == hash);
+
+	/* If code generation is disabled, don't save the class file bytes */
+	if (!vm->generation_enabled)
+		cbytes = NULL;
+
+	/* Search for existing node */
+	key.name = name;
+	if ((node = _jc_splay_find(&vm->classfiles, &key)) != NULL) {
+
+		/* Hash values must be the same */
+		if (hash != node->hash) {
+			_JC_EX_STORE(env, LinkageError, "class file for `%s'"
+			    " has an unexpected hash value 0x%" _JC_JLONG_FMT
+			    " != 0x%" _JC_JLONG_FMT, name, hash, node->hash);
+			return NULL;
+		}
+
+		/* Save class file if we don't have it yet */
+		if (cbytes != NULL && node->bytes == NULL)
+			node->bytes = _jc_dup_classbytes(cbytes);
+
+		/* Increment node reference count */
+		node->refs++;
+
+		/* Return node */
+		return node;
+	}
+
+	/* Create a new class file node */
+	nlen = strlen(name);
+	if ((node = _jc_vm_alloc(env, sizeof(*node) + nlen + 1)) == NULL)
+		return NULL;
+	memcpy(node + 1, name, nlen + 1);
+	node->name = (char *)(node + 1);
+	node->hash = hash;
+	node->refs = 1;
+	node->bytes = cbytes != NULL ? _jc_dup_classbytes(cbytes) : NULL;
+
+	/* Add node to our classfile tree */
+#ifndef NDEBUG
+	memset(&node->node, 0, sizeof(node->node));
+#endif
+	_jc_splay_insert(&vm->classfiles, node);
+
+	/* Done */
+	return node;
+}
+
+/*
+ * Unreference several class file nodes from a dependency list.
+ *
+ * NOTE: This assumes the VM global mutex is locked.
+ */
+void
+_jc_unref_class_deps(_jc_jvm *vm, _jc_class_depend *deps, int num_deps)
+{
+	int i;
+
+	/* Sanity check */
+	_JC_MUTEX_ASSERT(_jc_get_current_env(), vm->mutex);
+
+	/* Iterate through list */
+	for (i = 0; i < num_deps; i++) {
+		_jc_class_depend *const dep = &deps[i];
+		_jc_class_node *node;
+		_jc_class_node key;
+
+		/* Find node; it must be there */
+		key.name = dep->name;
+		node = _jc_splay_find(&vm->classfiles, &key);
+		_JC_ASSERT(node != NULL);
+		_JC_ASSERT(node->refs > 0);
+
+		/* Decrement reference count */
+		if (--node->refs == 0) {
+			_jc_splay_remove(&vm->classfiles, node);
+			_jc_free_classbytes(&node->bytes);
+			_jc_vm_free(&node);
+		}
+	}
+}
+
+/*
+ * Unreference a class file node.
+ *
+ * NOTE: This assumes the VM global mutex is locked.
+ */
+void
+_jc_unref_class_node(_jc_jvm *vm, _jc_class_node **nodep)
+{
+	_jc_class_node *node = *nodep;
+
+	/* Sanity check */
+	_JC_MUTEX_ASSERT(_jc_get_current_env(), vm->mutex);
+	if (node == NULL)
+		return;
+	*nodep = NULL;
+
+	/* Decrement reference count */
+	_JC_ASSERT(node->refs > 0);
+	if (--node->refs == 0) {
+		_jc_splay_remove(&vm->classfiles, node);
+		_jc_free_classbytes(&node->bytes);
+		_jc_vm_free(&node);
+	}
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_loader.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_loader.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_loader.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_loader.c Tue Oct  4 19:19:16 2005
@@ -0,0 +1,365 @@
+
+/*
+ * 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: class_loader.c,v 1.12 2005/03/16 15:31:11 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/*
+ * Find the internal _jc_class_loader structure corresponding to
+ * a ClassLoader object. Create one if it doesn't already exist,
+ * but do so atomically.
+ *
+ * Posts an exception on failure.
+ */
+_jc_class_loader *
+_jc_get_loader(_jc_env *env, _jc_object *obj)
+{
+	_jc_jvm *const vm = env->vm;
+	jboolean vm_locked = JNI_FALSE;
+	_jc_class_loader *loader;
+	_jc_resolve_info info;
+
+	/* Check for null */
+	if (obj == NULL) {
+		_jc_post_exception(env, _JC_NullPointerException);
+		return NULL;
+	}
+	_JC_ASSERT(_jc_subclass_of(obj, vm->boot.types.ClassLoader));
+
+	/* Lock VM */
+	_JC_MUTEX_LOCK(env, vm->mutex);
+	vm_locked = JNI_TRUE;
+
+	/* See if loader structure already exists */
+	if ((loader = _jc_get_vm_pointer(obj,
+	    vm->boot.fields.ClassLoader.vmdata)) != NULL)
+		goto done;
+
+	/* Create a new loader structure */
+	if ((loader = _jc_create_loader(env)) == NULL) {
+		_jc_post_exception_info(env);
+		goto done;
+	}
+	loader->instance = obj;
+
+	/* Set the ClassLoader.vmdata field */
+	_jc_set_vm_pointer(obj, vm->boot.fields.ClassLoader.vmdata, loader);
+
+	/* Unlock VM */
+	_JC_MUTEX_UNLOCK(env, vm->mutex);
+	vm_locked = JNI_FALSE;
+
+	/* Create reference list with one reference */
+	memset(&info, 0, sizeof(info));
+	info.loader = loader,
+	info.implicit_refs = &loader->instance;
+	info.num_implicit_refs = 1;
+
+	/* Put ClassLoader object on implicit reference list */
+	if (_jc_merge_implicit_refs(env, &info) != JNI_OK) {
+		_jc_destroy_loader(vm, &loader);
+		_jc_post_exception_info(env);
+		goto done;
+	}
+
+done:
+	/* Unlock VM */
+	if (vm_locked)
+		_JC_MUTEX_UNLOCK(env, vm->mutex);
+
+	/* Done */
+	return loader;
+}
+
+/*
+ * Find the class loader to use when loading a type from a JNI function.
+ *
+ * The specified algorithm is:
+ *  (a) Are we running within a JNI method? If so, find the ClassLoader
+ *      associated with the native method's class.
+ *  (b) Otherwise, we are being called using the invocation interface
+ *      (e.g., from the main java startup C program) so we must use the
+ *      loader returned by ClassLoader.getSystemClassLoader().
+ *
+ * Note: the caller must retain a native reference to the class loader
+ * instance (if any) while the class loader is being used.
+ */
+_jc_class_loader *
+_jc_get_jni_loader(_jc_env *env)
+{
+	_jc_jvm *const vm = env->vm;
+
+	/* Use calling method's loader, if known */
+	if (env->jni_method != NULL)
+		return env->jni_method->class->loader;
+
+	/* Invoke ClassLoader.getSystemClassLoader() */
+	if (_jc_invoke_static(env,
+	    vm->boot.methods.ClassLoader.getSystemClassLoader) != JNI_OK)
+		return NULL;
+
+	/* Get internal loader structure from ClassLoader instance */
+	return _jc_get_loader(env, env->retval.l);
+}
+
+/*
+ * Allocate and link a new classloader structure into a VM.
+ *
+ * An exception is stored if unsuccessful.
+ *
+ * NOTE: The global VM mutex must be held when calling this function.
+ */
+_jc_class_loader *
+_jc_create_loader(_jc_env *env)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_class_loader *loader;
+
+	/* Sanity check */
+	_JC_MUTEX_ASSERT(env, vm->mutex);
+
+	/* Create and initialize new structure */
+	if ((loader = _jc_vm_zalloc(env, sizeof(*loader)
+	    + vm->object_path_len * sizeof(*loader->objects_loaded))) == NULL)
+		return NULL;
+	loader->objects_loaded = (jboolean *)(loader + 1);
+
+	/* Initialize class loader memory manager */
+	_jc_uni_alloc_init(&loader->uni, _JC_CL_ALLOC_MIN_PAGES,
+	    &vm->avail_loader_pages);
+
+	/* Initialize mutex and condition variable */
+	if (_jc_mutex_init(env, &loader->mutex) != JNI_OK)
+		goto fail1;
+	if (_jc_cond_init(env, &loader->cond) != JNI_OK)
+		goto fail2;
+
+	/* Initialize initiated, defining, and partially derived type trees */
+	_jc_splay_init(&loader->initiated_types,
+	    _jc_node_cmp, _JC_OFFSETOF(_jc_type_node, node));
+	_jc_splay_init(&loader->deriving_types,
+	    _jc_node_cmp, _JC_OFFSETOF(_jc_type_node, node));
+	_jc_splay_init(&loader->defined_types,
+	    _jc_type_cmp, _JC_OFFSETOF(_jc_type, node));
+
+	/* Initialize native library list */
+	STAILQ_INIT(&loader->native_libs);
+
+	/* Link new class loader into the VM */
+	LIST_INSERT_HEAD(&vm->class_loaders, loader, link);
+
+	/* Done */
+	return loader;
+
+	/* Clean up after failure */
+fail2:	_jc_mutex_destroy(&loader->mutex);
+fail1:	_jc_uni_alloc_free(&loader->uni);
+	_jc_vm_free(&loader);
+	return NULL;
+}
+
+/*
+ * Free a class loader info structure.
+ *
+ * Most loader specific memory is allocated from the loader's memory
+ * pool, so it all gets automatically freed via _jc_cl_alloc_free().
+ *
+ * NOTE: The global VM mutex must be held or the world must be stopped.
+ */
+void
+_jc_destroy_loader(_jc_jvm *vm, _jc_class_loader **loaderp)
+{
+	_jc_class_loader *loader = *loaderp;
+
+	/* Sanity check */
+	_JC_ASSERT(vm->world_stopped || vm->world_ending);
+
+	/* Sanity check */
+	if (loader == NULL)
+		return;
+	*loaderp = NULL;
+
+	/* Sanity check */
+	_JC_ASSERT(loader->deriving_types.size == 0);
+
+	/* Unload associated native libraries */
+	_jc_unload_native_libraries(vm, loader);
+
+	/*
+	 * Walk the tree of classes defined by this loader
+	 * and for each class:
+	 *
+	 * 1. Remove the class' methods from the method tree
+	 * 2. Unreference class and dependencies from VM class file tree
+	 * 3. Destroy any associated ELF linking information
+	 */
+	while (loader->defined_types.size > 0) {
+		_jc_class_node *cnode;
+		_jc_class_node key;
+		_jc_type *type;
+		int j;
+
+		/* Get type at the root of the tree */
+		_JC_ASSERT(loader->defined_types.root != NULL);
+		type = _JC_NODE2ITEM(&loader->defined_types,
+		    loader->defined_types.root);
+
+		/* The following stuff does not apply to array types */
+		if (_JC_FLG_TEST(type, ARRAY))
+			goto remove_type;
+
+		/* Remove all this class' methods from the method tree */
+		if (!_JC_ACC_TEST(type, INTERP)) {
+			for (j = 0; j < type->u.nonarray.num_methods; j++) {
+				_jc_method *const method
+				    = type->u.nonarray.methods[j];
+
+				if (method->function == NULL)
+					continue;
+				_jc_splay_remove(&vm->method_tree, method);
+			}
+		}
+
+		/* Unreference the class file associated with this class */
+		key.name = type->name;
+		cnode = _jc_splay_find(&vm->classfiles, &key);
+		_JC_ASSERT(cnode != NULL);
+		_jc_unref_class_node(vm, &cnode);
+
+		/* Unreference class files this class depends on */
+		_jc_unref_class_deps(vm, type->u.nonarray.class_depends,
+		    type->u.nonarray.num_class_depends);
+
+		/* Free supers info (unresolved ELF types) */
+		_jc_vm_free(&type->u.nonarray.supers);
+
+		/* Unreference parsed class file or ELF object */
+		if (_JC_ACC_TEST(type, INTERP))
+			_jc_destroy_classfile(&type->u.nonarray.u.cfile);
+		else
+			_jc_elf_unref(&type->u.nonarray.u.elf);
+
+remove_type:
+		/* Remove this type from the tree */
+		_jc_splay_remove(&loader->defined_types, type);
+	}
+
+	/* Free implicit reference list */
+	_jc_vm_free(&loader->implicit_refs);
+
+	/* Free class loader memory */
+	_jc_uni_alloc_free(&loader->uni);
+
+	/* Destroy mutex and condition variable */
+	_jc_mutex_destroy(&loader->mutex);
+	_jc_cond_destroy(&loader->cond);
+
+	/* Unlink from VM */
+	LIST_REMOVE(loader, link);
+
+	/* Free class loader */
+	_jc_vm_free(&loader);
+}
+
+/*
+ * Wait for any other thread which the process of loading
+ * a type to finish.
+ *
+ * NOTE: This assumes that the loader mutex is locked.
+ */
+void
+_jc_loader_wait(_jc_env *env, _jc_class_loader *loader)
+{
+	/* Sanity check */
+	_JC_MUTEX_ASSERT(env, loader->mutex);
+
+	/* Exit Java mode */
+	_jc_stopping_java(env, "waiting for class loader %p (%s)",
+	    loader, (loader->instance == NULL) ?
+	      "boot loader" : loader->instance->type->name);
+
+	/* Notify thread we're waiting */
+	loader->waiters = JNI_TRUE;
+
+	/* Wait for other thread */
+	_JC_COND_WAIT(env, loader->cond, loader->mutex);
+
+	/* Resume Java */
+	_jc_resuming_java(env);
+}
+
+/*
+ * Add some implicit references to the implicit reference list
+ * associated with a class loader. We keep this list sorted.
+ * This assumes that the 'refs' array is itself already sorted.
+ *
+ * If unsuccessful an exception is stored.
+ */
+jint
+_jc_merge_implicit_refs(_jc_env *env, _jc_resolve_info *info)
+{
+	_jc_class_loader *const loader = info->loader;
+	_jc_object **refs = info->implicit_refs;
+	int num_refs = info->num_implicit_refs;
+	_jc_object **new_implicit_refs;
+	int i0;
+	int i;
+	int j;
+
+	/* Avoid realloc() of size zero */
+	if (num_refs == 0)
+		return JNI_OK;
+
+	/* Lock loader */
+	_JC_MUTEX_LOCK(env, loader->mutex);
+
+	/* Extend loader's implicit reference array */
+	if ((new_implicit_refs = _jc_vm_realloc(env,
+	    loader->implicit_refs, (loader->num_implicit_refs + num_refs)
+	      * sizeof(*loader->implicit_refs))) == NULL) {
+		_JC_MUTEX_UNLOCK(env, loader->mutex);
+		return JNI_ERR;
+	}
+	loader->implicit_refs = new_implicit_refs;
+
+	/* Sortedly merge in new refs, working backwards */
+	i = loader->num_implicit_refs;
+	for (j = num_refs; j > 0; j--) {
+		for (i0 = i; i > 0
+		    && loader->implicit_refs[i - 1] > refs[j - 1]; i--);
+		if (i > 0 && loader->implicit_refs[i - 1] == refs[j - 1]) {
+			num_refs--;
+			continue;
+		}
+		memmove(loader->implicit_refs + i + j,
+		    loader->implicit_refs + i,
+		    (i0 - i) * sizeof(*loader->implicit_refs));
+		loader->implicit_refs[i + j - 1] = refs[j - 1];
+	}
+
+	/* Update array length */
+	loader->num_implicit_refs += num_refs;
+
+	/* Unlock loader */
+	_JC_MUTEX_UNLOCK(env, loader->mutex);
+
+	/* Done */
+	return JNI_OK;
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_object.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_object.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_object.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/class_object.c Tue Oct  4 19:19:16 2005
@@ -0,0 +1,305 @@
+
+/*
+ * 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: class_object.c,v 1.12 2005/05/18 22:04:45 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/* Internal functions */
+static _jc_elf	*_jc_load_object_dir(_jc_env *env, _jc_class_loader *loader,
+			const char *dir, const char *name);
+
+/*
+ * Find the ELF object that defines the named class, then load the ELF object
+ * and all types defined within it. All class file hash values in the ELF
+ * object must match any already stored in the VM class file tree.
+ *
+ * If unsuccessful an exception is stored.
+ */
+jint
+_jc_load_object(_jc_env *env, _jc_class_loader *loader, const char *name)
+{
+	_jc_jvm *const vm = env->vm;
+	_jc_type *const key = (_jc_type *)((char *)&name
+	    - _JC_OFFSETOF(_jc_type, name));
+	int i;
+
+	/* Sanity check */
+	_JC_ASSERT(vm->loader_enabled);
+
+	/* Try each entry in the object path */
+	for (i = 0; i < vm->object_path_len; i++) {
+		_jc_objpath_entry *const ent = &vm->object_path[i];
+		_jc_elf *elf;
+
+try_again:
+		switch (ent->type) {
+		case _JC_OBJPATH_DIRECTORY:
+
+			/* Look for object file in this directory */
+			if ((elf = _jc_load_object_dir(env,
+			    loader, ent->pathname, name)) != NULL)
+				break;
+
+			/* If something unexpected happened, bail out */
+			if (env->ex.num != _JC_LinkageError)
+				return JNI_ERR;
+
+			/* Try next entry */
+			continue;
+		case _JC_OBJPATH_ELFFILE:
+
+			/* Has this loader already loaded this object? */
+			if (loader->objects_loaded[i])
+				continue;
+
+			/* Try to load specified ELF object file */
+			if ((elf = _jc_elf_load(env,
+			    loader, ent->pathname)) != NULL)
+				break;
+
+			/* If something unexpected happened, bail out */
+			if (env->ex.num != _JC_LinkageError)
+				return JNI_ERR;
+
+			/* Mark this entry as erroneous */
+			VERBOSE(OBJ, vm, "`%s' is invalid: %s",
+			    ent->pathname, env->ex.msg);
+			ent->type = _JC_OBJPATH_ERROR;
+
+			/* Try next entry */
+			continue;
+		case _JC_OBJPATH_UNKNOWN:
+		    {
+			struct stat info;
+
+			/* Examine file; if invalid, skip it from now on */
+			if (stat(ent->pathname, &info) == -1) {
+				VERBOSE(OBJ, vm, "`%s' is invalid: %s",
+				    ent->pathname, strerror(errno));
+				continue;
+			}
+
+			/* If it's a directory, change type and try again */
+			if ((info.st_mode & S_IFMT) == S_IFDIR) {
+				_JC_MUTEX_LOCK(env, vm->mutex);
+				if (ent->type == _JC_OBJPATH_UNKNOWN)
+					ent->type = _JC_OBJPATH_DIRECTORY;
+				_JC_MUTEX_UNLOCK(env, vm->mutex);
+				goto try_again;
+			}
+
+			/* Assume it's an ELF file and try again */
+			_JC_MUTEX_LOCK(env, vm->mutex);
+			if (ent->type == _JC_OBJPATH_UNKNOWN)
+				ent->type = _JC_OBJPATH_ELFFILE;
+			_JC_MUTEX_UNLOCK(env, vm->mutex);
+			goto try_again;
+		    }
+		case _JC_OBJPATH_ERROR:
+			continue;
+		default:
+			_JC_ASSERT(JNI_FALSE);
+		}
+
+		/* We should have a loaded ELF object at this point */
+		_JC_ASSERT(elf != NULL);
+
+		/* Does the ELF file define the type we're looking for? */
+		if (_jc_splay_find(&elf->types, key) == NULL) {
+			VERBOSE(OBJ, vm, "failed: `%s' does not define `%s'",
+			    elf->pathname, name);
+			_jc_elf_unref(&elf);
+			continue;
+		}
+
+		/* Load all types defined in the object */
+		if (_jc_derive_types_from_object(env, elf) != JNI_OK) {
+			if (env->ex.num != _JC_LinkageError)
+				return JNI_ERR;
+			VERBOSE(OBJ, vm, "failed: %s%s%s",
+			    _jc_vmex_names[env->ex.num],
+			    *env->ex.msg != '\0' ? ": " : "", env->ex.msg);
+			_jc_elf_unref(&elf);
+			continue;
+		}
+
+		/* Output object file in object file list if desired */
+		if (vm->object_list != NULL) {
+			fprintf(vm->object_list, "%s\n", elf->pathname);
+			fflush(vm->object_list);
+		}
+
+		/* If object path entry was an ELF file, mark it as loaded */
+		if (ent->type == _JC_OBJPATH_ELFFILE) {
+			_JC_ASSERT(!loader->objects_loaded[i]);
+			loader->objects_loaded[i] = JNI_TRUE;
+		}
+
+		/* Release our reference on ELF file */
+		_jc_elf_unref(&elf);
+
+		/* Done */
+		return JNI_OK;
+	}
+
+	/* Not found */
+	_JC_EX_STORE(env, LinkageError,
+	    "no valid ELF object found containing `%s'", name);
+	return JNI_ERR;
+}
+
+/*
+ * Find a class' ELF object file in a directory hierarchy and read
+ * it in if found. Here we also look for "_package.o".
+ *
+ * If unsuccessful an exception is stored.
+ */
+static _jc_elf *
+_jc_load_object_dir(_jc_env *env, _jc_class_loader *loader,
+	const char *dir, const char *name)
+{
+	_jc_elf *elf;
+	char *ename;
+	char *path;
+	char *s;
+
+	/* Generate encoded name for class */
+	if ((ename = _JC_STACK_ALLOC(env,
+	    _jc_name_encode(name, NULL, JNI_TRUE) + 1)) == NULL)
+		return NULL;
+	_jc_name_encode(name, ename, JNI_TRUE);
+
+	/* Get buffer big enough for both pathnames we'll try */
+	if ((path = _JC_STACK_ALLOC(env, strlen(dir)
+	    + sizeof(_JC_FILE_SEPARATOR) + strlen(ename)
+	    + sizeof(_JC_PACKAGE_OBJECT_NAME))) == NULL)
+		return NULL;
+
+	/* Generate class-specific object file name */
+	sprintf(path, "%s%s%s.o", dir, _JC_FILE_SEPARATOR, ename);
+
+	/* Try to load class-specific ELF object file */
+	if ((elf = _jc_elf_load(env, loader, path)) != NULL)
+		return elf;
+
+	/* Generate package object file name */
+	for (s = path + strlen(path); s > path && s[-1] != '/'; s--);
+	strcpy(s, _JC_PACKAGE_OBJECT_NAME);
+
+	/* Try to load combo ELF object file */
+	if ((elf = _jc_elf_load(env, loader, path)) != NULL)
+		return elf;
+
+	/* Not found */
+	return NULL;
+}
+
+/*
+ * Generate the ELF object file for the named class.
+ *
+ * If unsuccessful an exception is posted.
+ */
+jint
+_jc_generate_object(_jc_env *env, _jc_class_loader *loader, const char *name)
+{
+	_jc_jvm *const vm = env->vm;
+	jobject nameString = NULL;
+	jobject genObj = NULL;
+	jint status = JNI_ERR;
+
+	/* Sanity check */
+	_JC_ASSERT(vm->loader_enabled);
+	_JC_ASSERT(vm->generation_enabled);
+
+	/* Is the "compiler" disabled? */
+	if (vm->compiler_disabled) {
+		_jc_post_exception_msg(env, _JC_LinkageError,
+		    "code generated is disabled");
+		return JNI_ERR;
+	}
+
+	/* Don't generate code during VM initialization */
+	if (vm->initialization != NULL) {
+		_jc_post_exception_msg(env, _JC_LinkageError,
+		    "can't generate code during VM initialization");
+		return JNI_ERR;
+	}
+
+	/*
+	 * Are we already in the middle of generating something?
+	 * If so, don't recurse because Soot is probably not reentrant.
+	 * Hopefully we're just trying to acquire the class file.
+	 */
+	if (env->generating != NULL) {
+		_jc_post_exception_msg(env, _JC_LinkageError,
+		    "recursive attempt to generate `%s' while generating `%s'",
+		    name, env->generating);
+		return JNI_ERR;
+	}
+
+	/* Verbosity */
+	VERBOSE(GEN, vm, "generating ELF object for `%s'", name);
+
+	/* Note that we're generating this object */
+	env->generating = name;
+
+	/* Get the Generate singleton object */
+	if (_jc_invoke_static(env, vm->boot.methods.Generate.v) != JNI_OK)
+		goto fail;
+	if ((genObj = _jc_new_local_native_ref(env, env->retval.l)) == NULL)
+		goto fail;
+
+	/* Put class name in a String object */
+	if ((nameString = _jc_new_local_native_ref(env,
+	    _jc_new_string(env, name, strlen(name)))) == NULL)
+		goto fail;
+
+	/* Invoke Generate.v().generateObject() */
+	if (_jc_invoke_virtual(env, vm->boot.methods.Generate.generateObject,
+	    *genObj, *nameString, loader->instance) != JNI_OK)
+		goto fail;
+
+	/* Done */
+	status = JNI_OK;
+
+fail:
+	/* Turn off generating flag */
+	_JC_ASSERT(env->generating == name);
+	env->generating = NULL;
+
+	/* Clean up native refs */
+	_jc_free_local_native_ref(&genObj);
+	_jc_free_local_native_ref(&nameString);
+
+	/* Report any error */
+	if (status != JNI_OK) {
+		if ((env->vm->verbose_flags & (1 << _JC_VERBOSE_GEN)) != 0) {
+			_jc_printf(vm,
+			    "[verbose %s: object generation for `%s' failed: ",
+			    _jc_verbose_names[_JC_VERBOSE_GEN], name);
+			_jc_fprint_exception_headline(env,
+			    stdout, env->head.pending);
+			_jc_printf(vm, "]\n");
+		}
+	}
+
+	/* Done */
+	return status;
+}
+

Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/debug_line.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/debug_line.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/debug_line.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/debug_line.c Tue Oct  4 19:19:16 2005
@@ -0,0 +1,647 @@
+
+/*
+ * 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: debug_line.c,v 1.7 2005/03/13 02:59:43 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/* Internal functions */
+static jint		_jc_debug_line_add(_jc_env *env, _jc_map_state *state,
+				const void *pc, uint32_t cline);
+static jint		_jc_debug_line_finish(_jc_env *env, _jc_method *method,
+				_jc_class_loader *loader, _jc_map_state *state);
+static Elf_Word		_jc_read_leb128(const u_char **datap, int is_signed);
+static int		_jc_method_addr_cmp(const void *v1, const void *v2);
+
+/*
+ * Process stabs line number information.
+ *
+ * If unsuccessful an exception is stored.
+ */
+jint
+_jc_debug_line_stabs(_jc_env *env, _jc_elf *elf, _jc_splay_tree *tree)
+{
+	_jc_elf_info *const info = elf->info;
+	const Elf_Shdr *const shdr = info->debug_lines.loadable.shdr;
+	_jc_stab *const stabs = (_jc_stab *)(info->map_base + shdr->sh_offset);
+	const int num_stabs = shdr->sh_size / sizeof(*stabs);
+	_jc_map_state state;
+	_jc_method *method;
+	int i;
+
+	/* Sanity check */
+	_JC_ASSERT(info->debug_lines.type == _JC_LINE_DEBUG_STABS);
+
+	/* Initialize state */
+	memset(&state, 0, sizeof(state));
+	method = NULL;
+
+	/* Run through stabs section */
+	for (i = 0; i < num_stabs; i++) {
+		_jc_stab *const stab = &stabs[i];
+
+		/* Check type */
+		switch (stab->type) {
+		case STAB_FUN:
+		    {
+			_jc_method_node *node;
+			_jc_method_node key;
+			const char *fun;
+			const char *s;
+
+			/* Check for end of method; reset state if so */
+			if (stab->sindex == 0) {
+
+				/* Were we skipping this method? */
+				if (method == NULL)
+					continue;
+
+				/* Finalize map */
+				if (_jc_debug_line_finish(env,
+				    method, elf->loader, &state) != JNI_OK)
+					goto fail;
+				method = NULL;
+				break;
+			}
+
+			/* Already doing this function? */
+			if (method != NULL)
+				continue;
+
+			/* Get FUN string containing function name */
+			fun = (const char *)info->debug_lines.strings
+			    + stab->sindex;
+
+			/* Sanity check not already within a method */
+			if (method != NULL) {
+				_JC_EX_STORE(env, LinkageError,
+				    "double opening stabs FUN entry `%s'", fun);
+				goto fail;
+			}
+
+			/* Try to parse out class & method name from symbol */
+			if (strncmp(fun, "_jc_", 4) != 0
+			    || (s = strchr(fun + 4, '$')) == NULL
+			    || strncmp(s + 1, "method$", 7) != 0)
+				continue;
+			key.cname = fun + 4;
+			key.clen = s - key.cname;
+			key.mname = s + 8;
+			if ((s = strchr(key.mname, ':')) == NULL)
+				s += strlen(s);		/* can this happen? */
+			key.mlen = s - key.mname;
+
+			/* Find corresponding method node, if any */
+			if ((node = _jc_splay_find(tree, &key)) == NULL)
+				continue;
+			method = node->method;
+			_JC_ASSERT(method != NULL);
+			_JC_ASSERT(method->function != NULL);
+			_JC_ASSERT(!_JC_ACC_TEST(method, INTERP));
+			_JC_ASSERT(method->u.exec.function_end != NULL);
+
+			/* If method has no line number table, nothing to do */
+			if (method->u.exec.u.linenum.len == 0) {
+				memset(&method->u.exec.u,
+				    0, sizeof(method->u.exec.u));
+				method = NULL;
+				continue;
+			}
+
+			/* Initialize state for this method */
+			_JC_ASSERT(state.pc_map.len == 0);
+			_JC_ASSERT(state.last_linenum == 0);
+			_JC_ASSERT(state.last_map == 0);
+			state.linenum = method->u.exec.u.linenum;
+			memset(&method->u.exec.u, 0, sizeof(method->u.exec.u));
+			break;
+		    }
+		case STAB_SLINE:
+
+			/* If skipping this method, skip lines */
+			if (method == NULL)
+				continue;
+
+			/* Add entry */
+			if (_jc_debug_line_add(env, &state,
+			    (const char *)method->function + stab->value,
+			    stab->desc) != JNI_OK)
+				goto fail;
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* Clean up and exit */
+	_jc_vm_free(&state.pc_map.map);
+	return JNI_OK;
+
+fail:
+	/* Clean up after failure */
+	_jc_vm_free(&state.pc_map.map);
+	return JNI_ERR;
+}
+
+/*
+ * Read a DWARF leb128 value.
+ */
+static inline Elf_Word
+_jc_read_leb128(const u_char **datap, int is_signed)
+{
+	Elf_Word value; 
+	int bitpos;
+
+	for (bitpos = value = 0; ; bitpos += 7) {
+		const u_char byte = *(*datap)++;
+
+		value |= (byte & 0x7f) << bitpos;
+		if ((byte & 0x80) == 0)
+			break;
+	}
+	if (is_signed && (value & (1 << (bitpos + 6))) != 0)
+		value |= (Elf_Word)~0L << (bitpos + 7);
+	return value;
+}
+
+/*
+ * Process DWARF2 line number information.
+ *
+ * If unsuccessful an exception is stored.
+ */
+jint
+_jc_debug_line_dwarf2(_jc_env *env, _jc_elf *elf, _jc_splay_tree *tree)
+{
+	_jc_elf_info *const info = elf->info;
+	const Elf_Shdr *const shdr = info->debug_lines.loadable.shdr;
+	const u_char *ptr = (const u_char *)info->map_base + shdr->sh_offset;
+	const u_char *const section_end = ptr + shdr->sh_size;
+	jboolean using64bit = JNI_FALSE;
+	_jc_dwarf2_line_hdr *hdr;
+	_jc_method_node **nodes;
+	_jc_map_state state;
+	_jc_method *method;
+	unsigned long totlen;
+	union _jc_value jvalue;
+	int node_index;
+	const u_char *ptr_end;
+	const u_char *pc;
+	int num_nodes;
+	int cline;
+	int i;
+
+	/* Put nodes in a list and elide methods with no line number table */
+	if ((nodes = _JC_STACK_ALLOC(env,
+	    tree->size * sizeof(*nodes))) == NULL)
+		goto fail;
+	_jc_splay_list(tree, (void **)nodes);
+	for (i = num_nodes = 0; i < tree->size; i++) {
+		_jc_method_node *const node = nodes[i];
+		_jc_method *const method = node->method;
+
+		_JC_ASSERT(method != NULL);
+		_JC_ASSERT(method->function != NULL);
+		_JC_ASSERT(!_JC_ACC_TEST(method, INTERP));
+		_JC_ASSERT(method->u.exec.function_end != NULL);
+		if (method->u.exec.u.linenum.len > 0)
+			nodes[num_nodes++] = nodes[i];
+	}
+
+	/* Anything to do? */
+	if (num_nodes == 0)
+		return JNI_OK;
+
+	/* Sort methods by starting address */
+	qsort(nodes, num_nodes, sizeof(*nodes), _jc_method_addr_cmp);
+
+	/* Initialize map state */
+	memset(&state, 0, sizeof(state));
+	node_index = 0;
+	method = NULL;
+
+again:
+	/* Read prologue header */
+	memcpy(&jvalue, ptr, sizeof(jint));
+	ptr += sizeof(jint);
+	totlen = jvalue.i;
+	if (totlen == 0xffffffff) {
+		memcpy(&jvalue, ptr, sizeof(jlong));
+		ptr += sizeof(jlong);
+		totlen = jvalue.j;
+		using64bit = JNI_TRUE;
+	} else if (totlen == 0) {
+		memcpy(&jvalue, ptr, sizeof(jint));
+		ptr += sizeof(jint);
+		totlen = jvalue.i;
+		using64bit = JNI_TRUE;
+	}
+	ptr_end = ptr + totlen;
+	ptr += 2;					/* skip version */
+	ptr += 4;					/* skip header len */
+	if (using64bit)
+		ptr += 4;
+	hdr = (_jc_dwarf2_line_hdr *)ptr;
+	ptr += sizeof(*hdr) + hdr->opcode_base - 1;
+
+	/* Skip over directory table */
+	while (*ptr++ != '\0')
+		ptr += strlen((const char *)ptr) + 1;
+
+	/* Skip over file name table */
+	while (*ptr++ != '\0') {
+		ptr += strlen((const char *)ptr) + 1;
+		(void)_jc_read_leb128(&ptr, JNI_FALSE);
+		(void)_jc_read_leb128(&ptr, JNI_FALSE);
+		(void)_jc_read_leb128(&ptr, JNI_FALSE);
+	}
+
+	/* Initialize statement program state */
+	pc = NULL;
+	cline = 1;
+
+	/* Process statement program */
+	while (ptr < ptr_end) {
+		jboolean writeout = JNI_FALSE;
+		jboolean reset = JNI_FALSE;
+		u_char opcode;
+
+		if ((opcode = *ptr++) >= hdr->opcode_base) {	/* special */
+			opcode -= hdr->opcode_base;
+			pc += (opcode / hdr->line_range)
+			    * hdr->minimum_instruction_length;
+			cline += hdr->line_base + opcode % hdr->line_range;
+			writeout = JNI_TRUE;
+		} else if (opcode == 0) {			/* extended */
+			unsigned int oplen;
+			u_char exop;
+
+			oplen = _jc_read_leb128(&ptr, JNI_FALSE);
+			exop = *ptr++;
+			switch (exop) {
+			case DW_LNE_end_sequence:
+				reset = JNI_TRUE;
+				writeout = JNI_TRUE;
+				break;
+			case DW_LNE_set_address:
+			    {
+				const u_char *new_pc;
+
+				/* Get new PC */
+				memcpy(&new_pc, ptr, sizeof(new_pc));
+
+				/* We don't support out-of-spec reversals */
+				if (new_pc < pc) {
+					_JC_EX_STORE(env, LinkageError,
+					    "address reversals in .debug_line"
+					    " section are not supported");
+					goto fail;
+				}
+
+				/* OK */
+				pc = new_pc;
+				break;
+			    }
+			default:
+				break;
+			}
+			ptr += oplen - 1;
+		} else {					/* standard */
+			switch (opcode) {
+			case DW_LNS_copy:
+				writeout = JNI_TRUE;
+				break;
+			case DW_LNS_advance_pc:
+				pc += _jc_read_leb128(&ptr, JNI_FALSE)
+				    * hdr->minimum_instruction_length;
+				break;
+			case DW_LNS_advance_line:
+				cline += _jc_read_leb128(&ptr, JNI_TRUE);
+				break;
+			case DW_LNS_const_add_pc:
+				pc += ((255 - hdr->opcode_base)
+				      / hdr->line_range)
+				    * hdr->minimum_instruction_length;
+				break;
+			case DW_LNS_fixed_advance_pc:
+			    {
+				uint16_t advance;
+
+				memcpy(&advance, ptr, 2);
+				pc += advance;
+				ptr += 2;
+				break;
+			    }
+			default:
+				for (i = 0; i < hdr->standard_opcode_lengths[
+				    opcode - 1]; i++)
+					_jc_read_leb128(&ptr, JNI_FALSE);
+				break;
+			}
+		}
+
+		/* Have we reached the next method? */
+		if (method == NULL
+		    && (const void *)pc
+		      >= nodes[node_index]->method->function) {
+
+			/* Initialize state for this method */
+			_JC_ASSERT(state.pc_map.len == 0);
+			_JC_ASSERT(state.last_linenum == 0);
+			_JC_ASSERT(state.last_map == 0);
+			method = nodes[node_index]->method;
+			_JC_ASSERT(!_JC_ACC_TEST(method, INTERP));
+			state.linenum = method->u.exec.u.linenum;
+			memset(&method->u.exec.u, 0, sizeof(method->u.exec.u));
+		}
+
+		/* Finished with the current method? */
+		if (method != NULL
+		    && (const void *)pc >= method->u.exec.function_end) {
+
+			/* Finalize map for current method */
+			if (_jc_debug_line_finish(env,
+			    method, elf->loader, &state) != JNI_OK)
+				goto fail;
+			method = NULL;
+
+			/* Look for next method */
+			if (++node_index == num_nodes)
+				goto done;
+		}
+
+		/* Write matrix row */
+		if (writeout && method != NULL) {
+			if (_jc_debug_line_add(env,
+			    &state, pc, cline) != JNI_OK)
+				goto fail;
+		}
+
+		/* Reset after DW_LNE_end_sequence */
+		if (reset) {
+			pc = NULL;
+			cline = 1;
+		}
+	}
+	if (ptr < section_end)
+		goto again;
+
+done:
+	/* Sanity check */
+	_JC_ASSERT(method == NULL);
+#ifndef NDEBUG
+	for (i = 0; i < num_nodes; i++) {
+		_jc_method_node *const node = nodes[i];
+		_jc_method *const method = node->method;
+
+		_JC_ASSERT(!_JC_ACC_TEST(method, INTERP));
+		_JC_ASSERT(method->u.exec.u.pc_map.map != NULL);
+	}
+#endif
+
+	/* Done */
+	return JNI_OK;
+
+fail:
+	/* Failed */
+	return JNI_ERR;
+}
+
+/*
+ * Map a PC return address within a function to a Java line number.
+ * This assumes the PC is within the function. Returns 0 if unknown.
+ *
+ * The PC return address should point to the instruction just after the
+ * instruction that makes the function call.
+ */
+int
+_jc_exec_pc_to_jline(_jc_method *method, const void *pc)
+{
+	_jc_pc_map_info *const pcmap = &method->u.exec.u.pc_map;
+	_jc_pc_map *base;
+	int span;
+
+	/* Sanity check */
+	_JC_ASSERT(!_JC_ACC_TEST(method, INTERP));
+
+	/* Sanity check that the PC lies within the method */
+	_JC_ASSERT(pc > method->function && pc <= method->u.exec.function_end);
+
+	/* If PC map does not exist, bail out */
+	if (!_JC_ACC_TEST(method, PCMAP))
+		return 0;
+
+	/* Binary search PC map */
+	for (base = pcmap->map, span = pcmap->len; span != 0; span >>= 1) {
+		_jc_pc_map *const sample = &base[span >> 1];
+
+		if (pc <= sample->pc)
+			continue;
+		if (pc > (sample + 1)->pc) {
+			base = sample + 1;
+			span--;
+			continue;
+		}
+		return sample->jline;
+	}
+
+	/* Not found */
+	return 0;
+}
+
+/*
+ * Add a new [addr => java line number] pair to the PC map, given
+ * an [addr => cline] mapping. We search the line number table to derive
+ * the intermediate [cline => line number table entry] mapping. If the
+ * address is before the first line number table entry, do nothing.
+ *
+ * We assume that the entries in the map are delivered roughly in order.
+ * Otherwise, this algorithm could be O(n^2) slow.
+ *
+ * If unsuccessful an exception is stored.
+ */
+static jint
+_jc_debug_line_add(_jc_env *env, _jc_map_state *state,
+	const void *pc, uint32_t cline)
+{
+	int linenum_index;
+	int map_index;
+
+	/* Sanity check */
+	_JC_ASSERT(state->linenum.len > 0);
+
+	/*
+	 * Map C line number into line number table index. We expect
+	 * this line number table index to be close to the last one.
+	 * If it's not in the table, no mapping is needed.
+	 */
+	linenum_index = state->last_linenum;
+	if (cline > state->linenum.table[linenum_index].cline) {
+		while (linenum_index < state->linenum.len - 1
+		    && cline >= state->linenum.table[linenum_index + 1].cline)
+			linenum_index++;
+	} else {
+		while (linenum_index > 0
+		   && cline < state->linenum.table[linenum_index].cline)
+			linenum_index--;
+		if (cline < state->linenum.table[0].cline)
+			return JNI_OK;
+	}
+
+	/*
+	 * Find insertion point for the new entry. We expect it
+	 * to be near the previous insertion point, if any.
+	 */
+	map_index = state->last_map;
+	if (state->pc_map.len == 0) {
+		_JC_ASSERT(map_index == 0);
+		goto insert;
+	}
+	if (pc > state->pc_map.map[map_index].pc) {
+		while (map_index < state->pc_map.len
+		    && pc >= state->pc_map.map[++map_index].pc)
+			;
+	} else {
+		while (map_index > 0 && pc < state->pc_map.map[map_index].pc)
+			map_index--;
+	}
+
+insert:
+	/* Extend PC map to make room for the new entry */
+	if (state->pc_map.len == state->map_alloc) {
+		void *mem;
+
+		state->map_alloc = state->map_alloc * 2 + 32;
+		if ((mem = _jc_vm_realloc(env, state->pc_map.map,
+		    state->map_alloc * sizeof(*state->pc_map.map))) == NULL)
+			return JNI_ERR;
+		state->pc_map.map = mem;
+	}
+
+	/* Shift higher entries up by one to make room */
+	if (map_index < state->pc_map.len) {
+		memmove(state->pc_map.map + map_index + 1,
+		    state->pc_map.map + map_index,
+		    (state->pc_map.len - map_index)
+		      * sizeof(*state->pc_map.map));
+	}
+
+	/* Fill in new entry */
+	state->pc_map.map[map_index].pc = pc;
+	state->pc_map.map[map_index].jline
+	    = state->linenum.table[linenum_index].jline;
+
+	/* Update state */
+	state->last_linenum = linenum_index;
+	state->last_map = map_index;
+	state->pc_map.len++;
+
+	/* Done */
+	return JNI_OK;
+}
+
+/*
+ * Finalize a PC map and store it with its method.
+ *
+ * If unsuccessful an exception is stored.
+ */
+static jint
+_jc_debug_line_finish(_jc_env *env, _jc_method *method,
+	_jc_class_loader *loader, _jc_map_state *state)
+{
+	_jc_pc_map_info *const pcmap = &method->u.exec.u.pc_map;
+	int num_dups;
+	int i;
+	int j;
+
+	/* Sanity check */
+	_JC_ASSERT(!_JC_ACC_TEST(method, INTERP));
+
+	/* TODO XXX understand why this happens */
+	if (_JC_ACC_TEST(method, PCMAP))
+		goto done;
+
+	/* Count number of redundant entries */
+	for (num_dups = 0, i = 0; i < state->pc_map.len - 1; i++) {
+		_jc_pc_map *const this = &state->pc_map.map[i];
+		_jc_pc_map *const next = &state->pc_map.map[i + 1];
+
+		_JC_ASSERT(this->pc <= next->pc);
+		if (this->jline == next->jline)
+			num_dups++;
+	}
+
+	/* Allocate memory for compressed PC map */
+	_JC_ASSERT(pcmap->map == NULL);
+	pcmap->len = state->pc_map.len - num_dups;
+	_JC_MUTEX_LOCK(env, loader->mutex);
+	pcmap->map = _jc_cl_alloc(env, loader,
+	    (pcmap->len + 1) * sizeof(*state->pc_map.map));
+	_JC_MUTEX_UNLOCK(env, loader->mutex);
+	if (pcmap->map == NULL)
+		return JNI_ERR;
+
+	/* Copy non-redundant entries */
+	for (i = j = 0; i < state->pc_map.len; j++) {
+		memcpy(&pcmap->map[j],
+		    &state->pc_map.map[i], sizeof(*state->pc_map.map));
+		while (++i < state->pc_map.len
+		    && state->pc_map.map[i].jline
+		      == state->pc_map.map[i - 1].jline);
+	}
+	_JC_ASSERT(j == pcmap->len);
+
+	/* Add terminating entry */
+	pcmap->map[j].pc = method->u.exec.function_end;
+	pcmap->map[j].jline = 0;
+
+#if 0
+    {
+	printf("MAP FOR `%s.%s%s':\n",
+	    method->class->name, method->name, method->signature);
+	for (i = 0; i < pcmap->len; i++) {
+		_jc_pc_map *const map = &pcmap->map[i];
+
+		printf("    [%d] %p -> %d\n", i, map->pc, map->jline);
+	}
+    }
+#endif
+
+done:
+	/* Reset map state */
+	state->pc_map.len = 0;
+	state->last_linenum = 0;
+	state->last_map = 0;
+	state->linenum.len = 0;
+	state->linenum.table = NULL;
+
+	/* Done */
+	method->access_flags |= _JC_ACC_PCMAP;
+	return JNI_OK;
+}
+
+static int
+_jc_method_addr_cmp(const void *v1, const void *v2)
+{
+	_jc_method_node *const node1 = *((_jc_method_node **)v1);
+	_jc_method_node *const node2 = *((_jc_method_node **)v2);
+
+	return (node1->method->function > node2->method->function)
+	    - (node1->method->function < node2->method->function);
+}
+
+