This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA/JVMTI] Implement GetLocalVariableTable and GetMaxLocals


Keith Seitz wrote:
Keith Seitz wrote:

> Kyle> + int get_local_var_table (char **name, char **sig, char **generic_sig,
> Kyle> + long *startloc, jint *length, jint *slot,
> Kyle> + int table_slot)
> Kyle> + *name = reinterpret_cast<char *>
> Kyle> + (_Jv_AllocBytes (strlen (local_var_table[table_slot].name) + 1));

Of course, your original concern about the use of _Jv_AllocBytes is still warranted: It should be using _Jv_MallocUnchecked, just like _Jv_JVMTI_Allocate.


I was simply responding to your original question about how the memory gets released. I apologize for any confusion.
So, what I have done is to change things a bit. get_local_var_table now just sets the pointers to point to the strings stored in _Jv_InterpMethod. in the JVMTI call, we allocate buffers of the correct size, then strcpy the strings over into the JVMTI structure. I think this addresses all the concers.

Any other issues?

- Kyle
Index: libjava/interpret.cc
===================================================================
--- libjava/interpret.cc	(revision 121887)
+++ libjava/interpret.cc	(working copy)
@@ -1414,6 +1414,30 @@
 #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<jlong> 
+                    (local_var_table[table_slot].bytecode_start_pc);
+      *length = static_cast<jint> (local_var_table[table_slot].length);
+      *slot = static_cast<jint> (local_var_table[table_slot].slot);
+    }
+  return local_var_table_len - table_slot -1;
+}
+
 pc_t
 _Jv_InterpMethod::install_break (jlong index)
 {
Index: libjava/include/java-interp.h
===================================================================
--- libjava/include/java-interp.h	(revision 121887)
+++ libjava/include/java-interp.h	(working copy)
@@ -137,6 +137,21 @@
   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 @@
   // 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 @@
   {
     return static_cast<int> (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. */
Index: libjava/testsuite/libjava.jvmti/interp/getlocalvartable.h
===================================================================
--- libjava/testsuite/libjava.jvmti/interp/getlocalvartable.h	(revision 0)
+++ libjava/testsuite/libjava.jvmti/interp/getlocalvartable.h	(revision 0)
@@ -0,0 +1,19 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+
+#ifndef __getlocalvartable__
+#define __getlocalvartable__
+
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+JNIEXPORT jint JNICALL Java_getlocalvartable_do_1getlocalvartable_1tests (JNIEnv *env, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __getlocalvartable__ */
Index: libjava/testsuite/libjava.jvmti/interp/getlocalvartable.out
===================================================================
--- libjava/testsuite/libjava.jvmti/interp/getlocalvartable.out	(revision 0)
+++ libjava/testsuite/libjava.jvmti/interp/getlocalvartable.out	(revision 0)
@@ -0,0 +1,109 @@
+JVMTI getlocalvartable Interpreted Test
+Slot: 0
+  Name: this
+  Sig: Lgetlocalvartable;
+  Gen Sig: Lgetlocalvartable;
+  Start Loc: 0
+  Length: 28
+Slot: 1
+  Name: pone
+  Sig: F
+  Gen Sig: F
+  Start Loc: 0
+  Length: 28
+Slot: 2
+  Name: ptwo
+  Sig: F
+  Gen Sig: F
+  Start Loc: 0
+  Length: 28
+Slot: 3
+  Name: fone
+  Sig: F
+  Gen Sig: F
+  Start Loc: 2
+  Length: 26
+Slot: 4
+  Name: ftwo
+  Sig: F
+  Gen Sig: F
+  Start Loc: 7
+  Length: 21
+Slot: 5
+  Name: done
+  Sig: D
+  Gen Sig: D
+  Start Loc: 14
+  Length: 14
+Slot: 7
+  Name: dtwo
+  Sig: D
+  Gen Sig: D
+  Start Loc: 22
+  Length: 6
+Slot: 0
+  Name: this
+  Sig: Lgetlocalvartable;
+  Gen Sig: Lgetlocalvartable;
+  Start Loc: 0
+  Length: 25
+Slot: 1
+  Name: ipone
+  Sig: I
+  Gen Sig: I
+  Start Loc: 0
+  Length: 25
+Slot: 2
+  Name: iptwo
+  Sig: I
+  Gen Sig: I
+  Start Loc: 0
+  Length: 25
+Slot: 3
+  Name: ione
+  Sig: I
+  Gen Sig: I
+  Start Loc: 2
+  Length: 23
+Slot: 4
+  Name: itwo
+  Sig: I
+  Gen Sig: I
+  Start Loc: 7
+  Length: 18
+Slot: 5
+  Name: lone
+  Sig: J
+  Gen Sig: J
+  Start Loc: 11
+  Length: 14
+Slot: 7
+  Name: ltwo
+  Sig: J
+  Gen Sig: J
+  Start Loc: 19
+  Length: 6
+Slot: 0
+  Name: this
+  Sig: Lgetlocalvartable;
+  Gen Sig: Lgetlocalvartable;
+  Start Loc: 0
+  Length: 8
+Slot: 1
+  Name: op
+  Sig: Ljava/lang/Object;
+  Gen Sig: Ljava/lang/Object;
+  Start Loc: 0
+  Length: 8
+Slot: 2
+  Name: oone
+  Sig: Ljava/lang/Object;
+  Gen Sig: Ljava/lang/Object;
+  Start Loc: 2
+  Length: 6
+Slot: 3
+  Name: otwo
+  Sig: Ljava/lang/Object;
+  Gen Sig: Ljava/lang/Object;
+  Start Loc: 4
+  Length: 4
Index: libjava/testsuite/libjava.jvmti/interp/natgetlocalvartable.cc
===================================================================
--- libjava/testsuite/libjava.jvmti/interp/natgetlocalvartable.cc	(revision 0)
+++ libjava/testsuite/libjava.jvmti/interp/natgetlocalvartable.cc	(revision 0)
@@ -0,0 +1,67 @@
+#include <jni.h>
+
+#include <jvmti.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "getlocalvartable.h"
+
+JNIEXPORT jint JNICALL Java_getlocalvartable_do_1getlocalvartable_1tests
+(JNIEnv *env, jclass klass)
+{
+  JavaVM *vm;
+  jint err = env->GetJavaVM (&vm);
+  if (err < 0)
+    {
+      fprintf (stderr, "error getting VM\n");
+      exit (1);
+    }
+
+  jvmtiEnv *jvmti = NULL;
+  vm->GetEnv ((void **) &jvmti, JVMTI_VERSION_1_0);
+
+  if (jvmti == NULL)
+    {
+      fprintf (stderr, "error getting jvmti environment\n");
+      exit (1);
+    }
+  
+  jint entrys;
+  jvmtiLocalVariableEntry *var_table;
+
+  jvmtiError jerr;
+  
+  jmethodID meth_ids[3];
+  
+  meth_ids[0] = env->GetMethodID (klass, "aMethod", "(FF)D");
+  meth_ids[1] = env->GetMethodID (klass, "bMethod", "(II)J");
+  meth_ids[2] = env->GetMethodID (klass, "cMethod", 
+                                  "(Ljava/lang/Object;)Ljava/lang/Object;");
+  for (int i = 0; i < 3; i++)
+    {
+      jerr = jvmti->GetLocalVariableTable (meth_ids[i], &entrys, &var_table);
+      if (jerr != JVMTI_ERROR_NONE)
+        {
+          char *error_name;
+          jvmti->GetErrorName (jerr, &error_name);
+          fprintf (stderr, "JVMTI Error: %s\n", error_name);
+          jvmti->Deallocate (reinterpret_cast<unsigned char *> (error_name));
+        }
+      else
+        {
+          for (int j = 0; j < entrys; j++)
+            {
+              printf ("Slot: %d\n", static_cast<int> (var_table[j].slot));
+              printf ("  Name: %s\n", var_table[j].name);
+              printf ("  Sig: %s\n", var_table[j].signature);
+              printf ("  Gen Sig: %s\n", var_table[j].generic_signature);
+              printf ("  Start Loc: %ld\n", static_cast<long> (var_table[j].start_location));
+              printf ("  Length: %d\n", static_cast<int> (var_table[j].length));
+            }
+          
+          jvmti->Deallocate (reinterpret_cast<unsigned char *> (var_table));
+        }
+    }
+    
+    return 0;
+}
Index: libjava/testsuite/libjava.jvmti/interp/getlocalvartable.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: libjava/testsuite/libjava.jvmti/interp/getlocalvartable.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Index: libjava/testsuite/libjava.jvmti/interp/getlocalvartable.java
===================================================================
--- libjava/testsuite/libjava.jvmti/interp/getlocalvartable.java	(revision 0)
+++ libjava/testsuite/libjava.jvmti/interp/getlocalvartable.java	(revision 0)
@@ -0,0 +1,63 @@
+public class getlocalvartable
+{
+  public boolean done = false;
+
+  // num_frames is the number of frames > the original run () call so if
+  // num_frames = 1, the thread will have 2 frames, the original Thread.run
+  // call, plus one additional
+  public int num_frames, thread_num;
+
+  public static int num_threads = 1;
+
+  static
+    {
+      System.loadLibrary("natgetlocalvartable");
+    }
+
+  public double aMethod (float pone, float ptwo)
+  {
+    float fone, ftwo;
+    double done, dtwo;
+    
+    fone = pone;
+    ftwo = 2 * ptwo;
+    
+    done = 5 * fone;
+    dtwo = 6 * ftwo;
+    
+    return done + dtwo;
+  }
+  
+  public long bMethod (int ipone, int iptwo)
+  {
+    int ione, itwo;
+    long lone, ltwo;
+    
+    ione = ipone;
+    itwo = 5 * iptwo;
+    
+    lone = ione;
+    ltwo = 8 * itwo;
+    
+    return lone + ltwo;
+  }
+  
+  public Object cMethod (Object op)
+  {
+    Object oone, otwo;
+    oone = op;
+    otwo = oone;
+    oone = null;
+    
+    return otwo;
+  }
+
+  public static native int do_getlocalvartable_tests ();
+
+  public static void main (String[] args)
+  {
+    System.out.println ("JVMTI getlocalvartable Interpreted Test");
+
+    do_getlocalvartable_tests ();
+  }
+}
Index: libjava/jvmti.cc
===================================================================
--- libjava/jvmti.cc	(revision 121887)
+++ libjava/jvmti.cc	(working copy)
@@ -704,6 +704,88 @@
 }
 
 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<jlong> 
+                          ((*num_locals) * sizeof (jvmtiLocalVariableEntry)),
+                        reinterpret_cast<unsigned char **> (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<jlong> (strlen (name) + 1),
+                             reinterpret_cast<unsigned char **>
+                               (&(*locals)[table_slot].name));
+      if (jerr != JVMTI_ERROR_NONE)
+        return jerr;
+      strcpy ((*locals)[table_slot].name, name);
+
+      jerr = env->Allocate (static_cast<jlong> (strlen (name) + 1),
+                               reinterpret_cast<unsigned char **>
+                                 (&(*locals)[table_slot].signature));
+      if (jerr != JVMTI_ERROR_NONE)
+        return jerr;
+      strcpy ((*locals)[table_slot].signature, sig);
+  
+      jerr = env->Allocate (static_cast<jlong> (strlen (name) + 1),
+                               reinterpret_cast<unsigned char **>
+                               (&(*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 @@
 }
 
 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 @@
   UNIMPLEMENTED,		// GetArgumentsSize
   _Jv_JVMTI_GetLineNumberTable,	// GetLineNumberTable
   UNIMPLEMENTED,		// GetMethodLocation
-  UNIMPLEMENTED,		// GetLocalVariableTable
+  _Jv_JVMTI_GetLocalVariableTable,		// GetLocalVariableTable
   RESERVED,			// reserved73
   RESERVED,			// reserved74
   UNIMPLEMENTED,		// GetBytecodes
Index: libjava/defineclass.cc
===================================================================
--- libjava/defineclass.cc	(revision 121887)
+++ libjava/defineclass.cc	(working copy)
@@ -299,6 +299,9 @@
 
   /** 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 @@
     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<char *> (_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 @@
       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_AllocBytes (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 */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]