From fe862dbf491fb9fa09b3581b6151b434835b7e1d Mon Sep 17 00:00:00 2001 From: kgallowa Date: Thu, 15 Feb 2007 15:08:27 +0000 Subject: [PATCH] 2007-02-15 Kyle Galloway * defineclass.cc (_Jv_ClassReader::read_one_code_attribute): Added LocalVariableTable attribute handling. (_Jv_ClassReader::pool_Utf8_to_char_arr): New method. * jvmti.cc (_Jv_JVMTI_GetLocalVariableTable): New method. * include/java-interp.h: Added local_var_table and local_var_table_len fields to _Jv_InterpMethod. (_Jv_InterpMethod::get_local_var_table): New method. * testsuite/libjava.jvmti/interp/getlocalvartable.java: New test. * testsuite/libjava.jvmti/interp/getlocalvartable.jar: New test. * testsuite/libjava.jvmti/interp/getlocalvartable.out: Output for new test. * testsuite/libjava.jvmti/interp/getlocalvartable.h: New test. * testsuite/libjava.jvmti/interp/natgetlocalvartable.cc: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@121999 138bc75d-0d04-0410-961f-82ee72b054a4 --- libjava/ChangeLog | 18 +++++++++ libjava/defineclass.cc | 43 +++++++++++++++++++++ libjava/include/java-interp.h | 33 ++++++++++++++++ libjava/interpret.cc | 24 ++++++++++++ libjava/jvmti.cc | 87 +++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 202 insertions(+), 3 deletions(-) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 5862f8f..f86ef85 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,4 +1,22 @@ 2007-02-15 Kyle Galloway + + * defineclass.cc (_Jv_ClassReader::read_one_code_attribute): + Added LocalVariableTable attribute handling. + (_Jv_ClassReader::pool_Utf8_to_char_arr): New method. + * jvmti.cc (_Jv_JVMTI_GetLocalVariableTable): New method. + * include/java-interp.h: Added local_var_table and + local_var_table_len fields to _Jv_InterpMethod. + (_Jv_InterpMethod::get_local_var_table): New method. + * testsuite/libjava.jvmti/interp/getlocalvartable.java: New + test. + * testsuite/libjava.jvmti/interp/getlocalvartable.jar: New test. + * testsuite/libjava.jvmti/interp/getlocalvartable.out: Output + for new test. + * testsuite/libjava.jvmti/interp/getlocalvartable.h: New test. + * testsuite/libjava.jvmti/interp/natgetlocalvartable.cc: New + test. + +2007-02-15 Kyle Galloway * gnu/classpath/jdwp/natVMVirtualMachine (getFrames): Implement. diff --git a/libjava/defineclass.cc b/libjava/defineclass.cc index 12c6032..c66fff8 100644 --- a/libjava/defineclass.cc +++ b/libjava/defineclass.cc @@ -299,6 +299,9 @@ struct _Jv_ClassReader /** check an utf8 entry, without creating a Utf8Const object */ bool is_attribute_name (int index, const char *name); + + /** return the value of a utf8 entry in the passed array */ + int pool_Utf8_to_char_arr (int index, char **entry); /** here goes the class-loader members defined out-of-line */ void handleConstantPool (); @@ -784,6 +787,18 @@ _Jv_ClassReader::is_attribute_name (int index, const char *name) return !memcmp (bytes+offsets[index]+2, name, len); } +// Get a UTF8 value from the constant pool and turn it into a garbage +// collected char array. +int _Jv_ClassReader::pool_Utf8_to_char_arr (int index, char** entry) +{ + check_tag (index, JV_CONSTANT_Utf8); + int len = get2u (bytes + offsets[index]); + *entry = reinterpret_cast (_Jv_AllocBytes (len + 1)); + (*entry)[len] = '\0'; + memcpy (*entry, bytes + offsets[index] + 2, len); + return len + 1; +} + void _Jv_ClassReader::read_one_field_attribute (int field_index, bool *found_value) { @@ -979,6 +994,34 @@ void _Jv_ClassReader::read_one_code_attribute (int method_index) method->line_table_len = table_len; method->line_table = table; } + else if (is_attribute_name (name, "LocalVariableTable")) + { + _Jv_InterpMethod *method = reinterpret_cast<_Jv_InterpMethod *> + (def_interp->interpreted_methods[method_index]); + if (method->local_var_table != NULL) + throw_class_format_error ("Method already has LocalVariableTable"); + + int table_len = read2u (); + _Jv_LocalVarTableEntry *table + = reinterpret_cast<_Jv_LocalVarTableEntry *> + (_Jv_AllocRawObj (table_len * sizeof (_Jv_LocalVarTableEntry))); + + for (int i = 0; i < table_len; i++) + { + table[i].bytecode_start_pc = read2u (); + table[i].length = read2u (); + int len; + len = pool_Utf8_to_char_arr (read2u (), &table[i].name); + len = pool_Utf8_to_char_arr (read2u (), &table[i].descriptor); + table[i].slot = read2u (); + + if (table[i].slot > method->max_locals || table[i].slot < 0) + throw_class_format_error ("Malformed Local Variable Table: Invalid Slot"); + } + + method->local_var_table_len = table_len; + method->local_var_table = table; + } else { /* ignore unknown code attributes */ diff --git a/libjava/include/java-interp.h b/libjava/include/java-interp.h index 2b3ae7c..40c3b28 100644 --- a/libjava/include/java-interp.h +++ b/libjava/include/java-interp.h @@ -137,6 +137,21 @@ struct _Jv_LineTableEntry int line; }; +// This structure holds local variable information. +// The pc value is the first pc where the variable must have a value and it +// must continue to have a value until (start_pc + length). +// The name is the variable name, and the descriptor contains type information. +// The slot is the index in the local variable array of this method, long and +// double occupy slot and slot+1. +struct _Jv_LocalVarTableEntry +{ + int bytecode_start_pc; + int length; + char *name; + char *descriptor; + int slot; +}; + class _Jv_InterpMethod : public _Jv_MethodBase { // Breakpoint instruction @@ -157,6 +172,10 @@ class _Jv_InterpMethod : public _Jv_MethodBase // Length of the line_table - when this is zero then line_table is NULL. int line_table_len; _Jv_LineTableEntry *line_table; + + // The local variable table length and the table itself + int local_var_table_len; + _Jv_LocalVarTableEntry *local_var_table; pc_t prepared; int number_insn_slots; @@ -224,6 +243,20 @@ class _Jv_InterpMethod : public _Jv_MethodBase { return static_cast (max_locals); } + + /* Get info for a local variable of this method. + * If there is no loca_var_table for this method it will return -1. + * table_slot indicates which slot in the local_var_table to get, if there is + * no variable at this location it will return 0. + * Otherwise, it will return the number of table slots after the selected + * slot, indexed from 0. + * + * Example: there are 5 slots in the table, you request slot 0 so it will + * return 4. + */ + int get_local_var_table (char **name, char **sig, char **generic_sig, + jlong *startloc, jint *length, jint *slot, + int table_slot); /* Installs a break instruction at the given code index. Returns the pc_t of the breakpoint or NULL if index is invalid. */ diff --git a/libjava/interpret.cc b/libjava/interpret.cc index 7e7d36d..8a4edac 100644 --- a/libjava/interpret.cc +++ b/libjava/interpret.cc @@ -1414,6 +1414,30 @@ _Jv_InterpMethod::get_line_table (jlong& start, jlong& end, #endif // !DIRECT_THREADED } +int +_Jv_InterpMethod::get_local_var_table (char **name, char **sig, + char **generic_sig, jlong *startloc, + jint *length, jint *slot, + int table_slot) +{ + if (local_var_table == NULL) + return -2; + if (table_slot >= local_var_table_len) + return -1; + else + { + *name = local_var_table[table_slot].name; + *sig = local_var_table[table_slot].descriptor; + *generic_sig = local_var_table[table_slot].descriptor; + + *startloc = static_cast + (local_var_table[table_slot].bytecode_start_pc); + *length = static_cast (local_var_table[table_slot].length); + *slot = static_cast (local_var_table[table_slot].slot); + } + return local_var_table_len - table_slot -1; +} + pc_t _Jv_InterpMethod::install_break (jlong index) { diff --git a/libjava/jvmti.cc b/libjava/jvmti.cc index 37e6727..ae906a0 100644 --- a/libjava/jvmti.cc +++ b/libjava/jvmti.cc @@ -704,6 +704,88 @@ _Jv_JVMTI_GetLineNumberTable (jvmtiEnv *env, jmethodID method, } static jvmtiError JNICALL +_Jv_JVMTI_GetLocalVariableTable (MAYBE_UNUSED jvmtiEnv *env, jmethodID method, + jint *num_locals, + jvmtiLocalVariableEntry **locals) +{ + REQUIRE_PHASE (env, JVMTI_PHASE_LIVE); + NULL_CHECK (num_locals); + NULL_CHECK (locals); + + CHECK_FOR_NATIVE_METHOD(method); + + jclass klass; + jvmtiError jerr = env->GetMethodDeclaringClass (method, &klass); + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + _Jv_InterpMethod *imeth = reinterpret_cast<_Jv_InterpMethod *> + (_Jv_FindInterpreterMethod (klass, method)); + + if (imeth == NULL) + return JVMTI_ERROR_INVALID_METHODID; + + jerr = env->GetMaxLocals (method, num_locals); + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + jerr = env->Allocate (static_cast + ((*num_locals) * sizeof (jvmtiLocalVariableEntry)), + reinterpret_cast (locals)); + + if (jerr != JVMTI_ERROR_NONE) + return jerr; + + //the slot in the methods local_var_table to get + int table_slot = 0; + char *name; + char *sig; + char *generic_sig; + + while (table_slot < *num_locals + && imeth->get_local_var_table (&name, &sig, &generic_sig, + &((((*locals)[table_slot].start_location))), + &((*locals)[table_slot].length), + &((*locals)[table_slot].slot), + table_slot) + >= 0) + { + jerr = env->Allocate (static_cast (strlen (name) + 1), + reinterpret_cast + (&(*locals)[table_slot].name)); + if (jerr != JVMTI_ERROR_NONE) + return jerr; + strcpy ((*locals)[table_slot].name, name); + + jerr = env->Allocate (static_cast (strlen (name) + 1), + reinterpret_cast + (&(*locals)[table_slot].signature)); + if (jerr != JVMTI_ERROR_NONE) + return jerr; + strcpy ((*locals)[table_slot].signature, sig); + + jerr = env->Allocate (static_cast (strlen (name) + 1), + reinterpret_cast + (&(*locals)[table_slot].generic_signature)); + if (jerr != JVMTI_ERROR_NONE) + return jerr; + strcpy ((*locals)[table_slot].generic_signature, generic_sig); + + table_slot++; + } + + if (table_slot == 0) + return JVMTI_ERROR_ABSENT_INFORMATION; + + // If there are double or long variables in the table, the the table will be + // smaller than the max number of slots, so correct for this here. + if ((table_slot) < *num_locals) + *num_locals = table_slot; + + return JVMTI_ERROR_NONE; +} + +static jvmtiError JNICALL _Jv_JVMTI_IsMethodNative (MAYBE_UNUSED jvmtiEnv *env, jmethodID method, jboolean *result) { @@ -733,8 +815,7 @@ _Jv_JVMTI_IsMethodSynthetic (MAYBE_UNUSED jvmtiEnv *env, jmethodID method, } static jvmtiError JNICALL -_Jv_JVMTI_GetMaxLocals (MAYBE_UNUSED jvmtiEnv *env, jmethodID method, - jint *max_locals) +_Jv_JVMTI_GetMaxLocals (jvmtiEnv *env, jmethodID method, jint *max_locals) { REQUIRE_PHASE (env, JVMTI_PHASE_START | JVMTI_PHASE_LIVE); NULL_CHECK (max_locals); @@ -1686,7 +1767,7 @@ struct _Jv_jvmtiEnv _Jv_JVMTI_Interface = UNIMPLEMENTED, // GetArgumentsSize _Jv_JVMTI_GetLineNumberTable, // GetLineNumberTable UNIMPLEMENTED, // GetMethodLocation - UNIMPLEMENTED, // GetLocalVariableTable + _Jv_JVMTI_GetLocalVariableTable, // GetLocalVariableTable RESERVED, // reserved73 RESERVED, // reserved74 UNIMPLEMENTED, // GetBytecodes -- 2.7.4