OSDN Git Service

2008-01-04 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / java / lang / natClass.cc
index 1298429..5b14160 100644 (file)
@@ -1,6 +1,6 @@
 // natClass.cc - Implementation of java.lang.Class native methods.
 
-/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation
 
    This file is part of libgcj.
@@ -29,6 +29,7 @@ details.  */
 #include <java/lang/reflect/Member.h>
 #include <java/lang/reflect/Method.h>
 #include <java/lang/reflect/Field.h>
+#include <java/lang/reflect/Proxy.h>
 #include <java/lang/reflect/Constructor.h>
 #include <java/lang/AbstractMethodError.h>
 #include <java/lang/ArrayStoreException.h>
@@ -50,12 +51,28 @@ details.  */
 #include <java/lang/NullPointerException.h>
 #include <java/lang/RuntimePermission.h>
 #include <java/lang/System.h>
+#include <java/lang/SecurityException.h>
 #include <java/lang/SecurityManager.h>
 #include <java/lang/StringBuffer.h>
 #include <java/lang/VMClassLoader.h>
 #include <gcj/method.h>
 #include <gnu/gcj/RawData.h>
 #include <java/lang/VerifyError.h>
+#include <java/lang/InternalError.h>
+#include <java/lang/TypeNotPresentException.h>
+#include <java/lang/Byte.h>
+#include <java/lang/Short.h>
+#include <java/lang/Integer.h>
+#include <java/lang/Float.h>
+#include <java/lang/Double.h>
+#include <java/lang/Long.h>
+#include <java/lang/Character.h>
+#include <java/lang/Boolean.h>
+#include <java/lang/annotation/Annotation.h>
+#include <java/util/HashMap.h>
+#include <java/util/Map.h>
+#include <sun/reflect/annotation/AnnotationInvocationHandler.h>
+#include <java/lang/Enum.h>
 
 #include <java-cpool.h>
 #include <java-interp.h>
@@ -426,25 +443,6 @@ java::lang::Class::getName (void)
 }
 
 JArray<jclass> *
-java::lang::Class::getDeclaredClasses (jboolean /*publicOnly*/)
-{
-  // Until we have inner classes, it always makes sense to return an
-  // empty array.
-  JArray<jclass> *result
-    = (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$,
-                                          NULL);
-  return result;
-}
-
-jclass
-java::lang::Class::getDeclaringClass (void)
-{
-  // Until we have inner classes, it makes sense to always return
-  // NULL.
-  return NULL;
-}
-
-JArray<jclass> *
 java::lang::Class::getInterfaces (void)
 {
   jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL);
@@ -673,6 +671,30 @@ java::lang::Class::finalize (void)
   engine->unregister(this);
 }
 
+#ifdef INTERPRETER
+void
+_Jv_ClosureList::releaseClosures (_Jv_ClosureList **closures)
+{
+  if (!closures)
+    return;
+
+  while (_Jv_ClosureList *current = *closures)
+    {
+      *closures = current->next;
+      ffi_closure_free (current->ptr);
+    }
+}
+
+void
+_Jv_ClosureList::registerClosure (jclass klass, void *ptr)
+{
+  _Jv_ClosureList **closures = klass->engine->get_closure_list (klass);
+  this->ptr = ptr;
+  this->next = *closures;
+  *closures = this;
+}
+#endif
+
 // This implements the initialization process for a class.  From Spec
 // section 12.4.2.
 void
@@ -694,6 +716,10 @@ java::lang::Class::initializeClass (void)
          {
            _Jv_Linker::wait_for_state(this, JV_STATE_LINKED);
          }
+       catch (java::lang::SecurityException *x)
+         {
+           throw x;
+         }
        catch (java::lang::Throwable *x)
          {
            // Turn into a NoClassDefFoundError.
@@ -731,6 +757,10 @@ java::lang::Class::initializeClass (void)
        {
          _Jv_InitClass (superclass);
        }
+      catch (java::lang::SecurityException *x)
+       {
+         throw x;
+       }
       catch (java::lang::Throwable *except)
        {
          // Caught an exception.
@@ -749,6 +779,10 @@ java::lang::Class::initializeClass (void)
       if (meth)
        ((void (*) (void)) meth->ncode) ();
     }
+  catch (java::lang::SecurityException *x)
+    {
+      throw x;
+    }
   catch (java::lang::Throwable *except)
     {
       if (! java::lang::Error::class$.isInstance(except))
@@ -851,6 +885,738 @@ java::lang::Class::setSigners(JArray<jobject> *s)
 
 \f
 
+static unsigned char
+read_u1 (unsigned char *&p)
+{
+  return *p++;
+}
+
+static unsigned char
+read_u1 (unsigned char *&p, unsigned char *next)
+{
+  if (next - p < 1)
+    throw new java::lang::InternalError();
+  return *p++;
+}
+
+static unsigned int
+read_u2 (unsigned char *&p)
+{
+  unsigned int b1 = *p++;
+  unsigned int b2 = *p++;
+  return (b1 << 8) | b2;
+}
+
+static unsigned int
+read_u2 (unsigned char *&p, unsigned char *next)
+{
+  if (next - p < 2)
+    throw new java::lang::InternalError();
+  return read_u2 (p);
+}
+
+static int
+read_4 (unsigned char *&p)
+{
+  int b1 = *p++;
+  int b2 = *p++;
+  int b3 = *p++;
+  int b4 = *p++;
+  return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
+}
+
+jstring
+java::lang::Class::getReflectionSignature (jint /*jv_attr_type*/ type,
+                                          jint obj_index)
+{
+  // We just re-parse the bytecode for this data each time.  If
+  // necessary we can cache results, but I suspect this is not
+  // performance sensitive.
+  unsigned char *bytes = reflection_data;
+  if (bytes == NULL)
+    return NULL;
+  while (true)
+    {
+      int kind = read_u1 (bytes);
+      if (kind == JV_DONE_ATTR)
+       return NULL;
+      int len = read_4 (bytes);
+      unsigned char *next = bytes + len;
+      if (kind != type)
+       {
+         bytes = next;
+         continue;
+       }
+      if (type != JV_CLASS_ATTR)
+       {
+         unsigned short index = read_u2 (bytes, next);
+         if (index != obj_index)
+           {
+             bytes = next;
+             continue;
+           }
+       }
+      int nt = read_u1 (bytes, next);
+      if (nt != JV_SIGNATURE_KIND)
+       {
+         bytes = next;
+         continue;
+       }
+      unsigned int cpool_idx = read_u2 (bytes, next);
+      if (cpool_idx >= (unsigned int) constants.size
+         || constants.tags[cpool_idx] != JV_CONSTANT_Utf8)
+       {
+         // We just ignore errors for now.  It isn't clear what is
+         // best to do here, as an encoding error here means a bug
+         // either in the compiler or in defineclass.cc.
+         return NULL;
+       }
+      return _Jv_NewStringUtf8Const (constants.data[cpool_idx].utf8);
+    }
+}
+
+jstring
+java::lang::Class::getReflectionSignature (::java::lang::reflect::Constructor *c)
+{
+  _Jv_Method *meth = _Jv_FromReflectedConstructor (c);
+  unsigned short meth_index = meth - methods;
+  return getReflectionSignature (JV_METHOD_ATTR, meth_index);
+}
+
+jstring
+java::lang::Class::getReflectionSignature (::java::lang::reflect::Method *m)
+{
+  _Jv_Method *meth = _Jv_FromReflectedMethod (m);
+  unsigned short meth_index = meth - methods;
+  return getReflectionSignature (JV_METHOD_ATTR, meth_index);
+}
+
+jstring
+java::lang::Class::getReflectionSignature (::java::lang::reflect::Field *f)
+{
+  _Jv_Field *fld = _Jv_FromReflectedField (f);
+  unsigned short fld_index = fld - fields;
+  return getReflectionSignature (JV_FIELD_ATTR, fld_index);
+}
+
+jstring
+java::lang::Class::getClassSignature()
+{
+  return getReflectionSignature (JV_CLASS_ATTR, 0);
+}
+
+jint
+java::lang::Class::getEnclosingMethodData()
+{
+  unsigned char *bytes = reflection_data;
+  if (bytes == NULL)
+    return 0;
+  while (true)
+    {
+      int kind = read_u1 (bytes);
+      if (kind == JV_DONE_ATTR)
+       return 0;
+      int len = read_4 (bytes);
+      unsigned char *next = bytes + len;
+      if (kind != JV_CLASS_ATTR)
+       {
+         bytes = next;
+         continue;
+       }
+      int type = read_u1 (bytes, next);
+      if (type != JV_ENCLOSING_METHOD_KIND)
+       {
+         bytes = next;
+         continue;
+       }
+      int class_index = read_u2 (bytes, next);
+      int method_index = read_u2 (bytes, next);
+      _Jv_word result;
+      _Jv_storeIndexes (&result, class_index, method_index);
+      return result.i;
+    }
+}
+
+jclass
+java::lang::Class::getEnclosingClass()
+{
+  _Jv_word indexes;
+  indexes.i = getEnclosingMethodData();
+  if (indexes.i == 0)
+    // No enclosing method, but perhaps a member or anonymous class
+    return getDeclaringClass();
+  _Jv_ushort class_index, method_index;
+  _Jv_loadIndexes (&indexes, class_index, method_index);
+  return _Jv_Linker::resolve_pool_entry (this, class_index).clazz;
+}
+
+::java::lang::reflect::Method *
+java::lang::Class::getEnclosingMethod()
+{
+  _Jv_word indexes;
+  indexes.i = getEnclosingMethodData();
+  if (indexes.i == 0)
+    return NULL;
+  _Jv_ushort class_index, method_index;
+  _Jv_loadIndexes (&indexes, class_index, method_index);
+  jclass found_class;
+  _Jv_Method *method = _Jv_Linker::resolve_method_entry (this, found_class,
+                                                        class_index,
+                                                        method_index,
+                                                        false, false);
+  using namespace java::lang::reflect;
+  Method *rmethod = new Method ();
+  rmethod->offset = (char *) method - (char *) found_class->methods;
+  rmethod->declaringClass = found_class;
+  return rmethod;
+}
+
+::java::lang::reflect::Constructor *
+java::lang::Class::getEnclosingConstructor()
+{
+  _Jv_word indexes;
+  indexes.i = getEnclosingMethodData();
+  if (indexes.i == 0)
+    return NULL;
+  _Jv_ushort class_index, method_index;
+  _Jv_loadIndexes (&indexes, class_index, method_index);
+  jclass found_class;
+  _Jv_Method *method = _Jv_Linker::resolve_method_entry (this, found_class,
+                                                        class_index,
+                                                        method_index,
+                                                        false, false);
+  using namespace java::lang::reflect;
+  Constructor *cons = new Constructor ();
+  cons->offset = (char *) method - (char *) found_class->methods;
+  cons->declaringClass = this;
+  return cons;
+}
+
+static void
+check_constant (_Jv_Constants *pool, jint cpool_index, jint type)
+{
+  if (cpool_index <= 0 || cpool_index >= pool->size)
+    throw new InternalError(JvNewStringLatin1("invalid constant pool index"));
+  if ((pool->tags[cpool_index] & 
+       ~(JV_CONSTANT_ResolvedFlag|JV_CONSTANT_LazyFlag)) != type)
+    {
+      ::java::lang::StringBuffer *sb = new ::java::lang::StringBuffer();
+      sb->append(JvNewStringLatin1("expected pool constant "));
+      sb->append(type);
+      sb->append(JvNewStringLatin1(" but got "));
+      sb->append(jint (pool->tags[cpool_index]));
+      throw new InternalError(sb->toString());
+    }
+}
+
+// Forward declaration
+static ::java::lang::annotation::Annotation *
+parseAnnotation(jclass klass, _Jv_Constants *pool,
+               unsigned char *&bytes, unsigned char *last);
+
+static jobject
+parseAnnotationElement(jclass klass, _Jv_Constants *pool,
+                      unsigned char *&bytes, unsigned char *last)
+{
+  int tag = read_u1 (bytes, last);
+  jobject result;
+  switch (tag)
+    {
+    case 'B':
+      {
+       int cindex = read_u2 (bytes, last);
+       check_constant (pool, cindex, JV_CONSTANT_Integer);
+       result = Byte::valueOf (pool->data[cindex].i);
+      }
+      break;
+    case 'C':
+      {
+       int cindex = read_u2 (bytes, last);
+       check_constant (pool, cindex, JV_CONSTANT_Integer);
+       result = Character::valueOf (pool->data[cindex].i);
+      }
+      break;
+    case 'S':
+      {
+       int cindex = read_u2 (bytes, last);
+       check_constant (pool, cindex, JV_CONSTANT_Integer);
+       result = Short::valueOf (pool->data[cindex].i);
+      }
+      break;
+    case 'Z':
+      {
+       int cindex = read_u2 (bytes, last);
+       check_constant (pool, cindex, JV_CONSTANT_Integer);
+       result = Boolean::valueOf (jboolean (pool->data[cindex].i));
+      }
+      break;
+    case 'I':
+      {
+       int cindex = read_u2 (bytes, last);
+       check_constant (pool, cindex, JV_CONSTANT_Integer);
+       result = Integer::valueOf (pool->data[cindex].i);
+      }
+      break;
+    case 'D':
+      {
+       int cindex = read_u2 (bytes, last);
+       check_constant (pool, cindex, JV_CONSTANT_Double);
+       _Jv_word2 word;
+       memcpy (&word, &pool->data[cindex], 2 * sizeof (_Jv_word));
+       result = Double::valueOf (word.d);
+      }
+      break;
+    case 'F':
+      {
+       int cindex = read_u2 (bytes, last);
+       check_constant (pool, cindex, JV_CONSTANT_Float);
+       result = Float::valueOf (pool->data[cindex].f);
+      }
+      break;
+    case 'J':
+      {
+       int cindex = read_u2 (bytes, last);
+       check_constant (pool, cindex, JV_CONSTANT_Long);
+       _Jv_word2 word;
+       memcpy (&word, &pool->data[cindex], 2 * sizeof (_Jv_word));
+       result = Long::valueOf (word.l);
+      }
+      break;
+    case 's':
+      {
+       int cindex = read_u2 (bytes, last);
+       // Despite what the JVM spec says, compilers generate a Utf8
+       // constant here, not a String.
+       check_constant (pool, cindex, JV_CONSTANT_Utf8);
+       result = pool->data[cindex].utf8->toString();
+      }
+      break;
+    case 'e':
+      {
+       int type_name_index = read_u2 (bytes, last);
+       check_constant (pool, type_name_index, JV_CONSTANT_Utf8);
+       int const_name_index = read_u2 (bytes, last);
+       check_constant (pool, const_name_index, JV_CONSTANT_Utf8);
+
+       _Jv_Utf8Const *u_name = pool->data[type_name_index].utf8;
+       _Jv_Utf8Const *e_name = pool->data[const_name_index].utf8;
+
+       // FIXME: throw correct exceptions at the correct times.
+       jclass e_class = _Jv_FindClassFromSignature(u_name->chars(),
+                                                   klass->getClassLoaderInternal());
+       result = ::java::lang::Enum::valueOf(e_class, e_name->toString());
+      }
+      break;
+    case 'c':
+      {
+       int cindex = read_u2 (bytes, last);
+       check_constant (pool, cindex, JV_CONSTANT_Utf8);
+       _Jv_Utf8Const *u_name = pool->data[cindex].utf8;
+       jclass anno_class
+         = _Jv_FindClassFromSignatureNoException(u_name->chars(),
+                                                 klass->getClassLoaderInternal());
+       // FIXME: not correct: we should lazily do this when trying to
+       // read the element.  This means that
+       // AnnotationInvocationHandler needs to have a special case.
+       if (! anno_class)
+         // FIXME: original exception...
+         throw new TypeNotPresentException(u_name->toString(), NULL);
+       result = anno_class;
+      }
+      break;
+    case '@':
+      result = parseAnnotation (klass, pool, bytes, last);
+      break;
+    case '[':
+      {
+       int n_array_elts = read_u2 (bytes, last);
+       jobjectArray aresult = _Jv_NewObjectArray (n_array_elts,
+                                                  &Object::class$, NULL);
+       jobject *elts = elements (aresult);
+       for (int i = 0; i < n_array_elts; ++i)
+         elts[i] = parseAnnotationElement(klass, pool, bytes, last);
+       result = aresult;
+      }
+      break;
+    default:
+      throw new java::lang::InternalError();
+    }
+  return result;
+}
+
+static ::java::lang::annotation::Annotation *
+parseAnnotation(jclass klass, _Jv_Constants *pool,
+               unsigned char *&bytes, unsigned char *last)
+{
+  int type_index = read_u2 (bytes, last);
+  check_constant (pool, type_index, JV_CONSTANT_Utf8);
+
+  _Jv_Utf8Const *u_name = pool->data[type_index].utf8;
+  jclass anno_class = _Jv_FindClassFromSignatureNoException(u_name->chars(),
+                                                           klass->getClassLoaderInternal());
+  // FIXME: what to do if anno_class==NULL?
+
+  ::java::util::HashMap *hmap = new ::java::util::HashMap();
+  int npairs = read_u2 (bytes, last);
+  for (int i = 0; i < npairs; ++i)
+    {
+      int name_index = read_u2 (bytes, last);
+      check_constant (pool, name_index, JV_CONSTANT_Utf8);
+      jstring name = _Jv_NewStringUtf8Const (pool->data[name_index].utf8);
+      jobject value = parseAnnotationElement (klass, pool, bytes, last);
+      // FIXME: any checks needed for name?
+      hmap->put(name, value);
+    }
+  using namespace ::sun::reflect::annotation;
+  return AnnotationInvocationHandler::create (anno_class,
+                                             (::java::util::Map *) hmap);
+}
+
+static jobjectArray
+parseAnnotations(jclass klass, _Jv_Constants *pool,
+                unsigned char *&bytes, unsigned char *last)
+{
+  int num = read_u2 (bytes, last);
+  jobjectArray result = _Jv_NewObjectArray (num,
+                                           &::java::lang::annotation::Annotation::class$,
+                                           NULL);
+  jobject *elts = elements (result);
+  for (int i = 0; i < num; ++i)
+    elts[i] = parseAnnotation(klass, pool, bytes, last);
+  return result;
+}
+
+static jobjectArray
+parseParameterAnnotations(jclass klass, _Jv_Constants *pool,
+                         unsigned char *&bytes, unsigned char *last)
+{
+  jclass anno = &::java::lang::annotation::Annotation::class$;
+  jclass annoary = _Jv_GetArrayClass (anno, anno->getClassLoaderInternal());
+
+  // FIXME: something should check the number of params versus the
+  // method
+  int n_params = read_u1 (bytes, last);
+  jobjectArray result = _Jv_NewObjectArray (n_params, annoary, NULL);
+  jobject *elts = elements (result);
+  for (int i = 0; i < n_params; ++i)
+    elts[i] = parseAnnotations(klass, pool, bytes, last);
+  return result;
+}
+
+jobject
+java::lang::Class::getMethodDefaultValue(::java::lang::reflect::Method *meth)
+{
+  // FIXME: could cache the value here...
+
+  unsigned char *bytes = reflection_data;
+  if (bytes == NULL)
+    return 0;
+
+  unsigned short meth_index = _Jv_FromReflectedMethod (meth) - methods;
+
+  while (true)
+    {
+      int type = read_u1 (bytes);
+      if (type == JV_DONE_ATTR)
+       return NULL;
+      int len = read_4 (bytes);
+      unsigned char *next = bytes + len;
+      if (type != JV_METHOD_ATTR)
+       {
+         bytes = next;
+         continue;
+       }
+      int kind = read_u1 (bytes, next);
+      if (kind != JV_ANNOTATION_DEFAULT_KIND)
+       {
+         bytes = next;
+         continue;
+       }
+      int index = read_u2 (bytes, next);
+      if (meth_index != index)
+       {
+         bytes = next;
+         continue;
+       }
+
+      // FIXME: could cache here.  If we do then we have to clone any
+      // array result.
+      return parseAnnotationElement(this, &this->constants, bytes, next);
+    }
+}
+
+jobjectArray
+java::lang::Class::getDeclaredAnnotations(jint /* jv_attr_type */ member_type,
+                                         jint member_index,
+                                         jint /* jv_attr_kind */ kind_req)
+{
+  using namespace java::lang::annotation;
+  jobjectArray result;
+
+  unsigned char *bytes = reflection_data;
+  if (bytes == NULL)
+    return 0;
+
+  if (loader == NULL)
+    loader = (ClassLoader *)VMClassLoader::bootLoader;
+
+  result = (loader->getDeclaredAnnotations
+           (this, member_type, member_index, kind_req));
+  if (result)
+    return result;
+
+  for (;;)
+    {
+      int type = read_u1 (bytes);
+      if (type == JV_DONE_ATTR)
+       return NULL;
+      int len = read_4 (bytes);
+      unsigned char *next = bytes + len;
+      if (type != member_type)
+       {
+         bytes = next;
+         continue;
+       }
+      int kind = read_u1 (bytes, next);
+      if (kind != kind_req)
+       {
+         bytes = next;
+         continue;
+       }
+      if (member_type != JV_CLASS_ATTR)
+       {
+         int index = read_u2 (bytes, next);
+         if (member_index != index)
+           {
+             bytes = next;
+             continue;
+           }
+       }
+
+      if (kind_req == JV_PARAMETER_ANNOTATIONS_KIND)
+       result = ((parseParameterAnnotations 
+                  (this, &this->constants, bytes, next)));
+      else
+       result = ((parseAnnotations (this, &this->constants, bytes, next)));
+      break;
+    }
+
+  return (loader->putDeclaredAnnotations
+         (this, member_type, member_index, kind_req, result));
+}
+
+jobjectArray
+java::lang::Class::getDeclaredAnnotations(::java::lang::reflect::Method *meth,
+                                         jboolean is_param)
+{
+  unsigned short meth_index = _Jv_FromReflectedMethod (meth) - methods;
+  return getDeclaredAnnotations(JV_METHOD_ATTR, meth_index,
+                               (is_param
+                                ? JV_PARAMETER_ANNOTATIONS_KIND
+                                : JV_ANNOTATIONS_KIND));
+}
+
+jobjectArray
+java::lang::Class::getDeclaredAnnotations(::java::lang::reflect::Constructor *cons,
+                                         jboolean is_param)
+{
+  unsigned short meth_index = _Jv_FromReflectedConstructor (cons) - methods;
+  return getDeclaredAnnotations(JV_METHOD_ATTR, meth_index,
+                               (is_param
+                                ? JV_PARAMETER_ANNOTATIONS_KIND
+                                : JV_ANNOTATIONS_KIND));
+}
+
+jobjectArray
+java::lang::Class::getDeclaredAnnotations(::java::lang::reflect::Field *fld)
+{
+  unsigned short field_index = _Jv_FromReflectedField (fld) - fields;
+  return getDeclaredAnnotations(JV_FIELD_ATTR, field_index,
+                               JV_ANNOTATIONS_KIND);
+}
+
+JArray< ::java::lang::annotation::Annotation *> *
+java::lang::Class::getDeclaredAnnotationsInternal()
+{
+  return (JArray< ::java::lang::annotation::Annotation *> *) getDeclaredAnnotations(JV_CLASS_ATTR, 0, JV_ANNOTATIONS_KIND);
+}
+
+static jclass
+resolve_class_constant (jclass klass, _Jv_Constants *pool, int cpool_index)
+{
+  check_constant (pool, cpool_index, JV_CONSTANT_Class);
+  // FIXME: what is the correct thing to do with an exception here?
+  return _Jv_Linker::resolve_pool_entry (klass, cpool_index, false).clazz;
+}
+
+jint
+java::lang::Class::findInnerClassAttribute()
+{
+  unsigned char *bytes = reflection_data;
+  if (bytes == NULL)
+    return -1;
+  while (true)
+    {
+      int type = read_u1 (bytes);
+      if (type == JV_DONE_ATTR)
+       break;
+      // After the type but before the length.
+      unsigned char *save = bytes;
+      int len = read_4 (bytes);
+      unsigned char *next = bytes + len;
+      if (type != JV_CLASS_ATTR)
+       {
+         bytes = next;
+         continue;
+       }
+      int kind = read_u1 (bytes, next);
+      if (kind != JV_INNER_CLASSES_KIND)
+       {
+         bytes = next;
+         continue;
+       }
+      return save - reflection_data;
+    }
+  return -1;
+}
+
+jint
+java::lang::Class::findDeclaredClasses(JArray<jclass> *result,
+                                      jboolean publicOnly,
+                                      jint offset)
+{
+  unsigned char *bytes = reflection_data + offset;
+  int len = read_4 (bytes);
+  unsigned char *next = bytes + len;
+  // Skip a byte.
+  read_u1 (bytes, next);
+  int n_classes = read_u2 (bytes, next);
+  int count = 0;
+  for (int i = 0; i < n_classes; ++i)
+    {
+      int inner_class_index = read_u2 (bytes, next);
+      int outer_class_index = read_u2 (bytes, next);
+      /*int inner_name_index = */ read_u2 (bytes, next);
+      int inner_flags = read_u2 (bytes, next);
+
+      if (inner_class_index == 0 || outer_class_index == 0)
+       continue;
+      if (resolve_class_constant (this, &constants, outer_class_index) == this)
+       {
+         jclass inner = resolve_class_constant (this, &constants,
+                                                inner_class_index);
+         if (! publicOnly
+             || ((inner_flags
+                  & java::lang::reflect::Modifier::PUBLIC) != 0))
+           {
+             if (result)
+               {
+                 jclass *elts = elements (result);
+                 elts[count] = inner;
+               }
+             ++count;
+           }
+       }
+    }
+
+  return count;
+}
+
+JArray<jclass> *
+java::lang::Class::getDeclaredClasses (jboolean publicOnly)
+{
+  int offset = findInnerClassAttribute();
+  int count;
+  if (offset == -1)
+    {
+      // No InnerClasses attribute, so no declared classes.
+      count = 0;
+    }
+  else
+    count = findDeclaredClasses(NULL, publicOnly, offset);
+  JArray<jclass> *result
+    = (JArray<jclass> *) JvNewObjectArray (count, &java::lang::Class::class$,
+                                          NULL);
+  if (count > 0)
+    findDeclaredClasses(result, publicOnly, offset);
+  return result;
+}
+
+jclass
+java::lang::Class::getDeclaringClass (void)
+{
+  int offset = findInnerClassAttribute();
+  if (offset == -1)
+    return NULL;
+
+  unsigned char *bytes = reflection_data + offset;
+  int len = read_4 (bytes);
+  unsigned char *next = bytes + len;
+  // Skip a byte.
+  read_u1 (bytes, next);
+  int n_classes = read_u2 (bytes, next);
+  for (int i = 0; i < n_classes; ++i)
+    {
+      int inner_class_index = read_u2 (bytes, next);
+      int outer_class_index = read_u2 (bytes, next);
+      /*int inner_name_index = */read_u2 (bytes, next);
+      /*int inner_flags = */read_u2 (bytes, next);
+
+      if (inner_class_index == 0 || outer_class_index == 0)
+       continue;
+      if (resolve_class_constant (this, &constants, inner_class_index) == this)
+       return resolve_class_constant (this, &constants, outer_class_index);
+    }
+
+  return NULL;
+}
+
+jboolean
+java::lang::Class::isAnonymousClass()
+{
+  int offset = findInnerClassAttribute();
+  if (offset == -1)
+    return false;
+
+  unsigned char *bytes = reflection_data + offset;
+  int len = read_4 (bytes);
+  unsigned char *next = bytes + len;
+  // Skip a byte.
+  read_u1 (bytes, next);
+  int n_classes = read_u2 (bytes, next);
+  for (int i = 0; i < n_classes; ++i)
+    {
+      int inner_class_index = read_u2 (bytes, next);
+      /*int outer_class_index = */read_u2 (bytes, next);
+      int inner_name_index = read_u2 (bytes, next);
+      /*int inner_flags = */read_u2 (bytes, next);
+
+      if (inner_class_index == 0)
+       continue;
+      if (resolve_class_constant (this, &constants, inner_class_index) == this)
+       return inner_name_index == 0;
+    }
+
+  return false;
+}
+
+jboolean
+java::lang::Class::isLocalClass()
+{
+  _Jv_word indexes;
+  indexes.i = getEnclosingMethodData();
+  return indexes.i != 0;
+}
+
+jboolean
+java::lang::Class::isMemberClass()
+{
+  // FIXME: is this correct?
+  return !isLocalClass() && getDeclaringClass() != NULL;
+}
+
+\f
+
 //
 // Some class-related convenience functions.
 //
@@ -890,6 +1656,26 @@ _Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name,
   return NULL;
 }
 
+java::lang::reflect::Method *
+_Jv_GetReflectedMethod (jclass klass, _Jv_Utf8Const *name,
+                      _Jv_Utf8Const *signature)
+{
+  for (; klass; klass = klass->getSuperclass())
+    {
+      _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature);
+      if (meth)
+       {
+         using namespace java::lang::reflect;
+         Method *rmethod = new Method ();
+         rmethod->offset = (char*) meth - (char*) klass->methods;
+         rmethod->declaringClass = klass;
+         return rmethod;
+       }
+    }
+  
+  return NULL;
+}
+
 #ifdef HAVE_TLS
 
 // NOTE: MCACHE_SIZE should be a power of 2 minus one.
@@ -1267,3 +2053,32 @@ _Jv_GetClassNameUtf8 (jclass klass)
 {
   return klass->name;
 }
+
+jclass
+_Jv_GetMethodDeclaringClass (jmethodID method)
+{
+  _Jv_StackTrace::UpdateNCodeMap ();
+  jobject obj = reinterpret_cast<jobject> (method->ncode);
+  return reinterpret_cast<jclass> (_Jv_StackTrace::ncodeMap->get (obj));
+}
+
+jbyte
+_Jv_GetClassState (jclass klass)
+{
+  return klass->state;
+}
+
+#ifdef INTERPRETER
+jstring
+_Jv_GetInterpClassSourceFile (jclass klass)
+{
+  if (_Jv_IsInterpretedClass (klass))
+    {
+      _Jv_InterpClass *iclass =
+       reinterpret_cast<_Jv_InterpClass *> (klass->aux_info);
+      return iclass->source_file_name;
+    }
+
+  return NULL;
+}
+#endif