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);
+}
+
+