You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ge...@apache.org on 2005/10/05 04:20:10 UTC
svn commit: r294974 [15/25] - in
/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm: ./ jchevm/
jchevm/doc/ jchevm/etc/ jchevm/include/ jchevm/java/ jchevm/java/org/
jchevm/java/org/dellroad/ jchevm/java/org/dellroad/jc/
jchevm/java/org/dellroad...
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/interp.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/interp.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/interp.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/interp.c Tue Oct 4 19:19:16 2005
@@ -0,0 +1,1794 @@
+
+/*
+ * Copyright 2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Id: interp.c,v 1.7 2005/07/10 21:03:54 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/* Internal functions */
+static jint _jc_interp(_jc_env *env, _jc_method *const method,
+ _jc_object *this, _jc_word *args);
+static int _jc_lookup_compare(const void *v1, const void *v2);
+static void _jc_vinterp(_jc_env *env, va_list args);
+static void _jc_vinterp_native(_jc_env *env, va_list args);
+
+/*
+ * Macros used in _jc_interp()
+ */
+#ifndef NDEBUG
+
+#define JUMP(_pc) \
+ do { \
+ pc = (_pc); \
+ _JC_ASSERT(sp >= state.locals + code->max_locals); \
+ _JC_ASSERT(sp <= state.locals \
+ + code->max_locals + code->max_stack); \
+ _JC_ASSERT(pc >= 0 && pc < code->num_insns); \
+ _JC_ASSERT(actions[code->opcodes[pc]] != NULL); \
+ _JC_ASSERT(ticker > 0); \
+ if (--ticker == 0) \
+ goto periodic_check; \
+ goto *actions[code->opcodes[pc]]; \
+ } while (0)
+
+#define NEXT() JUMP(pc + 1)
+
+#else /* !NDEBUG */
+
+#define JUMP(_pc) \
+ do { \
+ pc = (_pc); \
+ if (--ticker == 0) \
+ goto periodic_check; \
+ goto *actions[code->opcodes[pc]]; \
+ } while (0)
+
+#define NEXT() \
+ do { \
+ goto *actions[code->opcodes[++pc]]; \
+ } while (0)
+
+#endif /* !NDEBUG */
+
+#define STACKI(i) (*(jint *)(sp + (i)))
+#define STACKF(i) (*(jfloat *)(sp + (i)))
+#define STACKJ(i) (*(jlong *)(sp + (i)))
+#define STACKD(i) (*(jdouble *)(sp + (i)))
+#define STACKL(i) (*(_jc_object **)(sp + (i)))
+#define LOCALI(i) (*(jint *)(state.locals + i))
+#define LOCALF(i) (*(jfloat *)(state.locals + i))
+#define LOCALJ(i) (*(jlong *)(state.locals + i))
+#define LOCALD(i) (*(jdouble *)(state.locals + i))
+#define LOCALL(i) (*(_jc_object **)(state.locals + i))
+#define PUSHI(v) do { STACKI(0) = (v); sp++; } while (0)
+#define PUSHF(v) do { STACKF(0) = (v); sp++; } while (0)
+#define PUSHJ(v) do { STACKJ(0) = (v); sp += 2; } while (0)
+#define PUSHD(v) do { STACKD(0) = (v); sp += 2; } while (0)
+#define PUSHL(v) do { STACKL(0) = (v); sp++; } while (0)
+#define POP(i) (sp -= (i))
+#define POP2(i) (sp -= 2 * (i))
+
+#define INFO(f) (code->info[pc].f)
+
+#define ARRAYCHECK(array, i) \
+ do { \
+ _jc_array *const _array = (_jc_array *)(array); \
+ jint _i = (i); \
+ \
+ if (_array == NULL) \
+ goto null_pointer_exception; \
+ if (_i < 0 || _i >= _array->length) { \
+ _jc_post_exception_msg(env, \
+ _JC_ArrayIndexOutOfBoundsException, "%d", _i); \
+ goto exception; \
+ } \
+ } while (0)
+#define _JC_INTERP_PRIM_ELEM(type, array, i) \
+ (((_jc_ ## type ## _array *)(array))->elems[(i)])
+#define _JC_INTERP_REF_ELEM(array, i) \
+ (((_jc_object_array *)(array))->elems[~(i)])
+
+#define PERIODIC_CHECK_TICKS 32
+
+/*
+ * Java interpreter. The "args" must contain two elements for long/double.
+ *
+ * If successful, return value is stored in env->retval and JNI_OK returned.
+ * Otherwise, an exception is posted and JNI_ERR is returned.
+ */
+static jint
+_jc_interp(_jc_env *const env, _jc_method *const method,
+ _jc_object *const this, _jc_word *args)
+{
+#define ACTION(name) [_JC_ ## name]= &&do_ ## name
+ static const void *const actions[0x100] = {
+ ACTION(aaload),
+ ACTION(aastore),
+ ACTION(aload),
+ ACTION(anewarray),
+ ACTION(areturn),
+ ACTION(arraylength),
+ ACTION(astore),
+ ACTION(athrow),
+ ACTION(baload),
+ ACTION(bastore),
+ ACTION(caload),
+ ACTION(castore),
+ ACTION(checkcast),
+ ACTION(d2f),
+ ACTION(d2i),
+ ACTION(d2l),
+ ACTION(dadd),
+ ACTION(daload),
+ ACTION(dastore),
+ ACTION(dcmpg),
+ ACTION(dcmpl),
+ ACTION(ddiv),
+ ACTION(dload),
+ ACTION(dmul),
+ ACTION(dneg),
+ ACTION(drem),
+ ACTION(dreturn),
+ ACTION(dstore),
+ ACTION(dsub),
+ ACTION(dup),
+ ACTION(dup_x1),
+ ACTION(dup_x2),
+ ACTION(dup2),
+ ACTION(dup2_x1),
+ ACTION(dup2_x2),
+ ACTION(f2d),
+ ACTION(f2i),
+ ACTION(f2l),
+ ACTION(fadd),
+ ACTION(faload),
+ ACTION(fastore),
+ ACTION(fcmpg),
+ ACTION(fcmpl),
+ ACTION(fdiv),
+ ACTION(fload),
+ ACTION(fmul),
+ ACTION(fneg),
+ ACTION(frem),
+ ACTION(freturn),
+ ACTION(fstore),
+ ACTION(fsub),
+ ACTION(getfield),
+ ACTION(getstatic),
+ ACTION(goto),
+ ACTION(i2b),
+ ACTION(i2c),
+ ACTION(i2d),
+ ACTION(i2f),
+ ACTION(i2l),
+ ACTION(i2s),
+ ACTION(iadd),
+ ACTION(iaload),
+ ACTION(iand),
+ ACTION(iastore),
+ ACTION(idiv),
+ ACTION(if_acmpeq),
+ ACTION(if_acmpne),
+ ACTION(if_icmpeq),
+ ACTION(if_icmpne),
+ ACTION(if_icmplt),
+ ACTION(if_icmpge),
+ ACTION(if_icmpgt),
+ ACTION(if_icmple),
+ ACTION(ifeq),
+ ACTION(ifne),
+ ACTION(iflt),
+ ACTION(ifge),
+ ACTION(ifgt),
+ ACTION(ifle),
+ ACTION(ifnonnull),
+ ACTION(ifnull),
+ ACTION(iinc),
+ ACTION(iload),
+ ACTION(imul),
+ ACTION(ineg),
+ ACTION(instanceof),
+ ACTION(invokeinterface),
+ ACTION(invokespecial),
+ ACTION(invokestatic),
+ ACTION(invokevirtual),
+ ACTION(ior),
+ ACTION(irem),
+ ACTION(ireturn),
+ ACTION(ishl),
+ ACTION(ishr),
+ ACTION(istore),
+ ACTION(isub),
+ ACTION(iushr),
+ ACTION(ixor),
+ ACTION(jsr),
+ ACTION(l2d),
+ ACTION(l2f),
+ ACTION(l2i),
+ ACTION(ladd),
+ ACTION(laload),
+ ACTION(land),
+ ACTION(lastore),
+ ACTION(lcmp),
+ ACTION(ldc),
+ ACTION(ldc_string),
+ ACTION(ldc2_w),
+ ACTION(ldiv),
+ ACTION(lload),
+ ACTION(lmul),
+ ACTION(lneg),
+ ACTION(lookupswitch),
+ ACTION(lor),
+ ACTION(lrem),
+ ACTION(lreturn),
+ ACTION(lshl),
+ ACTION(lshr),
+ ACTION(lstore),
+ ACTION(lsub),
+ ACTION(lushr),
+ ACTION(lxor),
+ ACTION(monitorenter),
+ ACTION(monitorexit),
+ ACTION(multianewarray),
+ ACTION(new),
+ ACTION(newarray),
+ ACTION(nop),
+ ACTION(pop),
+ ACTION(pop2),
+ ACTION(putfield),
+ ACTION(putstatic),
+ ACTION(ret),
+ ACTION(return),
+ ACTION(saload),
+ ACTION(sastore),
+ ACTION(swap),
+ ACTION(tableswitch),
+ };
+ _jc_method_code *const code = &method->u.code;
+ int ticker = PERIODIC_CHECK_TICKS;
+ _jc_interp_stack state;
+ _jc_object *lock = NULL;
+ _jc_word *sp;
+ int pc = 0;
+
+ /* Stack overflow check */
+#if _JC_DOWNWARD_STACK
+ if ((char *)&env < env->stack_limit)
+#else
+ if ((char *)&env > env->stack_limit)
+#endif
+ {
+ _jc_post_exception(env, _JC_StackOverflowError);
+ return JNI_ERR;
+ }
+
+ /* Is method abstract? */
+ if (_JC_ACC_TEST(method, ABSTRACT)) {
+ _jc_post_exception_msg(env, _JC_AbstractMethodError,
+ "%s.%s%s", method->class->name, method->name,
+ method->signature);
+ return JNI_ERR;
+ }
+
+ /* Sanity check */
+ _JC_ASSERT((this == NULL) == _JC_ACC_TEST(method, STATIC));
+ _JC_ASSERT(!_JC_ACC_TEST(method->class, INTERFACE)
+ || strcmp(method->name, "<clinit>") == 0);
+ _JC_ASSERT(_JC_FLG_TEST(method->class, RESOLVED));
+ _JC_ASSERT(_JC_ACC_TEST(method, INTERP));
+ _JC_ASSERT(!_JC_ACC_TEST(method, NATIVE));
+
+ /* Push Java stack frame */
+ memset(&state, 0, sizeof(state));
+ state.jstack.interp = JNI_TRUE;
+ state.jstack.next = env->java_stack;
+ state.method = method;
+ state.pcp = &pc;
+ env->java_stack = &state.jstack;
+
+ /* Allocate combined space for locals and stack */
+ if ((state.locals = _JC_STACK_ALLOC(env,
+ (code->max_locals + code->max_stack)
+ * sizeof(*state.locals))) == NULL) {
+ _jc_post_exception_info(env);
+ goto exception;
+ }
+ sp = &state.locals[code->max_locals];
+
+ /* Sanity check */
+ _JC_ASSERT(code->opcodes != NULL);
+ _JC_ASSERT(code->num_insns > 0);
+
+ /* Copy method parameters into local variables */
+ if (!_JC_ACC_TEST(method, STATIC)) {
+ state.locals[0] = (_jc_word)this;
+ memcpy(state.locals + 1, args,
+ code->num_params2 * sizeof(*args));
+ } else
+ memcpy(state.locals, args, code->num_params2 * sizeof(*args));
+
+ /* Synchronize */
+ if (_JC_ACC_TEST(method, SYNCHRONIZED)) {
+ lock = _JC_ACC_TEST(method, STATIC) ?
+ method->class->instance : this;
+ if (_jc_lock_object(env, lock) != JNI_OK) {
+ lock = NULL;
+ goto exception;
+ }
+ }
+
+ /* Start */
+ JUMP(0);
+
+do_aaload:
+ {
+ _jc_object_array *array;
+ jint index;
+
+ POP(2);
+ array = (_jc_object_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ _JC_ASSERT(_JC_LW_TEST(array->lockword, ARRAY)
+ && _JC_LW_EXTRACT(array->lockword, TYPE) == _JC_TYPE_REFERENCE);
+ PUSHL(array->elems[~index]);
+ NEXT();
+ }
+do_aastore:
+ {
+ _jc_object_array *array;
+ _jc_object *obj;
+ jint index;
+
+ POP(3);
+ array = (_jc_object_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ obj = STACKL(2);
+ if (obj != NULL) {
+ switch (_jc_assignable_from(env, obj->type,
+ array->type->u.array.element_type)) {
+ case 1:
+ break;
+ case 0:
+ _jc_post_exception_msg(env, _JC_ArrayStoreException,
+ "can't store object of type `%s' into array"
+ " of `%s'", obj->type->name,
+ array->type->u.array.element_type->name);
+ /* FALLTHROUGH */
+ case -1:
+ goto exception;
+ }
+ }
+ array->elems[~index] = obj;
+ NEXT();
+ }
+do_aload:
+ PUSHL(LOCALL(INFO(local)));
+ NEXT();
+do_anewarray:
+ {
+ _jc_array *array;
+ jint length;
+
+ POP(1);
+ length = STACKI(0);
+ if ((array = _jc_new_array(env, INFO(type), length)) == NULL)
+ goto exception;
+ PUSHL((_jc_object *)array);
+ NEXT();
+ }
+do_areturn:
+ POP(1);
+ env->retval.l = STACKL(0);
+ goto done;
+do_arraylength:
+ {
+ _jc_array *array;
+
+ POP(1);
+ array = (_jc_array *)STACKL(0);
+ if (array == NULL)
+ goto null_pointer_exception;
+ PUSHI(array->length);
+ NEXT();
+ }
+do_astore:
+ POP(1);
+ LOCALL(INFO(local)) = STACKL(0);
+ NEXT();
+do_athrow:
+ POP(1);
+ if (STACKL(0) == NULL)
+ goto null_pointer_exception;
+ _jc_post_exception_object(env, STACKL(0));
+ goto exception;
+do_baload:
+ {
+ _jc_array *array;
+ jint index;
+ int ptype;
+
+ POP(2);
+ array = (_jc_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ ptype = _JC_LW_EXTRACT(array->lockword, TYPE);
+ _JC_ASSERT(ptype == _JC_TYPE_BOOLEAN || ptype == _JC_TYPE_BYTE);
+ if (ptype == _JC_TYPE_BOOLEAN)
+ PUSHI(((_jc_boolean_array *)array)->elems[index]);
+ else
+ PUSHI(((_jc_byte_array *)array)->elems[index]);
+ NEXT();
+ }
+do_bastore:
+ {
+ _jc_array *array;
+ jint index;
+ int ptype;
+
+ POP(3);
+ array = (_jc_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ ptype = _JC_LW_EXTRACT(array->lockword, TYPE);
+ _JC_ASSERT(ptype == _JC_TYPE_BOOLEAN || ptype == _JC_TYPE_BYTE);
+ if (ptype == _JC_TYPE_BOOLEAN)
+ ((_jc_boolean_array *)array)->elems[index] = STACKI(2) & 0x1;
+ else
+ ((_jc_byte_array *)array)->elems[index] = STACKI(2) & 0xff;
+ NEXT();
+ }
+do_caload:
+ {
+ _jc_char_array *array;
+ jint index;
+
+ POP(2);
+ array = (_jc_char_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ PUSHI(array->elems[index]);
+ NEXT();
+ }
+do_castore:
+ {
+ _jc_char_array *array;
+ jint index;
+
+ POP(3);
+ array = (_jc_char_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ array->elems[index] = STACKI(2) & 0xffff;
+ NEXT();
+ }
+do_checkcast:
+ {
+ _jc_object *const obj = STACKL(-1);
+
+ if (obj != NULL) {
+ _jc_type *const type = INFO(type);
+
+ switch (_jc_instance_of(env, obj, type)) {
+ case 1:
+ break;
+ case 0:
+ _jc_post_exception_msg(env, _JC_ClassCastException,
+ "can't cast `%s' to `%s'", obj->type->name,
+ type->name);
+ /* FALLTHROUGH */
+ case -1:
+ goto exception;
+ default:
+ _JC_ASSERT(JNI_FALSE);
+ }
+ }
+ NEXT();
+ }
+do_d2f:
+ POP2(1);
+ PUSHF(STACKD(0));
+ NEXT();
+do_d2i:
+ POP2(1);
+ PUSHI(_JC_CAST_FLT2INT(env, jdouble, jint, STACKD(0)));
+ NEXT();
+do_d2l:
+ POP2(1);
+ PUSHJ(_JC_CAST_FLT2INT(env, jdouble, jlong, STACKD(0)));
+ NEXT();
+do_dadd:
+ POP2(2);
+ PUSHD(STACKD(0) + STACKD(2));
+ NEXT();
+do_daload:
+ {
+ _jc_double_array *array;
+ jint index;
+
+ POP(2);
+ array = (_jc_double_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ PUSHD(array->elems[index]);
+ NEXT();
+ }
+do_dastore:
+ {
+ _jc_double_array *array;
+ jint index;
+
+ POP(4);
+ array = (_jc_double_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ array->elems[index] = STACKD(2);
+ NEXT();
+ }
+do_dcmpg:
+ POP2(2);
+ PUSHI(_JC_DCMPG(STACKD(0), STACKD(2)));
+ NEXT();
+do_dcmpl:
+ POP2(2);
+ PUSHI(_JC_DCMPL(STACKD(0), STACKD(2)));
+ NEXT();
+do_ddiv:
+ POP2(2);
+ PUSHD(STACKD(0) / STACKD(2));
+ NEXT();
+do_dload:
+ PUSHD(LOCALD(INFO(local)));
+ NEXT();
+do_dmul:
+ POP2(2);
+ PUSHD(STACKD(0) * STACKD(2));
+ NEXT();
+do_dneg:
+ POP2(1);
+ PUSHD(-STACKD(0));
+ NEXT();
+do_drem:
+ POP2(2);
+ PUSHD(fmod(STACKD(0), STACKD(2)));
+ NEXT();
+do_dreturn:
+ POP2(1);
+ env->retval.d = STACKD(0);
+ goto done;
+do_dstore:
+ POP2(1);
+ LOCALD(INFO(local)) = STACKD(0);
+ NEXT();
+do_dsub:
+ POP2(2);
+ PUSHD(STACKD(0) - STACKD(2));
+ NEXT();
+do_dup:
+ STACKI(0) = STACKI(-1);
+ POP(-1);
+ NEXT();
+do_dup_x1:
+ STACKI(0) = STACKI(-1);
+ STACKI(-1) = STACKI(-2);
+ STACKI(-2) = STACKI(0);
+ POP(-1);
+ NEXT();
+do_dup_x2:
+ STACKI(0) = STACKI(-1);
+ STACKI(-1) = STACKI(-2);
+ STACKI(-2) = STACKI(-3);
+ STACKI(-3) = STACKI(0);
+ POP(-1);
+ NEXT();
+do_dup2:
+ STACKI(1) = STACKI(-1);
+ STACKI(0) = STACKI(-2);
+ POP(-2);
+ NEXT();
+do_dup2_x1:
+ STACKI(1) = STACKI(-1);
+ STACKI(0) = STACKI(-2);
+ STACKI(-1) = STACKI(-3);
+ STACKI(-2) = STACKI(1);
+ STACKI(-3) = STACKI(0);
+ POP(-2);
+ NEXT();
+do_dup2_x2:
+ STACKI(1) = STACKI(-1);
+ STACKI(0) = STACKI(-2);
+ STACKI(-1) = STACKI(-3);
+ STACKI(-2) = STACKI(-4);
+ STACKI(-3) = STACKI(1);
+ STACKI(-4) = STACKI(0);
+ POP(-2);
+ NEXT();
+do_f2d:
+ POP(1);
+ PUSHD(STACKF(0));
+ NEXT();
+do_f2i:
+ POP(1);
+ PUSHI(_JC_CAST_FLT2INT(env, jfloat, jint, STACKF(0)));
+ NEXT();
+do_f2l:
+ POP(1);
+ PUSHJ(_JC_CAST_FLT2INT(env, jfloat, jlong, STACKF(0)));
+ NEXT();
+do_fadd:
+ POP(2);
+ PUSHF(STACKF(0) + STACKF(1));
+ NEXT();
+do_faload:
+ {
+ _jc_float_array *array;
+ jint index;
+
+ POP(2);
+ array = (_jc_float_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ PUSHF(array->elems[index]);
+ NEXT();
+ }
+do_fastore:
+ {
+ _jc_float_array *array;
+ jint index;
+
+ POP(3);
+ array = (_jc_float_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ array->elems[index] = STACKF(2);
+ NEXT();
+ }
+do_fcmpg:
+ POP(2);
+ PUSHI(_JC_FCMPG(STACKF(0), STACKF(1)));
+ NEXT();
+do_fcmpl:
+ POP(2);
+ PUSHI(_JC_FCMPL(STACKF(0), STACKF(1)));
+ NEXT();
+do_fdiv:
+ POP(2);
+ PUSHF(STACKF(0) / STACKF(1));
+ NEXT();
+do_fload:
+ PUSHF(LOCALF(INFO(local)));
+ NEXT();
+do_fmul:
+ POP(2);
+ PUSHF(STACKF(0) * STACKF(1));
+ NEXT();
+do_fneg:
+ POP(1);
+ PUSHF(-STACKF(0));
+ NEXT();
+do_frem:
+ POP(2);
+ PUSHF(fmod(STACKF(0), STACKF(1)));
+ NEXT();
+do_freturn:
+ POP(1);
+ env->retval.f = STACKF(0);
+ goto done;
+do_fstore:
+ POP(1);
+ LOCALF(INFO(local)) = STACKF(0);
+ NEXT();
+do_fsub:
+ POP(2);
+ PUSHF(STACKF(0) - STACKF(1));
+ NEXT();
+do_getfield:
+ {
+ _jc_field *const field = INFO(field);
+ _jc_object *obj;
+ void *data;
+
+ POP(1);
+ obj = STACKL(0);
+
+ if (obj == NULL)
+ goto null_pointer_exception;
+ data = (char *)obj + field->offset;
+ switch (field->type->flags & _JC_TYPE_MASK) {
+ case _JC_TYPE_BOOLEAN:
+ PUSHI(*(jboolean *)data);
+ break;
+ case _JC_TYPE_BYTE:
+ PUSHI(*(jbyte *)data);
+ break;
+ case _JC_TYPE_CHAR:
+ PUSHI(*(jchar *)data);
+ break;
+ case _JC_TYPE_SHORT:
+ PUSHI(*(jshort *)data);
+ break;
+ case _JC_TYPE_INT:
+ PUSHI(*(jint *)data);
+ break;
+ case _JC_TYPE_FLOAT:
+ PUSHF(*(jfloat *)data);
+ break;
+ case _JC_TYPE_LONG:
+ PUSHJ(*(jlong *)data);
+ break;
+ case _JC_TYPE_DOUBLE:
+ PUSHD(*(jdouble *)data);
+ break;
+ case _JC_TYPE_REFERENCE:
+ PUSHL(*(_jc_object **)data);
+ break;
+ default:
+ _JC_ASSERT(JNI_FALSE);
+ break;
+ }
+ NEXT();
+ }
+do_getstatic:
+ {
+ _jc_field *const field = INFO(field);
+ void *data;
+
+ /* Initialize field's class */
+ if (!_JC_FLG_TEST(field->class, INITIALIZED)) {
+ if (_jc_initialize_type(env, field->class) != JNI_OK)
+ goto exception;
+ }
+
+ /* Get field */
+ data = (char *)field->class->u.nonarray.class_fields + field->offset;
+ switch (field->type->flags & _JC_TYPE_MASK) {
+ case _JC_TYPE_BOOLEAN:
+ PUSHI(*(jboolean *)data);
+ break;
+ case _JC_TYPE_BYTE:
+ PUSHI(*(jbyte *)data);
+ break;
+ case _JC_TYPE_CHAR:
+ PUSHI(*(jchar *)data);
+ break;
+ case _JC_TYPE_SHORT:
+ PUSHI(*(jshort *)data);
+ break;
+ case _JC_TYPE_INT:
+ PUSHI(*(jint *)data);
+ break;
+ case _JC_TYPE_FLOAT:
+ PUSHF(*(jfloat *)data);
+ break;
+ case _JC_TYPE_LONG:
+ PUSHJ(*(jlong *)data);
+ break;
+ case _JC_TYPE_DOUBLE:
+ PUSHD(*(jdouble *)data);
+ break;
+ case _JC_TYPE_REFERENCE:
+ PUSHL(*(_jc_object **)data);
+ break;
+ default:
+ _JC_ASSERT(JNI_FALSE);
+ break;
+ }
+ NEXT();
+ }
+do_goto:
+ JUMP(INFO(target));
+do_i2b:
+ POP(1);
+ PUSHI((jbyte)STACKI(0));
+ NEXT();
+do_i2c:
+ POP(1);
+ PUSHI((jchar)STACKI(0));
+ NEXT();
+do_i2d:
+ POP(1);
+ PUSHD(STACKI(0));
+ NEXT();
+do_i2f:
+ POP(1);
+ PUSHF(STACKI(0));
+ NEXT();
+do_i2l:
+ POP(1);
+ PUSHJ(STACKI(0));
+ NEXT();
+do_i2s:
+ POP(1);
+ PUSHI((jshort)STACKI(0));
+ NEXT();
+do_iadd:
+ POP(2);
+ PUSHI(STACKI(0) + STACKI(1));
+ NEXT();
+do_iaload:
+ {
+ _jc_int_array *array;
+ jint index;
+
+ POP(2);
+ array = (_jc_int_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ PUSHI(array->elems[index]);
+ NEXT();
+ }
+do_iand:
+ POP(2);
+ PUSHI(STACKI(0) & STACKI(1));
+ NEXT();
+do_iastore:
+ {
+ _jc_int_array *array;
+ jint index;
+
+ POP(3);
+ array = (_jc_int_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ array->elems[index] = STACKI(2);
+ NEXT();
+ }
+do_idiv:
+ POP(2);
+ if (STACKI(1) == 0)
+ goto arithmetic_exception;
+ PUSHI(STACKI(0) / STACKI(1));
+ NEXT();
+do_if_acmpeq:
+ POP(2);
+ JUMP(STACKL(0) == STACKL(1) ? INFO(target) : pc + 1);
+do_if_acmpne:
+ POP(2);
+ JUMP(STACKL(0) != STACKL(1) ? INFO(target) : pc + 1);
+do_if_icmpeq:
+ POP(2);
+ JUMP(STACKI(0) == STACKI(1) ? INFO(target) : pc + 1);
+do_if_icmpne:
+ POP(2);
+ JUMP(STACKI(0) != STACKI(1) ? INFO(target) : pc + 1);
+do_if_icmplt:
+ POP(2);
+ JUMP(STACKI(0) < STACKI(1) ? INFO(target) : pc + 1);
+do_if_icmpge:
+ POP(2);
+ JUMP(STACKI(0) >= STACKI(1) ? INFO(target) : pc + 1);
+do_if_icmpgt:
+ POP(2);
+ JUMP(STACKI(0) > STACKI(1) ? INFO(target) : pc + 1);
+do_if_icmple:
+ POP(2);
+ JUMP(STACKI(0) <= STACKI(1) ? INFO(target) : pc + 1);
+do_ifeq:
+ POP(1);
+ JUMP(STACKI(0) == 0 ? INFO(target) : pc + 1);
+do_ifne:
+ POP(1);
+ JUMP(STACKI(0) != 0 ? INFO(target) : pc + 1);
+do_iflt:
+ POP(1);
+ JUMP(STACKI(0) < 0 ? INFO(target) : pc + 1);
+do_ifge:
+ POP(1);
+ JUMP(STACKI(0) >= 0 ? INFO(target) : pc + 1);
+do_ifgt:
+ POP(1);
+ JUMP(STACKI(0) > 0 ? INFO(target) : pc + 1);
+do_ifle:
+ POP(1);
+ JUMP(STACKI(0) <= 0 ? INFO(target) : pc + 1);
+do_ifnonnull:
+ POP(1);
+ JUMP(STACKL(0) != NULL ? INFO(target) : pc + 1);
+do_ifnull:
+ POP(1);
+ JUMP(STACKL(0) == NULL ? INFO(target) : pc + 1);
+do_iinc:
+ LOCALI(INFO(iinc).index) += INFO(iinc).value;
+ NEXT();
+do_iload:
+ PUSHI(LOCALI(INFO(local)));
+ NEXT();
+do_imul:
+ POP(2);
+ PUSHI(STACKI(0) * STACKI(1));
+ NEXT();
+do_ineg:
+ POP(1);
+ PUSHI(-STACKI(0));
+ NEXT();
+do_instanceof:
+ POP(1);
+ switch (_jc_instance_of(env, STACKL(0), INFO(type))) {
+ case 1:
+ PUSHI(1);
+ break;
+ case 0:
+ PUSHI(0);
+ break;
+ case -1:
+ goto exception;
+ default:
+ _JC_ASSERT(JNI_FALSE);
+ }
+ NEXT();
+do_invokespecial:
+do_invokevirtual:
+do_invokestatic:
+do_invokeinterface:
+ {
+ _jc_method *imethod = INFO(method);
+ _jc_word *params;
+ _jc_object *obj;
+ int ndoubles;
+ jint status;
+ int i;
+
+ /* Count number of long/double parameters */
+ ndoubles = 0;
+ for (i = 0; i < imethod->num_parameters; i++) {
+ if (_jc_dword_type[imethod->param_ptypes[i]])
+ ndoubles++;
+ }
+
+ /* Pop the stack and check for null */
+ if (code->opcodes[pc] == _JC_invokestatic) {
+ POP(imethod->num_parameters + ndoubles);
+ obj = NULL;
+ } else {
+ POP(imethod->num_parameters + ndoubles + 1);
+ if ((obj = STACKL(0)) == NULL)
+ goto null_pointer_exception;
+ }
+
+ /* Sanity check */
+ _JC_ASSERT((code->opcodes[pc] == _JC_invokeinterface)
+ == _JC_ACC_TEST(imethod->class, INTERFACE));
+
+ /* Do method lookup */
+ switch (code->opcodes[pc]) {
+ case _JC_invokeinterface:
+ {
+ const jlong sig_hash = imethod->signature_hash;
+ _jc_method *const *methodp;
+ int bucket;
+
+ /* Sanity check */
+ _JC_ASSERT(_JC_ACC_TEST(imethod->class, INTERFACE));
+
+ /* Verify object implements the interface */
+ switch (_jc_instance_of(env, obj, imethod->class)) {
+ case 0:
+ _jc_post_exception_msg(env,
+ _JC_IncompatibleClassChangeError,
+ "`%s' does not implement interface `%s'",
+ obj->type->name, imethod->class->name);
+ goto exception;
+ case 1:
+ break;
+ case -1:
+ goto exception;
+ }
+
+ /* Lookup interface method entry point */
+ _JC_ASSERT(obj->type->imethod_quick_table != NULL);
+ _JC_ASSERT(obj->type->imethod_hash_table != NULL);
+ bucket = (int)sig_hash & (_JC_IMETHOD_HASHSIZE - 1);
+ methodp = obj->type->imethod_hash_table[bucket];
+ if (methodp == NULL)
+ goto not_found;
+ while (*methodp != NULL) {
+ if ((*methodp)->signature_hash == sig_hash) {
+ imethod = *methodp;
+ break;
+ }
+ methodp++;
+ }
+ if (*methodp == NULL) {
+not_found: _jc_post_exception_msg(env, _JC_AbstractMethodError,
+ "%s.%s%s invoked from %s.%s%s on a %s",
+ imethod->class->name, imethod->name,
+ imethod->signature, method->class->name,
+ method->name, method->signature, obj->type->name);
+ goto exception;
+ }
+
+ /* Verify method is public */
+ if (!_JC_ACC_TEST(imethod, PUBLIC)) {
+ _jc_post_exception_msg(env, _JC_IllegalAccessError,
+ "%s.%s%s invoked from %s.%s%s on a %s",
+ imethod->class->name, imethod->name,
+ imethod->signature, method->class->name,
+ method->name, method->signature, obj->type->name);
+ goto exception;
+ }
+ break;
+ }
+ case _JC_invokevirtual:
+ {
+ _jc_type *vtype;
+
+ vtype = _JC_LW_TEST(obj->lockword, ARRAY) ?
+ env->vm->boot.types.Object : obj->type;
+ imethod = vtype->u.nonarray.mtable[imethod->vtable_index];
+ break;
+ }
+ case _JC_invokespecial:
+ break;
+ case _JC_invokestatic:
+ if (!_JC_FLG_TEST(imethod->class, INITIALIZED)
+ && _jc_initialize_type(env, imethod->class) != JNI_OK)
+ goto exception;
+ break;
+ default:
+ _JC_ASSERT(JNI_FALSE);
+ break;
+ }
+
+ /* Get pointer to parameters */
+ params = sp + (code->opcodes[pc] != _JC_invokestatic);
+
+ /* Invoke the method */
+ if (_JC_ACC_TEST(imethod, NATIVE))
+ status = _jc_invoke_native_method(env, imethod, JNI_TRUE, sp);
+ else if (_JC_ACC_TEST(imethod, INTERP))
+ status = _jc_interp(env, imethod, obj, params);
+ else {
+ status = _jc_invoke_jcni_a(env,
+ imethod, imethod->function, obj, params);
+ }
+
+ /* Did method throw an exception? */
+ if (status != JNI_OK)
+ goto exception;
+
+ /* Push return value, if any */
+ switch (imethod->param_ptypes[imethod->num_parameters]) {
+ case _JC_TYPE_BOOLEAN:
+ PUSHI(env->retval.z);
+ break;
+ case _JC_TYPE_BYTE:
+ PUSHI(env->retval.b);
+ break;
+ case _JC_TYPE_CHAR:
+ PUSHI(env->retval.c);
+ break;
+ case _JC_TYPE_SHORT:
+ PUSHI(env->retval.s);
+ break;
+ case _JC_TYPE_INT:
+ PUSHI(env->retval.i);
+ break;
+ case _JC_TYPE_FLOAT:
+ PUSHF(env->retval.f);
+ break;
+ case _JC_TYPE_REFERENCE:
+ PUSHL(env->retval.l);
+ break;
+ case _JC_TYPE_LONG:
+ PUSHJ(env->retval.j);
+ break;
+ case _JC_TYPE_DOUBLE:
+ PUSHD(env->retval.d);
+ break;
+ case _JC_TYPE_VOID:
+ break;
+ default:
+ _JC_ASSERT(JNI_FALSE);
+ }
+ NEXT();
+ }
+do_ior:
+ POP(2);
+ PUSHI(STACKI(0) | STACKI(1));
+ NEXT();
+do_irem:
+ POP(2);
+ if (STACKI(1) == 0)
+ goto arithmetic_exception;
+ PUSHI(STACKI(0) % STACKI(1));
+ NEXT();
+do_ireturn:
+ POP(1);
+ env->retval.i = STACKI(0);
+ goto done;
+do_ishl:
+ POP(2);
+ PUSHI(STACKI(0) << (STACKI(1) & 0x1f));
+ NEXT();
+do_ishr:
+ POP(2);
+ PUSHI(_JC_ISHR(STACKI(0), STACKI(1) & 0x1f));
+ NEXT();
+do_istore:
+ POP(1);
+ LOCALI(INFO(local)) = STACKI(0);
+ NEXT();
+do_isub:
+ POP(2);
+ PUSHI(STACKI(0) - STACKI(1));
+ NEXT();
+do_iushr:
+ POP(2);
+ PUSHI(_JC_IUSHR(STACKI(0), STACKI(1) & 0x1f));
+ NEXT();
+do_ixor:
+ POP(2);
+ PUSHI(STACKI(0) ^ STACKI(1));
+ NEXT();
+do_jsr:
+ PUSHI(pc + 1);
+ JUMP(INFO(target));
+do_l2d:
+ POP2(1);
+ PUSHD(STACKJ(0));
+ NEXT();
+do_l2f:
+ POP2(1);
+ PUSHF(STACKJ(0));
+ NEXT();
+do_l2i:
+ POP2(1);
+ PUSHI(STACKJ(0));
+ NEXT();
+do_ladd:
+ POP2(2);
+ PUSHJ(STACKJ(0) + STACKJ(2));
+ NEXT();
+do_laload:
+ {
+ _jc_long_array *array;
+ jint index;
+
+ POP(2);
+ array = (_jc_long_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ PUSHJ(array->elems[index]);
+ NEXT();
+ }
+do_land:
+ POP2(2);
+ PUSHJ(STACKJ(0) & STACKJ(2));
+ NEXT();
+do_lastore:
+ {
+ _jc_long_array *array;
+ jint index;
+
+ POP(4);
+ array = (_jc_long_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ array->elems[index] = STACKJ(2);
+ NEXT();
+ }
+do_lcmp:
+ POP2(2);
+ PUSHI(_JC_LCMP(STACKJ(0), STACKJ(2)));
+ NEXT();
+do_ldc:
+ memcpy(sp, &INFO(constant), sizeof(jint));
+ POP(-1);
+ NEXT();
+do_ldc_string:
+ {
+ _jc_resolve_info rinfo;
+ _jc_object *string;
+
+ /* Create intern'd string */
+ if ((string = _jc_new_intern_string(env,
+ INFO(utf8), strlen(INFO(utf8)))) == NULL)
+ goto exception;
+
+ /* Create reference list with one reference */
+ memset(&rinfo, 0, sizeof(rinfo));
+ rinfo.loader = method->class->loader;
+ rinfo.implicit_refs = &string;
+ rinfo.num_implicit_refs = 1;
+
+ /* Add implicit reference to string from class loader */
+ if (_jc_merge_implicit_refs(env, &rinfo) != JNI_OK) {
+ _jc_post_exception_info(env);
+ goto exception;
+ }
+
+ /* Update instruction */
+ INFO(constant).l = string;
+ code->opcodes[pc] = _JC_ldc;
+
+ /* Now execute it again */
+ JUMP(pc);
+ }
+do_ldc2_w:
+ memcpy(sp, &INFO(constant), 2 * sizeof(jint));
+ POP(-2);
+ NEXT();
+do_ldiv:
+ POP2(2);
+ if (STACKJ(2) == 0)
+ goto arithmetic_exception;
+ PUSHJ(STACKJ(0) / STACKJ(2));
+ NEXT();
+do_lload:
+ PUSHJ(LOCALJ(INFO(local)));
+ NEXT();
+do_lmul:
+ POP2(2);
+ PUSHJ(STACKJ(0) * STACKJ(2));
+ NEXT();
+do_lneg:
+ POP2(1);
+ PUSHJ(-STACKJ(0));
+ NEXT();
+do_lookupswitch:
+ {
+ _jc_lookupswitch *const lsw = INFO(lookupswitch);
+ _jc_lookup *entry;
+ _jc_lookup key;
+
+ POP(1);
+ key.match = STACKI(0);
+ entry = bsearch(&key, lsw->pairs, lsw->num_pairs,
+ sizeof(*lsw->pairs), _jc_lookup_compare);
+ JUMP(entry != NULL ? entry->target : lsw->default_target);
+ }
+do_lor:
+ POP2(2);
+ PUSHJ(STACKJ(0) | STACKJ(2));
+ NEXT();
+do_lrem:
+ POP2(2);
+ if (STACKJ(2) == 0)
+ goto arithmetic_exception;
+ PUSHJ(STACKJ(0) % STACKJ(2));
+ NEXT();
+do_lreturn:
+ POP2(1);
+ env->retval.j = STACKJ(0);
+ goto done;
+do_lshl:
+ POP(3);
+ PUSHJ(STACKJ(0) << (STACKI(2) & 0x3f));
+ NEXT();
+do_lshr:
+ POP(3);
+ PUSHJ(_JC_LSHR(STACKJ(0), STACKI(2)));
+ NEXT();
+do_lstore:
+ POP2(1);
+ LOCALJ(INFO(local)) = STACKJ(0);
+ NEXT();
+do_lsub:
+ POP2(2);
+ PUSHJ(STACKJ(0) - STACKJ(2));
+ NEXT();
+do_lushr:
+ POP(3);
+ PUSHJ(_JC_LUSHR(STACKJ(0), STACKI(2)));
+ NEXT();
+do_lxor:
+ POP2(2);
+ PUSHJ(STACKJ(0) ^ STACKJ(2));
+ NEXT();
+do_monitorenter:
+ POP(1);
+ if (STACKL(0) == NULL)
+ goto null_pointer_exception;
+ if (_jc_lock_object(env, STACKL(0)) != JNI_OK)
+ goto exception;
+ NEXT();
+do_monitorexit:
+ POP(1);
+ if (STACKL(0) == NULL)
+ goto null_pointer_exception;
+ if (_jc_unlock_object(env, STACKL(0)) != JNI_OK)
+ goto exception;
+ NEXT();
+do_multianewarray:
+ {
+ _jc_multianewarray *const info = &INFO(multianewarray);
+ _jc_array *array;
+ jint *sizes;
+ int i;
+
+ POP(info->dims);
+ sizes = &STACKI(0); /* overwrite popped stack */
+ for (i = 0; i < info->dims; i++)
+ sizes[i] = STACKI(i);
+ if ((array = _jc_new_multiarray(env,
+ info->type, info->dims, sizes)) == NULL)
+ goto exception;
+ PUSHL((_jc_object *)array);
+ NEXT();
+ }
+do_new:
+ {
+ _jc_object *obj;
+
+ if ((obj = _jc_new_object(env, INFO(type))) == NULL)
+ goto exception;
+ PUSHL(obj);
+ NEXT();
+ }
+do_newarray:
+ {
+ _jc_array *array;
+
+ POP(1);
+ if ((array = _jc_new_array(env, INFO(type), STACKI(0))) == NULL)
+ goto exception;
+ PUSHL((_jc_object *)array);
+ NEXT();
+ }
+do_nop:
+ NEXT();
+do_pop:
+ POP(1);
+ NEXT();
+do_pop2:
+ POP2(1);
+ NEXT();
+do_putfield:
+ {
+ _jc_field *const field = INFO(field);
+ _jc_type *const ftype = field->type;
+ const void *data;
+
+ /* Pop the stack */
+ if (_jc_dword_type[ftype->flags & _JC_TYPE_MASK])
+ POP2(1);
+ else
+ POP(1);
+ POP(1);
+
+ /* Check for null instance */
+ if (STACKL(0) == NULL)
+ goto null_pointer_exception;
+
+ /* Set the field */
+ data = (char *)STACKL(0) + field->offset;
+ switch (ftype->flags & _JC_TYPE_MASK) {
+ case _JC_TYPE_BOOLEAN:
+ *(jboolean *)data = STACKI(1) & 0x01;
+ break;
+ case _JC_TYPE_BYTE:
+ *(jbyte *)data = STACKI(1);
+ break;
+ case _JC_TYPE_CHAR:
+ *(jchar *)data = STACKI(1);
+ break;
+ case _JC_TYPE_SHORT:
+ *(jshort *)data = STACKI(1);
+ break;
+ case _JC_TYPE_INT:
+ *(jint *)data = STACKI(1);
+ break;
+ case _JC_TYPE_FLOAT:
+ *(jfloat *)data = STACKF(1);
+ break;
+ case _JC_TYPE_LONG:
+ *(jlong *)data = STACKJ(1);
+ break;
+ case _JC_TYPE_DOUBLE:
+ *(jdouble *)data = STACKD(1);
+ break;
+ case _JC_TYPE_REFERENCE:
+ *(_jc_object **)data = STACKL(1);
+ break;
+ default:
+ _JC_ASSERT(JNI_FALSE);
+ break;
+ }
+ NEXT();
+ }
+do_putstatic:
+ {
+ _jc_field *const field = INFO(field);
+ const u_char ptype = _jc_sig_types[(u_char)*field->signature];
+ const void *data;
+
+ /*
+ * Pop the stack. We can't look directly at the field's type
+ * here because the field's class may not be resolved yet.
+ */
+ if (_jc_dword_type[ptype])
+ POP2(1);
+ else
+ POP(1);
+
+ /* Initialize field's class */
+ if (!_JC_FLG_TEST(field->class, INITIALIZED)) {
+ if (_jc_initialize_type(env, field->class) != JNI_OK)
+ goto exception;
+ }
+
+ /* Set the field */
+ data = (char *)field->class->u.nonarray.class_fields + field->offset;
+ switch (ptype) {
+ case _JC_TYPE_BOOLEAN:
+ *(jboolean *)data = STACKI(0) & 0x01;
+ break;
+ case _JC_TYPE_BYTE:
+ *(jbyte *)data = STACKI(0);
+ break;
+ case _JC_TYPE_CHAR:
+ *(jchar *)data = STACKI(0);
+ break;
+ case _JC_TYPE_SHORT:
+ *(jshort *)data = STACKI(0);
+ break;
+ case _JC_TYPE_INT:
+ *(jint *)data = STACKI(0);
+ break;
+ case _JC_TYPE_FLOAT:
+ *(jfloat *)data = STACKF(0);
+ break;
+ case _JC_TYPE_LONG:
+ *(jlong *)data = STACKJ(0);
+ break;
+ case _JC_TYPE_DOUBLE:
+ *(jdouble *)data = STACKD(0);
+ break;
+ case _JC_TYPE_REFERENCE:
+ *(_jc_object **)data = STACKL(0);
+ break;
+ default:
+ _JC_ASSERT(JNI_FALSE);
+ break;
+ }
+ NEXT();
+ }
+do_ret:
+ JUMP(LOCALI(INFO(local)));
+do_return:
+ goto done;
+do_saload:
+ {
+ _jc_short_array *array;
+ jint index;
+
+ POP(2);
+ array = (_jc_short_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ PUSHI(array->elems[index]);
+ NEXT();
+ }
+do_sastore:
+ {
+ _jc_short_array *array;
+ jint index;
+
+ POP(3);
+ array = (_jc_short_array *)STACKL(0);
+ index = STACKI(1);
+ ARRAYCHECK(array, index);
+ array->elems[index] = STACKI(2);
+ NEXT();
+ }
+do_swap:
+ {
+ jint temp;
+
+ temp = STACKI(-2);
+ STACKI(-2) = STACKI(-1);
+ STACKI(-1) = temp;
+ NEXT();
+ }
+do_tableswitch:
+ {
+ _jc_tableswitch *const tsw = INFO(tableswitch);
+ jint key;
+
+ POP(1);
+ key = STACKI(0);
+ JUMP((key >= tsw->low && key <= tsw->high) ?
+ tsw->targets[key - tsw->low] : tsw->default_target);
+ }
+
+periodic_check:
+ if (_jc_thread_check(env) != JNI_OK)
+ goto exception;
+ ticker = PERIODIC_CHECK_TICKS;
+ JUMP(pc);
+
+null_pointer_exception:
+ _jc_post_exception(env, _JC_NullPointerException);
+ goto exception;
+
+arithmetic_exception:
+ _jc_post_exception(env, _JC_ArithmeticException);
+ goto exception;
+
+exception:
+ {
+ jint status;
+ int i;
+
+ /* Sanity check */
+ _JC_ASSERT(env->head.pending != NULL);
+
+ /* Check this method for a matching trap */
+ for (i = 0; i < code->num_traps; i++) {
+ _jc_jvm *const vm = env->vm;
+ _jc_interp_trap *const trap = &code->traps[i];
+ _jc_object *e;
+
+ /* See if trap matches */
+ if (pc < trap->start || pc >= trap->end)
+ continue;
+ if ((e = _jc_retrieve_exception(env, trap->type)) == NULL)
+ continue;
+
+ /* Verbosity for caught exception */
+ if ((env->vm->verbose_flags
+ & (1 << _JC_VERBOSE_EXCEPTIONS)) != 0) {
+ _jc_printf(vm, "[verbose %s: caught via trap"
+ " %d (%d-%d) in %s.%s%s in thread %p: ",
+ _jc_verbose_names[_JC_VERBOSE_EXCEPTIONS],
+ i, trap->start, trap->end,
+ method->class->name, method->name,
+ method->signature, env);
+ _jc_fprint_exception_headline(env, stdout, e);
+ _jc_printf(vm, "]\n");
+ }
+
+ /* Push exception and proceed with handler */
+ state.locals[code->max_locals] = (_jc_word)e;
+ sp = &state.locals[code->max_locals + 1];
+ JUMP(trap->target);
+ }
+
+ /* Exception not caught */
+ status = JNI_ERR;
+ goto exit;
+
+done:
+ status = JNI_OK;
+
+exit:
+ /* Sanity check */
+ _JC_ASSERT(status == JNI_OK || env->head.pending != NULL);
+
+ /* De-synchronize if necessary */
+ if (lock != NULL) {
+ _jc_value retval;
+
+ /* Temporarily save return value */
+ retval = env->retval;
+
+ /* Unlock monitor */
+ if (_jc_unlock_object(env, lock) != JNI_OK)
+ status = JNI_ERR;
+
+ /* Restore return value */
+ env->retval = retval;
+ }
+
+ /* Pop Java stack frame */
+ env->java_stack = state.jstack.next;
+
+ /* Done */
+ return status;
+ }
+}
+
+/*
+ * Comparison function for binary search of lookupswitch tables.
+ */
+static int
+_jc_lookup_compare(const void *v1, const void *v2)
+{
+ const _jc_lookup *const l1 = v1;
+ const _jc_lookup *const l2 = v2;
+
+ return (l1->match > l2->match) - (l1->match < l2->match);
+}
+
+/*
+ * Look up a Java source file line number.
+ */
+int
+_jc_interp_pc_to_jline(_jc_method *method, int index)
+{
+ _jc_method_code *const code = &method->u.code;
+ _jc_linemap *base;
+ int span;
+
+ /* Sanity check */
+ _JC_ASSERT(_JC_ACC_TEST(method, INTERP));
+ _JC_ASSERT(_JC_FLG_TEST(method->class, RESOLVED));
+ _JC_ASSERT(index >= 0 && index < code->num_insns);
+
+ /* Binary search for line number */
+ for (base = code->linemaps, span = code->num_linemaps;
+ span != 0; span >>= 1) {
+ _jc_linemap *const sample = &base[span >> 1];
+
+ if (index <= sample->index)
+ continue;
+ if (index > (sample + 1)->index) {
+ base = sample + 1;
+ span--;
+ continue;
+ }
+ return sample->line;
+ }
+
+ /* Not found */
+ return 0;
+}
+
+/*
+ * Type-specific gateway functions into _jc_vinterp()
+ */
+#define _JC_INTERP_ENTRY(_letter, _name, _type, _rtn) \
+_type \
+_jc_ ## _name ## _ ## _letter(_jc_env *env, ...) \
+{ \
+ va_list args; \
+ \
+ va_start(args, env); \
+ _jc_v ## _name(env, args); \
+ va_end(args); \
+ return _rtn; \
+}
+_JC_INTERP_ENTRY(z, interp, jboolean, env->retval.z)
+_JC_INTERP_ENTRY(b, interp, jbyte, env->retval.b)
+_JC_INTERP_ENTRY(c, interp, jchar, env->retval.c)
+_JC_INTERP_ENTRY(s, interp, jshort, env->retval.s)
+_JC_INTERP_ENTRY(i, interp, jint, env->retval.i)
+_JC_INTERP_ENTRY(j, interp, jlong, env->retval.j)
+_JC_INTERP_ENTRY(f, interp, jfloat, env->retval.f)
+_JC_INTERP_ENTRY(d, interp, jdouble, env->retval.d)
+_JC_INTERP_ENTRY(l, interp, _jc_object *, env->retval.l)
+_JC_INTERP_ENTRY(v, interp, void, )
+_JC_INTERP_ENTRY(z, interp_native, jboolean, env->retval.z)
+_JC_INTERP_ENTRY(b, interp_native, jbyte, env->retval.b)
+_JC_INTERP_ENTRY(c, interp_native, jchar, env->retval.c)
+_JC_INTERP_ENTRY(s, interp_native, jshort, env->retval.s)
+_JC_INTERP_ENTRY(i, interp_native, jint, env->retval.i)
+_JC_INTERP_ENTRY(j, interp_native, jlong, env->retval.j)
+_JC_INTERP_ENTRY(f, interp_native, jfloat, env->retval.f)
+_JC_INTERP_ENTRY(d, interp_native, jdouble, env->retval.d)
+_JC_INTERP_ENTRY(l, interp_native, _jc_object *, env->retval.l)
+_JC_INTERP_ENTRY(v, interp_native, void, )
+
+/*
+ * Entry point for interpreted methods when invoked from ELF methods.
+ * We get here by way of a trampoline set up by _jc_build_trampoline(),
+ * which also sets env->interp to the method we are going to interpret.
+ */
+static void
+_jc_vinterp(_jc_env *env, va_list args)
+{
+ _jc_method *const method = env->interp;
+ jboolean clipped_stack;
+ _jc_word *params;
+ _jc_object *this;
+ jint status;
+ int pnum;
+ int i;
+
+ /* Sanity check */
+ _JC_ASSERT(_JC_ACC_TEST(method, INTERP));
+ _JC_ASSERT(!_JC_ACC_TEST(method, NATIVE));
+ _JC_ASSERT(_JC_FLG_TEST(method->class, RESOLVED));
+
+ /* Allocate space for parameter array */
+ if ((params = _JC_STACK_ALLOC(env,
+ method->u.code.num_params2)) == NULL) {
+ _jc_post_exception_info(env);
+ _jc_throw_exception(env);
+ }
+
+ /* Get 'this' if method is non-static */
+ this = !_JC_ACC_TEST(method, STATIC) ?
+ va_arg(args, _jc_object *) : NULL;
+
+ /* Get method parameters, occupying two slots for long/double */
+ for (pnum = i = 0; i < method->num_parameters; i++) {
+ switch (method->param_ptypes[i]) {
+ case _JC_TYPE_BOOLEAN:
+ params[pnum++] = (jint)(jboolean)va_arg(args, jint);
+ break;
+ case _JC_TYPE_BYTE:
+ params[pnum++] = (jint)(jbyte)va_arg(args, jint);
+ break;
+ case _JC_TYPE_CHAR:
+ params[pnum++] = (jint)(jchar)va_arg(args, jint);
+ break;
+ case _JC_TYPE_SHORT:
+ params[pnum++] = (jint)(jshort)va_arg(args, jint);
+ break;
+ case _JC_TYPE_INT:
+ params[pnum++] = va_arg(args, jint);
+ break;
+ case _JC_TYPE_FLOAT:
+ {
+ jfloat param = (jfloat)va_arg(args, jdouble);
+
+ memcpy(params + pnum, ¶m, sizeof(param));
+ pnum++;
+ break;
+ }
+ case _JC_TYPE_LONG:
+ {
+ jlong param = va_arg(args, jlong);
+
+ memcpy(params + pnum, ¶m, sizeof(param));
+ pnum += 2;
+ break;
+ }
+ case _JC_TYPE_DOUBLE:
+ {
+ jdouble param = va_arg(args, jdouble);
+
+ memcpy(params + pnum, ¶m, sizeof(param));
+ pnum += 2;
+ break;
+ }
+ case _JC_TYPE_REFERENCE:
+ params[pnum++] = (_jc_word)va_arg(args, _jc_object *);
+ break;
+ default:
+ _JC_ASSERT(JNI_FALSE);
+ break;
+ }
+ }
+ _JC_ASSERT(pnum == method->u.code.num_params2);
+
+ /* Clip the current top of the Java stack */
+ clipped_stack = !env->java_stack->interp && _jc_stack_clip(env);
+
+ /* Invoke method */
+ status = _jc_interp(env, method, this, params);
+
+ /* Unclip the current top of the Java stack */
+ if (clipped_stack)
+ _jc_stack_unclip(env);
+
+ /* Throw exception if any */
+ if (status != JNI_OK)
+ _jc_throw_exception(env);
+}
+
+/*
+ * Same thing as _jc_vinterp() but for native methods.
+ */
+static void
+_jc_vinterp_native(_jc_env *env, va_list args)
+{
+ _jc_method *const method = env->interp;
+
+ /* Sanity check */
+ _JC_ASSERT(_JC_ACC_TEST(method, INTERP));
+ _JC_ASSERT(_JC_ACC_TEST(method, NATIVE));
+ _JC_ASSERT(_JC_FLG_TEST(method->class, RESOLVED));
+
+ /* Invoke method */
+ if (_jc_invoke_native_method(env, method, JNI_FALSE, args) != JNI_OK)
+ _jc_throw_exception(env);
+}
+
Added: incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/invoke.c
URL: http://svn.apache.org/viewcvs/incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/invoke.c?rev=294974&view=auto
==============================================================================
--- incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/invoke.c (added)
+++ incubator/harmony/enhanced/trunk/sandbox/contribs/jchevm/jchevm/libjc/invoke.c Tue Oct 4 19:19:16 2005
@@ -0,0 +1,1014 @@
+
+/*
+ * Copyright 2005 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Id: invoke.c,v 1.17 2005/07/10 21:03:54 archiecobbs Exp $
+ */
+
+#include "libjc.h"
+
+/*
+ * These functions invoke a Java method. The thread status must already
+ * be set to _JC_THRDSTAT_RUNNING_NORMAL or _JC_THRDSTAT_HALTING_NORMAL.
+ *
+ * Reference method parameters are either "raw" object references or
+ * "wrapped" native object references. "Normal" Java code executes
+ * using unwrapped references, while JNI functions use "wrapped"
+ * references, both when being invoked and when invoking other methods.
+ *
+ * So there are three flavors of invocation functions defined here:
+ *
+ * (1) Accepts unwrapped parameters, invokes with unwrapped parameters
+ * (2) Accepts wrapped parameters, invokes with unwrapped parameters
+ * (3) Accepts unwrapped parameters, invokes with wrapped parameters
+ *
+ * (1) is used for normal Java, (2) for the JNI Call<Type>XXXMethodX()
+ * functions, and (3) for when normal Java needs to invoke a JNI native
+ * function. The (2) functions have "unwrap" in their names while the
+ * (3) functions have "jni" in their names. In cases (1) and (2) we
+ * must catch thrown exceptions. In case (3) exceptions are only posted,
+ * not thrown.
+ *
+ * There are three kinds of Java method invocation: non-virtual, virtual,
+ * and static. We don't need virtual for case (3) because native methods
+ * have already been virtually resolved by the time we get here.
+ *
+ * Finally, there are three types of C function that can be used: a
+ * variadic funtion, a function that takes a va_list, and a function that
+ * takes an array of _jc_word or jvalues.
+ *
+ * All (1) or (2) functions go through _jc_invoke_jcni_a() which is the
+ * "gateway" function between internal libjc code and "normal" JCNI Java
+ * object code. Note that it must catch all thrown exceptions (because
+ * no exceptions may be thrown within libjc), and so requires a trap table,
+ * line number table, etc. All (3) functions go through _jc_invoke_jni_a().
+ *
+ * If the method returns normally, JNI_OK is returned and the return
+ * value from the method is stored in env->retval. Note that the return
+ * value is always a _jc_value, even if for the "wrapped" functions.
+ * This means that callers of "wrapped" functions returning object
+ * references must do the "wrapping" themselves (e.g., by calling
+ * "_jc_new_local_native_ref(env, env->retval.l)") before doing anything
+ * else that could cause a GC cycle, etc.
+ *
+ * Otherwise, JNI_ERR is returned and an exception is posted to the thread.
+ *
+ * Note that it is not necessary for the caller to retain native references
+ * to 'this' or any object parameters, as they will be visible to the GC
+ * scan via the normal stack scanning mechanism.
+ */
+
+/* Internal functions */
+static jint _jc_invoke_unwrap_v(_jc_env *env, _jc_method *method,
+ const void *func, jobject obj, va_list args);
+static jint _jc_invoke_unwrap_a(_jc_env *env, _jc_method *method,
+ const void *func, jobject obj, jvalue *jparams);
+
+/************************************************************************
+ * Non-virtual method invocation *
+ ************************************************************************/
+
+jint
+_jc_invoke_nonvirtual(_jc_env *env, _jc_method *method, _jc_object *this, ...)
+{
+ va_list args;
+ jint status;
+
+ _JC_ASSERT(!_JC_ACC_TEST(method, STATIC));
+ va_start(args, this);
+ status = _jc_invoke_v(env, method,
+ method->function, this, args, JNI_FALSE);
+ va_end(args);
+ return status;
+}
+
+jint
+_jc_invoke_unwrap_nonvirtual(_jc_env *env, _jc_method *method,
+ jobject this, ...)
+{
+ va_list args;
+ jint status;
+
+ _JC_ASSERT(!_JC_ACC_TEST(method, STATIC));
+ va_start(args, this);
+ status = _jc_invoke_unwrap_v(env, method, method->function, this, args);
+ va_end(args);
+ return status;
+}
+
+jint
+_jc_invoke_nonvirtual_v(_jc_env *env, _jc_method *method,
+ _jc_object *this, va_list args)
+{
+ _JC_ASSERT(!_JC_ACC_TEST(method, STATIC));
+ return _jc_invoke_v(env, method,
+ method->function, this, args, JNI_FALSE);
+}
+
+jint
+_jc_invoke_unwrap_nonvirtual_v(_jc_env *env, _jc_method *method,
+ jobject this, va_list args)
+{
+ _JC_ASSERT(!_JC_ACC_TEST(method, STATIC));
+ return _jc_invoke_unwrap_v(env, method, method->function, this, args);
+}
+
+jint
+_jc_invoke_nonvirtual_a(_jc_env *env, _jc_method *method,
+ _jc_object *this, _jc_word *params)
+{
+ _JC_ASSERT(!_JC_ACC_TEST(method, STATIC));
+ return _jc_invoke_jcni_a(env, method, method->function, this, params);
+}
+
+jint
+_jc_invoke_unwrap_nonvirtual_a(_jc_env *env, _jc_method *method,
+ jobject this, jvalue *params)
+{
+ _JC_ASSERT(!_JC_ACC_TEST(method, STATIC));
+ return _jc_invoke_unwrap_a(env, method, method->function, this, params);
+}
+
+/************************************************************************
+ * Virtual method invocation *
+ ************************************************************************/
+
+jint
+_jc_invoke_virtual(_jc_env *env, _jc_method *method, _jc_object *this, ...)
+{
+ va_list args;
+ jint status;
+
+ va_start(args, this);
+ status = _jc_invoke_virtual_v(env, method, this, args);
+ va_end(args);
+ return status;
+}
+
+jint
+_jc_invoke_unwrap_virtual(_jc_env *env, _jc_method *method, jobject this, ...)
+{
+ va_list args;
+ jint status;
+
+ va_start(args, this);
+ status = _jc_invoke_unwrap_virtual_v(env, method, this, args);
+ va_end(args);
+ return status;
+}
+
+jint
+_jc_invoke_virtual_v(_jc_env *env, _jc_method *method,
+ _jc_object *this, va_list args)
+{
+ const void *func;
+
+ /* Sanity check */
+ _JC_ASSERT(!_JC_ACC_TEST(method, STATIC));
+ _JC_ASSERT(*method->name != '<');
+
+ /* Check for null */
+ if (this == NULL) {
+ _jc_post_exception(env, _JC_NullPointerException);
+ return JNI_ERR;
+ }
+
+ /* Virtual method lookup */
+ func = this->type->vtable[method->vtable_index];
+
+ /* Invoke it */
+ return _jc_invoke_v(env, method, func, this, args, JNI_FALSE);
+}
+
+jint
+_jc_invoke_unwrap_virtual_v(_jc_env *env, _jc_method *method,
+ jobject this, va_list args)
+{
+ const void *func;
+
+ /* Sanity check */
+ _JC_ASSERT(!_JC_ACC_TEST(method, STATIC));
+ _JC_ASSERT(strcmp(method->name, "<init>") != 0);
+
+ /* Check for null */
+ if (this == NULL) {
+ _jc_post_exception(env, _JC_NullPointerException);
+ return JNI_ERR;
+ }
+ _JC_ASSERT(*this != NULL);
+
+ /* Virtual method lookup */
+ func = (*this)->type->vtable[method->vtable_index];
+
+ /* Invoke it */
+ return _jc_invoke_unwrap_v(env, method, func, this, args);
+}
+
+jint
+_jc_invoke_virtual_a(_jc_env *env, _jc_method *method,
+ _jc_object *this, _jc_word *params)
+{
+ const void *func;
+
+ /* Sanity check */
+ _JC_ASSERT(!_JC_ACC_TEST(method, STATIC));
+ _JC_ASSERT(strcmp(method->name, "<init>") != 0);
+
+ /* Check for null */
+ if (this == NULL) {
+ _jc_post_exception(env, _JC_NullPointerException);
+ return JNI_ERR;
+ }
+
+ /* Virtual method lookup */
+ func = this->type->vtable[method->vtable_index];
+
+ /* Invoke it */
+ return _jc_invoke_jcni_a(env, method, func, this, params);
+}
+
+jint
+_jc_invoke_unwrap_virtual_a(_jc_env *env, _jc_method *method,
+ jobject this, jvalue *params)
+{
+ const void *func;
+
+ /* Sanity check */
+ _JC_ASSERT(!_JC_ACC_TEST(method, STATIC));
+ _JC_ASSERT(strcmp(method->name, "<init>") != 0);
+
+ /* Check for null */
+ if (this == NULL) {
+ _jc_post_exception(env, _JC_NullPointerException);
+ return JNI_ERR;
+ }
+ _JC_ASSERT(*this != NULL);
+
+ /* Virtual method lookup */
+ func = (*this)->type->vtable[method->vtable_index];
+
+ /* Invoke it */
+ return _jc_invoke_unwrap_a(env, method, func, this, params);
+}
+
+/************************************************************************
+ * Static method invocation *
+ ************************************************************************/
+
+jint
+_jc_invoke_static(_jc_env *env, _jc_method *method, ...)
+{
+ va_list args;
+ jint status;
+
+ va_start(args, method);
+ status = _jc_invoke_static_v(env, method, args);
+ va_end(args);
+ return status;
+}
+
+jint
+_jc_invoke_unwrap_static(_jc_env *env, _jc_method *method, ...)
+{
+ va_list args;
+ jint status;
+
+ va_start(args, method);
+ status = _jc_invoke_unwrap_static_v(env, method, args);
+ va_end(args);
+ return status;
+}
+
+jint
+_jc_invoke_static_v(_jc_env *env, _jc_method *method, va_list args)
+{
+ jint status;
+
+ /* Sanity check */
+ _JC_ASSERT(_JC_ACC_TEST(method, STATIC));
+
+ /* Initialize class if necessary */
+ if (!_JC_FLG_TEST(method->class, INITIALIZED)
+ && (status = _jc_initialize_type(env, method->class)) != JNI_OK)
+ return status;
+
+ /* Invoke method */
+ return _jc_invoke_v(env, method,
+ method->function, NULL, args, JNI_FALSE);
+}
+
+jint
+_jc_invoke_unwrap_static_v(_jc_env *env, _jc_method *method, va_list args)
+{
+ jobject class;
+ jint status;
+
+ /* Sanity check */
+ _JC_ASSERT(_JC_ACC_TEST(method, STATIC));
+ _JC_ASSERT(method->class->instance != NULL);
+
+ /* Initialize class if necessary */
+ if (!_JC_FLG_TEST(method->class, INITIALIZED)
+ && (status = _jc_initialize_type(env, method->class)) != JNI_OK)
+ return status;
+
+ /* Wrap class object */
+ if ((class = _jc_new_local_native_ref(env,
+ method->class->instance)) == NULL)
+ return JNI_ERR;
+
+ /* Invoke method */
+ status = _jc_invoke_unwrap_v(env,
+ method, method->function, class, args);
+
+ /* Free native reference to class object */
+ _jc_free_local_native_ref(&class);
+
+ /* Done */
+ return status;
+}
+
+jint
+_jc_invoke_static_a(_jc_env *env, _jc_method *method, _jc_word *params)
+{
+ jint status;
+
+ /* Sanity check */
+ _JC_ASSERT(_JC_ACC_TEST(method, STATIC));
+
+ /* Initialize class if necessary */
+ if (!_JC_FLG_TEST(method->class, INITIALIZED)
+ && (status = _jc_initialize_type(env, method->class)) != JNI_OK)
+ return status;
+
+ /* Invoke method */
+ return _jc_invoke_jcni_a(env, method, method->function, NULL, params);
+}
+
+jint
+_jc_invoke_unwrap_static_a(_jc_env *env, _jc_method *method, jvalue *params)
+{
+ jobject class;
+ jint status;
+
+ /* Sanity check */
+ _JC_ASSERT(_JC_ACC_TEST(method, STATIC));
+ _JC_ASSERT(method->class->instance != NULL);
+
+ /* Initialize class if necessary */
+ if (!_JC_FLG_TEST(method->class, INITIALIZED)
+ && (status = _jc_initialize_type(env, method->class)) != JNI_OK)
+ return status;
+
+ /* Wrap class object */
+ if ((class = _jc_new_local_native_ref(env,
+ method->class->instance)) == NULL)
+ return JNI_ERR;
+
+ /* Invoke method */
+ status = _jc_invoke_unwrap_a(env,
+ method, method->function, class, params);
+
+ /* Free native reference to class object */
+ _jc_free_local_native_ref(&class);
+
+ /* Done */
+ return status;
+}
+
+/************************************************************************
+ * Generic 'va_list' method invocation *
+ ************************************************************************/
+
+jint
+_jc_invoke_v(_jc_env *env, _jc_method *method,
+ const void *func, _jc_object *obj, va_list args, jboolean jni)
+{
+ _jc_word *params;
+ int nwords;
+ int pi;
+ int i;
+
+ /* Count parameter words */
+ nwords = method->num_parameters;
+ for (i = 0; i < method->num_parameters; i++) {
+ if (_jc_dword_type[method->param_ptypes[i]])
+ nwords++;
+ }
+
+ /* Allocate array of _jc_word's to hold the parameters */
+ if ((params = _JC_STACK_ALLOC(env, nwords * sizeof(*params))) == NULL) {
+ _jc_post_exception_info(env);
+ return JNI_ERR;
+ }
+
+ /* Copy variadic arguments to the _jc_word array */
+ for (pi = i = 0; i < method->num_parameters; i++) {
+ const int ptype = method->param_ptypes[i];
+
+ switch (ptype) {
+ case _JC_TYPE_BOOLEAN:
+ params[pi++] = (jint)(jboolean)va_arg(args, jint);
+ break;
+ case _JC_TYPE_BYTE:
+ params[pi++] = (jint)(jbyte)va_arg(args, jint);
+ break;
+ case _JC_TYPE_CHAR:
+ params[pi++] = (jint)(jchar)va_arg(args, jint);
+ break;
+ case _JC_TYPE_SHORT:
+ params[pi++] = (jint)(jshort)va_arg(args, jint);
+ break;
+ case _JC_TYPE_INT:
+ params[pi++] = va_arg(args, jint);
+ break;
+ case _JC_TYPE_FLOAT:
+ {
+ const jfloat param = va_arg(args, jdouble);
+
+ memcpy(params + pi, ¶m, sizeof(param));
+ pi++;
+ break;
+ }
+ case _JC_TYPE_LONG:
+ {
+ const jlong param = va_arg(args, jlong);
+
+ memcpy(params + pi, ¶m, sizeof(param));
+ pi += 2;
+ break;
+ }
+ case _JC_TYPE_DOUBLE:
+ {
+ const jdouble param = va_arg(args, jdouble);
+
+ memcpy(params + pi, ¶m, sizeof(param));
+ pi += 2;
+ break;
+ }
+ case _JC_TYPE_REFERENCE:
+ params[pi++] = (_jc_word)va_arg(args, _jc_object *);
+ break;
+ default:
+ _JC_ASSERT(JNI_FALSE);
+ break;
+ }
+ }
+
+ /* Invoke method */
+ return jni ?
+ _jc_invoke_jni_a(env, method, func, obj, params) :
+ _jc_invoke_jcni_a(env, method, func, obj, params);
+}
+
+static jint
+_jc_invoke_unwrap_v(_jc_env *env, _jc_method *method,
+ const void *func, jobject obj, va_list args)
+{
+ _jc_word *params;
+ _jc_object *this;
+ int nwords;
+ int pi;
+ int i;
+
+ /* Count parameter words */
+ nwords = method->num_parameters;
+ for (i = 0; i < method->num_parameters; i++) {
+ if (_jc_dword_type[method->param_ptypes[i]])
+ nwords++;
+ }
+
+ /* Allocate array of _jc_word's to hold the parameters */
+ if ((params = _JC_STACK_ALLOC(env, nwords * sizeof(*params))) == NULL) {
+ _jc_post_exception_info(env);
+ return JNI_ERR;
+ }
+
+ /* Copy "unwrapped" variadic arguments to the _jc_word array */
+ for (pi = i = 0; i < method->num_parameters; i++) {
+ const int ptype = method->param_ptypes[i];
+
+ switch (ptype) {
+ case _JC_TYPE_BOOLEAN:
+ params[pi++] = (jint)(jboolean)va_arg(args, jint);
+ break;
+ case _JC_TYPE_BYTE:
+ params[pi++] = (jint)(jbyte)va_arg(args, jint);
+ break;
+ case _JC_TYPE_CHAR:
+ params[pi++] = (jint)(jchar)va_arg(args, jint);
+ break;
+ case _JC_TYPE_SHORT:
+ params[pi++] = (jint)(jshort)va_arg(args, jint);
+ break;
+ case _JC_TYPE_INT:
+ params[pi++] = va_arg(args, jint);
+ break;
+ case _JC_TYPE_FLOAT:
+ {
+ const jfloat param = va_arg(args, jdouble);
+
+ memcpy(params + pi, ¶m, sizeof(param));
+ pi++;
+ break;
+ }
+ case _JC_TYPE_LONG:
+ {
+ const jlong param = va_arg(args, jlong);
+
+ memcpy(params + pi, ¶m, sizeof(param));
+ pi += 2;
+ break;
+ }
+ case _JC_TYPE_DOUBLE:
+ {
+ const jdouble param = va_arg(args, jdouble);
+
+ memcpy(params + pi, ¶m, sizeof(param));
+ pi += 2;
+ break;
+ }
+ case _JC_TYPE_REFERENCE:
+ {
+ const jobject param = va_arg(args, jobject);
+
+ params[pi++] = (_jc_word)
+ ((param != NULL) ? *param : NULL);
+ break;
+ }
+ default:
+ _JC_ASSERT(JNI_FALSE);
+ break;
+ }
+ }
+
+ /* Unwrap "this" */
+ this = (!_JC_ACC_TEST(method, STATIC) && obj != NULL) ? *obj : NULL;
+
+ /* Invoke method */
+ return _jc_invoke_jcni_a(env, method, func, this, params);
+}
+
+/************************************************************************
+ * Generic 'value list' method invocation *
+ ************************************************************************/
+
+/*
+ * Invoke a JNI method using supplied parameters.
+ */
+jint
+_jc_invoke_jni_a(_jc_env *env, _jc_method *method,
+ const void *func, _jc_object *obj, _jc_word *params)
+{
+ JNIEnv *jenv = _JC_ENV2JNI(env);
+ _jc_method *previous_jni_method;
+ jboolean clipped_stack_top = JNI_FALSE;
+ jboolean pushed_frame = JNI_FALSE;
+ jboolean got_monitor = JNI_FALSE;
+ _jc_native_frame frame;
+ jint status = JNI_ERR;
+ int num_ref_params;
+ _jc_word *params2;
+ u_char *ptypes;
+ jobject ref;
+ int nparams2;
+ int i;
+ int j;
+
+ /* Sanity check */
+ _JC_ASSERT(env->status == _JC_THRDSTAT_RUNNING_NORMAL
+ || env->status == _JC_THRDSTAT_HALTING_NORMAL);
+ _JC_ASSERT(_JC_ACC_TEST(method, NATIVE));
+ _JC_ASSERT(func != NULL);
+
+ /* Count number of method parameters, counting long/double twice */
+ nparams2 = method->num_parameters;
+ for (i = 0; i < method->num_parameters; i++) {
+ if (_jc_dword_type[method->param_ptypes[i]])
+ nparams2++;
+ }
+
+ /* Check for null */
+ if (!_JC_ACC_TEST(method, STATIC) && obj == NULL) {
+ _jc_post_exception(env, _JC_NullPointerException);
+ goto done;
+ }
+ _JC_ASSERT(_JC_ACC_TEST(method, STATIC) == (obj == NULL));
+
+ /* JNI requires Class instance passed for static methods */
+ if (_JC_ACC_TEST(method, STATIC))
+ obj = method->class->instance;
+
+ /* Push a new local native reference frame (allocated on the stack) */
+ _jc_push_stack_local_native_frame(env, &frame);
+ pushed_frame = JNI_TRUE;
+
+ /* Ensure enough local native references for all parameters */
+ num_ref_params = 1; /* for the implicit object parameter */
+ for (i = 0; i < method->num_parameters; i++) {
+ const int ptype = method->param_ptypes[i];
+
+ if (ptype == _JC_TYPE_REFERENCE)
+ num_ref_params++;
+ }
+ if (num_ref_params + _JC_NATIVE_REFS_MIN_PER_FRAME
+ > _JC_NATIVE_REFS_PER_FRAME
+ && _jc_extend_local_native_frame(env, num_ref_params
+ + _JC_NATIVE_REFS_MIN_PER_FRAME
+ - _JC_NATIVE_REFS_PER_FRAME) != JNI_OK)
+ goto done;
+
+ /* Create array of C function parameters */
+ if ((params2 = _JC_STACK_ALLOC(env, (2 + nparams2) * sizeof(*params2)
+ + (2 + method->num_parameters + 1))) == NULL) {
+ _jc_post_exception_info(env);
+ goto done;
+ }
+ params2[0] = (_jc_word)jenv;
+ ref = _jc_new_local_native_ref(env, obj);
+ _JC_ASSERT(ref != NULL);
+ params2[1] = (_jc_word)ref;
+ for (i = 0, j = 0; i < method->num_parameters; i++) {
+ const int ptype = method->param_ptypes[i];
+
+ /* Wrap reference parameters in a local native reference */
+ if (ptype == _JC_TYPE_REFERENCE) {
+ _jc_object *const pobj = (_jc_object *)*params++;
+
+ ref = _jc_new_local_native_ref(env, pobj);
+ _JC_ASSERT(pobj == NULL || ref != NULL);
+ params2[2 + j++] = (_jc_word)ref;
+ } else {
+ params2[2 + j++] = *params++;
+ if (_jc_dword_type[ptype])
+ params2[2 + j++] = *params++;
+ }
+ }
+ _JC_ASSERT(j == nparams2);
+ nparams2 += 2;
+
+ /* Set up parameter types */
+ ptypes = (u_char *)(params2 + nparams2);
+ ptypes[0] = _JC_TYPE_REFERENCE; /* JNIEnv parameter */
+ ptypes[1] = _JC_TYPE_REFERENCE; /* 'this' or Class object */
+ memcpy(ptypes + 2, method->param_ptypes, method->num_parameters + 1);
+
+ /* Synchronized? */
+ if (_JC_ACC_TEST(method, SYNCHRONIZED)) {
+ if (_jc_lock_object(env, obj) != JNI_OK)
+ goto done;
+ got_monitor = JNI_TRUE;
+ }
+
+ /* Keep track of the inner-most JNI method */
+ previous_jni_method = env->jni_method;
+ env->jni_method = method;
+
+ /* Clip the current top of the Java stack if not clipped already */
+ clipped_stack_top = _jc_stack_clip(env);
+
+ /* Going native */
+ _jc_stopping_java(env, NULL);
+
+ /* Invoke the method */
+ _jc_dynamic_invoke(func, JNI_FALSE, 2 + method->num_parameters,
+ ptypes, nparams2, params2, &env->retval);
+
+ /* Returning from native */
+ _jc_resuming_java(env);
+
+ /* Unclip stack */
+ if (clipped_stack_top)
+ _jc_stack_unclip(env);
+
+ /* Restore inner-most JNI method on the stack */
+ env->jni_method = previous_jni_method;
+
+ /* Return an error if an exception was posted */
+ status = (env->head.pending != NULL) ? JNI_ERR : JNI_OK;
+
+done:
+ /* Pop local native reference frame */
+ if (pushed_frame)
+ _jc_pop_local_native_frame(env, NULL);
+
+ /* Synchronized? */
+ if (got_monitor) {
+ _jc_value retval;
+ jint status2;
+
+ retval = env->retval;
+ if ((status2 = _jc_unlock_object(env, obj)) != JNI_OK)
+ status = status2;
+ env->retval = retval;
+ }
+
+ /*
+ * If an exception was thrown, reset return value for good measure.
+ * Otherwise, convert jvalue -> _jc_value.
+ */
+ if (status != JNI_OK)
+ memset(&env->retval, 0, sizeof(env->retval));
+ else if (method->param_ptypes[method->num_parameters]
+ == _JC_TYPE_REFERENCE) {
+ ref = (jobject)env->retval.l;
+ env->retval.l = (ref != NULL) ? *ref : NULL;
+ }
+
+ /* Done */
+ return status;
+}
+
+/*
+ * Invoke a JCNI method using supplied 'wrapped' parameters.
+ */
+static jint
+_jc_invoke_unwrap_a(_jc_env *env, _jc_method *method,
+ const void *func, jobject obj, jvalue *jparams)
+{
+ _jc_word *params;
+ _jc_object *this;
+ int nwords;
+ int pi;
+ int i;
+
+ /* Count parameter words */
+ nwords = method->num_parameters;
+ for (i = 0; i < method->num_parameters; i++) {
+ if (_jc_dword_type[method->param_ptypes[i]])
+ nwords++;
+ }
+
+ /* Allocate array of _jc_word's to hold the parameters */
+ if ((params = _JC_STACK_ALLOC(env, nwords * sizeof(*params))) == NULL) {
+ _jc_post_exception_info(env);
+ return JNI_ERR;
+ }
+
+ /* Copy "unwrapped" variadic arguments to the _jc_word array */
+ for (pi = i = 0; i < method->num_parameters; i++) {
+ const int ptype = method->param_ptypes[i];
+
+ switch (ptype) {
+ case _JC_TYPE_BOOLEAN:
+ params[pi++] = (jint)jparams[i].z;
+ break;
+ case _JC_TYPE_BYTE:
+ params[pi++] = (jint)jparams[i].b;
+ break;
+ case _JC_TYPE_CHAR:
+ params[pi++] = (jint)jparams[i].c;
+ break;
+ case _JC_TYPE_SHORT:
+ params[pi++] = (jint)jparams[i].s;
+ break;
+ case _JC_TYPE_INT:
+ params[pi++] = jparams[i].i;
+ break;
+ case _JC_TYPE_FLOAT:
+ {
+ const jfloat param = jparams[i].f;
+
+ memcpy(params + pi, ¶m, sizeof(param));
+ pi++;
+ break;
+ }
+ case _JC_TYPE_LONG:
+ {
+ const jlong param = jparams[i].j;
+
+ memcpy(params + pi, ¶m, sizeof(param));
+ pi += 2;
+ break;
+ }
+ case _JC_TYPE_DOUBLE:
+ {
+ const jdouble param = jparams[i].d;
+
+ memcpy(params + pi, ¶m, sizeof(param));
+ pi += 2;
+ break;
+ }
+ case _JC_TYPE_REFERENCE:
+ {
+ const jobject param = jparams[i].l;
+
+ params[pi++] = (_jc_word)
+ ((param != NULL) ? *param : NULL);
+ break;
+ }
+ default:
+ _JC_ASSERT(JNI_FALSE);
+ break;
+ }
+ }
+
+ /* Unwrap "this" */
+ this = (!_JC_ACC_TEST(method, STATIC) && obj != NULL) ? *obj : NULL;
+
+ /* Invoke method */
+ return _jc_invoke_jcni_a(env, method, func, this, params);
+}
+
+/*
+ * Invoke a JCNI method using supplied 'value list' parameters.
+ *
+ * This function is the main "gateway" from the libjc world (where exceptions
+ * are posted, not thrown) to the Java world (where exceptions are explicitly
+ * thrown by unwinding the stack). Any exceptions thrown by the invoked method
+ * cause this function to return JNI_ERR instead of JNI_OK (and the field
+ * env->head.pending contains the exception).
+ *
+ * In order to catch exceptions thrown by Java code, we rely on the function
+ * _jc_throw_exception() specially recognizing this function on the stack.
+ * Therefore we have to look somewhat like a compiled Java method, with a
+ * method table entry and line number table, etc.
+ *
+ * If the method is static, 'obj' should be NULL and is not passed as a
+ * parameter as JCNI does not pass the Class object to static methods.
+ */
+
+/*
+ * Method descriptor for _jc_invoke_jcni_a(), so that it can be found
+ * in a stack trace like compiled Java methods. Note the "function" and
+ * "function_end" values are computed at runtime in _jc_create_vm().
+ */
+const _jc_method _jc_invoke_jcni_a$method_info = {
+ .name= "_jc_invoke_jcni_a",
+ .signature= "()V",
+};
+
+jint
+_jc_invoke_jcni_a(_jc_env *env, _jc_method *method,
+ const void *func, _jc_object *volatile obj, _jc_word *volatile params)
+{
+ _jc_jvm *const vm = env->vm;
+ volatile jboolean pushed_java_stack = JNI_FALSE;
+ volatile jboolean pushed_native_frame = JNI_FALSE;
+ volatile jboolean set_stack_limit = JNI_FALSE;
+ volatile jboolean got_monitor = JNI_FALSE;
+ volatile jboolean clipped_stack_top = JNI_FALSE;
+ volatile jint status = JNI_ERR;
+ _jc_word *volatile params2 = NULL; /* avoid gcc warning */
+ _jc_exec_stack java_stack;
+ _jc_native_frame frame;
+ _jc_catch_frame catch;
+ u_char *ptypes;
+ int nparams2;
+ int i;
+
+ /* Define exception traps */
+ _JC_DEFINE_TRAPS(env, catch, &vm->invoke_method, &&exception);
+
+ /* Sanity check */
+ _JC_ASSERT(env->status == _JC_THRDSTAT_RUNNING_NORMAL
+ || env->status == _JC_THRDSTAT_HALTING_NORMAL);
+
+ /* Check for null (non-static methods only) */
+ if (!_JC_ACC_TEST(method, STATIC) && obj == NULL) {
+ _jc_post_exception(env, _JC_NullPointerException);
+ goto done;
+ }
+ _JC_ASSERT(_JC_ACC_TEST(method, STATIC) == (obj == NULL));
+
+ /* Clip the current top of the Java stack if not clipped already */
+ clipped_stack_top = _jc_stack_clip(env);
+
+ /* Push a new local native reference frame (allocated on the stack) */
+ _jc_push_stack_local_native_frame(env, &frame);
+ pushed_native_frame = JNI_TRUE;
+
+ /* Mark the stack overflow limit */
+ if (env->stack_limit == NULL) {
+ if (env->stack_size == 0)
+ env->stack_size = vm->threads.stack_default;
+#if _JC_DOWNWARD_STACK
+ env->stack_limit = (char *)&env - env->stack_size
+ + _JC_STACK_OVERFLOW_MARGIN;
+#else
+ env->stack_limit = (char *)&env + env->stack_size
+ - _JC_STACK_OVERFLOW_MARGIN;
+#endif
+ set_stack_limit = JNI_TRUE;
+ }
+
+ /* Sanity check */
+ _JC_ASSERT(func != NULL);
+
+ /* Count number of method parameters, counting long/double twice */
+ nparams2 = method->num_parameters;
+ for (i = 0; i < method->num_parameters; i++) {
+ if (_jc_dword_type[method->param_ptypes[i]])
+ nparams2++;
+ }
+
+ /* Create array of _jc_word's for the C function parameters */
+ if ((params2 = _JC_STACK_ALLOC(env, (2 + nparams2) * sizeof(*params2)
+ + (2 + method->num_parameters + 1))) == NULL) {
+ _jc_post_exception_info(env);
+ goto done;
+ }
+ if (!_JC_ACC_TEST(method, STATIC)) {
+ params2[0] = (_jc_word)env;
+ params2[1] = (_jc_word)obj;
+ memcpy(params2 + 2, params, nparams2 * sizeof(*params2));
+ nparams2 += 2;
+ ptypes = (u_char *)(params2 + nparams2);
+ ptypes[0] = _JC_TYPE_REFERENCE;
+ ptypes[1] = _JC_TYPE_REFERENCE;
+ memcpy(ptypes + 2, method->param_ptypes,
+ method->num_parameters + 1);
+ } else {
+ params2[0] = (_jc_word)env;
+ memcpy(params2 + 1, params, nparams2 * sizeof(*params2));
+ nparams2++;
+ ptypes = (u_char *)(params2 + nparams2);
+ ptypes[0] = _JC_TYPE_REFERENCE;
+ memcpy(ptypes + 1, method->param_ptypes,
+ method->num_parameters + 1);
+ }
+
+ /* Synchronize native methods; non-native code synchronizes itself */
+ if (_JC_ACC_TEST(method, SYNCHRONIZED)
+ && func == method->native_function) {
+ if (_JC_ACC_TEST(method, STATIC))
+ obj = method->class->instance;
+ if (_jc_lock_object(env, obj) != JNI_OK)
+ goto done;
+ got_monitor = JNI_TRUE;
+ }
+
+ /* Start a new contiguous Java stack frame sequence */
+ memset(&java_stack, 0, sizeof(java_stack));
+ java_stack.jstack.interp = JNI_FALSE;
+ java_stack.jstack.next = env->java_stack;
+ java_stack.pc = NULL;
+#ifndef NDEBUG
+ _jc_stack_frame_init(&java_stack.frame);
+#endif
+ env->java_stack = &java_stack.jstack;
+ pushed_java_stack = JNI_TRUE;
+
+ /* Invoke the method */
+ _jc_dynamic_invoke(func, JNI_TRUE,
+ (_JC_ACC_TEST(method, STATIC) ? 1 : 2) + method->num_parameters,
+ ptypes, nparams2, params2, &env->retval);
+
+ /* No exceptions were thrown */
+ status = JNI_OK;
+ goto done;
+
+exception:
+ /* Handle any caught exceptions by re-posting them */
+ _jc_post_exception_object(env, env->head.caught);
+ env->head.caught = NULL;
+ status = JNI_ERR;
+
+done:
+ /* Pop local native reference frame and Java stack frame segment */
+ if (pushed_java_stack)
+ env->java_stack = java_stack.jstack.next;
+ if (pushed_native_frame)
+ _jc_pop_local_native_frame(env, NULL);
+ if (set_stack_limit)
+ env->stack_limit = NULL;
+
+ /* Unclip stack */
+ if (clipped_stack_top)
+ _jc_stack_unclip(env);
+
+ /* Synchronized? */
+ if (got_monitor) {
+ _jc_value retval;
+ jint status2;
+
+ retval = env->retval;
+ if ((status2 = _jc_unlock_object(env, obj)) != JNI_OK)
+ status = status2;
+ env->retval = retval;
+ }
+
+ /* If an exception was thrown, reset return value */
+ if (status != JNI_OK)
+ memset(&env->retval, 0, sizeof(env->retval));
+
+ /* Unlink catch frame */
+ _JC_CANCEL_TRAPS(env, catch);
+
+ /* Done */
+ return status;
+}
+