diff options
author | green <green@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-08-08 14:06:23 +0000 |
---|---|---|
committer | green <green@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-08-08 14:06:23 +0000 |
commit | 9a6624c49770e9b5e630a7c51eb0a13002d9df83 (patch) | |
tree | 277498eeeff558237a9cd88b0ea8b3788b31d645 /libjava/interpret.cc | |
parent | 47c5fab6136c7525f4abe013644d7d20570d1b94 (diff) | |
download | gcc-9a6624c49770e9b5e630a7c51eb0a13002d9df83.tar.gz |
1999-08-09 Anthony Green <green@cygnus.com>
* gij.cc: New file.
* include/config.h.in: Rebuilt.
* acconfig.h: Add INTERPRETER.
* configure: Rebuilt.
* Makefile.in: Rebuilt.
* Makefile.am (libffi_files): Identify the libffi object files for
inclusion in libgcj.
(LIBFFIINCS): Define.
* interpret.cc (gnu::gcj::runtime::MethodInvocation::continue1):
Dummy definition for configurations without an interpreter.
* java/net/natPlainSocketImpl.cc (getOption): Disamiguate call to
java::lang::Boolean constructor.
* include/java-interp.h: Always include java-cpool.h.
* java/lang/natClassLoader.cc (getVMClassLoader0): Always return 0
when INTERPRETER not defined.
* java/lang/Class.h (finalize): Define.
* gnu/gcj/util/path/DirectoryPathEntry.java (getURL): Catch
IOException from File.getCanonicalPath.
(getStream): Likewise.
* NEWS: More news.
* THANKS: More thanks.
1999-08-09 Kresten Krab Thorup <krab@gnu.org>
* resolve.cc (get_ffi_type_from_signature): Generate uint16 for
jchar type.
(_Jv_PrepareClass): Allow non-abstract classes to
have abstract subclasses.
(_Jv_ResolvePoolEntry): Revert subclass check for protected
fields and methods.
* interpret.cc (continue1/perform_invoke): Don't sign extend
uint16 return val.
(continue1/lshl,lshr): Push long, not int.
(continue1/ulshr): Use UINT64, not long long.
* defineclass.cc (handleFieldsEnd): Handle case when all fields
are static.
* java/lang/natClass.cc (forName): Add call to _Jv_InitClass.
* java/lang/FirstThread.java (run): Add top-level exception
handler.
(run0): Renamed from run.
1999-08-08 Kresten Krab Thorup <krab@gnu.org>
* configure.in (--with-interpreter): Added.
* include/config.h.in (INTERPRETER): Added.
* java/lang/ClassLoader.java: File replaced.
* java/lang/VMClassLoader.java: New file.
* java/lang/natClassLoader.cc: New file.
* gnu/gcj/runtime/MethodInvocation.java: New file.
* gnu/gcj/util/path/SearchPath.java: New file.
* gnu/gcj/util/path/PathEntry.java: New file.
* gnu/gcj/util/path/DirectoryPathEntry.java: New file.
* gnu/gcj/util/path/ZipPathEntry.java: New file.
* gnu/gcj/util/path/URLPathEntry.java: New file.
* gnu/gcj/util/path/CacheEntry.java: New file.
* include/java-interp.h: New file.
* include/java-cpool.h: New file.
* include/java-insns.h: New file.
* defineclass.cc: New file.
* interpret.cc: New file.
* resolve.cc: New file.
* java/lang/natClass.cc (loaded_classes, _Jv_RegisterClass,
_Jv_RegisterClasses, _Jv_FindClassInCache, _Jv_FindClass,
_Jv_NewClass, _Jv_FindArrayClass): Moved to natClassLoader.cc.
(finalize): New.
(STATE_NOTHING, STATE_RESOLVED, STATE_IN_PROGRESS, STATE_DONE,
STATE_ERROR): Moved to java/lang/Class.h and renamed with JV_
prefix.
(initializeClass): Use new JV_ prefixed names. Also, call
ClassLoader::resolveClass instead of _Jv_ResolveClass.
* java/lang/Class.h (JV_STATE_PRELOADING, JV_STATE_LOADING,
JV_STATE_LOADED, JV_STATE_COMPILED, JV_STATE_PREPARED,
JV_STATE_LINKED): New.
(_Jv_WaitForState, _Jv_RegisterInitiatingLoader,
_Jv_UnregisterClass, _Jv_InternClassStrings): New friends.
(_Jv_IsInterpretedClass, _Jv_InitField, _Jv_LookupDeclaredMethod,
_Jv_DetermineVTableIndex, _Jv_ResolvePoolEntry, _Jv_PrepareClass,
_Jv_ClassReader, _Jv_InterpClass, _Jv_InterpMethod,
_Jv_InterpMethodInvocation): New friends for interpreter.
(finalize): New.
(CONSTANT_Class, CONSTANT_String, etc.): Moved to
include/java-cpool.h and renamed with JV_ prefix.
* include/jvm.h (_Jv_makeUtf8Const, _Jv_makeUtf8TypeConst): New
decls.
(_Jv_UnregisterClass): New decl.
* java/lang/natClassLoader.cc (_Jv_FindArrayClass): Added
class loader argument.
(_Jv_FindClass): Use class loader.
* prims.cc (_Jv_makeUtf8Const): New function.
(_Jv_NewObjectArray): Change use of _Jv_FindArrayClass.
(_Jv_NewPrimArray): Ditto.
(_Jv_FindClassFromSignature): Ditto.
* java/lang/reflect/natArray.cc (newInstance): Ditto.
* java/lang/reflect/natMethod.cc (getType): Ditto.
* include/java-field.h (_Jv_Field::isRef): Make robust for
non-resolved contexts.
* boehm.cc (_Jv_MarkObj): Mark interpreter-related fields.
Also, don't mark class->next field.
* java/lang/VirtualMachineError.java: Added FIXME note.
* configure.in (INTERPSPEC): New spec.
* libgcj.spec.in: Added INTERPSPEC.
* Makefile.am: Added gcjh friends for java/lang/VMClassLoader and
gnu/gcj/runtime/MethodInvocation.
(libgcj_la_SOURCES): Added resolve.cc defineclass.cc interpret.cc.
(ordinary_java_source_files): Added above mentioned java classes.
* configure: Rebuilt.
* Makefile.in: Rebuilt.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@28597 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/interpret.cc')
-rw-r--r-- | libjava/interpret.cc | 2449 |
1 files changed, 2449 insertions, 0 deletions
diff --git a/libjava/interpret.cc b/libjava/interpret.cc new file mode 100644 index 00000000000..1b9b8006da7 --- /dev/null +++ b/libjava/interpret.cc @@ -0,0 +1,2449 @@ +// interpret.cc - Code for the interpreter + +/* Copyright (C) 1999 Cygnus Solutions + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +/* define this to get instruction timings. */ +/* #define TIME_MAINLOOP */ + +#include <config.h> + +#pragma implementation "java-interp.h" + +#include <cni.h> +#include <jvm.h> +#include <java-field.h> +#include <java-cpool.h> +#include <java-interp.h> +#include <java/lang/fdlibm.h> +#include <java/lang/System.h> +#include <java/lang/String.h> +#include <java/lang/Integer.h> +#include <java/lang/StringBuffer.h> +#include <java/io/PrintStream.h> +#include <java/lang/Class.h> +#include <java/lang/reflect/Modifier.h> +#include <java/lang/ClassCastException.h> +#include <java/lang/VirtualMachineError.h> +#include <java/lang/InternalError.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/ArithmeticException.h> +#include <java/lang/IncompatibleClassChangeError.h> +#include <java-insns.h> +#include <java-signal.h> +#ifdef TIME_MAINLOOP +#include <sys/time.h> +#include <stdio.h> +#endif + +#ifndef INTERPRETER + +#include <gnu/gcj/runtime/MethodInvocation.h> + +/* this is the exception handler hack, for the interpreter */ +void +gnu::gcj::runtime::MethodInvocation::continue1 (gnu::gcj::RawData *, + gnu::gcj::RawData *) +{ + JvFail ("no interpreter"); +} + +#else + +#define ClassError _CL_Q34java4lang5Error +extern java::lang::Class ClassError; + +static const int PUBLIC = 0x001; +static const int PRIVATE = 0x002; +static const int PROTECTED = 0x004; +static const int STATIC = 0x008; +static const int FINAL = 0x010; +static const int SYNCHRONIZED = 0x020; +static const int VOLATILE = 0x040; +static const int TRANSIENT = 0x080; +static const int NATIVE = 0x100; +static const int INTERFACE = 0x200; +static const int ABSTRACT = 0x400; +static const int ALL_FLAGS = 0x7FF; + +static _Jv_Utf8Const *init_name = _Jv_makeUtf8Const ("<init>", 6); + +static void throw_internal_error (char *msg) + __attribute__ ((__noreturn__)); +static void throw_incompatible_class_change_error (jstring msg) + __attribute__ ((__noreturn__)); +#if !HANDLE_SEGV +static void throw_null_pointer_exception () + __attribute__ ((__noreturn__)); +#endif +#if !HANDLE_FPE +static void throw_arithmetic_exception () + __attribute__ ((__noreturn__)); +#endif + + +static inline void dupx (void **&sp, int n, int x) +{ + // first "slide" n+x elements n to the right + int top = n-1; + for (int i = 0; i < n+x; i++) + { + sp[(top-i)] = sp[(top-i)-n]; + } + + // next, copy the n top elements, n+x down + for (int i = 0; i < n; i++) + { + sp[top-(n+x)-i] = sp[top-i]; + } + + // the net effect + sp += n; +}; + + +#define PUSHA(V) \ + ({ jobject __v=(V); *(jobject*)sp++ = __v; }) +#define PUSHI(V) \ + ({ jint __v=(V); *(jint*)sp++ = __v; }) +#define PUSHF(V) \ + ({ jfloat __v=(V); *(jfloat*)sp++ = __v; }) +#define PUSHL(V) \ + ({ jlong __v=(V); memcpy ((void*)sp, (void*)&__v, 8); sp+=2; }) +#define PUSHD(V) \ + ({ jdouble __v=(V); memcpy ((void*)sp, (void*)&__v, 8); sp+=2; }) + +#define POPA() (*(jobject*)--sp) +#define POPI() (*(jint*)--sp) +#define POPF() (*(jfloat*)--sp) +#define POPL() ({ jlong __r; sp-=2; memcpy ((void*)&__r, sp, 8); __r; }) +#define POPD() ({ jdouble __r; sp-=2; memcpy ((void*)&__r, sp, 8); __r; }) + +#define LOADA(I) *sp++ = locals[I] +#define LOADI(I) *sp++ = locals[I] +#define LOADF(I) *sp++ = locals[I] +#define LOADL(I) ({ memcpy (sp, locals+(I), 8); sp+=2; }) +#define LOADD(I) ({ memcpy (sp, locals+(I), 8); sp+=2; }) + +#define STOREA(I) locals[I] = *--sp +#define STOREI(I) locals[I] = *--sp +#define STOREF(I) locals[I] = *--sp +#define STOREL(I) ({ sp-=2; memcpy (locals+(I), sp, 8); }) +#define STORED(I) ({ sp-=2; memcpy (locals+(I), sp, 8); }) + +#define PEEKI(I) (*(jint*) (locals+(I))) +#define PEEKA(I) (*(jobject*) (locals+(I))) + +#define POKEI(I,V) (*(jint*) (locals+(I)) = (V)) + + +#define BINOPI(OP) { \ + jint value2 = POPI(); \ + jint value1 = POPI(); \ + PUSHI(value1 OP value2); \ +} + +#define BINOPF(OP) { \ + jfloat value2 = POPF(); \ + jfloat value1 = POPF(); \ + PUSHF(value1 OP value2); \ +} + +#define BINOPL(OP) { \ + jlong value2 = POPL(); \ + jlong value1 = POPL(); \ + PUSHL(value1 OP value2); \ +} + +#define BINOPD(OP) { \ + jdouble value2 = POPD(); \ + jdouble value1 = POPD(); \ + PUSHD(value1 OP value2); \ +} + +static inline jint get1s(unsigned char* loc) { + return *(signed char*)loc; +} + +static inline jint get1u(unsigned char* loc) { + return *loc; +} + +static inline jint get2s(unsigned char* loc) { + return (((jint)*(signed char*)loc) << 8) | ((jint)*(loc+1)); +} + +static inline jint get2u(unsigned char* loc) { + return (((jint)(*loc)) << 8) | ((jint)*(loc+1)); +} + +static jint get4(unsigned char* loc) { + return (((jint)(loc[0])) << 24) + | (((jint)(loc[1])) << 16) + | (((jint)(loc[2])) << 8) + | (((jint)(loc[3])) << 0); +} + + +#if HANDLE_SEGV +#define NULLCHECK(X) +#else +#define NULLCHECK(X) \ + do { if ((X)==NULL) throw_null_pointer_exception (); } while (0) +#endif + +#if HANDLE_FPE +#define ZEROCHECK(X) +#else +#define ZEROCHECK(X) \ + do { if ((X) == 0) throw_arithmetic_exception (); } while (0) +#endif + +// this method starts the actual running of the method. It is inlined +// in three different variants in the static methods run_normal, +// run_sync_object and run_sync_class (see below). Those static methods +// are installed directly in the stub for this method (by +// _Jv_InterpMethod::ncode, in resolve.cc). + +inline jobject +_Jv_InterpMethod::run (ffi_cif* cif, + void *retp, + void**args, + _Jv_InterpMethodInvocation *inv) +{ + inv->running = this; + inv->pc = bytecode (); + inv->sp = inv->stack_base (); + void **locals = inv->local_base (); + + /* Go straight at it! the ffi raw format matches the internal + stack representation exactly! + */ + memcpy ((void*) locals, (void*) args, args_raw_size); + + next_segment: + /* this will call the method _Jv_InterpMethod::continue0, see below */ + jobject ex = + gnu::gcj::runtime::MethodInvocation::continue0 + ((gnu::gcj::RawData *)this, (gnu::gcj::RawData *)inv); + + if (ex == 0) // no exception... + { + /* define sp locally, so the POP? macros will pick it up */ + void **sp = (void**)inv->sp; + int rtype = cif->rtype->type; + + if (rtype == FFI_TYPE_POINTER) + { + jobject r = POPA(); + *(jobject*) retp = r; + return 0; + } + else if (rtype == FFI_TYPE_SINT32) + { + jint r = POPI(); + *(jint*)retp = r; + return 0; + } + else if (rtype == FFI_TYPE_VOID) + { + return 0; + } + else switch (rtype) + { + case FFI_TYPE_FLOAT: + { + jfloat r = POPF(); + *(jfloat*)retp = r; + return 0; + } + + case FFI_TYPE_DOUBLE: + { + jdouble r = POPD(); + *(jdouble*)retp = r; + return 0; + } + + case FFI_TYPE_UINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT8: + case FFI_TYPE_SINT16: + { + jint r = POPI(); + *(jint*)retp = r; + return 0; + } + + case FFI_TYPE_SINT64: + { + jlong r = POPL(); + *(jlong*)retp = r; + return 0; + } + + default: + throw_internal_error ("unknown return type"); + } + + } + + /** handle an exception */ + if ( find_exception (ex, inv) ) + goto next_segment; + + java::lang::System::out->println + (_Jv_NewStringUTF (self->name->data)); + + return ex; +} + +bool _Jv_InterpMethod::find_exception (jobject ex, + _Jv_InterpMethodInvocation *inv) +{ + int logical_pc = inv->pc - bytecode (); + _Jv_InterpException *exc = exceptions (); + jclass exc_class = ex->getClass (); + + for (int i = 0; i < exc_count; i++) + { + if (exc[i].start_pc <= logical_pc && logical_pc < exc[i].end_pc) + { + jclass handler; + + if (exc[i].handler_type != 0) + handler = (jclass) + _Jv_ResolvePoolEntry (defining_class, + exc[i].handler_type); + else + handler = NULL; + + if (handler==NULL || handler->isAssignableFrom (exc_class)) + { + inv->pc = bytecode () + exc[i].handler_pc; + inv->sp = inv->stack_base (); // reset stack + *(jobject*) (inv->sp ++) = ex; + return true; + } + } + } + return false; +} + +void _Jv_InterpMethod::run_normal (ffi_cif* cif, + void* ret, + void** args, + void* __this) +{ + _Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this; + + // we do the alloca of the method invocation here, to allow the method + // "run" ro be inlined. Otherwise gcc will ignore the inline directive. + int storage_size = _this->max_stack+_this->max_locals; + _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*) + alloca (sizeof (_Jv_InterpMethodInvocation) + + storage_size * sizeof (void*)); + + jobject ex = _this->run (cif, ret, args, inv); + if (ex != 0) _Jv_Throw (ex); +} + +void _Jv_InterpMethod::run_synch_object (ffi_cif* cif, + void* ret, + void** args, + void* __this) +{ + _Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this; + jobject rcv = (jobject)args[0]; + + int storage_size = _this->max_stack+_this->max_locals; + _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*) + alloca (sizeof (_Jv_InterpMethodInvocation) + + storage_size * sizeof (void*)); + + _Jv_MonitorEnter (rcv); + jobject ex = _this->run (cif, ret, args, inv); + _Jv_MonitorExit (rcv); + + if (ex != 0) _Jv_Throw (ex); +} + +void _Jv_InterpMethod::run_synch_class (ffi_cif* cif, + void* ret, + void** args, + void* __this) +{ + _Jv_InterpMethod* _this = (_Jv_InterpMethod*)__this; + jclass sync = _this->defining_class; + + int storage_size = _this->max_stack+_this->max_locals; + _Jv_InterpMethodInvocation* inv = (_Jv_InterpMethodInvocation*) + alloca (sizeof (_Jv_InterpMethodInvocation) + + storage_size * sizeof (void*)); + + _Jv_MonitorEnter (sync); + jobject ex = _this->run (cif, ret, args, inv); + _Jv_MonitorExit (sync); + + if (ex != 0) _Jv_Throw (ex); +} + +/* this is the exception handler hack, for the interpreter */ +void +gnu::gcj::runtime::MethodInvocation::continue1 (gnu::gcj::RawData *meth, + gnu::gcj::RawData *inv) +{ + _Jv_InterpMethod *meth0 = (_Jv_InterpMethod*)meth; + _Jv_InterpMethodInvocation *inv0 = (_Jv_InterpMethodInvocation*)inv; + meth0->continue1 (inv0); +} + +/* + This proceeds execution, as designated in "inv". If an exception + happens, then it is simply thrown, and handled in Java. Thus, the pc + needs to be stored in the invocation at all times, so we can figure + out which handler (if any) to invoke. + + One design issue, which I have not completely considered, is if it + should be possible to have interpreted classes linked in! Seldom used + (or non-critical) classes could reasonably be interpreted. +*/ + + +#ifdef TIME_MAINLOOP +static jlong insn_time [256] = { 0 }; +static jlong insn_count[256] = { 0 }; + +static void +dump_time () +{ + double total_all = 0; + for (int i = 0; i < 256; i++) + { + total_all += insn_time[i]; + } + + for (int i = 0; i < 256; i++) + { + jlong total = insn_time[i]; + jlong count = insn_count[i]; + + if (count == 0) continue; + + jlong amount = total/count; + + printf ("in 0x%02x: %7Li %7Li %7Li %2.1f%%\n", i, + (long long)count, (long long)total, (long long)amount, + (float) (100.0*(double)total/total_all) + ); + } +} +#endif + +void _Jv_InterpMethod::continue1 (_Jv_InterpMethodInvocation *inv) +{ + /* for some reason, which I do not understand, the compiler on x86 + * allocates almost 4k stack space for this function! Even though + * there are many local variables, they are all nicely contained + * within a block scope, except for the few declared right below + * here. What's going on?? It could well be, that there in fact is + * on the order of 1000 local variables, including all those inlined + * and expanded from macros... Compiling with -O0, it allocates a + * "modest" 300 bytes of stack space. Among all those options of + * gcc, why isn't there a -fpack-stack, allowing reuse of stack + * locations? */ + + void** sp = inv->sp; + unsigned char *pc = inv->pc; + void** locals = inv->local_base (); + int opcode; + + jclass defining_class = this->defining_class; + void **pool_data = defining_class->constants.data; + + /* these two are used in the invokeXXX instructions */ + void (*fun)(...); + _Jv_ResolvedMethod* rmeth; + +#ifdef TIME_MAINLOOP + struct timeval tv; + int last_opcode; + jlong last_time; + static jlong time_warp = 0; + +#define USEC(TV) \ + ((jlong) (TV).tv_sec * 1000000LL + (jlong)(TV).tv_usec) + + + if (time_warp == 0) + { + struct timeval tv2; + + gettimeofday (&tv, 0); + for (int i = 0; i < 100; i++) + gettimeofday (&tv2, 0); + + jlong then = USEC(tv); + jlong now = USEC(tv2); + time_warp = (now - then) / 100; + + if (time_warp == 0) + time_warp = 1; + } + +#define TIME_SUSPEND do { \ + gettimeofday (&tv, 0); \ + jlong now = USEC(tv); \ + insn_time[last_opcode] += (now - last_time) - time_warp; \ +} while(0) + +#define TIME_RESUME do { \ + gettimeofday (&tv, 0); \ + last_time = USEC(tv); \ +} while(0) + + last_opcode = 0; + gettimeofday (&tv, 0); + last_time = (jlong)tv.tv_sec * 1000000LL + (jlong)tv.tv_usec; + +#else + +#define TIME_SUSPEND +#define TIME_RESUME + +#endif + + next_insn: + inv->pc = pc; + +#ifdef TIME_MAINLOOP + + gettimeofday (&tv, 0); + jlong now = USEC(tv); + insn_time[last_opcode] += (now - last_time) - time_warp; + last_time = now; + last_opcode = *pc; + insn_count[last_opcode] += 1; + +#endif + opcode = *pc++; + + /* we special-case the single opcode aload_0 -- it makes + up 10% of the time spent in the main loop. */ + + switch (opcode) + { + case op_aload_0: // 0x2a + LOADA(0); + goto next_insn; + + case op_iload: // 0x15 + LOADI (get1u (pc++)); + goto next_insn; + + case op_getfield_4: // 0xd8 + { + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + PUSHI (*(jint*) ((char*)obj + field_offset)); + } + goto next_insn; + + case op_iload_1: // 0x1b + LOADI (1); + goto next_insn; + + case op_getfield_a: // 0xda + { + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + PUSHA(*(jobject*) ((char*)obj + field_offset)); + } + goto next_insn; + + case op_invokevirtual: // 0xb6 + { + int index = get2u (pc); pc += 2; + + /* _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. */ + + rmeth = (_Jv_ResolvedMethod*) + _Jv_ResolvePoolEntry (defining_class, index); + + sp -= rmeth->stack_item_count; + NULLCHECK(sp[0]); + + if (rmeth->vtable_index == -1) + { + // final methods do not appear in the vtable, + // if it does not appear in the superclass. + fun = (void (*) (...)) rmeth->method->ncode; + } + else + { + jobject rcv = (jobject)sp[0]; + _Jv_VTable *table = *(_Jv_VTable**)rcv; + fun = (void (*) (...))table->method[rmeth->vtable_index]; + } + } + goto perform_invoke; + + perform_invoke: + { + /* here goes the magic again... */ + ffi_cif *cif = &rmeth->cif; + void **raw = sp; + + jdouble rvalue; + + TIME_SUSPEND; + ffi_raw_call (cif, fun, (void*)&rvalue, (ffi_raw*) raw); + TIME_RESUME; + + int rtype = cif->rtype->type; + + /* the likelyhood of object, int, or void return is very high, + * so those are checked before the switch */ + if (rtype == FFI_TYPE_POINTER) + { + PUSHA (*(jobject*)&rvalue); + } + else if (rtype == FFI_TYPE_SINT32) + { + PUSHI (*(jint*)&rvalue); + } + else if (rtype == FFI_TYPE_VOID) + { + /* skip */ + } + else switch (rtype) + { + case FFI_TYPE_SINT8: + { + jbyte value = (*(jint*)&rvalue) & 0xff; + PUSHI (value); + } + break; + + case FFI_TYPE_SINT16: + { + jshort value = (*(jint*)&rvalue) & 0xffff; + PUSHI (value); + } + break; + + case FFI_TYPE_UINT16: + { + jint value = (*(jint*)&rvalue) & 0xffff; + PUSHI (value); + } + break; + + case FFI_TYPE_FLOAT: + PUSHF (*(jfloat*)&rvalue); + break; + + case FFI_TYPE_DOUBLE: + PUSHD (rvalue); + break; + + case FFI_TYPE_SINT64: + PUSHL (*(jlong*)&rvalue); + break; + + default: + throw_internal_error ("unknown return type in invokeXXX"); + } + + } + goto next_insn; + + + case op_nop: + goto next_insn; + + case op_aconst_null: + PUSHA (NULL); + goto next_insn; + + case op_iconst_m1: + case op_iconst_0: + case op_iconst_1: + case op_iconst_2: + case op_iconst_3: + case op_iconst_4: + case op_iconst_5: + PUSHI (opcode-op_iconst_0); + goto next_insn; + + case op_lconst_0: + case op_lconst_1: + PUSHL ((jlong) (opcode-op_lconst_0)); + goto next_insn; + + case op_fconst_0: + case op_fconst_1: + case op_fconst_2: + PUSHF ((jfloat) (opcode-op_fconst_0)); + goto next_insn; + + case op_dconst_0: + case op_dconst_1: + PUSHD ((jdouble) (opcode-op_dconst_0)); + goto next_insn; + + case op_bipush: + PUSHI (get1s(pc++)); + goto next_insn; + + case op_sipush: + PUSHI (get2s(pc)); pc += 2; + goto next_insn; + + case op_ldc: + { + int index = get1u (pc++); + PUSHA((jobject) pool_data[index]); + } + goto next_insn; + + case op_ldc_w: + { + int index = get2u (pc); pc += 2; + PUSHA((jobject) pool_data[index]); + } + goto next_insn; + + case op_ldc2_w: + { + int index = get2u (pc); pc += 2; + memcpy (sp, &pool_data[index], 8); + sp += 2; + } + goto next_insn; + + case op_lload: + LOADL (get1u (pc++)); + goto next_insn; + + case op_fload: + LOADF (get1u (pc++)); + goto next_insn; + + case op_dload: + LOADD (get1u (pc++)); + goto next_insn; + + case op_aload: + LOADA (get1u (pc++)); + goto next_insn; + + case op_iload_0: + LOADI (0); + goto next_insn; + + case op_iload_2: + LOADI (2); + goto next_insn; + + case op_iload_3: + LOADI (3); + goto next_insn; + + case op_lload_0: + case op_lload_1: + case op_lload_2: + case op_lload_3: + LOADL (opcode-op_lload_0); + goto next_insn; + + case op_fload_0: + case op_fload_1: + case op_fload_2: + case op_fload_3: + LOADF (opcode-op_fload_0); + goto next_insn; + + case op_dload_0: + case op_dload_1: + case op_dload_2: + case op_dload_3: + LOADD (opcode-op_dload_0); + goto next_insn; + + case op_aload_1: + LOADA(1); + goto next_insn; + + case op_aload_2: + LOADA(2); + goto next_insn; + + case op_aload_3: + LOADA(3); + goto next_insn; + + case op_iaload: + { + jint index = POPI(); + jintArray arr = (jintArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHI( elements(arr)[index] ); + } + goto next_insn; + + case op_laload: + { + jint index = POPI(); + jlongArray arr = (jlongArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHL( elements(arr)[index] ); + } + goto next_insn; + + case op_faload: + { + jint index = POPI(); + jfloatArray arr = (jfloatArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHF( elements(arr)[index] ); + } + goto next_insn; + + case op_daload: + { + jint index = POPI(); + jdoubleArray arr = (jdoubleArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHD( elements(arr)[index] ); + } + goto next_insn; + + case op_aaload: + { + jint index = POPI(); + jobjectArray arr = (jobjectArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHA( elements(arr)[index] ); + } + goto next_insn; + + case op_baload: + { + jint index = POPI(); + jbyteArray arr = (jbyteArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHI( elements(arr)[index] ); + } + goto next_insn; + + case op_caload: + { + jint index = POPI(); + jcharArray arr = (jcharArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHI( elements(arr)[index] ); + } + goto next_insn; + + case op_saload: + { + jint index = POPI(); + jshortArray arr = (jshortArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + PUSHI( elements(arr)[index] ); + } + goto next_insn; + + case op_istore: + STOREI (get1u (pc++)); + goto next_insn; + + case op_lstore: + STOREL (get1u (pc++)); + goto next_insn; + + case op_fstore: + STOREF (get1u (pc++)); + goto next_insn; + + case op_dstore: + STORED (get1u (pc++)); + goto next_insn; + + case op_astore: + STOREI (get1u (pc++)); + goto next_insn; + + case op_istore_0: + case op_istore_1: + case op_istore_2: + case op_istore_3: + STOREI (opcode-op_istore_0); + goto next_insn; + + case op_lstore_0: + case op_lstore_1: + case op_lstore_2: + case op_lstore_3: + STOREL (opcode-op_lstore_0); + goto next_insn; + + case op_fstore_0: + case op_fstore_1: + case op_fstore_2: + case op_fstore_3: + STOREF (opcode-op_fstore_0); + goto next_insn; + + case op_dstore_0: + case op_dstore_1: + case op_dstore_2: + case op_dstore_3: + STORED (opcode-op_dstore_0); + goto next_insn; + + case op_astore_0: + case op_astore_1: + case op_astore_2: + case op_astore_3: + STOREA (opcode-op_astore_0); + goto next_insn; + + case op_iastore: + { + jint value = POPI(); + jint index = POPI(); + jintArray arr = (jintArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + elements(arr)[index] = value; + } + goto next_insn; + + case op_lastore: + { + jlong value = POPL(); + jint index = POPI(); + jlongArray arr = (jlongArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + elements(arr)[index] = value; + } + goto next_insn; + + case op_fastore: + { + jfloat value = POPF(); + jint index = POPI(); + jfloatArray arr = (jfloatArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + elements(arr)[index] = value; + } + goto next_insn; + + case op_dastore: + { + jdouble value = POPD(); + jint index = POPI(); + jdoubleArray arr = (jdoubleArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + elements(arr)[index] = value; + } + goto next_insn; + + case op_aastore: + { + jobject value = POPA(); + jint index = POPI(); + jobjectArray arr = (jobjectArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + _Jv_CheckArrayStore (arr, value); + elements(arr)[index] = value; + } + goto next_insn; + + case op_bastore: + { + jbyte value = (jbyte) POPI(); + jint index = POPI(); + jbyteArray arr = (jbyteArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + elements(arr)[index] = value; + } + goto next_insn; + + case op_castore: + { + jchar value = (jchar) POPI(); + jint index = POPI(); + jcharArray arr = (jcharArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + elements(arr)[index] = value; + } + goto next_insn; + + case op_sastore: + { + jshort value = (jshort) POPI(); + jint index = POPI(); + jshortArray arr = (jshortArray) POPA(); + NULLCHECK (arr); + if (index < 0 || index >= arr->length) + { + TIME_SUSPEND; + _Jv_ThrowBadArrayIndex (index); + } + elements(arr)[index] = value; + } + goto next_insn; + + case op_pop: + sp -= 1; + goto next_insn; + + case op_pop2: + sp -= 2; + goto next_insn; + + case op_dup: + sp[0] = sp[-1]; + sp += 1; + goto next_insn; + + case op_dup_x1: + dupx (sp, 1, 1); + goto next_insn; + + case op_dup_x2: + dupx (sp, 1, 2); + goto next_insn; + + case op_dup2: + sp[0] = sp[-2]; + sp[1] = sp[-1]; + sp += 2; + goto next_insn; + + case op_dup2_x1: + dupx (sp, 2, 1); + goto next_insn; + + case op_dup2_x2: + dupx (sp, 2, 2); + goto next_insn; + + case op_swap: + { + jobject tmp1 = POPA(); + jobject tmp2 = POPA(); + PUSHA (tmp1); + PUSHA (tmp2); + } + goto next_insn; + + case op_iadd: + BINOPI(+); + goto next_insn; + + case op_ladd: + BINOPL(+); + goto next_insn; + + case op_fadd: + BINOPF(+); + goto next_insn; + + case op_dadd: + BINOPD(+); + goto next_insn; + + case op_isub: + BINOPI(-); + goto next_insn; + + case op_lsub: + BINOPL(-); + goto next_insn; + + case op_fsub: + BINOPF(-); + goto next_insn; + + case op_dsub: + BINOPD(-); + goto next_insn; + + case op_imul: + BINOPI(*); + goto next_insn; + + case op_lmul: + BINOPL(*); + goto next_insn; + + case op_fmul: + BINOPF(*); + goto next_insn; + + case op_dmul: + BINOPD(*); + goto next_insn; + + case op_idiv: + { + jint value2 = POPI(); + jint value1 = POPI(); + ZEROCHECK (value2); + jint res = value1 / value2; + PUSHI (res); + } + goto next_insn; + + case op_ldiv: + { + jlong value2 = POPL(); + jlong value1 = POPL(); + ZEROCHECK (value2); + jlong res = value1 / value2; + PUSHL (res); + } + goto next_insn; + + case op_fdiv: + { + jfloat value2 = POPF(); + jfloat value1 = POPF(); + ZEROCHECK (value2); + jfloat res = value1 / value2; + PUSHF (res); + } + goto next_insn; + + case op_ddiv: + { + jdouble value2 = POPD(); + jdouble value1 = POPD(); + ZEROCHECK (value2); + jdouble res = value1 / value2; + PUSHD (res); + } + goto next_insn; + + case op_irem: + { + jint value2 = POPI(); + jint value1 = POPI(); + ZEROCHECK (value2); + jint res = value1 % value2; + PUSHI (res); + } + goto next_insn; + + case op_lrem: + { + jlong value2 = POPL(); + jlong value1 = POPL(); + ZEROCHECK (value2); + jlong res = value1 % value2; + PUSHL (res); + } + goto next_insn; + + case op_frem: + { + jfloat value2 = POPF(); + jfloat value1 = POPF(); + ZEROCHECK (value2); + jfloat res = __ieee754_fmod (value1, value2); + PUSHF (res); + } + goto next_insn; + + case op_drem: + { + jdouble value2 = POPD(); + jdouble value1 = POPD(); + ZEROCHECK (value2); + jdouble res = __ieee754_fmod (value1, value2); + PUSHD (res); + } + goto next_insn; + + case op_ineg: + *(jint*) (sp-1) *= -1; + goto next_insn; + + case op_lneg: + *(jlong*) (sp-1) *= -1; + goto next_insn; + + case op_fneg: + *(jfloat*) (sp-1) *= -1; + goto next_insn; + + case op_dneg: + *(jdouble*) (sp-1) *= -1; + goto next_insn; + + case op_ishl: + { + jint shift = (POPI() & 0x1f); + jint value = POPI(); + PUSHI (value << shift); + } + goto next_insn; + + case op_lshl: + { + jint shift = (POPI() & 0x3f); + jlong value = POPL(); + PUSHL (value << shift); + } + goto next_insn; + + case op_ishr: + { + jint shift = (POPI() & 0x1f); + jint value = POPI(); + PUSHI (value >> shift); + } + goto next_insn; + + case op_lshr: + { + jint shift = (POPI() & 0x3f); + jlong value = POPL(); + PUSHL (value >> shift); + } + goto next_insn; + + case op_iushr: + { + jint shift = (POPI() & 0x1f); + unsigned long value = POPI(); + PUSHI ((jint) (value >> shift)); + } + goto next_insn; + + case op_lushr: + { + jint shift = (POPI() & 0x3f); + UINT64 value = (UINT64) POPL(); + PUSHL ((value >> shift)); + } + goto next_insn; + + case op_iand: + BINOPI (&); + goto next_insn; + + case op_land: + BINOPL (&); + goto next_insn; + + case op_ior: + BINOPI (|); + goto next_insn; + + case op_lor: + BINOPL (|); + goto next_insn; + + case op_ixor: + BINOPI (^); + goto next_insn; + + case op_lxor: + BINOPL (^); + goto next_insn; + + case op_iinc: + { + jint index = get1u (pc++); + jint amount = get1s (pc++); + *(jint*) (locals + index) += amount; + } + goto next_insn; + + case op_i2l: + PUSHL ((jlong)POPI ()); + goto next_insn; + + case op_i2f: + PUSHF ((jfloat)POPI ()); + goto next_insn; + + case op_i2d: + PUSHD ((jdouble)POPI ()); + goto next_insn; + + case op_l2i: + PUSHI ((jint)POPL ()); + goto next_insn; + + case op_l2f: + PUSHF ((jfloat)POPL ()); + goto next_insn; + + case op_l2d: + PUSHD ((jdouble)POPL ()); + goto next_insn; + + case op_f2i: + PUSHI ((jint)POPF ()); + goto next_insn; + + case op_f2l: + PUSHL ((jlong)POPF ()); + goto next_insn; + + case op_f2d: + PUSHD ((jdouble)POPF ()); + goto next_insn; + + case op_d2i: + PUSHI ((jint)POPD ()); + goto next_insn; + + case op_d2l: + PUSHL ((jlong)POPD ()); + goto next_insn; + + case op_d2f: + PUSHF ((jfloat)POPD ()); + goto next_insn; + + case op_i2b: + PUSHI ((jbyte)POPI ()); + goto next_insn; + + case op_i2c: + PUSHI ((jchar)POPI ()); + goto next_insn; + + case op_i2s: + PUSHI ((jshort)POPI ()); + goto next_insn; + + case op_lcmp: + { + jlong value2 = POPL (); + jlong value1 = POPL (); + if (value1 > value2) + { PUSHI (1); } + else if (value1 == value2) + { PUSHI (0); } + else + { PUSHI (-1); } + } + goto next_insn; + + case op_fcmpl: + case op_fcmpg: + { + jfloat value2 = POPF (); + jfloat value1 = POPF (); + if (value1 > value2) + PUSHI (1); + else if (value1 == value2) + PUSHI (0); + else if (value1 < value2) + PUSHI (-1); + else if (opcode == op_fcmpg) + PUSHI (1); + else + PUSHI (-1); + } + goto next_insn; + + case op_dcmpl: + case op_dcmpg: + { + jdouble value2 = POPD (); + jdouble value1 = POPD (); + if (value1 > value2) + PUSHI (1); + else if (value1 == value2) + PUSHI (0); + else if (value1 < value2) + PUSHI (-1); + else if (opcode == op_dcmpg) + PUSHI (1); + else + PUSHI (-1); + } + goto next_insn; + + case op_ifeq: + { + jint offset = get2s (pc); + if (POPI() == 0) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_ifne: + { + jint offset = get2s (pc); + if (POPI() != 0) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_iflt: + { + jint offset = get2s (pc); + if (POPI() < 0) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_ifge: + { + jint offset = get2s (pc); + if (POPI() >= 0) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_ifgt: + { + jint offset = get2s (pc); + if (POPI() > 0) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_ifle: + { + jint offset = get2s (pc); + if (POPI() <= 0) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_icmpeq: + { + jint offset = get2s (pc); + jint value2 = POPI(); + jint value1 = POPI(); + if (value1 == value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_icmpne: + { + jint offset = get2s (pc); + jint value2 = POPI(); + jint value1 = POPI(); + if (value1 != value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_icmplt: + { + jint offset = get2s (pc); + jint value2 = POPI(); + jint value1 = POPI(); + if (value1 < value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_icmpge: + { + jint offset = get2s (pc); + jint value2 = POPI(); + jint value1 = POPI(); + if (value1 >= value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_icmpgt: + { + jint offset = get2s (pc); + jint value2 = POPI(); + jint value1 = POPI(); + if (value1 > value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_icmple: + { + jint offset = get2s (pc); + jint value2 = POPI(); + jint value1 = POPI(); + if (value1 <= value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_acmpeq: + { + jint offset = get2s (pc); + jobject value2 = POPA(); + jobject value1 = POPA(); + if (value1 == value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_if_acmpne: + { + jint offset = get2s (pc); + jobject value2 = POPA(); + jobject value1 = POPA(); + if (value1 != value2) + pc = pc-1+offset; + else + pc = pc+2; + } + goto next_insn; + + case op_goto: + { + jint offset = get2s (pc); + pc = pc-1+offset; + } + goto next_insn; + + case op_jsr: + { + unsigned char *base_pc = pc-1; + jint offset = get2s (pc); pc += 2; + PUSHA ((jobject)pc); + pc = base_pc+offset; + } + goto next_insn; + + case op_ret: + { + jint index = get1u (pc); + pc = (unsigned char*) PEEKA (index); + } + goto next_insn; + + case op_tableswitch: + { + unsigned char *base_pc = pc-1; + int index = POPI(); + + unsigned char* base = bytecode (); + while ((pc-base) % 4 != 0) + pc++; + + jint def = get4 (pc); + jint low = get4 (pc+4); + jint high = get4 (pc+8); + + if (index < low || index > high) + pc = base_pc + def; + else + pc = base_pc + get4 (pc+4*(index-low+3)); + } + goto next_insn; + + case op_lookupswitch: + { + unsigned char *base_pc = pc-1; + int index = POPI(); + + unsigned char* base = bytecode (); + while ((pc-base) % 4 != 0) + pc++; + + jint def = get4 (pc); + jint npairs = get4 (pc+4); + + int max = npairs-1; + int min = 0; + + // simple binary search... + while (min < max) + { + int half = (min+max)/2; + int match = get4 (pc+ 4*(2 + 2*half)); + + if (index == match) + min = max = half; + + else if (index < match) + max = half-1; + + else + min = half+1; + } + + if (index == get4 (pc+ 4*(2 + 2*min))) + pc = base_pc + get4 (pc+ 4*(2 + 2*min + 1)); + else + pc = base_pc + def; + } + goto next_insn; + + /* on return, just save the sp and return to caller */ + case op_ireturn: + case op_lreturn: + case op_freturn: + case op_dreturn: + case op_areturn: + case op_return: + inv->sp = sp; + TIME_SUSPEND; + return; + + case op_getstatic: + { + unsigned char *base_pc = pc-1; + jint fieldref_index = get2u (pc); pc += 2; + _Jv_ResolvePoolEntry (defining_class, fieldref_index); + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + + if ((field->flags & STATIC) == 0) + throw_incompatible_class_change_error + (JvNewStringLatin1 ("field no longer static")); + + jclass type = field->type; + + if (type->isPrimitive ()) + { + switch (type->size_in_bytes) + { + case 1: + *base_pc = op_getstatic_1; + break; + + case 2: + if (type == JvPrimClass (char)) + *base_pc = op_getstatic_2u; + else + *base_pc = op_getstatic_2s; + break; + + case 4: + *base_pc = op_getstatic_4; + break; + + case 8: + *base_pc = op_getstatic_8; + break; + } + } + else + { + *base_pc = op_getstatic_a; + } + + pc = base_pc; + } + goto next_insn; + + case op_getfield: + { + unsigned char *base_pc = pc-1; + jint fieldref_index = get2u (pc); pc += 2; + _Jv_ResolvePoolEntry (defining_class, fieldref_index); + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + + if ((field->flags & STATIC) != 0) + throw_incompatible_class_change_error + (JvNewStringLatin1 ("field is static")); + + jclass type = field->type; + + if (type->isPrimitive ()) + { + switch (type->size_in_bytes) + { + case 1: + *base_pc = op_getfield_1; + break; + + case 2: + if (type == JvPrimClass (char)) + *base_pc = op_getfield_2u; + else + *base_pc = op_getfield_2s; + break; + + case 4: + *base_pc = op_getfield_4; + break; + + case 8: + *base_pc = op_getfield_8; + break; + } + } + else + { + *base_pc = op_getfield_a; + } + + if (field->u.boffset > 0xffff) + JvThrow (new java::lang::VirtualMachineError); + + base_pc[1] = (field->u.boffset>>8) & 0xff; + base_pc[2] = field->u.boffset & 0xff; + + pc = base_pc; + } + goto next_insn; + + case op_putstatic: + { + unsigned char* base_pc = pc-1; + jint fieldref_index = get2u (pc); pc += 2; + _Jv_ResolvePoolEntry (defining_class, fieldref_index); + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + + jclass type = field->type; + + // ResolvePoolEntry cannot check this + if ((field->flags & STATIC) == 0) + throw_incompatible_class_change_error + (JvNewStringLatin1 ("field no longer static")); + + /* if this is patented, then maybe we could install + a function in the constant pool, to do the right thing */ + + if (type->isPrimitive ()) + { + switch (type->size_in_bytes) + { + case 1: + *base_pc = op_putstatic_1; + break; + + case 2: + *base_pc = op_putstatic_2; + break; + + case 4: + *base_pc = op_putstatic_4; + break; + + case 8: + *base_pc = op_putstatic_8; + break; + } + } + else + { + *base_pc = op_putstatic_a; + } + + // do the instruction again! + pc = base_pc; + } + goto next_insn; + + + case op_putfield: + { + unsigned char* base_pc = pc-1; + jint fieldref_index = get2u (pc); pc += 2; + _Jv_ResolvePoolEntry (defining_class, fieldref_index); + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + + jclass type = field->type; + + if ((field->flags & STATIC) != 0) + throw_incompatible_class_change_error + (JvNewStringLatin1 ("field is static")); + + if (type->isPrimitive ()) + { + switch (type->size_in_bytes) + { + case 1: + *base_pc = op_putfield_1; + break; + + case 2: + *base_pc = op_putfield_2; + break; + + case 4: + *base_pc = op_putfield_4; + break; + + case 8: + *base_pc = op_putfield_8; + break; + } + } + else + { + *base_pc = op_putfield_a; + } + + if (field->u.boffset > 0xffff) + JvThrow (new java::lang::VirtualMachineError); + + base_pc[1] = (field->u.boffset>>8) & 0xff; + base_pc[2] = field->u.boffset & 0xff; + + // do the instruction again! + pc = base_pc; + } + goto next_insn; + + + case op_getfield_1: + { + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + PUSHI (*(jbyte*) ((char*)obj + field_offset)); + } + goto next_insn; + + case op_getfield_2s: + { + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + PUSHI (*(jshort*) ((char*)obj + field_offset)); + } + goto next_insn; + + case op_getfield_2u: + { + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + PUSHI (*(jchar*) ((char*)obj + field_offset)); + } + goto next_insn; + + case op_getfield_8: + { + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + PUSHL(*(jlong*) ((char*)obj + field_offset)); + } + goto next_insn; + + case op_getstatic_1: + { + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + PUSHI (*(jbyte*) (field->u.addr)); + } + goto next_insn; + + case op_getstatic_2s: + { + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + PUSHI(*(jshort*) (field->u.addr)); + } + goto next_insn; + + case op_getstatic_2u: + { + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + PUSHI(*(jchar*) (field->u.addr)); + } + goto next_insn; + + case op_getstatic_4: + { + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + PUSHI(*(jint*) (field->u.addr)); + } + goto next_insn; + + case op_getstatic_8: + { + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + PUSHL(*(jlong*) (field->u.addr)); + } + goto next_insn; + + case op_getstatic_a: + { + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + PUSHA(*(jobject*) (field->u.addr)); + } + goto next_insn; + + case op_putfield_1: + { + jint value = POPI(); + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + *(jbyte*) ((char*)obj + field_offset) = value; + } + goto next_insn; + + case op_putfield_2: + { + jint value = POPI(); + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + *(jchar*) ((char*)obj + field_offset) = value; + } + goto next_insn; + + case op_putfield_4: + { + jint value = POPI(); + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + *(jint*) ((char*)obj + field_offset) = value; + } + goto next_insn; + + case op_putfield_8: + { + jlong value = POPL(); + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + *(jlong*) ((char*)obj + field_offset) = value; + } + goto next_insn; + + case op_putfield_a: + { + jobject value = POPA(); + jobject obj = POPA(); + NULLCHECK(obj); + jint field_offset = get2u (pc); pc += 2; + *(jobject*) ((char*)obj + field_offset) = value; + } + goto next_insn; + + case op_putstatic_1: + { + jint value = POPI(); + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + *(jbyte*) (field->u.addr) = value; + } + goto next_insn; + + case op_putstatic_2: + { + jint value = POPI(); + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + *(jchar*) (field->u.addr) = value; + } + goto next_insn; + + case op_putstatic_4: + { + jint value = POPI(); + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + *(jint*) (field->u.addr) = value; + } + goto next_insn; + + case op_putstatic_8: + { + jlong value = POPL(); + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + *(jlong*) (field->u.addr) = value; + } + goto next_insn; + + case op_putstatic_a: + { + jobject value = POPA(); + jint fieldref_index = get2u (pc); pc += 2; + _Jv_Field *field = (_Jv_Field*) pool_data[fieldref_index]; + *(jobject*) (field->u.addr) = value; + } + goto next_insn; + + case op_invokespecial: + { + int index = get2u (pc); pc += 2; + + rmeth = (_Jv_ResolvedMethod*) + _Jv_ResolvePoolEntry (defining_class, index); + + sp -= rmeth->stack_item_count; + + NULLCHECK(sp[0]); + + fun = (void (*) (...))rmeth->method->ncode; + } + goto perform_invoke; + + case op_invokestatic: + { + int index = get2u (pc); pc += 2; + + rmeth = (_Jv_ResolvedMethod*) + _Jv_ResolvePoolEntry (defining_class, index); + + sp -= rmeth->stack_item_count; + + _Jv_InitClass (rmeth->klass); + fun = (void (*) (...))rmeth->method->ncode; + } + goto perform_invoke; + + case op_invokeinterface: + { + int index = get2u (pc); pc += 2; + + // invokeinterface has two unused bytes... + pc += 2; + + rmeth = (_Jv_ResolvedMethod*) + _Jv_ResolvePoolEntry (defining_class, index); + + sp -= rmeth->stack_item_count; + NULLCHECK(sp[0]); + + jobject rcv = (jobject)sp[0]; + + fun = (void (*) (...)) + _Jv_LookupInterfaceMethod (rcv->getClass (), + rmeth->method->name, + rmeth->method->signature); + } + goto perform_invoke; + + + case op_new: + { + int index = get2u (pc); pc += 2; + jclass klass = (jclass) _Jv_ResolvePoolEntry (defining_class, + index); + _Jv_InitClass (klass); + jobject res = _Jv_AllocObject (klass, klass->size_in_bytes); + PUSHA (res); + } + goto next_insn; + + case op_newarray: + { + int atype = get1u (pc++); + int size = POPI(); + jobject result = _Jv_NewArray (atype, size); + PUSHA (result); + } + goto next_insn; + + case op_anewarray: + { + int index = get2u (pc); pc += 2; + jclass klass = (jclass) _Jv_ResolvePoolEntry (defining_class, index); + int size = POPI(); + _Jv_InitClass (klass); + jobject result = _Jv_NewObjectArray (size, klass, 0); + PUSHA (result); + } + goto next_insn; + + case op_arraylength: + { + __JArray *arr = (__JArray*)POPA(); + PUSHI (arr->length); + } + goto next_insn; + + case op_athrow: + { + jobject value = POPA(); + TIME_SUSPEND; + JvThrow (value); + } + goto next_insn; + + case op_checkcast: + { + jobject value = POPA(); + jint index = get2u (pc); pc += 2; + jclass to = (jclass)_Jv_ResolvePoolEntry (defining_class, + index); + + if (value != NULL && ! to->isInstance (value)) + { + TIME_SUSPEND; + JvThrow (new java::lang::ClassCastException + (to->getName())); + } + + PUSHA (value); + } + goto next_insn; + + case op_instanceof: + { + jobject value = POPA(); + jint index = get2u (pc); pc += 2; + jclass to = (jclass)_Jv_ResolvePoolEntry (defining_class, + index); + PUSHI (to->isInstance (value)); + } + goto next_insn; + + case op_monitorenter: + { + jobject value = POPA(); + NULLCHECK(value); + _Jv_MonitorEnter (value); + } + goto next_insn; + + case op_monitorexit: + { + jobject value = POPA(); + NULLCHECK(value); + _Jv_MonitorExit (value); + } + goto next_insn; + + case op_ifnull: + { + unsigned char* base_pc = pc-1; + jint offset = get2s (pc); pc += 2; + jobject val = POPA(); + if (val == NULL) + pc = base_pc+offset; + } + goto next_insn; + + case op_ifnonnull: + { + unsigned char* base_pc = pc-1; + jint offset = get2s (pc); pc += 2; + jobject val = POPA(); + if (val != NULL) + pc = base_pc+offset; + } + goto next_insn; + + case op_wide: + { + jint the_mod_op = get1u (pc++); + jint wide = get2u (pc); pc += 2; + + switch (the_mod_op) + { + case op_istore: + STOREI (wide); + goto next_insn; + + case op_fstore: + STOREF (wide); + goto next_insn; + + case op_astore: + STOREA (wide); + goto next_insn; + + case op_lload: + LOADL (wide); + goto next_insn; + + case op_dload: + LOADD (wide); + goto next_insn; + + case op_iload: + LOADI (wide); + goto next_insn; + + case op_aload: + LOADA (wide); + goto next_insn; + + case op_lstore: + STOREL (wide); + goto next_insn; + + case op_dstore: + STORED (wide); + goto next_insn; + + case op_ret: + pc = (unsigned char*) PEEKA (wide); + goto next_insn; + + case op_iinc: + { + jint amount = get2s (pc); pc += 2; + jint value = PEEKI (wide); + POKEI (wide, value+amount); + } + goto next_insn; + + default: + throw_internal_error ("illegal bytecode modified by wide"); + } + + } + + case op_multianewarray: + { + int kind_index = get2u (pc); pc += 2; + int dim = get1u (pc); pc += 1; + + jclass type = (jclass) _Jv_ResolvePoolEntry (defining_class, + kind_index); + _Jv_InitClass (type); + jint *sizes = (jint*) alloca (sizeof (jint)*dim); + + for (int i = dim - 1; i >= 0; i--) + { + sizes[i] = POPI (); + } + + jobject res = _Jv_NewMultiArray (type,dim, sizes); + + PUSHA (res); + } + goto next_insn; + + case op_goto_w: + { + unsigned char* base_pc = pc-1; + int offset = get4 (pc); pc += 4; + pc = base_pc+offset; + } + goto next_insn; + + case op_jsr_w: + { + unsigned char* base_pc = pc-1; + int offset = get4 (pc); pc += 4; + PUSHA((jobject)pc); + pc = base_pc+offset; + } + goto next_insn; + + default: + throw_internal_error ("opcode not implemented"); + + } + goto next_insn; +} + + +static void +throw_internal_error (char *msg) +{ + JvThrow (new java::lang::InternalError (JvNewStringLatin1 (msg))); +} + +static void +throw_incompatible_class_change_error (jstring msg) +{ + JvThrow (new java::lang::IncompatibleClassChangeError (msg)); +} + +#if !HANDLE_SEGV +static java::lang::NullPointerException *null_pointer_exc; +static void +throw_null_pointer_exception () +{ + if (null_pointer_exc == NULL) + null_pointer_exc = new java::lang::NullPointerException; + + JvThrow (null_pointer_exc); +} +#endif + +#if !HANDLE_FPE +static java::lang::ArithmeticException *arithmetic_exc; +static void +throw_arithmetic_exception () +{ + if (arithmetic_exc == NULL) + arithmetic_exc = new java::lang::ArithmeticException + (JvNewStringLatin1 ("/ by zero")); + + JvThrow (arithmetic_exc); +} +#endif + +void +jvdump(jobject o) +{ + _Jv_InterpMethod::dump_object(o); +} + +/* FIXME: This is not finished! */ +void +_Jv_InterpMethod::dump_object(jobject o) +{ + java::io::PrintStream *out = java::lang::System::out; + + if (o == NULL) + { + out->println (JvNewStringLatin1 ("<null>")); + return; + } + + jclass klass = o->getClass (); + + out->print (klass->getName ()); + out->print (JvNewStringLatin1 ("@0x")); + out->print (java::lang::Integer::toHexString ((jint)o)); + out->print (JvNewStringLatin1 ("{")); +#if 0 + while (klass && klass != &ObjectClass) + { + _Jv_Field *fields = klass->fields; + int max = klass->field_count; + + for (int i = 0; i < max; ++i) + { + out->print (_Jv_NewStringUTF (field->name->data)); + out->print (JvNewStringLatin1 ("=")); + + if (JvFieldIsRef (field)) + { + if (field->flags & STATIC) + out->print (JvGetSt) + } + field = field->getNextInstanceField (); + + if (i+1 < max && klass->getSuperclass () != null) + out->print (JvNewStringLatin1 ("; ")); + } + + klass = klass->getSuperclass(); + } +#endif + out->print (JvNewStringLatin1 ("}\n")); + +} + +#endif // INTERPRETER |