summaryrefslogtreecommitdiff
path: root/libjava/interpret.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/interpret.cc')
-rw-r--r--libjava/interpret.cc609
1 files changed, 587 insertions, 22 deletions
diff --git a/libjava/interpret.cc b/libjava/interpret.cc
index 0446c729623..91d4b194774 100644
--- a/libjava/interpret.cc
+++ b/libjava/interpret.cc
@@ -11,6 +11,7 @@ details. */
/* Author: Kresten Krab Thorup <krab@gnu.org> */
#include <config.h>
+#include <platform.h>
// Define this to get the direct-threaded interpreter. If undefined,
// we revert to a basic bytecode interpreter. The former is faster
@@ -38,9 +39,15 @@ details. */
#include <java/lang/Thread.h>
#include <java-insns.h>
#include <java-signal.h>
+#include <java/lang/ClassFormatError.h>
+#include <execution.h>
+#include <java/lang/reflect/Modifier.h>
#ifdef INTERPRETER
+// Execution engine for interpreted code.
+_Jv_InterpreterEngine _Jv_soleInterpreterEngine;
+
#include <stdlib.h>
using namespace gcj;
@@ -54,6 +61,11 @@ static void throw_null_pointer_exception ()
__attribute__ ((__noreturn__));
#endif
+static void throw_class_format_error (jstring msg)
+ __attribute__ ((__noreturn__));
+static void throw_class_format_error (char *msg)
+ __attribute__ ((__noreturn__));
+
#ifdef DIRECT_THREADED
// Lock to ensure that methods are not compiled concurrently.
// We could use a finer-grained lock here, however it is not safe to use
@@ -765,8 +777,9 @@ _Jv_InterpMethod::compile (const void * const *insn_targets)
exc[i].start_pc.p = &insns[pc_mapping[exc[i].start_pc.i]];
exc[i].end_pc.p = &insns[pc_mapping[exc[i].end_pc.i]];
exc[i].handler_pc.p = &insns[pc_mapping[exc[i].handler_pc.i]];
- jclass handler = (_Jv_ResolvePoolEntry (defining_class,
- exc[i].handler_type.i)).clazz;
+ jclass handler
+ = (_Jv_Linker::resolve_pool_entry (defining_class,
+ exc[i].handler_type.i)).clazz;
exc[i].handler_type.p = handler;
}
@@ -1113,13 +1126,14 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
{
int index = GET2U ();
- /* _Jv_ResolvePoolEntry returns immediately if the value already
- * is resolved. If we want to clutter up the code here to gain
- * a little performance, then we can check the corresponding bit
- * JV_CONSTANT_ResolvedFlag in the tag directly. For now, I
- * don't think it is worth it. */
+ /* _Jv_Linker::resolve_pool_entry returns immediately if the
+ * value already is resolved. If we want to clutter up the
+ * code here to gain a little performance, then we can check
+ * the corresponding bit JV_CONSTANT_ResolvedFlag in the tag
+ * directly. For now, I don't think it is worth it. */
- rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod;
+ rmeth = (_Jv_Linker::resolve_pool_entry (defining_class,
+ index)).rmethod;
sp -= rmeth->stack_item_count;
// We don't use NULLCHECK here because we can't rely on that
@@ -2409,7 +2423,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_getstatic:
{
jint fieldref_index = GET2U ();
- _Jv_ResolvePoolEntry (defining_class, fieldref_index);
+ _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
if ((field->flags & Modifier::STATIC) == 0)
@@ -2496,7 +2510,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_getfield:
{
jint fieldref_index = GET2U ();
- _Jv_ResolvePoolEntry (defining_class, fieldref_index);
+ _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
if ((field->flags & Modifier::STATIC) != 0)
@@ -2612,7 +2626,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_putstatic:
{
jint fieldref_index = GET2U ();
- _Jv_ResolvePoolEntry (defining_class, fieldref_index);
+ _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
jclass type = field->type;
@@ -2699,7 +2713,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_putfield:
{
jint fieldref_index = GET2U ();
- _Jv_ResolvePoolEntry (defining_class, fieldref_index);
+ _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index);
_Jv_Field *field = pool_data[fieldref_index].field;
jclass type = field->type;
@@ -2825,7 +2839,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
{
int index = GET2U ();
- rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod;
+ rmeth = (_Jv_Linker::resolve_pool_entry (defining_class,
+ index)).rmethod;
sp -= rmeth->stack_item_count;
@@ -2863,7 +2878,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
{
int index = GET2U ();
- rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod;
+ rmeth = (_Jv_Linker::resolve_pool_entry (defining_class,
+ index)).rmethod;
sp -= rmeth->stack_item_count;
@@ -2892,7 +2908,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
{
int index = GET2U ();
- rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod;
+ rmeth = (_Jv_Linker::resolve_pool_entry (defining_class,
+ index)).rmethod;
sp -= rmeth->stack_item_count;
@@ -2935,7 +2952,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_new:
{
int index = GET2U ();
- jclass klass = (_Jv_ResolvePoolEntry (defining_class, index)).clazz;
+ jclass klass = (_Jv_Linker::resolve_pool_entry (defining_class,
+ index)).clazz;
jobject res = _Jv_AllocObject (klass);
PUSHA (res);
@@ -2968,7 +2986,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
insn_anewarray:
{
int index = GET2U ();
- jclass klass = (_Jv_ResolvePoolEntry (defining_class, index)).clazz;
+ jclass klass = (_Jv_Linker::resolve_pool_entry (defining_class,
+ index)).clazz;
int size = POPI();
jobject result = _Jv_NewObjectArray (size, klass, 0);
PUSHA (result);
@@ -3010,7 +3029,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
{
jobject value = POPA();
jint index = GET2U ();
- jclass to = (_Jv_ResolvePoolEntry (defining_class, index)).clazz;
+ jclass to = (_Jv_Linker::resolve_pool_entry (defining_class,
+ index)).clazz;
if (value != NULL && ! to->isInstance (value))
throw new java::lang::ClassCastException (to->getName());
@@ -3040,7 +3060,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
{
jobject value = POPA();
jint index = GET2U ();
- jclass to = (_Jv_ResolvePoolEntry (defining_class, index)).clazz;
+ jclass to = (_Jv_Linker::resolve_pool_entry (defining_class,
+ index)).clazz;
PUSHI (to->isInstance (value));
#ifdef DIRECT_THREADED
@@ -3102,7 +3123,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
int dim = GET1U ();
jclass type
- = (_Jv_ResolvePoolEntry (defining_class, kind_index)).clazz;
+ = (_Jv_Linker::resolve_pool_entry (defining_class,
+ kind_index)).clazz;
jint *sizes = (jint*) __builtin_alloca (sizeof (jint)*dim);
for (int i = dim - 1; i >= 0; i--)
@@ -3203,8 +3225,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args)
#else
jclass handler = NULL;
if (exc[i].handler_type.i != 0)
- handler = (_Jv_ResolvePoolEntry (defining_class,
- exc[i].handler_type.i)).clazz;
+ handler = (_Jv_Linker::resolve_pool_entry (defining_class,
+ exc[i].handler_type.i)).clazz;
#endif /* DIRECT_THREADED */
if (handler == NULL || handler->isAssignableFrom (exc_class))
@@ -3250,4 +3272,547 @@ throw_null_pointer_exception ()
}
#endif
+/** Do static initialization for fields with a constant initializer */
+void
+_Jv_InitField (jobject obj, jclass klass, int index)
+{
+ using namespace java::lang::reflect;
+
+ if (obj != 0 && klass == 0)
+ klass = obj->getClass ();
+
+ if (!_Jv_IsInterpretedClass (klass))
+ return;
+
+ _Jv_InterpClass *iclass = (_Jv_InterpClass*)klass->aux_info;
+
+ _Jv_Field * field = (&klass->fields[0]) + index;
+
+ if (index > klass->field_count)
+ throw_internal_error ("field out of range");
+
+ int init = iclass->field_initializers[index];
+ if (init == 0)
+ return;
+
+ _Jv_Constants *pool = &klass->constants;
+ int tag = pool->tags[init];
+
+ if (! field->isResolved ())
+ throw_internal_error ("initializing unresolved field");
+
+ if (obj==0 && ((field->flags & Modifier::STATIC) == 0))
+ throw_internal_error ("initializing non-static field with no object");
+
+ void *addr = 0;
+
+ if ((field->flags & Modifier::STATIC) != 0)
+ addr = (void*) field->u.addr;
+ else
+ addr = (void*) (((char*)obj) + field->u.boffset);
+
+ switch (tag)
+ {
+ case JV_CONSTANT_String:
+ {
+ jstring str;
+ str = _Jv_NewStringUtf8Const (pool->data[init].utf8);
+ pool->data[init].string = str;
+ pool->tags[init] = JV_CONSTANT_ResolvedString;
+ }
+ /* fall through */
+
+ case JV_CONSTANT_ResolvedString:
+ if (! (field->type == &java::lang::String::class$
+ || field->type == &java::lang::Class::class$))
+ throw_class_format_error ("string initialiser to non-string field");
+
+ *(jstring*)addr = pool->data[init].string;
+ break;
+
+ case JV_CONSTANT_Integer:
+ {
+ int value = pool->data[init].i;
+
+ if (field->type == JvPrimClass (boolean))
+ *(jboolean*)addr = (jboolean)value;
+
+ else if (field->type == JvPrimClass (byte))
+ *(jbyte*)addr = (jbyte)value;
+
+ else if (field->type == JvPrimClass (char))
+ *(jchar*)addr = (jchar)value;
+
+ else if (field->type == JvPrimClass (short))
+ *(jshort*)addr = (jshort)value;
+
+ else if (field->type == JvPrimClass (int))
+ *(jint*)addr = (jint)value;
+
+ else
+ throw_class_format_error ("erroneous field initializer");
+ }
+ break;
+
+ case JV_CONSTANT_Long:
+ if (field->type != JvPrimClass (long))
+ throw_class_format_error ("erroneous field initializer");
+
+ *(jlong*)addr = _Jv_loadLong (&pool->data[init]);
+ break;
+
+ case JV_CONSTANT_Float:
+ if (field->type != JvPrimClass (float))
+ throw_class_format_error ("erroneous field initializer");
+
+ *(jfloat*)addr = pool->data[init].f;
+ break;
+
+ case JV_CONSTANT_Double:
+ if (field->type != JvPrimClass (double))
+ throw_class_format_error ("erroneous field initializer");
+
+ *(jdouble*)addr = _Jv_loadDouble (&pool->data[init]);
+ break;
+
+ default:
+ throw_class_format_error ("erroneous field initializer");
+ }
+}
+
+inline static unsigned char*
+skip_one_type (unsigned char* ptr)
+{
+ int ch = *ptr++;
+
+ while (ch == '[')
+ {
+ ch = *ptr++;
+ }
+
+ if (ch == 'L')
+ {
+ do { ch = *ptr++; } while (ch != ';');
+ }
+
+ return ptr;
+}
+
+static ffi_type*
+get_ffi_type_from_signature (unsigned char* ptr)
+{
+ switch (*ptr)
+ {
+ case 'L':
+ case '[':
+ return &ffi_type_pointer;
+ break;
+
+ case 'Z':
+ // On some platforms a bool is a byte, on others an int.
+ if (sizeof (jboolean) == sizeof (jbyte))
+ return &ffi_type_sint8;
+ else
+ {
+ JvAssert (sizeof (jbyte) == sizeof (jint));
+ return &ffi_type_sint32;
+ }
+ break;
+
+ case 'B':
+ return &ffi_type_sint8;
+ break;
+
+ case 'C':
+ return &ffi_type_uint16;
+ break;
+
+ case 'S':
+ return &ffi_type_sint16;
+ break;
+
+ case 'I':
+ return &ffi_type_sint32;
+ break;
+
+ case 'J':
+ return &ffi_type_sint64;
+ break;
+
+ case 'F':
+ return &ffi_type_float;
+ break;
+
+ case 'D':
+ return &ffi_type_double;
+ break;
+
+ case 'V':
+ return &ffi_type_void;
+ break;
+ }
+
+ throw_internal_error ("unknown type in signature");
+}
+
+/* this function yields the number of actual arguments, that is, if the
+ * function is non-static, then one is added to the number of elements
+ * found in the signature */
+
+int
+_Jv_count_arguments (_Jv_Utf8Const *signature,
+ jboolean staticp)
+{
+ unsigned char *ptr = (unsigned char*) signature->chars();
+ int arg_count = staticp ? 0 : 1;
+
+ /* first, count number of arguments */
+
+ // skip '('
+ ptr++;
+
+ // count args
+ while (*ptr != ')')
+ {
+ ptr = skip_one_type (ptr);
+ arg_count += 1;
+ }
+
+ return arg_count;
+}
+
+/* This beast will build a cif, given the signature. Memory for
+ * the cif itself and for the argument types must be allocated by the
+ * caller.
+ */
+
+static int
+init_cif (_Jv_Utf8Const* signature,
+ int arg_count,
+ jboolean staticp,
+ ffi_cif *cif,
+ ffi_type **arg_types,
+ ffi_type **rtype_p)
+{
+ unsigned char *ptr = (unsigned char*) signature->chars();
+
+ int arg_index = 0; // arg number
+ int item_count = 0; // stack-item count
+
+ // setup receiver
+ if (!staticp)
+ {
+ arg_types[arg_index++] = &ffi_type_pointer;
+ item_count += 1;
+ }
+
+ // skip '('
+ ptr++;
+
+ // assign arg types
+ while (*ptr != ')')
+ {
+ arg_types[arg_index++] = get_ffi_type_from_signature (ptr);
+
+ if (*ptr == 'J' || *ptr == 'D')
+ item_count += 2;
+ else
+ item_count += 1;
+
+ ptr = skip_one_type (ptr);
+ }
+
+ // skip ')'
+ ptr++;
+ ffi_type *rtype = get_ffi_type_from_signature (ptr);
+
+ ptr = skip_one_type (ptr);
+ if (ptr != (unsigned char*)signature->chars() + signature->len())
+ throw_internal_error ("did not find end of signature");
+
+ if (ffi_prep_cif (cif, FFI_DEFAULT_ABI,
+ arg_count, rtype, arg_types) != FFI_OK)
+ throw_internal_error ("ffi_prep_cif failed");
+
+ if (rtype_p != NULL)
+ *rtype_p = rtype;
+
+ return item_count;
+}
+
+#if FFI_NATIVE_RAW_API
+# define FFI_PREP_RAW_CLOSURE ffi_prep_raw_closure
+# define FFI_RAW_SIZE ffi_raw_size
+#else
+# define FFI_PREP_RAW_CLOSURE ffi_prep_java_raw_closure
+# define FFI_RAW_SIZE ffi_java_raw_size
+#endif
+
+/* we put this one here, and not in interpret.cc because it
+ * calls the utility routines _Jv_count_arguments
+ * which are static to this module. The following struct defines the
+ * layout we use for the stubs, it's only used in the ncode method. */
+
+typedef struct {
+ ffi_raw_closure closure;
+ ffi_cif cif;
+ ffi_type *arg_types[0];
+} ncode_closure;
+
+typedef void (*ffi_closure_fun) (ffi_cif*,void*,ffi_raw*,void*);
+
+void *
+_Jv_InterpMethod::ncode ()
+{
+ using namespace java::lang::reflect;
+
+ if (self->ncode != 0)
+ return self->ncode;
+
+ jboolean staticp = (self->accflags & Modifier::STATIC) != 0;
+ int arg_count = _Jv_count_arguments (self->signature, staticp);
+
+ ncode_closure *closure =
+ (ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure)
+ + arg_count * sizeof (ffi_type*));
+
+ init_cif (self->signature,
+ arg_count,
+ staticp,
+ &closure->cif,
+ &closure->arg_types[0],
+ NULL);
+
+ ffi_closure_fun fun;
+
+ args_raw_size = FFI_RAW_SIZE (&closure->cif);
+
+ JvAssert ((self->accflags & Modifier::NATIVE) == 0);
+
+ if ((self->accflags & Modifier::SYNCHRONIZED) != 0)
+ {
+ if (staticp)
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class;
+ else
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object;
+ }
+ else
+ {
+ if (staticp)
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class;
+ else
+ fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal;
+ }
+
+ FFI_PREP_RAW_CLOSURE (&closure->closure,
+ &closure->cif,
+ fun,
+ (void*)this);
+
+ self->ncode = (void*)closure;
+ return self->ncode;
+}
+
+void *
+_Jv_JNIMethod::ncode ()
+{
+ using namespace java::lang::reflect;
+
+ if (self->ncode != 0)
+ return self->ncode;
+
+ jboolean staticp = (self->accflags & Modifier::STATIC) != 0;
+ int arg_count = _Jv_count_arguments (self->signature, staticp);
+
+ ncode_closure *closure =
+ (ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure)
+ + arg_count * sizeof (ffi_type*));
+
+ ffi_type *rtype;
+ init_cif (self->signature,
+ arg_count,
+ staticp,
+ &closure->cif,
+ &closure->arg_types[0],
+ &rtype);
+
+ ffi_closure_fun fun;
+
+ args_raw_size = FFI_RAW_SIZE (&closure->cif);
+
+ // Initialize the argument types and CIF that represent the actual
+ // underlying JNI function.
+ int extra_args = 1;
+ if ((self->accflags & Modifier::STATIC))
+ ++extra_args;
+ jni_arg_types = (ffi_type **) _Jv_AllocBytes ((extra_args + arg_count)
+ * sizeof (ffi_type *));
+ int offset = 0;
+ jni_arg_types[offset++] = &ffi_type_pointer;
+ if ((self->accflags & Modifier::STATIC))
+ jni_arg_types[offset++] = &ffi_type_pointer;
+ memcpy (&jni_arg_types[offset], &closure->arg_types[0],
+ arg_count * sizeof (ffi_type *));
+
+ if (ffi_prep_cif (&jni_cif, _Jv_platform_ffi_abi,
+ extra_args + arg_count, rtype,
+ jni_arg_types) != FFI_OK)
+ throw_internal_error ("ffi_prep_cif failed for JNI function");
+
+ JvAssert ((self->accflags & Modifier::NATIVE) != 0);
+
+ // FIXME: for now we assume that all native methods for
+ // interpreted code use JNI.
+ fun = (ffi_closure_fun) &_Jv_JNIMethod::call;
+
+ FFI_PREP_RAW_CLOSURE (&closure->closure,
+ &closure->cif,
+ fun,
+ (void*) this);
+
+ self->ncode = (void *) closure;
+ return self->ncode;
+}
+
+static void
+throw_class_format_error (jstring msg)
+{
+ throw (msg
+ ? new java::lang::ClassFormatError (msg)
+ : new java::lang::ClassFormatError);
+}
+
+static void
+throw_class_format_error (char *msg)
+{
+ throw_class_format_error (JvNewStringLatin1 (msg));
+}
+
+
+
+void
+_Jv_InterpreterEngine::do_verify (jclass klass)
+{
+ _Jv_InterpClass *iclass = (_Jv_InterpClass *) klass->aux_info;
+ for (int i = 0; i < klass->method_count; i++)
+ {
+ using namespace java::lang::reflect;
+ _Jv_MethodBase *imeth = iclass->interpreted_methods[i];
+ _Jv_ushort accflags = klass->methods[i].accflags;
+ if ((accflags & (Modifier::NATIVE | Modifier::ABSTRACT)) == 0)
+ {
+ _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (imeth);
+ _Jv_VerifyMethod (im);
+ }
+ }
+}
+
+void
+_Jv_InterpreterEngine::do_create_ncode (jclass klass)
+{
+ _Jv_InterpClass *iclass = (_Jv_InterpClass *) klass->aux_info;
+ for (int i = 0; i < klass->method_count; i++)
+ {
+ // Just skip abstract methods. This is particularly important
+ // because we don't resize the interpreted_methods array when
+ // miranda methods are added to it.
+ if ((klass->methods[i].accflags
+ & java::lang::reflect::Modifier::ABSTRACT)
+ != 0)
+ continue;
+
+ _Jv_MethodBase *imeth = iclass->interpreted_methods[i];
+
+ if ((klass->methods[i].accflags & java::lang::reflect::Modifier::NATIVE)
+ != 0)
+ {
+ // You might think we could use a virtual `ncode' method in
+ // the _Jv_MethodBase and unify the native and non-native
+ // cases. Well, we can't, because we don't allocate these
+ // objects using `new', and thus they don't get a vtable.
+ _Jv_JNIMethod *jnim = reinterpret_cast<_Jv_JNIMethod *> (imeth);
+ klass->methods[i].ncode = jnim->ncode ();
+ }
+ else if (imeth != 0) // it could be abstract
+ {
+ _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (imeth);
+ klass->methods[i].ncode = im->ncode ();
+ }
+ }
+}
+
+void
+_Jv_InterpreterEngine::do_allocate_static_fields (jclass klass,
+ int static_size)
+{
+ _Jv_InterpClass *iclass = (_Jv_InterpClass *) klass->aux_info;
+
+ char *static_data = (char *) _Jv_AllocBytes (static_size);
+ memset (static_data, 0, static_size);
+
+ for (int i = 0; i < klass->field_count; i++)
+ {
+ _Jv_Field *field = &klass->fields[i];
+
+ if ((field->flags & java::lang::reflect::Modifier::STATIC) != 0)
+ {
+ field->u.addr = static_data + field->u.boffset;
+
+ if (iclass->field_initializers[i] != 0)
+ {
+ _Jv_Linker::resolve_field (field, klass->loader);
+ _Jv_InitField (0, klass, i);
+ }
+ }
+ }
+
+ // Now we don't need the field_initializers anymore, so let the
+ // collector get rid of it.
+ iclass->field_initializers = 0;
+}
+
+_Jv_ResolvedMethod *
+_Jv_InterpreterEngine::do_resolve_method (_Jv_Method *method, jclass klass,
+ jboolean staticp, jint vtable_index)
+{
+ int arg_count = _Jv_count_arguments (method->signature, staticp);
+
+ _Jv_ResolvedMethod* result = (_Jv_ResolvedMethod*)
+ _Jv_AllocBytes (sizeof (_Jv_ResolvedMethod)
+ + arg_count*sizeof (ffi_type*));
+
+ result->stack_item_count
+ = init_cif (method->signature,
+ arg_count,
+ staticp,
+ &result->cif,
+ &result->arg_types[0],
+ NULL);
+
+ result->vtable_index = vtable_index;
+ result->method = method;
+ result->klass = klass;
+
+ return result;
+}
+
+void
+_Jv_InterpreterEngine::do_post_miranda_hook (jclass klass)
+{
+ _Jv_InterpClass *iclass = (_Jv_InterpClass *) klass->aux_info;
+ for (int i = 0; i < klass->method_count; i++)
+ {
+ // Just skip abstract methods. This is particularly important
+ // because we don't resize the interpreted_methods array when
+ // miranda methods are added to it.
+ if ((klass->methods[i].accflags
+ & java::lang::reflect::Modifier::ABSTRACT)
+ != 0)
+ continue;
+ // Miranda method additions mean that the `methods' array moves.
+ // We cache a pointer into this array, so we have to update.
+ iclass->interpreted_methods[i]->self = &klass->methods[i];
+ }
+}
+
#endif // INTERPRETER