| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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. |
| */ |
| #include "interpreter.h" |
| #include "interpreter_exports.h" |
| #include "interpreter_imports.h" |
| #include "open/vm_field_access.h" |
| #include "open/vm_method_access.h" |
| #include "open/vm_class_manipulation.h" |
| #include <math.h> |
| |
| #include "vtable.h" |
| #include "exceptions.h" |
| #include "exceptions_int.h" |
| #include "vm_arrays.h" |
| #include "vm_strings.h" |
| #include "jit_runtime_support_common.h" |
| |
| #include "interp_native.h" |
| #include "interp_defs.h" |
| #include "interp_vm_helpers.h" |
| #include "ini.h" |
| #include "compile.h" |
| |
| #include "thread_manager.h" |
| #include <sstream> |
| |
| #ifndef PLATFORM_POSIX |
| #include <float.h> |
| #define isnan _isnan |
| #endif |
| |
| bool interpreter_enable_debug = true; |
| int interpreter_enable_debug_trigger = -1; |
| |
| const char *opcodeNames[256] = { |
| "NOP", "ACONST_NULL", "ICONST_M1", "ICONST_0", "ICONST_1", "ICONST_2", |
| "ICONST_3", "ICONST_4", "ICONST_5", "LCONST_0", "LCONST_1", "FCONST_0", |
| "FCONST_1", "FCONST_2", "DCONST_0", "DCONST_1", "BIPUSH", "SIPUSH", |
| "LDC", "LDC_W", "LDC2_W", "ILOAD", "LLOAD", "FLOAD", "DLOAD", "ALOAD", |
| "ILOAD_0", "ILOAD_1", "ILOAD_2", "ILOAD_3", "LLOAD_0", "LLOAD_1", "LLOAD_2", |
| "LLOAD_3", "FLOAD_0", "FLOAD_1", "FLOAD_2", "FLOAD_3", "DLOAD_0", "DLOAD_1", |
| "DLOAD_2", "DLOAD_3", "ALOAD_0", "ALOAD_1", "ALOAD_2", "ALOAD_3", "IALOAD", |
| "LALOAD", "FALOAD", "DALOAD", "AALOAD", "BALOAD", "CALOAD", "SALOAD", |
| "ISTORE", "LSTORE", "FSTORE", "DSTORE", "ASTORE", "ISTORE_0", "ISTORE_1", |
| "ISTORE_2", "ISTORE_3", "LSTORE_0", "LSTORE_1", "LSTORE_2", "LSTORE_3", |
| "FSTORE_0", "FSTORE_1", "FSTORE_2", "FSTORE_3", "DSTORE_0", "DSTORE_1", |
| "DSTORE_2", "DSTORE_3", "ASTORE_0", "ASTORE_1", "ASTORE_2", "ASTORE_3", |
| "IASTORE", "LASTORE", "FASTORE", "DASTORE", "AASTORE", "BASTORE", "CASTORE", |
| "SASTORE", "POP", "POP2", "DUP", "DUP_X1", "DUP_X2", "DUP2", "DUP2_X1", |
| "DUP2_X2", "SWAP", "IADD", "LADD", "FADD", "DADD", "ISUB", "LSUB", "FSUB", |
| "DSUB", "IMUL", "LMUL", "FMUL", "DMUL", "IDIV", "LDIV", "FDIV", "DDIV", |
| "IREM", "LREM", "FREM", "DREM", "INEG", "LNEG", "FNEG", "DNEG", "ISHL", |
| "LSHL", "ISHR", "LSHR", "IUSHR", "LUSHR", "IAND", "LAND", "IOR", "LOR", |
| "IXOR", "LXOR", "IINC", "I2L", "I2F", "I2D", "L2I", "L2F", "L2D", "F2I", |
| "F2L", "F2D", "D2I", "D2L", "D2F", "I2B", "I2C", "I2S", "LCMP", "FCMPL", |
| "FCMPG", "DCMPL", "DCMPG", "IFEQ", "IFNE", "IFLT", "IFGE", "IFGT", "IFLE", |
| "IF_ICMPEQ", "IF_ICMPNE", "IF_ICMPLT", "IF_ICMPGE", "IF_ICMPGT", |
| "IF_ICMPLE", "IF_ACMPEQ", "IF_ACMPNE", "GOTO", "JSR", "RET", "TABLESWITCH", |
| "LOOKUPSWITCH", "IRETURN", "LRETURN", "FRETURN", "DRETURN", "ARETURN", |
| "RETURN", "GETSTATIC", "PUTSTATIC", "GETFIELD", "PUTFIELD", "INVOKEVIRTUAL", |
| "INVOKESPECIAL", "INVOKESTATIC", "INVOKEINTERFACE", "_OPCODE_UNDEFINED", |
| "NEW", "NEWARRAY", "ANEWARRAY", "ARRAYLENGTH", "ATHROW", "CHECKCAST", |
| "INSTANCEOF", "MONITORENTER", "MONITOREXIT", "WIDE", "MULTIANEWARRAY", |
| "IFNULL", "IFNONNULL", "GOTO_W", "JSR_W", |
| |
| "BREAKPOINT", |
| "UNKNOWN_0xCB", "UNKNOWN_0xCC", "UNKNOWN_0xCD", "UNKNOWN_0xCE", |
| "UNKNOWN_0xCF", "UNKNOWN_0xD0", "UNKNOWN_0xD1", "UNKNOWN_0xD2", |
| "UNKNOWN_0xD3", "UNKNOWN_0xD4", "UNKNOWN_0xD5", "UNKNOWN_0xD6", |
| "UNKNOWN_0xD7", "UNKNOWN_0xD8", "UNKNOWN_0xD9", "UNKNOWN_0xDA", |
| "UNKNOWN_0xDB", "UNKNOWN_0xDC", "UNKNOWN_0xDD", "UNKNOWN_0xDE", |
| "UNKNOWN_0xDF", "UNKNOWN_0xE0", "UNKNOWN_0xE1", "UNKNOWN_0xE2", |
| "UNKNOWN_0xE3", "UNKNOWN_0xE4", "UNKNOWN_0xE5", "UNKNOWN_0xE6", |
| "UNKNOWN_0xE7", "UNKNOWN_0xE8", "UNKNOWN_0xE9", "UNKNOWN_0xEA", |
| "UNKNOWN_0xEB", "UNKNOWN_0xEC", "UNKNOWN_0xED", "UNKNOWN_0xEE", |
| "UNKNOWN_0xEF", "UNKNOWN_0xF0", "UNKNOWN_0xF1", "UNKNOWN_0xF2", |
| "UNKNOWN_0xF3", "UNKNOWN_0xF4", "UNKNOWN_0xF5", "UNKNOWN_0xF6", |
| "UNKNOWN_0xF7", "UNKNOWN_0xF8", "UNKNOWN_0xF9", "UNKNOWN_0xFA", |
| "UNKNOWN_0xFB", "UNKNOWN_0xFC", "UNKNOWN_0xFD", "UNKNOWN_0xFE", |
| "UNKNOWN_0xFF" |
| }; |
| |
| |
| static void interpreterInvokeStatic(StackFrame& prevFrame, Method *method); |
| static void interpreterInvokeVirtual(StackFrame& prevFrame, Method *method); |
| static void interpreterInvokeInterface(StackFrame& prevFrame, Method *method); |
| static void interpreterInvokeSpecial(StackFrame& prevFrame, Method *method); |
| |
| /****************************************************/ |
| /*** INLINE FUNCTIONS *******************************/ |
| /****************************************************/ |
| |
| static inline int16 |
| read_uint8(U_8 *addr) { |
| return *addr; |
| } |
| |
| static inline int16 |
| read_int8(U_8 *addr) { |
| return ((I_8*)addr)[0]; |
| } |
| |
| static inline int16 |
| read_int16(U_8 *addr) { |
| int res = (((I_8*)addr)[0] << 8); |
| return (int16)(res + (int)addr[1]); |
| } |
| |
| static inline uint16 |
| read_uint16(U_8 *addr) { |
| return (int16)((addr[0] << 8) + addr[1]); |
| } |
| |
| static inline I_32 |
| read_int32(U_8 *addr) { |
| U_32 res = (addr[0] << 24) + (addr[1] << 16) + (addr[2] << 8) + addr[3]; |
| return (I_32) res; |
| } |
| |
| |
| static void throwAIOOBE(I_32 index) { |
| char buf[64]; |
| sprintf(buf, "%i", index); |
| DEBUG("****** ArrayIndexOutOfBoundsException ******\n"); |
| interp_throw_exception("java/lang/ArrayIndexOutOfBoundsException", buf); |
| } |
| |
| static void throwNPE() { |
| DEBUG("****** NullPointerException ******\n"); |
| interp_throw_exception("java/lang/NullPointerException"); |
| } |
| |
| static void throwAME(const char *msg) { |
| DEBUG("****** AbstractMethodError ******\n"); |
| interp_throw_exception("java/lang/AbstractMethodError", msg); |
| } |
| |
| static void throwIAE(const char *msg) { |
| DEBUG("****** IllegalAccessError ******\n"); |
| interp_throw_exception("java/lang/IllegalAccessError", msg); |
| } |
| |
| static inline void |
| Opcode_NOP(StackFrame& frame) { |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_ACONST_NULL(StackFrame& frame) { |
| frame.stack.push(); |
| frame.stack.pick().ref = 0; |
| frame.stack.ref() = FLAG_OBJECT; |
| frame.ip++; |
| } |
| |
| #define DEF_OPCODE_CONST32_N(T,V,t,VAL) \ |
| static inline void \ |
| Opcode_ ## T ## CONST_ ## V(StackFrame& frame) { \ |
| frame.stack.push(); \ |
| frame.stack.pick().t = VAL; \ |
| frame.ip++; \ |
| } |
| |
| DEF_OPCODE_CONST32_N(I,M1,i,-1) // Opcode_ICONST_M1 |
| DEF_OPCODE_CONST32_N(I,0,i,0) // Opcode_ICONST_0 |
| DEF_OPCODE_CONST32_N(I,1,i,1) // Opcode_ICONST_1 |
| DEF_OPCODE_CONST32_N(I,2,i,2) // Opcode_ICONST_2 |
| DEF_OPCODE_CONST32_N(I,3,i,3) // Opcode_ICONST_3 |
| DEF_OPCODE_CONST32_N(I,4,i,4) // Opcode_ICONST_4 |
| DEF_OPCODE_CONST32_N(I,5,i,5) // Opcode_ICONST_5 |
| DEF_OPCODE_CONST32_N(F,0,f,0) // Opcode_FCONST_0 |
| DEF_OPCODE_CONST32_N(F,1,f,1) // Opcode_FCONST_1 |
| DEF_OPCODE_CONST32_N(F,2,f,2) // Opcode_FCONST_2 |
| |
| #define DEF_OPCODE_CONST64_N(T,V,t) \ |
| static inline void \ |
| Opcode_ ## T ## V(StackFrame& frame) { \ |
| frame.stack.push(2); \ |
| Value2 val; \ |
| val.t = V; \ |
| frame.stack.setLong(0, val); \ |
| frame.ip++; \ |
| } |
| |
| DEF_OPCODE_CONST64_N(LCONST_,0,i64) // Opcode_LCONST_0 |
| DEF_OPCODE_CONST64_N(LCONST_,1,i64) // Opcode_LCONST_1 |
| DEF_OPCODE_CONST64_N(DCONST_,0,d) // Opcode_DCONST_0 |
| DEF_OPCODE_CONST64_N(DCONST_,1,d) // Opcode_DCONST_0 |
| |
| |
| |
| static inline void |
| Opcode_BIPUSH(StackFrame& frame) { |
| frame.stack.push(); |
| frame.stack.pick().i = read_int8(frame.ip + 1); |
| DEBUG_BYTECODE("push " << frame.stack.pick().i); |
| frame.ip += 2; |
| } |
| |
| static inline void |
| Opcode_SIPUSH(StackFrame& frame) { |
| frame.stack.push(); |
| frame.stack.pick().i = read_int16(frame.ip + 1); |
| DEBUG_BYTECODE("push " << frame.stack.pick().i); |
| frame.ip += 3; |
| } |
| |
| static inline void |
| Opcode_ALOAD(StackFrame& frame) { |
| // get value from local variable |
| U_32 varId = read_uint8(frame.ip + 1); |
| Value& val = frame.locals(varId); |
| ASSERT_TAGS(frame.locals.ref(varId)); |
| |
| // store value in operand stack |
| frame.stack.push(); |
| frame.stack.pick() = val; |
| frame.stack.ref() = frame.locals.ref(varId); |
| if (frame.locals.ref(varId) == FLAG_OBJECT) { ASSERT_OBJECT(UNCOMPRESS_INTERP(val.ref)); } |
| DEBUG_BYTECODE("var" << (int)varId << " -> stack (val = " << (int)frame.stack.pick().i << ")"); |
| frame.ip += 2; |
| } |
| |
| static inline void |
| Opcode_WIDE_ALOAD(StackFrame& frame) { |
| // get value from local variable |
| U_32 varId = read_uint16(frame.ip + 2); |
| Value& val = frame.locals(varId); |
| ASSERT_TAGS(frame.locals.ref(varId)); |
| |
| // store value in operand stack |
| frame.stack.push(); |
| frame.stack.pick() = val; |
| frame.stack.ref() = frame.locals.ref(varId); |
| DEBUG_BYTECODE("var" << (int)varId << " -> stack (val = " << (int)frame.stack.pick().i << ")"); |
| frame.ip += 4; |
| } |
| |
| static inline void |
| Opcode_ILOAD(StackFrame& frame) { |
| // get value from local variable |
| U_32 varId = read_uint8(frame.ip + 1); |
| Value& val = frame.locals(varId); |
| ASSERT_TAGS(!frame.locals.ref(varId)); |
| |
| // store value in operand stack |
| frame.stack.push(); |
| frame.stack.pick() = val; |
| DEBUG_BYTECODE("var" << (int)varId << " -> stack (val = " << (int)frame.stack.pick().i << ")"); |
| frame.ip += 2; |
| } |
| |
| static inline void |
| Opcode_WIDE_ILOAD(StackFrame& frame) { |
| // get value from local variable |
| U_32 varId = read_uint16(frame.ip + 2); |
| Value& val = frame.locals(varId); |
| ASSERT_TAGS(!frame.locals.ref(varId)); |
| |
| // store value in operand stack |
| frame.stack.push(); |
| frame.stack.pick() = val; |
| DEBUG_BYTECODE("var" << (int)varId << " -> stack (val = " << (int)frame.stack.pick().i << ")"); |
| frame.ip += 4; |
| } |
| |
| #define DEF_OPCODE_ALOAD_N(N) \ |
| static inline void \ |
| Opcode_ALOAD_ ## N(StackFrame& frame) { \ |
| Value& val = frame.locals(N); \ |
| ASSERT_TAGS(frame.locals.ref(N)); \ |
| frame.stack.push(); \ |
| frame.stack.pick() = val; \ |
| frame.stack.ref() = FLAG_OBJECT; \ |
| frame.stack.ref() = frame.locals.ref(N);\ |
| DEBUG_BYTECODE("var" #N " -> stack (val = " << (int)frame.stack.pick().i << ")"); \ |
| frame.ip++; \ |
| } |
| |
| DEF_OPCODE_ALOAD_N(0) // Opcode_ALOAD_0 |
| DEF_OPCODE_ALOAD_N(1) // Opcode_ALOAD_1 |
| DEF_OPCODE_ALOAD_N(2) // Opcode_ALOAD_2 |
| DEF_OPCODE_ALOAD_N(3) // Opcode_ALOAD_3 |
| |
| #define DEF_OPCODE_ILOAD_N(N) \ |
| static inline void \ |
| Opcode_ILOAD_ ## N(StackFrame& frame) { \ |
| Value& val = frame.locals(N); \ |
| ASSERT_TAGS(!frame.locals.ref(N)); \ |
| frame.stack.push(); \ |
| frame.stack.pick() = val; \ |
| DEBUG_BYTECODE("var" #N " -> stack (val = " << (int)frame.stack.pick().i << ")"); \ |
| frame.ip++; \ |
| } |
| |
| DEF_OPCODE_ILOAD_N(0) // Opcode_ILOAD_0 |
| DEF_OPCODE_ILOAD_N(1) // Opcode_ILOAD_1 |
| DEF_OPCODE_ILOAD_N(2) // Opcode_ILOAD_2 |
| DEF_OPCODE_ILOAD_N(3) // Opcode_ILOAD_3 |
| |
| static inline void |
| Opcode_LLOAD(StackFrame& frame) { |
| // store value to local variable |
| U_32 varId = read_uint8(frame.ip + 1); |
| |
| frame.stack.push(2); |
| frame.stack.pick(s1) = frame.locals(varId + l1); |
| frame.stack.pick(s0) = frame.locals(varId + l0); |
| ASSERT_TAGS(!frame.locals.ref(varId + 0)); |
| ASSERT_TAGS(!frame.locals.ref(varId + 1)); |
| |
| DEBUG_BYTECODE("stack -> var" << (int)varId); |
| frame.ip += 2; |
| } |
| |
| static inline void |
| Opcode_WIDE_LLOAD(StackFrame& frame) { |
| // store value to local variable |
| U_32 varId = read_uint16(frame.ip + 2); |
| |
| frame.stack.push(2); |
| frame.stack.pick(s1) = frame.locals(varId + l1); |
| frame.stack.pick(s0) = frame.locals(varId + l0); |
| ASSERT_TAGS(!frame.locals.ref(varId + 0)); |
| ASSERT_TAGS(!frame.locals.ref(varId + 1)); |
| |
| DEBUG_BYTECODE("stack -> var" << (int)varId); |
| frame.ip += 4; |
| } |
| |
| #define DEF_OPCODE_LLOAD_N(N) \ |
| static inline void \ |
| Opcode_LLOAD_ ## N(StackFrame& frame) { \ |
| frame.stack.push(2); \ |
| frame.stack.pick(s1) = frame.locals(N + l1); \ |
| frame.stack.pick(s0) = frame.locals(N + l0); \ |
| ASSERT_TAGS(!frame.locals.ref(N + 0)); \ |
| ASSERT_TAGS(!frame.locals.ref(N + 1)); \ |
| \ |
| DEBUG_BYTECODE("var" #N " -> stack"); \ |
| frame.ip++; \ |
| } |
| |
| DEF_OPCODE_LLOAD_N(0) // Opcode_LLOAD_0 |
| DEF_OPCODE_LLOAD_N(1) // Opcode_LLOAD_1 |
| DEF_OPCODE_LLOAD_N(2) // Opcode_LLOAD_2 |
| DEF_OPCODE_LLOAD_N(3) // Opcode_LLOAD_3 |
| |
| |
| |
| static inline void |
| Opcode_ASTORE(StackFrame& frame) { |
| Value &val = frame.stack.pick(); |
| ASSERT_TAGS(frame.stack.ref()); |
| |
| // store value to local variable |
| U_32 varId = read_uint8(frame.ip + 1); |
| frame.locals(varId) = val; |
| frame.locals.ref(varId) = frame.stack.ref(); |
| |
| frame.stack.ref() = FLAG_NONE; |
| frame.stack.pop(); |
| DEBUG_BYTECODE("stack -> var" << (int)varId); |
| frame.ip += 2; |
| } |
| |
| static inline void |
| Opcode_ISTORE(StackFrame& frame) { |
| Value &val = frame.stack.pick(); |
| ASSERT_TAGS(!frame.stack.ref()); |
| |
| // store value to local variable |
| U_32 varId = read_uint8(frame.ip + 1); |
| frame.locals(varId) = val; |
| frame.locals.ref(varId) = FLAG_NONE; |
| |
| frame.stack.pop(); |
| DEBUG_BYTECODE("stack -> var" << (int)varId); |
| frame.ip += 2; |
| } |
| |
| static inline void |
| Opcode_WIDE_ASTORE(StackFrame& frame) { |
| Value &val = frame.stack.pick(); |
| ASSERT_TAGS(frame.stack.ref()); |
| |
| // store value to local variable |
| U_32 varId = read_uint16(frame.ip + 2); |
| |
| frame.locals(varId) = val; |
| frame.locals.ref(varId) = frame.stack.ref(); |
| |
| frame.stack.ref() = FLAG_NONE; |
| frame.stack.pop(); |
| DEBUG_BYTECODE("stack -> var" << (int)varId); |
| frame.ip += 4; |
| } |
| |
| static inline void |
| Opcode_WIDE_ISTORE(StackFrame& frame) { |
| Value &val = frame.stack.pick(); |
| ASSERT_TAGS(!frame.stack.ref()); |
| |
| // store value to local variable |
| U_32 varId = read_uint16(frame.ip + 2); |
| frame.locals(varId) = val; |
| frame.locals.ref(varId) = FLAG_NONE; |
| |
| frame.stack.pop(); |
| DEBUG_BYTECODE("stack -> var" << (int)varId); |
| frame.ip += 4; |
| } |
| |
| #define DEF_OPCODE_ASTORE_N(N) \ |
| static inline void \ |
| Opcode_ASTORE_##N(StackFrame& frame) { \ |
| Value& val = frame.stack.pick(); \ |
| ASSERT_TAGS(frame.stack.ref()); \ |
| frame.locals(N) = val; \ |
| frame.locals.ref(N) = frame.stack.ref(); \ |
| frame.stack.ref() = FLAG_NONE; \ |
| frame.stack.pop(); \ |
| DEBUG_BYTECODE("stack -> var" #N ); \ |
| frame.ip++; \ |
| } |
| |
| DEF_OPCODE_ASTORE_N(0) // Opcode_ASTORE_0 |
| DEF_OPCODE_ASTORE_N(1) // Opcode_ASTORE_1 |
| DEF_OPCODE_ASTORE_N(2) // Opcode_ASTORE_2 |
| DEF_OPCODE_ASTORE_N(3) // Opcode_ASTORE_3 |
| |
| #define DEF_OPCODE_ISTORE_N(N) \ |
| static inline void \ |
| Opcode_ISTORE_##N(StackFrame& frame) { \ |
| Value& val = frame.stack.pick(); \ |
| ASSERT_TAGS(!frame.stack.ref()); \ |
| frame.locals(N) = val; \ |
| frame.locals.ref(N) = FLAG_NONE; \ |
| frame.stack.pop(); \ |
| DEBUG_BYTECODE("stack -> var" #N ); \ |
| frame.ip++; \ |
| } |
| |
| DEF_OPCODE_ISTORE_N(0) // Opcode_ASTORE_0 |
| DEF_OPCODE_ISTORE_N(1) // Opcode_ASTORE_1 |
| DEF_OPCODE_ISTORE_N(2) // Opcode_ASTORE_2 |
| DEF_OPCODE_ISTORE_N(3) // Opcode_ASTORE_3 |
| |
| static inline void |
| Opcode_LSTORE(StackFrame& frame) { |
| U_32 varId = read_uint8(frame.ip + 1); |
| ASSERT_TAGS(!frame.stack.ref(0)); |
| ASSERT_TAGS(!frame.stack.ref(1)); |
| frame.locals(varId + l1) = frame.stack.pick(s1); |
| frame.locals(varId + l0) = frame.stack.pick(s0); |
| frame.locals.ref(varId + 0) = FLAG_NONE; |
| frame.locals.ref(varId + 1) = FLAG_NONE; |
| frame.stack.pop(2); |
| DEBUG_BYTECODE("stack -> var" << (int)varId); |
| frame.ip += 2; |
| } |
| |
| static inline void |
| Opcode_WIDE_LSTORE(StackFrame& frame) { |
| U_32 varId = read_uint16(frame.ip + 2); |
| ASSERT_TAGS(!frame.stack.ref(0)); |
| ASSERT_TAGS(!frame.stack.ref(1)); |
| frame.locals(varId + l1) = frame.stack.pick(s1); |
| frame.locals(varId + l0) = frame.stack.pick(s0); |
| frame.locals.ref(varId + 0) = FLAG_NONE; |
| frame.locals.ref(varId + 1) = FLAG_NONE; |
| frame.stack.pop(2); |
| DEBUG_BYTECODE("stack -> var" << (int)varId); |
| frame.ip += 4; |
| } |
| |
| #define DEF_OPCODE_LSTORE_N(N) \ |
| static inline void \ |
| Opcode_LSTORE_ ## N(StackFrame& frame) { \ |
| ASSERT_TAGS(!frame.stack.ref(0)); \ |
| ASSERT_TAGS(!frame.stack.ref(1)); \ |
| frame.locals(N + l1) = frame.stack.pick(s1); \ |
| frame.locals(N + l0) = frame.stack.pick(s0); \ |
| frame.locals.ref(N + 0) = FLAG_NONE; \ |
| frame.locals.ref(N + 1) = FLAG_NONE; \ |
| frame.stack.pop(2); \ |
| DEBUG_BYTECODE("stack -> var" #N); \ |
| frame.ip++; \ |
| } |
| |
| DEF_OPCODE_LSTORE_N(0) // Opcode_LSTORE_0 |
| DEF_OPCODE_LSTORE_N(1) // Opcode_LSTORE_1 |
| DEF_OPCODE_LSTORE_N(2) // Opcode_LSTORE_2 |
| DEF_OPCODE_LSTORE_N(3) // Opcode_LSTORE_3 |
| |
| #if defined (__INTEL_COMPILER) |
| #pragma warning(push) |
| #pragma warning (disable:1572) // conversion from pointer to same-sized integral type (potential portability problem) |
| #endif |
| |
| static inline int |
| fcmpl(float a, float b) { |
| if (a > b) return 1; |
| if (a == b) return 0; |
| return -1; |
| } |
| |
| static inline int |
| fcmpg(float a, float b) { |
| if (a < b) return -1; |
| if (a == b) return 0; |
| return 1; |
| } |
| |
| static inline int |
| dcmpl(double a, double b) { |
| if (a > b) return 1; |
| if (a == b) return 0; |
| return -1; |
| } |
| |
| static inline int |
| dcmpg(double a, double b) { |
| if (a < b) return -1; |
| if (a == b) return 0; |
| return 1; |
| } |
| #if defined (__INTEL_COMPILER) |
| #pragma warning(pop) |
| #endif |
| |
| |
| #define DEF_OPCODE_MATH_32_32_TO_32(CODE, expr) \ |
| static inline void \ |
| Opcode_##CODE(StackFrame& frame) { \ |
| Value& arg0 = frame.stack.pick(0); \ |
| Value& arg1 = frame.stack.pick(1); \ |
| Value& res = arg1; \ |
| DEBUG_BYTECODE("(" << arg1.i << ", "); \ |
| expr; \ |
| DEBUG_BYTECODE(arg0.i << " ) = " << res.i); \ |
| frame.stack.pop(); \ |
| frame.ip++; \ |
| } |
| |
| #define DEF_OPCODE_MATH_32_TO_32(CODE, expr) \ |
| static inline void \ |
| Opcode_## CODE(StackFrame& frame) { \ |
| Value& arg = frame.stack.pick(0); \ |
| Value& res = arg; \ |
| expr; \ |
| frame.ip++; \ |
| } |
| |
| #define DEF_OPCODE_MATH_32_TO_64(OPCODE, expr) \ |
| static inline void \ |
| Opcode_ ## OPCODE(StackFrame& frame) { \ |
| Value& arg = frame.stack.pick(); \ |
| Value2 res; \ |
| expr; \ |
| frame.stack.push(); \ |
| frame.stack.setLong(0, res); \ |
| frame.ip++; \ |
| } |
| |
| #define DEF_OPCODE_MATH_64_TO_64(OPCODE, expr) \ |
| static inline void \ |
| Opcode_ ## OPCODE(StackFrame& frame) { \ |
| Value2 arg, res; \ |
| arg = frame.stack.getLong(0); \ |
| expr; \ |
| frame.stack.setLong(0, res); \ |
| frame.ip++; \ |
| } |
| |
| #define DEF_OPCODE_MATH_64_64_TO_64(CODE, expr) \ |
| static inline void \ |
| Opcode_ ## CODE(StackFrame& frame) { \ |
| Value2 arg0, arg1, res; \ |
| arg0 = frame.stack.getLong(0); \ |
| arg1 = frame.stack.getLong(2); \ |
| frame.stack.pop(2); \ |
| expr; \ |
| frame.stack.setLong(0, res); \ |
| DEBUG_BYTECODE("(" << arg0.d << ", " << arg1.d << ") = " << res.d); \ |
| frame.ip++; \ |
| } |
| |
| #define DEF_OPCODE_MATH_64_64_TO_32(CODE, expr) \ |
| static inline void \ |
| Opcode_ ## CODE(StackFrame& frame) { \ |
| Value2 arg0, arg1; \ |
| Value res; \ |
| arg0 = frame.stack.getLong(0); \ |
| arg1 = frame.stack.getLong(2); \ |
| frame.stack.pop(3); \ |
| expr; \ |
| frame.stack.pick() = res; \ |
| DEBUG_BYTECODE("(" << arg0.d << ", " << arg1.d << ") = " << res.i); \ |
| frame.ip++; \ |
| } |
| |
| #define DEF_OPCODE_MATH_64_TO_32(CODE,expr) \ |
| static inline void \ |
| Opcode_ ## CODE(StackFrame& frame) { \ |
| Value2 arg; \ |
| Value res; \ |
| arg = frame.stack.getLong(0); \ |
| expr; \ |
| frame.stack.pop(); \ |
| frame.stack.pick() = res; \ |
| frame.ip++; \ |
| } |
| |
| #define DEF_OPCODE_MATH_64_32_TO_64(CODE, expr) \ |
| static inline void \ |
| Opcode_ ## CODE(StackFrame& frame) { \ |
| Value arg0; \ |
| Value2 arg1, res; \ |
| arg0 = frame.stack.pick(0); \ |
| arg1 = frame.stack.getLong(1); \ |
| frame.stack.pop(); \ |
| expr; \ |
| frame.stack.setLong(0, res); \ |
| frame.ip++; \ |
| } |
| |
| |
| DEF_OPCODE_MATH_32_32_TO_32(IADD, res.i = arg1.i + arg0.i) // Opcode_IADD |
| DEF_OPCODE_MATH_32_32_TO_32(ISUB, res.i = arg1.i - arg0.i) // Opcode_ISUB |
| DEF_OPCODE_MATH_32_32_TO_32(IMUL, res.i = arg1.i * arg0.i) // Opcode_IMUL |
| DEF_OPCODE_MATH_32_32_TO_32(IOR, res.i = arg1.i | arg0.i) // Opcode_IOR |
| DEF_OPCODE_MATH_32_32_TO_32(IAND, res.i = arg1.i & arg0.i) // Opcode_IAND |
| DEF_OPCODE_MATH_32_32_TO_32(IXOR, res.i = arg1.i ^ arg0.i) // Opcode_IXOR |
| DEF_OPCODE_MATH_32_32_TO_32(ISHL, res.i = arg1.i << (arg0.i & 0x1f)) // Opcode_ISHL |
| DEF_OPCODE_MATH_32_32_TO_32(ISHR, res.i = arg1.i >> (arg0.i & 0x1f)) // Opcode_ISHR |
| DEF_OPCODE_MATH_32_32_TO_32(IUSHR, res.i = ((U_32)arg1.i) >> (arg0.i & 0x1f)) // Opcode_IUSHR |
| |
| DEF_OPCODE_MATH_32_32_TO_32(FADD, res.f = arg1.f + arg0.f) // Opcode_FADD |
| DEF_OPCODE_MATH_32_32_TO_32(FSUB, res.f = arg1.f - arg0.f) // Opcode_FSUB |
| DEF_OPCODE_MATH_32_32_TO_32(FMUL, res.f = arg1.f * arg0.f) // Opcode_FMUL |
| DEF_OPCODE_MATH_32_32_TO_32(FDIV, res.f = arg1.f / arg0.f) // Opcode_FDIV |
| // FIXME: is it correct? bitness is ok? |
| DEF_OPCODE_MATH_32_32_TO_32(FREM, res.f = fmodf(arg1.f, arg0.f)) // Opcode_FREM |
| |
| DEF_OPCODE_MATH_64_64_TO_64(LADD, res.i64 = arg1.i64 + arg0.i64) |
| DEF_OPCODE_MATH_64_64_TO_64(LSUB, res.i64 = arg1.i64 - arg0.i64) |
| DEF_OPCODE_MATH_64_64_TO_64(LMUL, res.i64 = arg1.i64 * arg0.i64) |
| DEF_OPCODE_MATH_64_64_TO_64(LOR, res.i64 = arg1.i64 | arg0.i64) |
| DEF_OPCODE_MATH_64_64_TO_64(LAND, res.i64 = arg1.i64 & arg0.i64) |
| DEF_OPCODE_MATH_64_64_TO_64(LXOR, res.i64 = arg1.i64 ^ arg0.i64) |
| |
| DEF_OPCODE_MATH_64_64_TO_64(DADD, res.d = arg1.d + arg0.d) |
| DEF_OPCODE_MATH_64_64_TO_64(DSUB, res.d = arg1.d - arg0.d) |
| DEF_OPCODE_MATH_64_64_TO_64(DMUL, res.d = arg1.d * arg0.d) |
| DEF_OPCODE_MATH_64_64_TO_64(DDIV, res.d = arg1.d / arg0.d) |
| DEF_OPCODE_MATH_64_64_TO_64(DREM, res.d = fmod(arg1.d, arg0.d)) |
| |
| DEF_OPCODE_MATH_64_32_TO_64(LSHL, res.i64 = arg1.i64 << (arg0.i & 0x3f)) |
| DEF_OPCODE_MATH_64_32_TO_64(LSHR, res.i64 = arg1.i64 >> (arg0.i & 0x3f)) |
| DEF_OPCODE_MATH_64_32_TO_64(LUSHR, res.i64 = ((uint64)arg1.i64) >> (arg0.i & 0x3f)) // Opcode_LUSHR |
| |
| DEF_OPCODE_MATH_32_32_TO_32(FCMPL, res.i = fcmpl(arg1.f, arg0.f)) // Opcode_FCMPL |
| DEF_OPCODE_MATH_32_32_TO_32(FCMPG, res.i = fcmpg(arg1.f, arg0.f)) // Opcode_FCMPG |
| DEF_OPCODE_MATH_64_64_TO_32(DCMPL, res.i = dcmpl(arg1.d, arg0.d)) // Opcode_FCMPL |
| DEF_OPCODE_MATH_64_64_TO_32(DCMPG, res.i = dcmpg(arg1.d, arg0.d)) // Opcode_FCMPG |
| |
| |
| DEF_OPCODE_MATH_32_TO_32(INEG, res.i = -arg.i) // Opcode_INEG |
| DEF_OPCODE_MATH_32_TO_32(FNEG, res.f = -arg.f) // Opcode_FNEG |
| DEF_OPCODE_MATH_64_TO_64(LNEG, res.i64 = -arg.i64) // Opcode_LNEG |
| DEF_OPCODE_MATH_64_TO_64(DNEG, res.d = -arg.d) // Opcode_DNEG |
| |
| |
| DEF_OPCODE_MATH_32_TO_32(I2F, res.f = (float) arg.i) // Opcode_I2F |
| //DEF_OPCODE_MATH_32_TO_32(F2I, res.i = (I_32) arg.f) // Opcode_F2I |
| DEF_OPCODE_MATH_32_TO_32(I2B, res.i = (I_8) arg.i) // Opcode_I2B |
| DEF_OPCODE_MATH_32_TO_32(I2S, res.i = (int16) arg.i) // Opcode_I2S |
| DEF_OPCODE_MATH_32_TO_32(I2C, res.i = (uint16) arg.i) // Opcode_I2C |
| |
| DEF_OPCODE_MATH_32_TO_64(I2L, res.i64 = (int64) arg.i) // Opcode_I2L |
| DEF_OPCODE_MATH_32_TO_64(I2D, res.d = (double) arg.i) // Opcode_I2D |
| //DEF_OPCODE_MATH_32_TO_64(F2L, res.i64 = (int64) arg.f) // Opcode_F2L |
| DEF_OPCODE_MATH_32_TO_64(F2D, res.d = (double) arg.f) // Opcode_F2D |
| |
| DEF_OPCODE_MATH_64_TO_64(L2D, res.d = (double) arg.i64) // Opcode_L2D |
| //DEF_OPCODE_MATH_64_TO_64(D2L, res.i64 = (int64) arg.d) // Opcode_D2L |
| |
| #if defined (__INTEL_COMPILER) |
| #pragma warning( push ) |
| #pragma warning (disable:1683) // to get rid of remark #1683: explicit conversion of a 64-bit integral type to a smaller integral type |
| #endif |
| |
| DEF_OPCODE_MATH_64_TO_32(D2F, res.f = (float) arg.d) // Opcode_D2F |
| //DEF_OPCODE_MATH_64_TO_32(D2I, res.i = (I_32) arg.d) // Opcode_D2I |
| DEF_OPCODE_MATH_64_TO_32(L2F, res.f = (float) arg.i64) // Opcode_L2F |
| DEF_OPCODE_MATH_64_TO_32(L2I, res.i = (I_32) arg.i64) // Opcode_L2I |
| |
| #if defined (__INTEL_COMPILER) |
| #pragma warning( pop ) |
| #endif |
| |
| static inline void |
| Opcode_D2I(StackFrame& frame) { |
| Value2 arg; |
| Value res; |
| arg = frame.stack.getLong(0); |
| |
| int64 val = arg.i64; |
| int64 exponent = val & ((int64)0x7FF << 52); |
| int64 max_exp = ((int64)0x3FF + 31) << 52; |
| |
| if (exponent < max_exp) { |
| res.i = (int) arg.d; |
| } else { |
| if (isnan(arg.d)) { |
| res.i = 0; |
| } else if (arg.d > 0) { |
| res.i = (I_32)2147483647; |
| } else { |
| res.i = (I_32)2147483648u; |
| } |
| } |
| |
| frame.stack.pop(); |
| frame.stack.pick() = res; |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_F2I(StackFrame& frame) { |
| Value& arg = frame.stack.pick(0); |
| |
| int val = arg.i; |
| int exponent = val & (0xFF << 23); |
| int max_exp = (0x7F + 31) << 23; |
| |
| if (exponent < max_exp) { |
| arg.i = (I_32) arg.f; |
| } else { |
| if (isnan(arg.f)) { |
| arg.i = 0; |
| } else if (arg.f > 0) { |
| arg.i = (I_32)2147483647; |
| } else { |
| arg.i = (I_32)2147483648u; |
| } |
| } |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_D2L(StackFrame& frame) { |
| Value2 arg; |
| Value2 res; |
| arg = frame.stack.getLong(0); |
| |
| int64 val = arg.i64; |
| int64 exponent = val & ((int64)0x7FF << 52); |
| int64 max_exp = ((int64)0x3FF + 63) << 52; |
| |
| if (exponent < max_exp) { |
| res.i64 = (int64) arg.d; |
| } else { |
| if (isnan(arg.d)) { |
| res.i64 = (int64) 0; |
| } else if (arg.d > 0) { |
| res.i64 = (int64)(((uint64)(int64)-1) >> 1); // 7FFFF...... |
| } else { |
| res.i64 = ((int64)-1) << 63; // 80000...... |
| } |
| } |
| |
| frame.stack.setLong(0, res); |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_F2L(StackFrame& frame) { |
| Value arg; |
| Value2 res; |
| arg = frame.stack.pick(0); |
| |
| int val = arg.i; |
| int exponent = val & (0xFF << 23); |
| int max_exp = (0x7F + 63) << 23; |
| |
| if (exponent < max_exp) { |
| res.i64 = (int64) arg.f; |
| } else { |
| if (isnan(arg.f)) { |
| res.i64 = (int64) 0; |
| } else if (arg.f > 0) { |
| res.i64 = (int64)(((uint64)(int64)-1) >> 1); // 7FFFF...... |
| } else { |
| res.i64 = ((int64)-1) << 63; // 80000...... |
| } |
| } |
| |
| frame.stack.push(); |
| frame.stack.setLong(0, res); |
| frame.ip++; |
| } |
| |
| #define DEF_OPCODE_DIV_32_32_TO_32(CODE, expr) \ |
| static inline void \ |
| Opcode_##CODE(StackFrame& frame) { \ |
| Value& arg0 = frame.stack.pick(0); \ |
| if (arg0.i == 0) { \ |
| interp_throw_exception("java/lang/ArithmeticException"); \ |
| return; \ |
| } \ |
| Value& arg1 = frame.stack.pick(1); \ |
| Value& res = arg1; \ |
| expr; \ |
| frame.stack.pop(); \ |
| frame.ip++; \ |
| } |
| |
| #if defined (__INTEL_COMPILER) |
| #pragma warning( push ) |
| #pragma warning (disable:1683) // to get rid of remark #1683: explicit conversion of a 64-bit integral type to a smaller integral type |
| #endif |
| |
| DEF_OPCODE_DIV_32_32_TO_32(IDIV, res.i = (I_32)((int64) arg1.i / arg0.i)) // Opcode_IDIV |
| DEF_OPCODE_DIV_32_32_TO_32(IREM, res.i = (I_32)((int64) arg1.i % arg0.i)) // Opcode_IREM |
| |
| #if defined (__INTEL_COMPILER) |
| #pragma warning( pop ) |
| #endif |
| |
| static inline void |
| Opcode_LDIV(StackFrame& frame) { |
| Value2 arg0, arg1, res; |
| arg0 = frame.stack.getLong(0); |
| if (arg0.i64 == 0) { |
| interp_throw_exception("java/lang/ArithmeticException"); |
| return; |
| } |
| arg1 = frame.stack.getLong(2); |
| frame.stack.pop(2); |
| |
| #ifdef HYX86_64 |
| if (arg1.i64 == -arg1.i64) { |
| if (arg0.i64 == -1) { |
| res.i64 = arg1.i64; |
| frame.stack.setLong(0, res); |
| frame.ip++; |
| return; |
| } |
| } |
| #endif |
| res.i64 = arg1.i64 / arg0.i64; |
| frame.stack.setLong(0, res); |
| frame.ip++; |
| } |
| static inline void |
| Opcode_LREM(StackFrame& frame) { |
| Value2 arg0, arg1, res; |
| arg0 = frame.stack.getLong(0); |
| if (arg0.i64 == 0) { |
| interp_throw_exception("java/lang/ArithmeticException"); |
| return; |
| } |
| arg1 = frame.stack.getLong(2); |
| frame.stack.pop(2); |
| #ifdef HYX86_64 |
| if (arg1.i64 == -arg1.i64) { |
| if (arg0.i64 == -1) { |
| res.i64 = 0l; |
| frame.stack.setLong(0, res); |
| frame.ip++; |
| return; |
| } |
| } |
| #endif |
| res.i64 = arg1.i64 % arg0.i64; |
| frame.stack.setLong(0, res); |
| frame.ip++; |
| } |
| |
| #define DEF_OPCODE_CMP(CMP,check) \ |
| static inline void \ |
| Opcode_##CMP(StackFrame& frame) { \ |
| I_32 val = frame.stack.pick().i; \ |
| frame.stack.ref() = FLAG_NONE; /* for OPCODE_IFNULL */ \ |
| DEBUG_BYTECODE("val = " << (int)val); \ |
| if (val check) { \ |
| frame.ip += read_int16(frame.ip + 1); \ |
| DEBUG_BYTECODE(", going to instruction"); \ |
| } else { \ |
| DEBUG_BYTECODE(", false condition"); \ |
| frame.ip += 3; \ |
| } \ |
| frame.stack.pop(); \ |
| hythread_safe_point(); \ |
| hythread_exception_safe_point(); \ |
| } |
| |
| DEF_OPCODE_CMP(IFEQ,==0) // Opcode_IFEQ |
| DEF_OPCODE_CMP(IFNE,!=0) // Opcode_IFNE |
| DEF_OPCODE_CMP(IFGE,>=0) // Opcode_IFGE |
| DEF_OPCODE_CMP(IFGT,>0) // Opcode_IFGT |
| DEF_OPCODE_CMP(IFLE,<=0) // Opcode_IFLE |
| DEF_OPCODE_CMP(IFLT,<0) // Opcode_IFLT |
| |
| #define DEF_OPCODE_IF_ICMPXX(NAME,cmp) \ |
| static inline void \ |
| Opcode_IF_ICMP ## NAME(StackFrame& frame) { \ |
| I_32 val0 = frame.stack.pick(1).i; \ |
| I_32 val1 = frame.stack.pick(0).i; \ |
| frame.stack.ref(1) = FLAG_NONE; \ |
| frame.stack.ref(0) = FLAG_NONE; \ |
| if (val0 cmp val1) { \ |
| frame.ip += read_int16(frame.ip + 1); \ |
| DEBUG_BYTECODE(val1 << " " << val0 << " branch taken"); \ |
| } else { \ |
| frame.ip += 3; \ |
| DEBUG_BYTECODE(val1 << " " << val0 << " branch not taken");\ |
| } \ |
| frame.stack.pop(2); \ |
| hythread_safe_point(); \ |
| hythread_exception_safe_point(); \ |
| } |
| |
| DEF_OPCODE_IF_ICMPXX(EQ,==) // Opcode_IF_ICMPEQ OPCODE_IF_ACMPEQ |
| DEF_OPCODE_IF_ICMPXX(NE,!=) // Opcode_IF_ICMPNE OPCODE_IF_ACMPNE |
| DEF_OPCODE_IF_ICMPXX(GE,>=) // Opcode_IF_ICMPGE |
| DEF_OPCODE_IF_ICMPXX(GT,>) // Opcode_IF_ICMPGT |
| DEF_OPCODE_IF_ICMPXX(LE,<=) // Opcode_IF_ICMPLE |
| DEF_OPCODE_IF_ICMPXX(LT,<) // Opcode_IF_ICMPLT |
| |
| |
| static inline void |
| Opcode_LCMP(StackFrame& frame) { |
| Value2 v0, v1; |
| int res; |
| v1 = frame.stack.getLong(0); |
| v0 = frame.stack.getLong(2); |
| if (v0.i64 < v1.i64) res = -1; |
| else if (v0.i64 == v1.i64) res = 0; |
| else res = 1; |
| frame.stack.pop(3); |
| frame.stack.pick().i = res; |
| DEBUG_BYTECODE("res = " << res); |
| frame.ip++; |
| } |
| |
| static bool |
| ldc(StackFrame& frame, U_32 index) { |
| Class* clazz = frame.method->get_class(); |
| ConstantPool& cp = clazz->get_constant_pool(); |
| |
| #ifndef NDEBUG |
| switch(cp.get_tag(index)) { |
| case CONSTANT_String: |
| DEBUG_BYTECODE("#" << (int)index << " String: \"" << cp.get_string_chars(index) << "\""); |
| break; |
| case CONSTANT_Integer: |
| DEBUG_BYTECODE("#" << (int)index << " Integer: " << (int)cp.get_int(index)); |
| break; |
| case CONSTANT_Float: |
| DEBUG_BYTECODE("#" << (int)index << " Float: " << cp.get_float(index)); |
| break; |
| case CONSTANT_Class: |
| DEBUG_BYTECODE("#" << (int)index << " Class: \"" << class_cp_get_class_name(clazz, index) << "\""); |
| break; |
| default: |
| DEBUG_BYTECODE("#" << (int)index << " Unknown type = " << cp.get_tag(index)); |
| LDIE(4, "ldc instruction: unexpected type ({0}) of constant pool entry [{1}]" |
| << cp.get_tag(index) << index); |
| break; |
| } |
| #endif |
| |
| frame.stack.push(); |
| if(cp.is_string(index)) |
| { |
| String* str = cp.get_string(index); |
| frame.stack.pick().ref = COMPRESS_INTERP(vm_instantiate_cp_string_resolved(str)); |
| frame.stack.ref() = FLAG_OBJECT; |
| return !check_current_thread_exception(); |
| } |
| else if (cp.is_class(index)) |
| { |
| Class *other_class = interp_resolve_class(clazz, index); |
| if (!other_class) { |
| return false; |
| } |
| assert(!hythread_is_suspend_enabled()); |
| |
| frame.stack.pick().ref = COMPRESS_INTERP(*(other_class->get_class_handle())); |
| frame.stack.ref() = FLAG_OBJECT; |
| |
| return !exn_raised(); |
| } |
| |
| frame.stack.pick().u = cp.get_4byte(index); |
| return true; |
| } |
| |
| |
| static inline void |
| Opcode_LDC(StackFrame& frame) { |
| U_32 index = read_uint8(frame.ip + 1); |
| if (!ldc(frame, index)) return; |
| frame.ip += 2; |
| } |
| |
| static inline void |
| Opcode_LDC_W(StackFrame& frame) { |
| U_32 index = read_uint16(frame.ip + 1); |
| if(!ldc(frame, index)) return; |
| frame.ip += 3; |
| } |
| |
| static inline void |
| Opcode_LDC2_W(StackFrame& frame) { |
| U_32 index = read_uint16(frame.ip + 1); |
| |
| Class *clazz = frame.method->get_class(); |
| ConstantPool& cp = clazz->get_constant_pool(); |
| frame.stack.push(2); |
| Value2 val; |
| val.u64 = ((uint64)cp.get_8byte_high_word(index) << 32) |
| | cp.get_8byte_low_word(index); |
| frame.stack.setLong(0, val); |
| DEBUG_BYTECODE("#" << (int)index << " (val = " << val.d << ")"); |
| frame.ip += 3; |
| } |
| |
| // TODO ivan 20041005: check if the types defined somewhere else |
| enum ArrayElementType { |
| AR_BOOLEAN = 4, // values makes sense for opcode NEWARRAY |
| AR_CHAR, |
| AR_FLOAT, |
| AR_DOUBLE, |
| AR_BYTE, |
| AR_SHORT, |
| AR_INT, |
| AR_LONG |
| }; |
| |
| static inline void |
| Opcode_NEWARRAY(StackFrame& frame) { |
| int type = read_int8(frame.ip + 1); |
| Class *clazz = NULL; |
| |
| // TODO ivan 20041005: can be optimized, rely on order |
| Global_Env *env = VM_Global_State::loader_env; |
| switch (type) { |
| case AR_BOOLEAN: clazz = env->ArrayOfBoolean_Class; break; |
| case AR_CHAR: clazz = env->ArrayOfChar_Class; break; |
| case AR_FLOAT: clazz = env->ArrayOfFloat_Class; break; |
| case AR_DOUBLE: clazz = env->ArrayOfDouble_Class; break; |
| case AR_BYTE: clazz = env->ArrayOfByte_Class; break; |
| case AR_SHORT: clazz = env->ArrayOfShort_Class; break; |
| case AR_INT: clazz = env->ArrayOfInt_Class; break; |
| case AR_LONG: clazz = env->ArrayOfLong_Class; break; |
| default: DIE(("Invalid array type")); |
| } |
| assert(clazz); |
| |
| // TODO: is it possible to optimize? |
| // array data size = length << (type & 3); |
| // how it can be usable? |
| I_32 length = frame.stack.pick().i; |
| |
| if (length < 0) { |
| interp_throw_exception("java/lang/NegativeArraySizeException"); |
| return; |
| } |
| |
| Vector_Handle array = vm_new_vector_primitive(clazz,length); |
| if (check_current_thread_exception()) { |
| // OutOfMemoryError occured |
| return; |
| } |
| |
| frame.stack.pick().ref = COMPRESS_INTERP((ManagedObject*)array); |
| DEBUG_BYTECODE(" (val = " << (int)frame.stack.pick().i << ")"); |
| frame.stack.ref() = FLAG_OBJECT; |
| frame.ip += 2; |
| } |
| |
| static inline void |
| Opcode_ANEWARRAY(StackFrame& frame) { |
| int classId = read_uint16(frame.ip + 1); |
| Class *clazz = frame.method->get_class(); |
| |
| Class *objClass = interp_resolve_class(clazz, classId); |
| if (!objClass) return; // exception |
| |
| Class *arrayClass = interp_class_get_array_of_class(objClass); |
| |
| I_32 length = frame.stack.pick().i; |
| |
| if (length < 0) { |
| interp_throw_exception("java/lang/NegativeArraySizeException"); |
| return; |
| } |
| |
| |
| Vector_Handle array = vm_new_vector(arrayClass, length); |
| if (check_current_thread_exception()) { |
| // OutOfMemoryError occured |
| return; |
| } |
| |
| set_vector_length(array, length); |
| DEBUG_BYTECODE("length = " << length); |
| |
| frame.stack.pick().ref = COMPRESS_INTERP((ManagedObject*)array); |
| frame.stack.ref() = FLAG_OBJECT; |
| frame.ip += 3; |
| } |
| |
| static inline bool |
| allocDimensions(StackFrame& frame, Class *arrayClass, int depth) { |
| |
| int *length = (int*)ALLOC_FRAME(sizeof(int) * (depth)); |
| int *pos = (int*)ALLOC_FRAME(sizeof(int) * (depth)); |
| Class **clss = (Class**)ALLOC_FRAME(sizeof(Class*) * (depth)); |
| int d; |
| int max_depth = depth - 1; |
| |
| // check dimensions phase |
| for(d = 0; d < depth; d++) { |
| pos[d] = 0; |
| int len = length[d] = frame.stack.pick(depth - 1 - d).i; |
| |
| if (len < 0) { |
| interp_throw_exception("java/lang/NegativeArraySizeException"); |
| return false; |
| } |
| |
| if (len == 0) { |
| if (d < max_depth) max_depth = d; |
| } |
| |
| frame.stack.pick(depth - 1 - d).ref = 0; |
| frame.stack.ref(depth - 1 - d) = FLAG_OBJECT; |
| } |
| |
| // init Class* array |
| Class *c = clss[0] = arrayClass; |
| |
| for(d = 1; d < depth; d++) { |
| c = c->get_array_element_class(); |
| clss[d] = c; |
| } |
| |
| // init root element |
| ManagedObject* array = (ManagedObject*) vm_new_vector(clss[0], length[0]); |
| if (check_current_thread_exception()) { |
| // OutOfMemoryError occured |
| return false; |
| } |
| set_vector_length(array, length[0]); |
| frame.stack.pick(depth - 1).ref = COMPRESS_INTERP(array); |
| if (max_depth == 0) return true; |
| |
| d = 1; |
| // allocation dimensions |
| while(true) { |
| ManagedObject *element = (ManagedObject*) vm_new_vector(clss[d], length[d]); |
| if (check_current_thread_exception()) { |
| // OutOfMemoryError occured |
| return false; |
| } |
| |
| set_vector_length(element, length[d]); |
| |
| if (d != max_depth) { |
| frame.stack.pick(depth - 1 - d).ref = COMPRESS_INTERP(element); |
| d++; |
| continue; |
| } |
| |
| while(true) { |
| array = UNCOMPRESS_INTERP(frame.stack.pick((depth - 1) - (d - 1)).ref); |
| // addr can be a pointer to either ManagedObject* or COMPRESSED_REFERENCE |
| ManagedObject** addr = get_vector_element_address_ref(array, pos[d-1]); |
| |
| STORE_UREF_BY_ADDR(addr, element); |
| pos[d-1]++; |
| |
| if (pos[d-1] < length[d-1]) { |
| break; |
| } |
| |
| pos[d-1] = 0; |
| element = array; |
| d--; |
| |
| if (d == 0) return true; |
| } |
| } |
| } |
| |
| static inline void |
| Opcode_MULTIANEWARRAY(StackFrame& frame) { |
| int classId = read_uint16(frame.ip + 1); |
| int depth = read_uint8(frame.ip + 3); |
| Class *clazz = frame.method->get_class(); |
| |
| Class *arrayClass = interp_resolve_class(clazz, classId); |
| if (!arrayClass) return; // exception |
| |
| DEBUG_BYTECODE(class_get_name(arrayClass) << " " << depth); |
| |
| bool success = allocDimensions(frame, arrayClass, depth); |
| if (!success) { |
| return; |
| } |
| |
| frame.stack.popClearRef(depth - 1); |
| DEBUG_BYTECODE(" (val = " << (int)frame.stack.pick().i << ")"); |
| frame.ip += 4; |
| } |
| |
| static inline void |
| Opcode_NEW(StackFrame& frame) { |
| U_32 classId = read_uint16(frame.ip + 1); |
| Class *clazz = frame.method->get_class(); |
| |
| Class *objClass = interp_resolve_class_new(clazz, classId); |
| if (!objClass) return; // exception |
| |
| DEBUG_BYTECODE("cless = " << class_get_name(objClass)); |
| |
| class_initialize(objClass); |
| |
| if (check_current_thread_exception()) { |
| return; |
| } |
| |
| ManagedObject *obj = class_alloc_new_object(objClass); |
| |
| if (check_current_thread_exception()) { |
| // OutOfMemoryError occured |
| return; |
| } |
| |
| assert(obj); |
| |
| frame.stack.push(); |
| |
| frame.stack.pick().ref = COMPRESS_INTERP(obj); |
| DEBUG_BYTECODE(" (val = " << (int)frame.stack.pick().i << ")"); |
| frame.stack.ref() = FLAG_OBJECT; |
| frame.ip += 3; |
| } |
| |
| static inline void |
| Opcode_POP(StackFrame& frame) { |
| frame.stack.ref() = FLAG_NONE; |
| frame.stack.pop(); |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_POP2(StackFrame& frame) { |
| frame.stack.ref(0) = FLAG_NONE; |
| frame.stack.ref(1) = FLAG_NONE; |
| frame.stack.pop(2); |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_SWAP(StackFrame& frame) { |
| Value tmp = frame.stack.pick(0); |
| frame.stack.pick(0) = frame.stack.pick(1); |
| frame.stack.pick(1) = tmp; |
| |
| U_8 ref = frame.stack.ref(0); |
| frame.stack.ref(0) = frame.stack.ref(1); |
| frame.stack.ref(1) = ref; |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_DUP(StackFrame& frame) { |
| frame.stack.push(); |
| frame.stack.pick(0) = frame.stack.pick(1); |
| frame.stack.ref(0) = frame.stack.ref(1); |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_DUP2(StackFrame& frame) { |
| frame.stack.push(2); |
| frame.stack.pick(0) = frame.stack.pick(2); |
| frame.stack.pick(1) = frame.stack.pick(3); |
| |
| frame.stack.ref(0) = frame.stack.ref(2); |
| frame.stack.ref(1) = frame.stack.ref(3); |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_DUP_X1(StackFrame& frame) { |
| frame.stack.push(); |
| frame.stack.pick(0) = frame.stack.pick(1); |
| frame.stack.pick(1) = frame.stack.pick(2); |
| frame.stack.pick(2) = frame.stack.pick(0); |
| |
| frame.stack.ref(0) = frame.stack.ref(1); |
| frame.stack.ref(1) = frame.stack.ref(2); |
| frame.stack.ref(2) = frame.stack.ref(0); |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_DUP_X2(StackFrame& frame) { |
| frame.stack.push(); |
| frame.stack.pick(0) = frame.stack.pick(1); |
| frame.stack.pick(1) = frame.stack.pick(2); |
| frame.stack.pick(2) = frame.stack.pick(3); |
| frame.stack.pick(3) = frame.stack.pick(0); |
| |
| frame.stack.ref(0) = frame.stack.ref(1); |
| frame.stack.ref(1) = frame.stack.ref(2); |
| frame.stack.ref(2) = frame.stack.ref(3); |
| frame.stack.ref(3) = frame.stack.ref(0); |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_DUP2_X1(StackFrame& frame) { |
| frame.stack.push(2); |
| frame.stack.pick(0) = frame.stack.pick(2); |
| frame.stack.pick(1) = frame.stack.pick(3); |
| frame.stack.pick(2) = frame.stack.pick(4); |
| frame.stack.pick(3) = frame.stack.pick(0); |
| frame.stack.pick(4) = frame.stack.pick(1); |
| |
| frame.stack.ref(0) = frame.stack.ref(2); |
| frame.stack.ref(1) = frame.stack.ref(3); |
| frame.stack.ref(2) = frame.stack.ref(4); |
| frame.stack.ref(3) = frame.stack.ref(0); |
| frame.stack.ref(4) = frame.stack.ref(1); |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_DUP2_X2(StackFrame& frame) { |
| frame.stack.push(2); |
| frame.stack.pick(0) = frame.stack.pick(2); |
| frame.stack.pick(1) = frame.stack.pick(3); |
| frame.stack.pick(2) = frame.stack.pick(4); |
| frame.stack.pick(3) = frame.stack.pick(5); |
| frame.stack.pick(4) = frame.stack.pick(0); |
| frame.stack.pick(5) = frame.stack.pick(1); |
| |
| frame.stack.ref(0) = frame.stack.ref(2); |
| frame.stack.ref(1) = frame.stack.ref(3); |
| frame.stack.ref(2) = frame.stack.ref(4); |
| frame.stack.ref(3) = frame.stack.ref(5); |
| frame.stack.ref(4) = frame.stack.ref(0); |
| frame.stack.ref(5) = frame.stack.ref(1); |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_IINC(StackFrame& frame) { |
| U_32 varNum = read_uint8(frame.ip + 1); |
| int incr = read_int8(frame.ip + 2); |
| frame.locals(varNum).i += incr; |
| DEBUG_BYTECODE("var" << (int)varNum << " += " << incr); |
| frame.ip += 3; |
| } |
| |
| static inline void |
| Opcode_WIDE_IINC(StackFrame& frame) { |
| U_32 varNum = read_uint16(frame.ip + 2); |
| int incr = read_int16(frame.ip + 4); |
| frame.locals(varNum).i += incr; |
| DEBUG_BYTECODE(" += " << incr); |
| frame.ip += 6; |
| } |
| |
| static inline void |
| Opcode_ARRAYLENGTH(StackFrame& frame) { |
| REF st_ref = frame.stack.pick().ref; |
| if (st_ref == 0) { |
| throwNPE(); |
| return; |
| } |
| ManagedObject *ref = UNCOMPRESS_INTERP(st_ref); |
| |
| frame.stack.ref() = FLAG_NONE; |
| frame.stack.pick().i = get_vector_length((Vector_Handle)ref); |
| DEBUG_BYTECODE("length = " << frame.stack.pick().i); |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_AALOAD(StackFrame& frame) { |
| REF st_ref = frame.stack.pick(1).ref; |
| if (st_ref == 0) { |
| throwNPE(); |
| return; |
| } |
| Vector_Handle array = (Vector_Handle) UNCOMPRESS_INTERP(st_ref); |
| U_32 length = get_vector_length(array); |
| U_32 pos = frame.stack.pick(0).u; |
| |
| DEBUG_BYTECODE("length = " << (int)length << " pos = " << (int)pos); |
| |
| if (pos >= length) { |
| throwAIOOBE(pos); |
| return; |
| } |
| |
| frame.stack.pop(); |
| |
| // Array contains elements according to REFS_IS_COMPRESSED_MODE |
| // But even in compressed mode on 64-bit platform interpreter's |
| // stack can contain uncompressed references (according to REF32) |
| // So we'll convert references if needed |
| ManagedObject** pelem = get_vector_element_address_ref(array, pos); |
| ManagedObject* urefelem = UNCOMPRESS_REF(*pelem); |
| frame.stack.pick().ref = COMPRESS_INTERP(urefelem); |
| frame.ip++; |
| } |
| |
| #define DEF_OPCODE_XALOAD(CODE,arraytype,type,store) \ |
| static inline void \ |
| Opcode_ ## CODE(StackFrame& frame) { \ |
| REF ref = frame.stack.pick(1).ref; \ |
| if (ref == 0) { \ |
| throwNPE(); \ |
| return; \ |
| } \ |
| Vector_Handle array = (Vector_Handle) UNCOMPRESS_INTERP(ref); \ |
| U_32 length = get_vector_length(array); \ |
| U_32 pos = frame.stack.pick(0).u; \ |
| \ |
| DEBUG_BYTECODE("length = " << (int)length << " pos = " << (int)pos); \ |
| \ |
| if (pos >= length) { \ |
| throwAIOOBE(pos); \ |
| return; \ |
| } \ |
| \ |
| frame.stack.pop(); \ |
| \ |
| type* addr = get_vector_element_address_ ## arraytype(array, pos); \ |
| frame.stack.pick().store = *addr; \ |
| frame.stack.ref() = FLAG_NONE; \ |
| frame.ip++; \ |
| } |
| |
| DEF_OPCODE_XALOAD(BALOAD, int8, I_8, i) |
| DEF_OPCODE_XALOAD(CALOAD, uint16, uint16, u) |
| DEF_OPCODE_XALOAD(SALOAD, int16, int16, i) |
| DEF_OPCODE_XALOAD(IALOAD, int32, I_32, i) |
| DEF_OPCODE_XALOAD(FALOAD, f32, float, f) |
| |
| static inline void |
| Opcode_LALOAD(StackFrame& frame) { |
| REF ref = frame.stack.pick(1).ref; |
| if (ref == 0) { |
| throwNPE(); |
| return; |
| } |
| Vector_Handle array = (Vector_Handle) UNCOMPRESS_INTERP(ref); |
| U_32 length = get_vector_length(array); |
| U_32 pos = frame.stack.pick(0).u; |
| |
| DEBUG_BYTECODE("length = " << (int)length << " pos = " << (int)pos); |
| |
| if (pos >= length) { |
| throwAIOOBE(pos); |
| return; |
| } |
| |
| frame.stack.ref(1) = FLAG_NONE; |
| |
| Value2* addr = (Value2*) get_vector_element_address_int64(array, pos); |
| frame.stack.setLong(0, *addr); |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_AASTORE(StackFrame& frame) { |
| REF ref = frame.stack.pick(2).ref; |
| if (ref == 0) { |
| throwNPE(); |
| return; |
| } |
| Vector_Handle array = (Vector_Handle) UNCOMPRESS_INTERP(ref); |
| U_32 length = get_vector_length(array); |
| U_32 pos = frame.stack.pick(1).u; |
| |
| DEBUG_BYTECODE("length = " << (int)length << " pos = " << (int)pos); |
| |
| if (pos >= length) { |
| throwAIOOBE(pos); |
| return; |
| } |
| |
| // Check ArrayStoreException |
| ManagedObject *arrayObj = (ManagedObject*) array; |
| Class *arrayClass = arrayObj->vt()->clss; |
| Class *elementClass = arrayClass->get_array_element_class(); |
| ManagedObject* obj = UNCOMPRESS_INTERP(frame.stack.pick().ref); |
| if (!obj == 0 && !vm_instanceof(obj, elementClass)) { |
| interp_throw_exception("java/lang/ArrayStoreException"); |
| return; |
| } |
| |
| // Array contains elements according to REFS_IS_COMPRESSED_MODE |
| // But even in compressed mode on 64-bit platform interpreter's |
| // stack can contain uncompressed references (according to REF32) |
| // So we'll convert references if needed |
| ManagedObject** pelem = get_vector_element_address_ref(array, pos); |
| STORE_UREF_BY_ADDR(pelem, obj); |
| frame.stack.ref(2) = FLAG_NONE; |
| frame.stack.ref(0) = FLAG_NONE; |
| frame.stack.pop(3); |
| frame.ip++; |
| } |
| |
| #define DEF_OPCODE_IASTORE(CODE,arraytype,type,ldtype) \ |
| static inline void \ |
| Opcode_ ## CODE(StackFrame& frame) { \ |
| REF ref = frame.stack.pick(2).ref; \ |
| if (ref == 0) { \ |
| throwNPE(); \ |
| return; \ |
| } \ |
| Vector_Handle array = (Vector_Handle) UNCOMPRESS_INTERP(ref); \ |
| U_32 length = get_vector_length(array); \ |
| U_32 pos = frame.stack.pick(1).u; \ |
| \ |
| DEBUG_BYTECODE("length = " << (int)length << " pos = " << (int)pos); \ |
| \ |
| if (pos >= length) { \ |
| throwAIOOBE(pos); \ |
| return; \ |
| } \ |
| \ |
| type* addr = (type*) get_vector_element_address_ ## arraytype(array, pos); \ |
| *addr = frame.stack.pick().ldtype; \ |
| frame.stack.ref(2) = FLAG_NONE; \ |
| frame.stack.pop(3); \ |
| frame.ip++; \ |
| } |
| |
| #if defined (__INTEL_COMPILER) |
| #pragma warning( push ) |
| #pragma warning (disable:810) // to get rid of remark #810: conversion from "int" to "unsigned char" may lose significant bits |
| #endif |
| |
| DEF_OPCODE_IASTORE(CASTORE, uint16, uint16, u) |
| DEF_OPCODE_IASTORE(BASTORE, int8, I_8, i) |
| DEF_OPCODE_IASTORE(SASTORE, int16, int16, i) |
| DEF_OPCODE_IASTORE(IASTORE, int32, I_32, i) |
| DEF_OPCODE_IASTORE(FASTORE, f32, float, f) |
| |
| #if defined (__INTEL_COMPILER) |
| #pragma warning( pop ) |
| #endif |
| |
| static inline void |
| Opcode_LASTORE(StackFrame& frame) { |
| REF ref = frame.stack.pick(3).ref; |
| if (ref == 0) { |
| throwNPE(); |
| return; |
| } |
| Vector_Handle array = (Vector_Handle) UNCOMPRESS_INTERP(ref); |
| U_32 length = get_vector_length(array); |
| U_32 pos = frame.stack.pick(2).u; |
| |
| DEBUG_BYTECODE("length = " << (int)length << " pos = " << (int)pos); |
| |
| if (pos >= length) { |
| /* FIXME ivan 20041005: array index out of bounds exception */ |
| throwAIOOBE(pos); |
| return; |
| } |
| |
| Value2* addr = (Value2*) get_vector_element_address_int64(array, pos); |
| *addr = frame.stack.getLong(0); |
| frame.stack.ref(3) = FLAG_NONE; |
| frame.stack.pop(4); |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_PUTSTATIC(StackFrame& frame) { |
| U_32 fieldId = read_uint16(frame.ip + 1); |
| Class *clazz = frame.method->get_class(); |
| |
| Field *field = interp_resolve_static_field(clazz, fieldId, true); |
| if (!field) return; // exception |
| |
| // FIXME: is it possible to move the code into !cp_is_resolved condition above? |
| class_initialize(field->get_class()); |
| |
| if (check_current_thread_exception()) { |
| return; |
| } |
| |
| if (interpreter_ti_notification_mode |
| & INTERPRETER_TI_FIELD_MODIFICATION) { |
| Method *method = frame.method; |
| M2N_ALLOC_MACRO; |
| putstatic_callback(field, frame); |
| M2N_FREE_MACRO; |
| } |
| |
| |
| if (field->is_final()) { |
| if(!frame.method->get_class()->is_initializing()) { |
| throwIAE(field_get_name(field)); |
| return; |
| } |
| } |
| |
| void* addr = field_get_address(field); |
| |
| DEBUG_BYTECODE(field->get_name()->bytes << " " << field->get_descriptor()->bytes |
| << " (val = " << (int)frame.stack.pick().i << ")"); |
| |
| switch (field->get_java_type()) { |
| #ifdef COMPACT_FIELDS // use compact fields on ipf |
| case VM_DATA_TYPE_BOOLEAN: |
| case VM_DATA_TYPE_INT8: |
| *(U_8*)addr = (U_8) frame.stack.pick().u; |
| frame.stack.pop(); |
| break; |
| |
| case VM_DATA_TYPE_CHAR: |
| case VM_DATA_TYPE_INT16: |
| *(uint16*)addr = (uint16) frame.stack.pick().u; |
| frame.stack.pop(); |
| break; |
| |
| #else // ia32 not using compact fields |
| case VM_DATA_TYPE_BOOLEAN: |
| *(U_32*)addr = (U_8) frame.stack.pick().u; |
| frame.stack.pop(); |
| break; |
| case VM_DATA_TYPE_CHAR: |
| *(U_32*)addr = (uint16) frame.stack.pick().u; |
| frame.stack.pop(); |
| break; |
| |
| case VM_DATA_TYPE_INT8: |
| *(I_32*)addr = (I_8) frame.stack.pick().i; |
| frame.stack.pop(); |
| break; |
| case VM_DATA_TYPE_INT16: |
| *(I_32*)addr = (int16) frame.stack.pick().i; |
| frame.stack.pop(); |
| break; |
| #endif |
| case VM_DATA_TYPE_INT32: |
| case VM_DATA_TYPE_F4: |
| *(I_32*)addr = frame.stack.pick().i; |
| frame.stack.pop(); |
| break; |
| |
| case VM_DATA_TYPE_ARRAY: |
| case VM_DATA_TYPE_CLASS: |
| { |
| ManagedObject* val = UNCOMPRESS_INTERP(frame.stack.pick().ref); |
| STORE_UREF_BY_ADDR(addr, val); |
| frame.stack.ref() = FLAG_NONE; |
| frame.stack.pop(); |
| break; |
| } |
| case VM_DATA_TYPE_INT64: |
| case VM_DATA_TYPE_F8: |
| { |
| double *vaddr = (double*) addr; |
| *vaddr = frame.stack.getLong(0).d; |
| frame.stack.pop(2); |
| break; |
| } |
| |
| default: |
| LDIE(52, "Unexpected data type"); |
| } |
| frame.ip += 3; |
| } |
| |
| static inline void |
| Opcode_GETSTATIC(StackFrame& frame) { |
| U_32 fieldId = read_uint16(frame.ip + 1); |
| Class *clazz = frame.method->get_class(); |
| |
| Field *field = interp_resolve_static_field(clazz, fieldId, false); |
| if (!field) return; // exception |
| |
| // FIXME: is it possible to move the code into !cp_is_resolved condition above? |
| class_initialize(field->get_class()); |
| |
| if (check_current_thread_exception()) { |
| return; |
| } |
| |
| if (interpreter_ti_notification_mode |
| & INTERPRETER_TI_FIELD_ACCESS) { |
| Method *method = frame.method; |
| M2N_ALLOC_MACRO; |
| getstatic_callback(field, frame); |
| M2N_FREE_MACRO; |
| } |
| |
| void *addr = field_get_address(field); |
| frame.stack.push(); |
| |
| switch (field->get_java_type()) { |
| #ifdef COMPACT_FIELDS // use compact fields on ipf |
| case VM_DATA_TYPE_BOOLEAN: |
| frame.stack.pick().u = *(U_8*)addr; |
| break; |
| |
| case VM_DATA_TYPE_INT8: |
| frame.stack.pick().i = *(I_8*)addr; |
| break; |
| |
| case VM_DATA_TYPE_CHAR: |
| frame.stack.pick().u = *(uint16*)addr; |
| break; |
| |
| case VM_DATA_TYPE_INT16: |
| frame.stack.pick().i = *(int16*)addr; |
| break; |
| |
| #else // ia32 not using compact fields |
| case VM_DATA_TYPE_BOOLEAN: |
| case VM_DATA_TYPE_CHAR: |
| frame.stack.pick().u = *(U_32*)addr; |
| break; |
| |
| case VM_DATA_TYPE_INT8: |
| case VM_DATA_TYPE_INT16: |
| #endif |
| case VM_DATA_TYPE_INT32: |
| case VM_DATA_TYPE_F4: |
| frame.stack.pick().i = *(I_32*)addr; |
| break; |
| case VM_DATA_TYPE_ARRAY: |
| case VM_DATA_TYPE_CLASS: |
| { |
| ManagedObject* val = UNCOMPRESS_REF(*((ManagedObject**)addr)); |
| frame.stack.pick().ref = COMPRESS_INTERP(val); |
| frame.stack.ref() = FLAG_OBJECT; |
| break; |
| } |
| case VM_DATA_TYPE_INT64: |
| case VM_DATA_TYPE_F8: |
| { |
| Value2 val; |
| val.d = *(double*)addr; |
| frame.stack.push(); |
| frame.stack.setLong(0, val); |
| break; |
| } |
| |
| default: |
| LDIE(52, "Unexpected data type"); |
| } |
| DEBUG_BYTECODE(field->get_name()->bytes << " " << field->get_descriptor()->bytes |
| << " (val = " << (int)frame.stack.pick().i << ")"); |
| frame.ip += 3; |
| } |
| |
| static inline void |
| Opcode_PUTFIELD(StackFrame& frame) { |
| U_32 fieldId = read_uint16(frame.ip + 1); |
| Class *clazz = frame.method->get_class(); |
| |
| Field *field = interp_resolve_nonstatic_field(clazz, fieldId, true); |
| if (!field) return; // exception |
| |
| if (interpreter_ti_notification_mode |
| & INTERPRETER_TI_FIELD_MODIFICATION) { |
| Method *method = frame.method; |
| M2N_ALLOC_MACRO; |
| putfield_callback(field, frame); |
| M2N_FREE_MACRO; |
| } |
| |
| if (field->is_final() && clazz != field->get_class()) { |
| throwIAE(field_get_name(field)); |
| return; |
| } |
| |
| DEBUG_BYTECODE(field->get_name()->bytes << " " << field->get_descriptor()->bytes |
| << " (val = " << (int)frame.stack.pick().i << ")"); |
| |
| uint16 obj_ref_pos = 1; |
| |
| if (field->get_java_type() == VM_DATA_TYPE_INT64 || |
| field->get_java_type() == VM_DATA_TYPE_F8) |
| ++obj_ref_pos; |
| |
| REF ref = frame.stack.pick(obj_ref_pos).ref; |
| |
| if (ref == 0) { |
| throwNPE(); |
| return; |
| } |
| |
| ManagedObject *obj = UNCOMPRESS_INTERP(ref); |
| U_8* addr = ((U_8*)obj) + field->get_offset(); |
| |
| switch (field->get_java_type()) { |
| |
| #ifdef COMPACT_FIELDS // use compact fields on ipf |
| case VM_DATA_TYPE_BOOLEAN: |
| case VM_DATA_TYPE_INT8: |
| *(U_8*)addr = (U_8)frame.stack.pick(0).u; |
| frame.stack.ref(1) = FLAG_NONE; |
| frame.stack.pop(2); |
| break; |
| |
| case VM_DATA_TYPE_CHAR: |
| case VM_DATA_TYPE_INT16: |
| *(uint16*)addr = (uint16)frame.stack.pick(0).u; |
| frame.stack.ref(1) = FLAG_NONE; |
| frame.stack.pop(2); |
| break; |
| |
| #else // ia32 not using compact fields |
| case VM_DATA_TYPE_BOOLEAN: |
| *(U_32*)addr = (U_8)frame.stack.pick(0).u; |
| frame.stack.ref(1) = FLAG_NONE; |
| frame.stack.pop(2); |
| break; |
| |
| case VM_DATA_TYPE_INT8: |
| *(I_32*)addr = (I_8)frame.stack.pick(0).i; |
| frame.stack.ref(1) = FLAG_NONE; |
| frame.stack.pop(2); |
| break; |
| |
| case VM_DATA_TYPE_CHAR: |
| *(U_32*)addr = (uint16)frame.stack.pick(0).u; |
| frame.stack.ref(1) = FLAG_NONE; |
| frame.stack.pop(2); |
| break; |
| |
| case VM_DATA_TYPE_INT16: |
| *(I_32*)addr = (int16)frame.stack.pick(0).i; |
| frame.stack.ref(1) = FLAG_NONE; |
| frame.stack.pop(2); |
| break; |
| #endif |
| case VM_DATA_TYPE_INT32: |
| case VM_DATA_TYPE_F4: |
| *(I_32*)addr = frame.stack.pick(0).i; |
| frame.stack.ref(1) = FLAG_NONE; |
| frame.stack.pop(2); |
| break; |
| |
| case VM_DATA_TYPE_ARRAY: |
| case VM_DATA_TYPE_CLASS: |
| { |
| ManagedObject* val = UNCOMPRESS_INTERP(frame.stack.pick(0).ref); |
| STORE_UREF_BY_ADDR(addr, val); |
| frame.stack.ref(0) = FLAG_NONE; |
| frame.stack.ref(1) = FLAG_NONE; |
| frame.stack.pop(2); |
| break; |
| } |
| case VM_DATA_TYPE_INT64: |
| case VM_DATA_TYPE_F8: |
| { |
| double *vaddr = (double*) addr; |
| *vaddr = frame.stack.getLong(0).d; |
| frame.stack.ref(2) = FLAG_NONE; |
| frame.stack.pop(3); |
| break; |
| } |
| |
| default: |
| LDIE(52, "Unexpected data type"); |
| } |
| frame.ip += 3; |
| } |
| |
| static inline void |
| Opcode_GETFIELD(StackFrame& frame) { |
| U_32 fieldId = read_uint16(frame.ip + 1); |
| Class *clazz = frame.method->get_class(); |
| |
| Field *field = interp_resolve_nonstatic_field(clazz, fieldId, false); |
| if (!field) return; // exception |
| |
| if (interpreter_ti_notification_mode |
| & INTERPRETER_TI_FIELD_ACCESS) { |
| Method *method = frame.method; |
| M2N_ALLOC_MACRO; |
| getfield_callback(field, frame); |
| M2N_FREE_MACRO; |
| } |
| |
| REF ref = frame.stack.pick(0).ref; |
| if (ref == 0) { |
| throwNPE(); |
| return; |
| } |
| ManagedObject *obj = UNCOMPRESS_INTERP(ref); |
| U_8 *addr = ((U_8*)obj) + field->get_offset(); |
| frame.stack.ref() = FLAG_NONE; |
| |
| switch (field->get_java_type()) { |
| |
| #ifdef COMPACT_FIELDS // use compact fields on ipf |
| case VM_DATA_TYPE_BOOLEAN: |
| frame.stack.pick(0).u = (U_32) *(U_8*)addr; |
| break; |
| |
| case VM_DATA_TYPE_INT8: |
| frame.stack.pick(0).i = (I_32) *(I_8*)addr; |
| break; |
| |
| case VM_DATA_TYPE_CHAR: |
| frame.stack.pick(0).u = (U_32) *(uint16*)addr; |
| break; |
| |
| case VM_DATA_TYPE_INT16: |
| frame.stack.pick(0).i = (I_32) *(int16*)addr; |
| break; |
| |
| #else // ia32 - not using compact fields |
| case VM_DATA_TYPE_BOOLEAN: |
| case VM_DATA_TYPE_CHAR: |
| frame.stack.pick(0).u = *(U_32*)addr; |
| break; |
| case VM_DATA_TYPE_INT8: |
| case VM_DATA_TYPE_INT16: |
| #endif |
| case VM_DATA_TYPE_INT32: |
| case VM_DATA_TYPE_F4: |
| frame.stack.pick(0).i = *(I_32*)addr; |
| break; |
| |
| case VM_DATA_TYPE_ARRAY: |
| case VM_DATA_TYPE_CLASS: |
| { |
| ManagedObject* val = UNCOMPRESS_REF(*((ManagedObject**)addr)); |
| frame.stack.pick(0).ref = COMPRESS_INTERP(val); |
| frame.stack.ref() = FLAG_OBJECT; |
| break; |
| } |
| case VM_DATA_TYPE_INT64: |
| case VM_DATA_TYPE_F8: |
| { |
| Value2 val; |
| val.d = *(double*)addr; |
| frame.stack.push(); |
| frame.stack.setLong(0, val); |
| break; |
| } |
| |
| default: |
| LDIE(52, "Unexpected data type"); |
| } |
| DEBUG_BYTECODE(field->get_name()->bytes << " " << field->get_descriptor()->bytes |
| << " (val = " << (int)frame.stack.pick().i << ")"); |
| |
| frame.ip += 3; |
| } |
| |
| static inline void |
| Opcode_INVOKEVIRTUAL(StackFrame& frame) { |
| U_32 methodId = read_uint16(frame.ip + 1); |
| Class *clazz = frame.method->get_class(); |
| |
| Method *method = interp_resolve_virtual_method(clazz, methodId); |
| if (!method) return; // exception |
| |
| DEBUG_BYTECODE(method); |
| |
| hythread_exception_safe_point(); |
| if(check_current_thread_exception()) { |
| return; |
| } |
| hythread_safe_point(); |
| interpreterInvokeVirtual(frame, method); |
| } |
| |
| static inline void |
| Opcode_INVOKEINTERFACE(StackFrame& frame) { |
| U_32 methodId = read_uint16(frame.ip + 1); |
| Class *clazz = frame.method->get_class(); |
| |
| Method *method = interp_resolve_interface_method(clazz, methodId); |
| if (!method) return; // exception |
| |
| DEBUG_BYTECODE(method); |
| |
| hythread_exception_safe_point(); |
| if(check_current_thread_exception()) { |
| return; |
| } |
| hythread_safe_point(); |
| interpreterInvokeInterface(frame, method); |
| } |
| |
| static inline void |
| Opcode_INVOKESTATIC(StackFrame& frame) { |
| U_32 methodId = read_uint16(frame.ip + 1); |
| Class *clazz = frame.method->get_class(); |
| |
| Method *method = interp_resolve_static_method(clazz, methodId); |
| if (!method) return; // exception |
| |
| DEBUG_BYTECODE(method); |
| |
| // FIXME: is it possible to move the code into !cp_is_resolved condition above? |
| class_initialize(method->get_class()); |
| |
| hythread_exception_safe_point(); |
| if (check_current_thread_exception()) { |
| return; |
| } |
| |
| hythread_safe_point(); |
| interpreterInvokeStatic(frame, method); |
| } |
| |
| static inline void |
| Opcode_INVOKESPECIAL(StackFrame& frame) { |
| U_32 methodId = read_uint16(frame.ip + 1); |
| Class *clazz = frame.method->get_class(); |
| |
| Method *method = interp_resolve_special_method(clazz, methodId); |
| if (!method) return; // exception |
| |
| DEBUG_BYTECODE(method); |
| |
| hythread_exception_safe_point(); |
| if (check_current_thread_exception()) { |
| return; |
| } |
| |
| hythread_safe_point(); |
| interpreterInvokeSpecial(frame, method); |
| } |
| |
| static inline void |
| Opcode_TABLESWITCH(StackFrame& frame) { |
| U_8* oldip = frame.ip; |
| U_8* ip = frame.ip + 1; |
| ip = ((ip - (U_8*)frame.method->get_byte_code_addr() + 3) & ~3) |
| + (U_8*)frame.method->get_byte_code_addr(); |
| I_32 deflt = read_int32(ip); |
| I_32 low = read_int32(ip+4); |
| I_32 high = read_int32(ip+8); |
| I_32 val = frame.stack.pick().i; |
| frame.stack.pop(); |
| DEBUG_BYTECODE("val = " << val << " low = " << low << " high = " << high); |
| if (val < low || val > high) { |
| DEBUG_BYTECODE("default offset taken!\n"); |
| frame.ip = oldip + deflt; |
| } |
| else { |
| frame.ip = oldip + read_int32(ip + 12 + ((val - low) << 2)); |
| } |
| } |
| |
| static inline void |
| Opcode_LOOKUPSWITCH(StackFrame& frame) { |
| U_8* oldip = frame.ip; |
| U_8* ip = frame.ip + 1; |
| ip = ((ip - (U_8*)frame.method->get_byte_code_addr() + 3) & ~3) |
| + (U_8*)frame.method->get_byte_code_addr(); |
| I_32 deflt = read_int32(ip); |
| I_32 num = read_int32(ip+4); |
| I_32 val = frame.stack.pick().i; |
| frame.stack.pop(); |
| |
| for(int i = 0; i < num; i++) { |
| I_32 key = read_int32(ip + 8 + i * 8); |
| if (val == key) { |
| frame.ip = oldip + read_int32(ip + 12 + i * 8); |
| return; |
| } |
| |
| } |
| DEBUG_BYTECODE("default offset taken!\n"); |
| frame.ip = oldip + deflt; |
| } |
| |
| static inline void |
| Opcode_GOTO(StackFrame& frame) { |
| hythread_safe_point(); |
| hythread_exception_safe_point(); |
| DEBUG_BYTECODE("going to instruction"); |
| frame.ip += read_int16(frame.ip + 1); |
| } |
| |
| static inline void |
| Opcode_GOTO_W(StackFrame& frame) { |
| hythread_safe_point(); |
| hythread_exception_safe_point(); |
| DEBUG_BYTECODE("going to instruction"); |
| frame.ip += read_int32(frame.ip + 1); |
| } |
| |
| static inline void |
| Opcode_JSR(StackFrame& frame) { |
| U_32 retAddr = (U_32)(frame.ip + 3 - |
| (U_8*)frame.method->get_byte_code_addr()); |
| frame.stack.push(); |
| frame.stack.pick().u = retAddr; |
| frame.stack.ref() = FLAG_RET_ADDR; |
| DEBUG_BYTECODE("going to instruction"); |
| frame.ip += read_int16(frame.ip + 1); |
| } |
| |
| static inline void |
| Opcode_JSR_W(StackFrame& frame) { |
| U_32 retAddr = (U_32)(frame.ip + 5 - |
| (U_8*)frame.method->get_byte_code_addr()); |
| frame.stack.push(); |
| frame.stack.pick().u = retAddr; |
| frame.stack.ref() = FLAG_RET_ADDR; |
| DEBUG_BYTECODE("going to instruction"); |
| frame.ip += read_int32(frame.ip + 1); |
| } |
| |
| static inline void |
| Opcode_RET(StackFrame& frame) { |
| U_32 varNum = read_uint8(frame.ip + 1); |
| U_32 retAddr = frame.locals(varNum).u; |
| assert(frame.locals.ref(varNum) == FLAG_RET_ADDR); |
| frame.ip = retAddr + (U_8*)frame.method->get_byte_code_addr(); |
| } |
| |
| static inline void |
| Opcode_WIDE_RET(StackFrame& frame) { |
| U_32 varNum = read_uint16(frame.ip + 2); |
| U_32 retAddr = frame.locals(varNum).u; |
| frame.ip = retAddr + (U_8*)frame.method->get_byte_code_addr(); |
| } |
| |
| static inline void |
| Opcode_CHECKCAST(StackFrame& frame) { |
| U_32 classId = read_uint16(frame.ip + 1); |
| Class *clazz = frame.method->get_class(); |
| Class *objClass = interp_resolve_class(clazz, classId); |
| if (!objClass) return; // exception |
| |
| DEBUG_BYTECODE("class = " << class_get_name(objClass)); |
| |
| ManagedObject *obj = UNCOMPRESS_INTERP(frame.stack.pick().ref); |
| |
| if (!(obj == 0 || vm_instanceof(obj, objClass))) { |
| interp_throw_exception("java/lang/ClassCastException", obj->vt()->clss->get_java_name()->bytes); |
| return; |
| } |
| frame.ip += 3; |
| } |
| |
| static inline void |
| Opcode_INSTANCEOF(StackFrame& frame) { |
| U_32 classId = read_uint16(frame.ip + 1); |
| Class *clazz = frame.method->get_class(); |
| Class *objClass = interp_resolve_class(clazz, classId); |
| if (!objClass) return; // exception |
| |
| DEBUG_BYTECODE("class = " << class_get_name(objClass)); |
| |
| ManagedObject *obj = UNCOMPRESS_INTERP(frame.stack.pick().ref); |
| // FIXME ivan 20041027: vm_instanceof checks null pointers, it assumes |
| // that null is Class::managed_null, but uncompress_compressed_reference |
| // doesn't return managed_null for null compressed references |
| frame.stack.pick().u = (obj != 0) && vm_instanceof(obj, objClass); |
| |
| frame.stack.ref() = FLAG_NONE; |
| frame.ip += 3; |
| } |
| |
| static inline void |
| Opcode_MONITORENTER(StackFrame& frame) { |
| REF ref = frame.stack.pick().ref; |
| if (ref == 0) { |
| throwNPE(); |
| return; |
| } |
| frame.locked_monitors->monitor = UNCOMPRESS_INTERP(ref); |
| |
| M2N_ALLOC_MACRO; |
| vm_monitor_enter_wrapper(frame.locked_monitors->monitor); |
| M2N_FREE_MACRO; |
| |
| if (exn_raised()) return; |
| |
| frame.stack.ref() = FLAG_NONE; |
| frame.stack.pop(); |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_MONITOREXIT(StackFrame& frame) { |
| REF ref = frame.stack.pick().ref; |
| if (ref == 0) { |
| throwNPE(); |
| return; |
| } |
| M2N_ALLOC_MACRO; |
| vm_monitor_exit_wrapper(UNCOMPRESS_INTERP(ref)); |
| M2N_FREE_MACRO; |
| |
| if (check_current_thread_exception()) |
| return; |
| |
| MonitorList *ml = frame.locked_monitors; |
| |
| frame.locked_monitors = ml->next; |
| ml->next = frame.free_monitors; |
| frame.free_monitors = ml; |
| |
| frame.stack.ref() = FLAG_NONE; |
| frame.stack.pop(); |
| frame.ip++; |
| } |
| |
| static inline void |
| Opcode_ATHROW(StackFrame& frame) { |
| REF ref = frame.stack.pick().ref; |
| ManagedObject *obj = UNCOMPRESS_INTERP(ref); |
| if (obj == NULL) { |
| throwNPE(); |
| return; |
| } |
| |
| // TODO: optimize, can add a flag to class which implements Throwable |
| // and set it when throwing for the first time. |
| if (!vm_instanceof(obj, VM_Global_State::loader_env->java_lang_Throwable_Class)) { |
| DEBUG("****** java.lang.VerifyError ******\n"); |
| interp_throw_exception("java/lang/VerifyError"); |
| return; |
| } |
| DEBUG_BYTECODE(obj); |
| assert(!hythread_is_suspend_enabled()); |
| set_current_thread_exception(obj); |
| } |
| |
| bool |
| findExceptionHandler(StackFrame& frame, ManagedObject **exception, Handler **hh) { |
| assert(!check_current_thread_exception()); |
| assert(!hythread_is_suspend_enabled()); |
| |
| Method *m = frame.method; |
| DEBUG_BYTECODE("Searching for exception handler:"); |
| DEBUG_BYTECODE(" In " << m); |
| |
| U_32 ip = (U_32)(frame.ip - (U_8*)m->get_byte_code_addr()); |
| DEBUG_BYTECODE("ip = " << (int)ip); |
| |
| // When VM is in shutdown stage we need to execute final block to |
| // release monitors and propogate an exception to the upper frames. |
| if (VM_Global_State::loader_env->IsVmShutdowning()) { |
| for(U_32 i = 0; i < m->num_bc_exception_handlers(); i++) { |
| Handler *h = m->get_bc_exception_handler_info(i); |
| if (h->get_catch_type_index() == 0 && |
| h->get_start_pc() <= ip && ip < h->get_end_pc()) { |
| *hh = h; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| Class *clazz = m->get_class(); |
| |
| for(U_32 i = 0; i < m->num_bc_exception_handlers(); i++) { |
| Handler *h = m->get_bc_exception_handler_info(i); |
| DEBUG_BYTECODE("handler" << (int) i |
| << ": start_pc=" << (int) h->get_start_pc() |
| << " end_pc=" << (int) h->get_end_pc()); |
| |
| if (ip < h->get_start_pc()) continue; |
| if (ip >= h->get_end_pc()) continue; |
| |
| U_32 catch_type_index = h->get_catch_type_index(); |
| |
| if (catch_type_index) { |
| // 0 - is handler for all |
| // if !0 - check if the handler catches this exception type |
| |
| DEBUG_BYTECODE("catch type index = " << (int)catch_type_index); |
| |
| // WARNING: GC may occur here !!! |
| Class *obj = interp_resolve_class(clazz, catch_type_index); |
| |
| if (!obj) { |
| // possible if verifier is disabled |
| return false; |
| } |
| |
| if (!vm_instanceof(*exception, obj)) continue; |
| } |
| *hh = h; |
| return true; |
| } |
| return false; |
| } |
| |
| static inline bool |
| processExceptionHandler(StackFrame& frame, ManagedObject **exception) { |
| Method *m = frame.method; |
| Handler *h; |
| if (findExceptionHandler(frame, exception, &h)){ |
| DEBUG_BYTECODE("Exception caught: " << (*exception)); |
| DEBUG_BYTECODE("Found handler!\n"); |
| frame.ip = (U_8*)m->get_byte_code_addr() + h->get_handler_pc(); |
| return true; |
| } |
| return false; |
| } |
| |
| void |
| findCatchMethod(ManagedObject **exception, Method **catch_method, jlocation *catch_location) { |
| StackFrame *frame = getLastStackFrame(); |
| *catch_method = NULL; |
| *catch_location = 0; |
| |
| for(StackFrame *frame = getLastStackFrame(); frame; frame = frame->prev) { |
| Method *method = frame->method; |
| if (method->is_native()) continue; |
| |
| Handler *h; |
| |
| if(findExceptionHandler(*frame, exception, &h)) { |
| *catch_method = frame->method; |
| *catch_location = h->get_handler_pc(); |
| return; |
| } |
| clear_current_thread_exception(); |
| } |
| } |
| |
| |
| static inline void |
| stackDump(FILE * file, StackFrame& frame) { |
| |
| StackFrame *f = &frame; |
| |
| while(f) { |
| Method *m = f->method; |
| Class *c = m->get_class(); |
| const char* fname = NULL; |
| int line = -2; |
| get_file_and_line(m, f->ip, false, -1, &fname, &line); |
| const char* filename = fname ? fname : "NULL"; |
| |
| #ifdef INTERPRETER_DEEP_DEBUG |
| fprintf(file, "%s.%s%s (%s:%i) last bcs: (8 of %i): %s %s %s %s %s %s %s %s", |
| c->name->bytes, m->get_name()->bytes, m->get_descriptor()->bytes, |
| filename, line, f->n_last_bytecode, |
| opcodeNames[f->last_bytecodes[(f->n_last_bytecode-1)&7]], |
| opcodeNames[f->last_bytecodes[(f->n_last_bytecode-2)&7]], |
| opcodeNames[f->last_bytecodes[(f->n_last_bytecode-3)&7]], |
| opcodeNames[f->last_bytecodes[(f->n_last_bytecode-4)&7]], |
| opcodeNames[f->last_bytecodes[(f->n_last_bytecode-5)&7]], |
| opcodeNames[f->last_bytecodes[(f->n_last_bytecode-6)&7]], |
| opcodeNames[f->last_bytecodes[(f->n_last_bytecode-7)&7]], |
| opcodeNames[f->last_bytecodes[(f->n_last_bytecode-8)&7]]); |
| #else |
| fprintf(file, " %s.%s%s (%s:%i)\n", class_get_name(c), m->get_name()->bytes, |
| m->get_descriptor()->bytes, filename, line); |
| #endif |
| f = f->prev; |
| } |
| } |
| |
| void stack_dump(FILE *f, VM_thread *thread) { |
| StackFrame *frame = getLastStackFrame(thread); |
| stackDump(f, *frame); |
| } |
| |
| #ifdef _WIN32 |
| #include <io.h> |
| #endif |
| |
| void stack_dump(int fd, VM_thread *thread) { |
| FILE *f; |
| #ifdef _WIN32 |
| fd = _dup(fd); |
| assert(fd != -1); |
| f = _fdopen(fd, "w"); |
| #else |
| fd = dup(fd); |
| assert(fd != -1); |
| f = fdopen(fd, "w"); |
| #endif |
| assert(f); |
| StackFrame *frame = getLastStackFrame(thread); |
| stackDump(f, *frame); |
| fclose(f); |
| } |
| |
| void stack_dump(VM_thread *thread) { |
| StackFrame *frame = getLastStackFrame(thread); |
| stackDump(stderr, *frame); |
| } |
| |
| void stack_dump() { |
| StackFrame *frame = getLastStackFrame(); |
| stackDump(stderr, *frame); |
| } |
| |
| static inline |
| void UNUSED dump_all_java_stacks() { |
| hythread_iterator_t iterator; |
| hythread_suspend_all(&iterator, NULL); |
| VM_thread *thread = jthread_get_vm_thread(hythread_iterator_next(&iterator)); |
| while(thread) { |
| stack_dump(thread); |
| thread = jthread_get_vm_thread(hythread_iterator_next(&iterator)); |
| } |
| |
| hythread_resume_all( NULL); |
| |
| INFO("****** END OF JAVA STACKS *****\n"); |
| } |
| |
| void |
| method_exit_callback_with_frame(Method *method, StackFrame& frame) { |
| NativeObjectHandles handles; |
| |
| bool exc = check_current_thread_exception(); |
| jvalue val; |
| |
| val.j = 0; |
| |
| if (exc) { |
| method_exit_callback(method, true, val); |
| return; |
| } |
| |
| |
| switch(method->get_return_java_type()) { |
| ObjectHandle h; |
| |
| case JAVA_TYPE_VOID: |
| val.i = 0; |
| break; |
| |
| case JAVA_TYPE_CLASS: |
| case JAVA_TYPE_ARRAY: |
| case JAVA_TYPE_STRING: |
| h = oh_allocate_local_handle(); |
| h->object = UNCOMPRESS_INTERP(frame.stack.pick().ref); |
| val.l = (jobject) h; |
| break; |
| |
| case JAVA_TYPE_FLOAT: |
| case JAVA_TYPE_BOOLEAN: |
| case JAVA_TYPE_BYTE: |
| case JAVA_TYPE_CHAR: |
| case JAVA_TYPE_SHORT: |
| case JAVA_TYPE_INT: |
| val.i = frame.stack.pick().i; |
| break; |
| |
| case JAVA_TYPE_LONG: |
| case JAVA_TYPE_DOUBLE: |
| val.j = frame.stack.getLong(0).i64; |
| break; |
| |
| default: |
| LDIE(53, "Unexpected java type"); |
| } |
| |
| method_exit_callback(method, false, val); |
| } |
| |
| void |
| interpreter(StackFrame &frame) { |
| U_8 *first = NULL; |
| U_8 ip0 = 0; |
| bool breakpoint_processed = false; |
| int stackLength = 0; |
| size_t available; |
| |
| TRACE("interpreter: " << frame.method); |
| |
| assert(frame.method->is_static() || frame.This); |
| |
| M2N_ALLOC_MACRO; |
| if (get_thread_ptr()->jvmti_thread.p_exception_object_ti || exn_raised()) { |
| frame.exc = get_current_thread_exception(); |
| goto got_exception; |
| } |
| assert(!hythread_is_suspend_enabled()); |
| |
| |
| |
| available = get_available_stack_size(); |
| |
| if (available < 100000) { |
| int &state = get_thread_ptr()->interpreter_state; |
| |
| if (!(state & INTERP_STATE_STACK_OVERFLOW)) { |
| state |= INTERP_STATE_STACK_OVERFLOW; |
| interp_throw_exception("java/lang/StackOverflowError"); |
| |
| if (frame.framePopListener) |
| frame_pop_callback(frame.framePopListener, frame.method, true); |
| M2N_FREE_MACRO; |
| return; |
| } |
| } |
| |
| frame.ip = (U_8*) frame.method->get_byte_code_addr(); |
| |
| if (interpreter_ti_notification_mode |
| & INTERPRETER_TI_METHOD_ENTRY_EVENT) { |
| M2N_ALLOC_MACRO; |
| method_entry_callback(frame.method); |
| M2N_FREE_MACRO; |
| } |
| |
| if (frame.method->is_synchronized()) { |
| MonitorList *ml = (MonitorList*) ALLOC_FRAME(sizeof(MonitorList)); |
| frame.locked_monitors = ml; |
| ml->next = 0; |
| |
| if (frame.method->is_static()) { |
| ml->monitor = *(frame.method->get_class()->get_class_handle()); |
| } else { |
| ml->monitor = UNCOMPRESS_INTERP(frame.locals(0).ref); |
| } |
| vm_monitor_enter_wrapper(ml->monitor); |
| } |
| |
| breakpoint_processed = false; |
| |
| while (true) { |
| ip0 = *frame.ip; |
| |
| DEBUG_BYTECODE("\n(" << frame.stack.getIndex() |
| << ") " << opcodeNames[ip0] << ": "); |
| |
| restart: |
| if (interpreter_ti_notification_mode) { |
| if (frame.jvmti_pop_frame == POP_FRAME_NOW) { |
| MonitorList *ml = frame.locked_monitors; |
| while(ml) { |
| M2N_ALLOC_MACRO; |
| vm_monitor_exit_wrapper(ml->monitor); |
| M2N_FREE_MACRO; |
| ml = ml->next; |
| } |
| M2N_FREE_MACRO; |
| return; |
| } |
| if (!breakpoint_processed && |
| interpreter_ti_notification_mode |
| & INTERPRETER_TI_SINGLE_STEP_EVENT) { |
| M2N_ALLOC_MACRO; |
| single_step_callback(frame); |
| M2N_FREE_MACRO; |
| } |
| if (frame.jvmti_pop_frame == POP_FRAME_NOW) { |
| MonitorList *ml = frame.locked_monitors; |
| while(ml) { |
| vm_monitor_exit_wrapper(ml->monitor); |
| ml = ml->next; |
| } |
| M2N_FREE_MACRO; |
| return; |
| } |
| breakpoint_processed = false; |
| |
| if (get_thread_ptr()->jvmti_thread.p_exception_object_ti || exn_raised()) { |
| frame.exc = get_current_thread_exception(); |
| goto got_exception; |
| } |
| } |
| |
| #ifdef INTERPRETER_DEEP_DEBUG |
| frame.last_bytecodes[(frame.n_last_bytecode++) & 7] = ip0; |
| #endif |
| |
| assert(!hythread_is_suspend_enabled()); |
| assert(&frame == getLastStackFrame()); |
| |
| switch(ip0) { |
| case OPCODE_NOP: |
| Opcode_NOP(frame); break; |
| |
| case OPCODE_ICONST_M1: Opcode_ICONST_M1(frame); break; |
| case OPCODE_ACONST_NULL: Opcode_ACONST_NULL(frame); break; |
| case OPCODE_ICONST_0: Opcode_ICONST_0(frame); break; |
| case OPCODE_ICONST_1: Opcode_ICONST_1(frame); break; |
| case OPCODE_ICONST_2: Opcode_ICONST_2(frame); break; |
| case OPCODE_ICONST_3: Opcode_ICONST_3(frame); break; |
| case OPCODE_ICONST_4: Opcode_ICONST_4(frame); break; |
| case OPCODE_ICONST_5: Opcode_ICONST_5(frame); break; |
| case OPCODE_FCONST_0: Opcode_FCONST_0(frame); break; |
| case OPCODE_FCONST_1: Opcode_FCONST_1(frame); break; |
| case OPCODE_FCONST_2: Opcode_FCONST_2(frame); break; |
| |
| case OPCODE_LCONST_0: Opcode_LCONST_0(frame); break; |
| case OPCODE_LCONST_1: Opcode_LCONST_1(frame); break; |
| case OPCODE_DCONST_0: Opcode_DCONST_0(frame); break; |
| case OPCODE_DCONST_1: Opcode_DCONST_1(frame); break; |
| |
| case OPCODE_ALOAD_0: Opcode_ALOAD_0(frame); break; |
| case OPCODE_ALOAD_1: Opcode_ALOAD_1(frame); break; |
| case OPCODE_ALOAD_2: Opcode_ALOAD_2(frame); break; |
| case OPCODE_ALOAD_3: Opcode_ALOAD_3(frame); break; |
| case OPCODE_ILOAD_0: Opcode_ILOAD_0(frame); break; |
| case OPCODE_ILOAD_1: Opcode_ILOAD_1(frame); break; |
| case OPCODE_ILOAD_2: Opcode_ILOAD_2(frame); break; |
| case OPCODE_ILOAD_3: Opcode_ILOAD_3(frame); break; |
| case OPCODE_FLOAD_0: Opcode_ILOAD_0(frame); break; |
| case OPCODE_FLOAD_1: Opcode_ILOAD_1(frame); break; |
| case OPCODE_FLOAD_2: Opcode_ILOAD_2(frame); break; |
| case OPCODE_FLOAD_3: Opcode_ILOAD_3(frame); break; |
| |
| case OPCODE_ASTORE_0: Opcode_ASTORE_0(frame); break; |
| case OPCODE_ASTORE_1: Opcode_ASTORE_1(frame); break; |
| case OPCODE_ASTORE_2: Opcode_ASTORE_2(frame); break; |
| case OPCODE_ASTORE_3: Opcode_ASTORE_3(frame); break; |
| |
| case OPCODE_ISTORE_0: Opcode_ISTORE_0(frame); break; |
| case OPCODE_ISTORE_1: Opcode_ISTORE_1(frame); break; |
| case OPCODE_ISTORE_2: Opcode_ISTORE_2(frame); break; |
| case OPCODE_ISTORE_3: Opcode_ISTORE_3(frame); break; |
| case OPCODE_FSTORE_0: Opcode_ISTORE_0(frame); break; |
| case OPCODE_FSTORE_1: Opcode_ISTORE_1(frame); break; |
| case OPCODE_FSTORE_2: Opcode_ISTORE_2(frame); break; |
| case OPCODE_FSTORE_3: Opcode_ISTORE_3(frame); break; |
| |
| case OPCODE_ALOAD: Opcode_ALOAD(frame); break; |
| case OPCODE_ILOAD: Opcode_ILOAD(frame); break; |
| case OPCODE_FLOAD: Opcode_ILOAD(frame); break; |
| |
| case OPCODE_ASTORE: Opcode_ASTORE(frame); break; |
| case OPCODE_ISTORE: Opcode_ISTORE(frame); break; |
| case OPCODE_FSTORE: Opcode_ISTORE(frame); break; |
| |
| case OPCODE_LLOAD_0: Opcode_LLOAD_0(frame); break; |
| case OPCODE_LLOAD_1: Opcode_LLOAD_1(frame); break; |
| case OPCODE_LLOAD_2: Opcode_LLOAD_2(frame); break; |
| case OPCODE_LLOAD_3: Opcode_LLOAD_3(frame); break; |
| case OPCODE_DLOAD_0: Opcode_LLOAD_0(frame); break; |
| case OPCODE_DLOAD_1: Opcode_LLOAD_1(frame); break; |
| case OPCODE_DLOAD_2: Opcode_LLOAD_2(frame); break; |
| case OPCODE_DLOAD_3: Opcode_LLOAD_3(frame); break; |
| case OPCODE_LSTORE_0: Opcode_LSTORE_0(frame); break; |
| case OPCODE_LSTORE_1: Opcode_LSTORE_1(frame); break; |
| case OPCODE_LSTORE_2: Opcode_LSTORE_2(frame); break; |
| case OPCODE_LSTORE_3: Opcode_LSTORE_3(frame); break; |
| case OPCODE_DSTORE_0: Opcode_LSTORE_0(frame); break; |
| case OPCODE_DSTORE_1: Opcode_LSTORE_1(frame); break; |
| case OPCODE_DSTORE_2: Opcode_LSTORE_2(frame); break; |
| case OPCODE_DSTORE_3: Opcode_LSTORE_3(frame); break; |
| |
| case OPCODE_LLOAD: Opcode_LLOAD(frame); break; |
| case OPCODE_DLOAD: Opcode_LLOAD(frame); break; |
| case OPCODE_LSTORE: Opcode_LSTORE(frame); break; |
| case OPCODE_DSTORE: Opcode_LSTORE(frame); break; |
| |
| case OPCODE_IADD: Opcode_IADD(frame); break; |
| case OPCODE_ISUB: Opcode_ISUB(frame); break; |
| case OPCODE_IMUL: Opcode_IMUL(frame); break; |
| case OPCODE_IOR: Opcode_IOR(frame); break; |
| case OPCODE_IAND: Opcode_IAND(frame); break; |
| case OPCODE_IXOR: Opcode_IXOR(frame); break; |
| case OPCODE_ISHL: Opcode_ISHL(frame); break; |
| case OPCODE_ISHR: Opcode_ISHR(frame); break; |
| case OPCODE_IUSHR: Opcode_IUSHR(frame); break; |
| case OPCODE_IDIV: Opcode_IDIV(frame); goto check_exception; |
| case OPCODE_IREM: Opcode_IREM(frame); goto check_exception; |
| |
| case OPCODE_FADD: Opcode_FADD(frame); break; |
| case OPCODE_FSUB: Opcode_FSUB(frame); break; |
| case OPCODE_FMUL: Opcode_FMUL(frame); break; |
| case OPCODE_FDIV: Opcode_FDIV(frame); break; |
| case OPCODE_FREM: Opcode_FREM(frame); break; |
| |
| case OPCODE_INEG: Opcode_INEG(frame); break; |
| case OPCODE_FNEG: Opcode_FNEG(frame); break; |
| case OPCODE_LNEG: Opcode_LNEG(frame); break; |
| case OPCODE_DNEG: Opcode_DNEG(frame); break; |
| |
| case OPCODE_LADD: Opcode_LADD(frame); break; |
| case OPCODE_LSUB: Opcode_LSUB(frame); break; |
| case OPCODE_LMUL: Opcode_LMUL(frame); break; |
| case OPCODE_LOR: Opcode_LOR(frame); break; |
| case OPCODE_LAND: Opcode_LAND(frame); break; |
| case OPCODE_LXOR: Opcode_LXOR(frame); break; |
| case OPCODE_LSHL: Opcode_LSHL(frame); break; |
| case OPCODE_LSHR: Opcode_LSHR(frame); break; |
| case OPCODE_LUSHR: Opcode_LUSHR(frame); break; |
| case OPCODE_LDIV: Opcode_LDIV(frame); goto check_exception; |
| case OPCODE_LREM: Opcode_LREM(frame); goto check_exception; |
| |
| case OPCODE_DADD: Opcode_DADD(frame); break; |
| case OPCODE_DSUB: Opcode_DSUB(frame); break; |
| case OPCODE_DMUL: Opcode_DMUL(frame); break; |
| case OPCODE_DDIV: Opcode_DDIV(frame); break; |
| case OPCODE_DREM: Opcode_DREM(frame); break; |
| |
| |
| case OPCODE_RETURN: |
| case OPCODE_IRETURN: |
| case OPCODE_FRETURN: |
| case OPCODE_ARETURN: |
| case OPCODE_LRETURN: |
| case OPCODE_DRETURN: |
| if (frame.locked_monitors) { |
| vm_monitor_exit_wrapper(frame.locked_monitors->monitor); |
| assert(!frame.locked_monitors->next); |
| } |
| if (interpreter_ti_notification_mode |
| & INTERPRETER_TI_METHOD_EXIT_EVENT) |
| method_exit_callback_with_frame(frame.method, frame); |
| |
| if (frame.framePopListener) |
| frame_pop_callback(frame.framePopListener, frame.method, false); |
| M2N_FREE_MACRO; |
| return; |
| |
| case OPCODE_BIPUSH: Opcode_BIPUSH(frame); break; |
| case OPCODE_SIPUSH: Opcode_SIPUSH(frame); break; |
| |
| case OPCODE_IINC: Opcode_IINC(frame); break; |
| case OPCODE_POP: Opcode_POP(frame); break; |
| case OPCODE_POP2: Opcode_POP2(frame); break; |
| case OPCODE_SWAP: Opcode_SWAP(frame); break; |
| case OPCODE_DUP: Opcode_DUP(frame); break; |
| case OPCODE_DUP2: Opcode_DUP2(frame); break; |
| case OPCODE_DUP_X1: Opcode_DUP_X1(frame); break; |
| case OPCODE_DUP_X2: Opcode_DUP_X2(frame); break; |
| case OPCODE_DUP2_X1: Opcode_DUP2_X1(frame); break; |
| case OPCODE_DUP2_X2: Opcode_DUP2_X2(frame); break; |
| |
| case OPCODE_MULTIANEWARRAY: |
| Opcode_MULTIANEWARRAY(frame); |
| goto check_exception; |
| case OPCODE_ANEWARRAY: |
| Opcode_ANEWARRAY(frame); |
| goto check_exception; |
| case OPCODE_NEWARRAY: |
| Opcode_NEWARRAY(frame); |
| goto check_exception; |
| case OPCODE_NEW: |
| Opcode_NEW(frame); |
| goto check_exception; |
| |
| case OPCODE_ARRAYLENGTH: |
| Opcode_ARRAYLENGTH(frame); |
| goto check_exception; |
| |
| case OPCODE_CHECKCAST: |
| Opcode_CHECKCAST(frame); |
| goto check_exception; |
| case OPCODE_INSTANCEOF: |
| Opcode_INSTANCEOF(frame); |
| goto check_exception; |
| |
| case OPCODE_ATHROW: |
| Opcode_ATHROW(frame); |
| frame.exc = get_current_thread_exception(); |
| goto got_exception; |
| |
| case OPCODE_MONITORENTER: |
| { |
| MonitorList *new_ml = frame.free_monitors; |
| if (new_ml) { |
| frame.free_monitors = new_ml->next; |
| } else { |
| new_ml = (MonitorList*) ALLOC_FRAME(sizeof(MonitorList)); |
| } |
| new_ml->next = frame.locked_monitors; |
| new_ml->monitor = NULL; |
| frame.locked_monitors = new_ml; |
| Opcode_MONITORENTER(frame); |
| frame.exc = get_current_thread_exception(); |
| |
| if (frame.exc != 0) { |
| frame.locked_monitors = new_ml->next; |
| |
| new_ml->next = frame.free_monitors; |
| frame.free_monitors = new_ml; |
| goto got_exception; |
| } |
| } |
| break; |
| case OPCODE_MONITOREXIT: |
| Opcode_MONITOREXIT(frame); |
| goto check_exception; |
| |
| case OPCODE_BASTORE: Opcode_BASTORE(frame); goto check_exception; |
| case OPCODE_CASTORE: Opcode_CASTORE(frame); goto check_exception; |
| case OPCODE_SASTORE: Opcode_SASTORE(frame); goto check_exception; |
| case OPCODE_IASTORE: Opcode_IASTORE(frame); goto check_exception; |
| case OPCODE_FASTORE: Opcode_FASTORE(frame); goto check_exception; |
| case OPCODE_AASTORE: Opcode_AASTORE(frame); goto check_exception; |
| |
| case OPCODE_BALOAD: Opcode_BALOAD(frame); goto check_exception; |
| case OPCODE_CALOAD: Opcode_CALOAD(frame); goto check_exception; |
| case OPCODE_SALOAD: Opcode_SALOAD(frame); goto check_exception; |
| case OPCODE_IALOAD: Opcode_IALOAD(frame); goto check_exception; |
| case OPCODE_FALOAD: Opcode_FALOAD(frame); goto check_exception; |
| case OPCODE_AALOAD: Opcode_AALOAD(frame); goto check_exception; |
| |
| case OPCODE_LASTORE: Opcode_LASTORE(frame); goto check_exception; |
| case OPCODE_DASTORE: Opcode_LASTORE(frame); goto check_exception; |
| |
| case OPCODE_LALOAD: Opcode_LALOAD(frame); goto check_exception; |
| case OPCODE_DALOAD: Opcode_LALOAD(frame); goto check_exception; |
| |
| case OPCODE_TABLESWITCH: Opcode_TABLESWITCH(frame); break; |
| case OPCODE_LOOKUPSWITCH: Opcode_LOOKUPSWITCH(frame); break; |
| case OPCODE_GOTO: Opcode_GOTO(frame); goto check_exception; |
| case OPCODE_GOTO_W: Opcode_GOTO_W(frame); goto check_exception; |
| case OPCODE_JSR: Opcode_JSR(frame); break; |
| case OPCODE_JSR_W: Opcode_JSR_W(frame); break; |
| case OPCODE_RET: Opcode_RET(frame); break; |
| case OPCODE_PUTSTATIC: |
| Opcode_PUTSTATIC(frame); |
| goto check_exception; |
| case OPCODE_GETSTATIC: |
| Opcode_GETSTATIC(frame); |
| goto check_exception; |
| |
| case OPCODE_PUTFIELD: |
| Opcode_PUTFIELD(frame); |
| goto check_exception; |
| case OPCODE_GETFIELD: |
| Opcode_GETFIELD(frame); |
| goto check_exception; |
| case OPCODE_INVOKESTATIC: |
| Opcode_INVOKESTATIC(frame); |
| frame.exc = get_current_thread_exception(); |
| if (frame.exc != 0) goto got_exception; |
| frame.ip += 3; |
| break; |
| |
| case OPCODE_INVOKESPECIAL: |
| Opcode_INVOKESPECIAL(frame); |
| frame.exc = get_current_thread_exception(); |
| if (frame.exc != 0) goto got_exception; |
| frame.ip += 3; |
| break; |
| |
| case OPCODE_INVOKEVIRTUAL: |
| Opcode_INVOKEVIRTUAL(frame); |
| frame.exc = get_current_thread_exception(); |
| if (frame.exc != 0) goto got_exception; |
| frame.ip += 3; |
| break; |
| |
| case OPCODE_INVOKEINTERFACE: |
| Opcode_INVOKEINTERFACE(frame); |
| frame.exc = get_current_thread_exception(); |
| if (frame.exc != 0) goto got_exception; |
| frame.ip += 5; |
| break; |
| |
| case OPCODE_LDC: Opcode_LDC(frame); goto check_exception; |
| case OPCODE_LDC_W: Opcode_LDC_W(frame); goto check_exception; |
| case OPCODE_LDC2_W: Opcode_LDC2_W(frame); break; |
| |
| case OPCODE_IFNULL: |
| case OPCODE_IFEQ: Opcode_IFEQ(frame); goto check_exception; |
| |
| case OPCODE_IFNONNULL: |
| case OPCODE_IFNE: Opcode_IFNE(frame); goto check_exception; |
| case OPCODE_IFGE: Opcode_IFGE(frame); goto check_exception; |
| case OPCODE_IFGT: Opcode_IFGT(frame); goto check_exception; |
| case OPCODE_IFLE: Opcode_IFLE(frame); goto check_exception; |
| case OPCODE_IFLT: Opcode_IFLT(frame); goto check_exception; |
| |
| case OPCODE_IF_ACMPEQ: |
| case OPCODE_IF_ICMPEQ: Opcode_IF_ICMPEQ(frame); goto check_exception; |
| |
| case OPCODE_IF_ACMPNE: |
| case OPCODE_IF_ICMPNE: Opcode_IF_ICMPNE(frame); goto check_exception; |
| |
| case OPCODE_IF_ICMPGE: Opcode_IF_ICMPGE(frame); goto check_exception; |
| case OPCODE_IF_ICMPGT: Opcode_IF_ICMPGT(frame); goto check_exception; |
| case OPCODE_IF_ICMPLE: Opcode_IF_ICMPLE(frame); goto check_exception; |
| case OPCODE_IF_ICMPLT: Opcode_IF_ICMPLT(frame); goto check_exception; |
| |
| case OPCODE_FCMPL: Opcode_FCMPL(frame); break; |
| case OPCODE_FCMPG: Opcode_FCMPG(frame); break; |
| case OPCODE_DCMPL: Opcode_DCMPL(frame); break; |
| case OPCODE_DCMPG: Opcode_DCMPG(frame); break; |
| |
| case OPCODE_LCMP: Opcode_LCMP(frame); break; |
| |
| case OPCODE_I2L: Opcode_I2L(frame); break; |
| case OPCODE_I2D: Opcode_I2D(frame); break; |
| case OPCODE_F2L: Opcode_F2L(frame); break; |
| case OPCODE_F2D: Opcode_F2D(frame); break; |
| case OPCODE_F2I: Opcode_F2I(frame); break; |
| case OPCODE_I2F: Opcode_I2F(frame); break; |
| case OPCODE_I2B: Opcode_I2B(frame); break; |
| case OPCODE_I2S: Opcode_I2S(frame); break; |
| case OPCODE_I2C: Opcode_I2C(frame); break; |
| case OPCODE_D2F: Opcode_D2F(frame); break; |
| case OPCODE_D2I: Opcode_D2I(frame); break; |
| case OPCODE_L2F: Opcode_L2F(frame); break; |
| case OPCODE_L2I: Opcode_L2I(frame); break; |
| case OPCODE_L2D: Opcode_L2D(frame); break; |
| case OPCODE_D2L: Opcode_D2L(frame); break; |
| case OPCODE_BREAKPOINT: |
| ip0 = Opcode_BREAKPOINT(frame); |
| breakpoint_processed = true; |
| goto restart; |
| |
| case OPCODE_WIDE: |
| { |
| U_8* ip1 = frame.ip + 1; |
| switch(*ip1) { |
| case OPCODE_ALOAD: Opcode_WIDE_ALOAD(frame); break; |
| case OPCODE_ILOAD: Opcode_WIDE_ILOAD(frame); break; |
| case OPCODE_FLOAD: Opcode_WIDE_ILOAD(frame); break; |
| case OPCODE_DLOAD: Opcode_WIDE_LLOAD(frame); break; |
| case OPCODE_LLOAD: Opcode_WIDE_LLOAD(frame); break; |
| case OPCODE_ASTORE: Opcode_WIDE_ASTORE(frame); break; |
| case OPCODE_ISTORE: Opcode_WIDE_ISTORE(frame); break; |
| case OPCODE_FSTORE: Opcode_WIDE_ISTORE(frame); break; |
| case OPCODE_LSTORE: Opcode_WIDE_LSTORE(frame); break; |
| case OPCODE_DSTORE: Opcode_WIDE_LSTORE(frame); break; |
| case OPCODE_IINC: Opcode_WIDE_IINC(frame); break; |
| case OPCODE_RET: Opcode_WIDE_RET(frame); break; |
| default: |
| INFO("wide bytecode " << (int)*ip1 << " not implemented\n"); |
| stackDump(stdout, frame); |
| DIE(("Unexpected wide bytecode")); |
| } |
| break; |
| } |
| |
| default: INFO("bytecode " << (int)ip0 << " not implemented\n"); |
| stackDump(stdout, frame); |
| DIE(("Unexpected bytecode")); |
| } |
| assert(&frame == getLastStackFrame()); |
| continue; |
| |
| check_exception: |
| frame.exc = get_current_thread_exception(); |
| if (frame.exc == 0) continue; |
| got_exception: |
| assert(&frame == getLastStackFrame()); |
| |
| clear_current_thread_exception(); |
| |
| if (interpreter_ti_notification_mode) { |
| frame.exc_catch = |
| (ManagedObject*) get_thread_ptr()->jvmti_thread.p_exception_object_ti; |
| p_TLS_vmthread->jvmti_thread.p_exception_object_ti = NULL; |
| |
| if (frame.exc != frame.exc_catch) { |
| |
| Method *method = frame.method; |
| jlocation loc = frame.ip - method->get_byte_code_addr(); |
| |
| if (frame.exc_catch != NULL) { |
| |
| // EXCEPTION_CATCH should be generated for frame.exc_catch |
| jvmti_interpreter_exception_catch_event_callback_call( |
| frame.exc_catch, method, loc); |
| |
| assert(!exn_raised()); |
| |
| // event is sent |
| frame.exc_catch = NULL; |
| |
| // if no pending exception continue execution |
| if (frame.exc == NULL) continue; |
| } |
| |
| // EXCEPTION event to be generated |
| assert(frame.exc); |
| Method *catch_method; |
| jlocation catch_location; |
| findCatchMethod(&frame.exc, &catch_method, &catch_location); |
| M2N_ALLOC_MACRO; |
| jvmti_interpreter_exception_event_callback_call(frame.exc, method, loc, catch_method, catch_location); |
| M2N_FREE_MACRO; |
| assert(!exn_raised()); |
| if (interpreter_ti_notification_mode) |
| p_TLS_vmthread->jvmti_thread.p_exception_object_ti = |
| (volatile ManagedObject*) frame.exc; |
| } |
| } |
| |
| if (processExceptionHandler(frame, &frame.exc)) { |
| frame.stack.clear(); |
| frame.stack.push(); |
| frame.stack.pick().ref = COMPRESS_INTERP(frame.exc); |
| frame.stack.ref() = FLAG_OBJECT; |
| frame.exc = NULL; |
| |
| int &state = get_thread_ptr()->interpreter_state; |
| |
| if (state & INTERP_STATE_STACK_OVERFLOW) { |
| state &= ~INTERP_STATE_STACK_OVERFLOW; |
| } |
| continue; |
| } |
| |
| set_current_thread_exception(frame.exc); |
| |
| if (frame.locked_monitors) { |
| M2N_ALLOC_MACRO; |
| vm_monitor_exit_wrapper(frame.locked_monitors->monitor); |
| M2N_FREE_MACRO; |
| assert(!frame.locked_monitors->next); |
| } |
| |
| DEBUG_TRACE("<EXCEPTION> "); |
| if (interpreter_ti_notification_mode |
| & INTERPRETER_TI_METHOD_EXIT_EVENT) |
| method_exit_callback_with_frame(frame.method, frame); |
| |
| if (frame.framePopListener) |
| frame_pop_callback(frame.framePopListener, frame.method, true); |
| |
| M2N_FREE_MACRO; |
| assert(!hythread_is_suspend_enabled()); |
| return; |
| } |
| } |
| |
| void |
| interpreter_execute_method( |
| Method *method, |
| jvalue *return_value, |
| jvalue *args) { |
| |
| assert(!hythread_is_suspend_enabled()); |
| |
| StackFrame frame; |
| memset(&frame, 0, sizeof(frame)); |
| frame.method = method; |
| frame.prev = getLastStackFrame(); |
| |
| // TODO: not optimal to call is_static twice. |
| if (!method->is_static()) { |
| frame.This = args[0].l->object; |
| } |
| if (frame.prev == 0) { |
| get_thread_ptr()->firstFrame = (void*) &frame; |
| } |
| setLastStackFrame(&frame); |
| |
| if (method->is_native()) { |
| interpreter_execute_native_method(method, return_value, args); |
| setLastStackFrame(frame.prev); |
| return; |
| } |
| |
| DEBUG_TRACE("\n{{{ interpreter_invoke: " << method); |
| |
| DEBUG("\tmax stack = " << method->get_max_stack() << endl); |
| DEBUG("\tmax locals = " << method->get_max_locals() << endl); |
| |
| // Setup locals and stack on C stack. |
| SETUP_LOCALS_AND_STACK(frame, method); |
| |
| int pos = 0; |
| int arg = 0; |
| |
| if(!method->is_static()) { |
| frame.locals.ref(pos) = FLAG_OBJECT; |
| REF ref = 0; |
| ObjectHandle h = (ObjectHandle) args[arg++].l; |
| if (h) { |
| ref = COMPRESS_INTERP(h->object); |
| frame.This = h->object; |
| } |
| frame.locals(pos++).ref = ref; |
| } |
| |
| Arg_List_Iterator iter = method_get_argument_list(method); |
| |
| Java_Type typ; |
| DEBUG("\targs types = "); |
| while((typ = curr_arg(iter)) != JAVA_TYPE_END) { |
| DEBUG((char)typ); |
| ObjectHandle h; |
| |
| switch(typ) { |
| case JAVA_TYPE_LONG: |
| case JAVA_TYPE_DOUBLE: |
| Value2 val; |
| val.i64 = args[arg++].j; |
| frame.locals.setLong(pos, val); |
| pos += 2; |
| break; |
| case JAVA_TYPE_CLASS: |
| case JAVA_TYPE_ARRAY: |
| { |
| h = (ObjectHandle) args[arg++].l; |
| |
| REF ref = (h == NULL) ? 0 : COMPRESS_INTERP(h->object); |
| frame.locals.ref(pos) = FLAG_OBJECT; |
| frame.locals(pos++).ref = ref; |
| ASSERT_OBJECT(UNCOMPRESS_INTERP(ref)); |
| } |
| break; |
| case JAVA_TYPE_FLOAT: |
| frame.locals(pos++).f = args[arg++].f; |
| break; |
| case JAVA_TYPE_SHORT: |
| frame.locals(pos++).i = (I_32)args[arg++].s; |
| break; |
| case JAVA_TYPE_CHAR: |
| frame.locals(pos++).i = (U_32)args[arg++].c; |
| break; |
| case JAVA_TYPE_BYTE: |
| frame.locals(pos++).i = (I_32)args[arg++].b; |
| break; |
| case JAVA_TYPE_BOOLEAN: |
| frame.locals(pos++).i = (I_32)args[arg++].z; |
| break; |
| default: |
| frame.locals(pos++).u = (U_32)args[arg++].i; |
| break; |
| } |
| iter = advance_arg_iterator(iter); |
| } |
| DEBUG(endl); |
| |
| Java_Type ret_type = method->get_return_java_type(); |
| |
| interpreter(frame); |
| |
| jvalue *resultPtr = (jvalue*) return_value; |
| |
| /** |
| gwu2: We should clear the result before checking exception, |
| otherwise we could exit this method with some undefined result, |
| JNI wrappers like CallObjectMethod will allocate object handle |
| according to the value of result, so an object handle refering wild |
| pointer will be inserted into local object list, and will be |
| enumerated,... It'll definitely fail. |
| */ |
| if ((resultPtr != NULL) && (ret_type != JAVA_TYPE_VOID)) { |
| resultPtr->l = 0; //clear it |
| } |
| |
| if (check_current_thread_exception()) { |
| setLastStackFrame(frame.prev); |
| DEBUG_TRACE("<EXCEPTION> interpreter_invoke }}}\n"); |
| return; |
| } |
| |
| switch(ret_type) { |
| case JAVA_TYPE_LONG: |
| case JAVA_TYPE_DOUBLE: |
| { |
| Value2 val; |
| val = frame.stack.getLong(0); |
| resultPtr->j = val.i64; |
| } |
| break; |
| |
| case JAVA_TYPE_FLOAT: |
| resultPtr->f = frame.stack.pick().f; |
| break; |
| |
| case JAVA_TYPE_VOID: |
| break; |
| |
| case JAVA_TYPE_BOOLEAN: |
| case JAVA_TYPE_BYTE: |
| case JAVA_TYPE_CHAR: |
| case JAVA_TYPE_SHORT: |
| case JAVA_TYPE_INT: |
| case VM_DATA_TYPE_MP: |
| case VM_DATA_TYPE_UP: |
| resultPtr->i = frame.stack.pick().i; |
| break; |
| |
| case JAVA_TYPE_CLASS: |
| case JAVA_TYPE_ARRAY: |
| case JAVA_TYPE_STRING: |
| |
| { |
| ASSERT_OBJECT(UNCOMPRESS_INTERP(frame.stack.pick().ref)); |
| ObjectHandle h = 0; |
| if (frame.stack.pick().ref) { |
| h = oh_allocate_local_handle(); |
| h->object = UNCOMPRESS_INTERP(frame.stack.pick().ref); |
| } |
| resultPtr->l = h; |
| } |
| break; |
| |
| default: |
| LDIE(53, "Unexpected java type"); |
| } |
| setLastStackFrame(frame.prev); |
| DEBUG_TRACE("interpreter_invoke }}}\n"); |
| } |
| |
| static void |
| interpreterInvokeStatic(StackFrame& prevFrame, Method *method) { |
| |
| StackFrame frame; |
| memset(&frame, 0, sizeof(frame)); |
| frame.prev = &prevFrame; |
| frame.method = method; |
| assert(frame.prev == getLastStackFrame()); |
| setLastStackFrame(&frame); |
| |
| if(method->is_native()) { |
| interpreterInvokeStaticNative(prevFrame, frame, method); |
| setLastStackFrame(frame.prev); |
| return; |
| } |
| |
| DEBUG_TRACE("\n{{{ invoke_static : " << method); |
| |
| DEBUG("\tmax stack = " << method->get_max_stack() << endl); |
| DEBUG("\tmax locals = " << method->get_max_locals() << endl); |
| |
| // Setup locals and stack on C stack. |
| SETUP_LOCALS_AND_STACK(frame, method); |
| |
| frame.This = *(method->get_class()->get_class_handle()); |
| int args = method->get_num_arg_slots(); |
| |
| for(int i = args-1; i >= 0; --i) { |
| frame.locals(i) = prevFrame.stack.pick(args-1 - i); |
| frame.locals.ref(i) = prevFrame.stack.ref(args-1 - i); |
| } |
| |
| frame.jvmti_pop_frame = POP_FRAME_AVAILABLE; |
| |
| interpreter(frame); |
| |
| if (frame.jvmti_pop_frame == POP_FRAME_NOW) { |
| setLastStackFrame(frame.prev); |
| clear_current_thread_exception(); |
| frame.prev->ip -= 3; |
| DEBUG_TRACE("<POP_FRAME> invoke_static }}}\n"); |
| return; |
| } |
| |
| prevFrame.stack.popClearRef(args); |
| |
| if (check_current_thread_exception()) { |
| setLastStackFrame(frame.prev); |
| DEBUG_TRACE("<EXCEPTION> invoke_static }}}\n"); |
| return; |
| } |
| |
| switch(method->get_return_java_type()) { |
| case JAVA_TYPE_VOID: |
| break; |
| |
| case JAVA_TYPE_CLASS: |
| case JAVA_TYPE_ARRAY: |
| case JAVA_TYPE_STRING: |
| prevFrame.stack.push(); |
| prevFrame.stack.pick() = frame.stack.pick(); |
| prevFrame.stack.ref() = FLAG_OBJECT; |
| break; |
| |
| case JAVA_TYPE_FLOAT: |
| case JAVA_TYPE_BOOLEAN: |
| case JAVA_TYPE_BYTE: |
| case JAVA_TYPE_CHAR: |
| case JAVA_TYPE_SHORT: |
| case JAVA_TYPE_INT: |
| prevFrame.stack.push(); |
| prevFrame.stack.pick() = frame.stack.pick(); |
| break; |
| |
| case JAVA_TYPE_LONG: |
| case JAVA_TYPE_DOUBLE: |
| prevFrame.stack.push(2); |
| prevFrame.stack.pick(s0) = frame.stack.pick(s0); |
| prevFrame.stack.pick(s1) = frame.stack.pick(s1); |
| break; |
| |
| default: |
| LDIE(53, "Unexpected java type"); |
| } |
| |
| setLastStackFrame(frame.prev); |
| DEBUG_TRACE("invoke_static }}}\n"); |
| } |
| |
| static void |
| interpreterInvoke(StackFrame& prevFrame, Method *method, int args, ManagedObject *obj, bool intf) { |
| |
| StackFrame frame; |
| memset(&frame, 0, sizeof(frame)); |
| frame.prev = &prevFrame; |
| assert(frame.prev == getLastStackFrame()); |
| frame.method = method; |
| frame.This = obj; |
| #ifndef NDEBUG |
| frame.dump_bytecodes = prevFrame.dump_bytecodes; |
| #endif |
| setLastStackFrame(&frame); |
| |
| |
| if(method->is_native()) { |
| interpreterInvokeVirtualNative(prevFrame, frame, method, args); |
| setLastStackFrame(frame.prev); |
| return; |
| } |
| |
| DEBUG("\tmax stack = " << method->get_max_stack() << endl); |
| DEBUG("\tmax locals = " << method->get_max_locals() << endl); |
| |
| // Setup locals and stack on C stack. |
| SETUP_LOCALS_AND_STACK(frame, method); |
| |
| for(int i = args-1; i >= 0; --i) { |
| frame.locals(i) = prevFrame.stack.pick(args-1 - i); |
| frame.locals.ref(i) = prevFrame.stack.ref(args-1 - i); |
| } |
| |
| |
| frame.jvmti_pop_frame = POP_FRAME_AVAILABLE; |
| |
| interpreter(frame); |
| |
| if (frame.jvmti_pop_frame == POP_FRAME_NOW) { |
| setLastStackFrame(frame.prev); |
| clear_current_thread_exception(); |
| if (intf) frame.prev->ip -= 5; else frame.prev->ip -= 3; |
| return; |
| } |
| |
| prevFrame.stack.popClearRef(args); |
| |
| if (check_current_thread_exception()) { |
| setLastStackFrame(frame.prev); |
| return; |
| } |
| |
| switch(method->get_return_java_type()) { |
| case JAVA_TYPE_VOID: |
| break; |
| |
| case JAVA_TYPE_CLASS: |
| case JAVA_TYPE_ARRAY: |
| case JAVA_TYPE_STRING: |
| prevFrame.stack.push(); |
| prevFrame.stack.pick() = frame.stack.pick(); |
| prevFrame.stack.ref() = FLAG_OBJECT; |
| break; |
| |
| case JAVA_TYPE_FLOAT: |
| case JAVA_TYPE_BOOLEAN: |
| case JAVA_TYPE_BYTE: |
| case JAVA_TYPE_CHAR: |
| case JAVA_TYPE_SHORT: |
| case JAVA_TYPE_INT: |
| prevFrame.stack.push(); |
| prevFrame.stack.pick() = frame.stack.pick(); |
| break; |
| |
| case JAVA_TYPE_LONG: |
| case JAVA_TYPE_DOUBLE: |
| prevFrame.stack.push(2); |
| prevFrame.stack.pick(s0) = frame.stack.pick(s0); |
| prevFrame.stack.pick(s1) = frame.stack.pick(s1); |
| break; |
| |
| default: |
| LDIE(53, "Unexpected java type"); |
| } |
| |
| setLastStackFrame(frame.prev); |
| } |
| |
| static void |
| interpreterInvokeVirtual(StackFrame& prevFrame, Method *method) { |
| |
| int args = method->get_num_arg_slots(); |
| REF ref = prevFrame.stack.pick(args-1).ref; |
| |
| if (ref == 0) { |
| throwNPE(); |
| return; |
| } |
| |
| ManagedObject *obj = UNCOMPRESS_INTERP(ref); |
| ASSERT_OBJECT(obj); |
| |
| Class *objClass = obj->vt()->clss; |
| method = objClass->get_method_from_vtable(method->get_index()); |
| |
| if (method->is_abstract()) { |
| std::ostringstream str; |
| str << class_get_name(method_get_class(method)) << "." << |
| method_get_name(method) << method_get_descriptor(method); |
| throwAME(str.str().c_str()); |
| return; |
| } |
| |
| DEBUG_TRACE("\n{{{ invoke_virtual : " << method); |
| |
| interpreterInvoke(prevFrame, method, args, obj, false); |
| DEBUG_TRACE("invoke_virtual }}}\n"); |
| } |
| |
| static void |
| interpreterInvokeInterface(StackFrame& prevFrame, Method *method) { |
| |
| int args = method->get_num_arg_slots(); |
| REF ref = prevFrame.stack.pick(args-1).ref; |
| |
| if (ref == 0) { |
| throwNPE(); |
| return; |
| } |
| |
| ManagedObject *obj = UNCOMPRESS_INTERP(ref); |
| ASSERT_OBJECT(obj); |
| |
| if (!vm_instanceof(obj, method->get_class())) { |
| interp_throw_exception("java/lang/IncompatibleClassChangeError", |
| class_get_name(method_get_class(method))); |
| return; |
| } |
| |
| Class *clss = obj->vt()->clss; |
| Method* found_method = class_lookup_method_recursive(clss, method->get_name(), method->get_descriptor()); |
| |
| if (found_method == NULL) { |
| interp_throw_exception("java/lang/AbstractMethodError", |
| method->get_name()->bytes); |
| return; |
| } |
| method = found_method; |
| |
| if (method->is_abstract()) { |
| std::ostringstream str; |
| str << class_get_name(method_get_class(method)) << "." << |
| method_get_name(method) << method_get_descriptor(method); |
| throwAME(str.str().c_str()); |
| return; |
| } |
| |
| if (!method->is_public()) { |
| std::ostringstream str; |
| str << class_get_name(method_get_class(method)) << "." << |
| method_get_name(method) << method_get_descriptor(method); |
| throwIAE(str.str().c_str()); |
| return; |
| } |
| |
| DEBUG_TRACE("\n{{{ invoke_interface : " << method); |
| |
| interpreterInvoke(prevFrame, method, args, obj, true); |
| |
| DEBUG_TRACE("invoke_interface }}}\n"); |
| } |
| |
| static void |
| interpreterInvokeSpecial(StackFrame& prevFrame, Method *method) { |
| |
| int args = method->get_num_arg_slots(); |
| REF ref = prevFrame.stack.pick(args-1).ref; |
| |
| if (ref == 0) { |
| throwNPE(); |
| return; |
| } |
| |
| if (method->is_abstract()) { |
| std::ostringstream str; |
| str << class_get_name(method_get_class(method)) << "." << |
| method_get_name(method) << method_get_descriptor(method); |
| throwAME(str.str().c_str()); |
| return; |
| } |
| |
| ManagedObject *obj = UNCOMPRESS_INTERP(ref); |
| |
| StackFrame frame; |
| memset(&frame, 0, sizeof(frame)); |
| frame.prev = &prevFrame; |
| assert(frame.prev == getLastStackFrame()); |
| frame.method = method; |
| frame.This = obj; |
| setLastStackFrame(&frame); |
| |
| if(method->is_native()) { |
| interpreterInvokeVirtualNative(prevFrame, frame, method, args); |
| |
| setLastStackFrame(frame.prev); |
| return; |
| } |
| |
| DEBUG_TRACE("\n{{{ invoke_special : " << method); |
| |
| DEBUG("\tmax stack = " << method->get_max_stack() << endl); |
| DEBUG("\tmax locals = " << method->get_max_locals() << endl); |
| |
| // Setup locals and stack on C stack. |
| SETUP_LOCALS_AND_STACK(frame, method); |
| |
| for(int i = args-1; i >= 0; --i) { |
| frame.locals(i) = prevFrame.stack.pick(args-1 - i); |
| frame.locals.ref(i) = prevFrame.stack.ref(args-1 - i); |
| } |
| |
| frame.jvmti_pop_frame = POP_FRAME_AVAILABLE; |
| |
| interpreter(frame); |
| |
| if (frame.jvmti_pop_frame == POP_FRAME_NOW) { |
| setLastStackFrame(frame.prev); |
| clear_current_thread_exception(); |
| frame.prev->ip -= 3; |
| DEBUG_TRACE("<POP_FRAME> invoke_special }}}\n"); |
| return; |
| } |
| |
| prevFrame.stack.popClearRef(args); |
| |
| if (check_current_thread_exception()) { |
| setLastStackFrame(frame.prev); |
| DEBUG_TRACE("<EXCEPTION> invoke_special }}}\n"); |
| return; |
| } |
| |
| switch(method->get_return_java_type()) { |
| case JAVA_TYPE_VOID: |
| break; |
| |
| case JAVA_TYPE_CLASS: |
| case JAVA_TYPE_ARRAY: |
| case JAVA_TYPE_STRING: |
| prevFrame.stack.push(); |
| prevFrame.stack.pick() = frame.stack.pick(); |
| prevFrame.stack.ref() = FLAG_OBJECT; |
| break; |
| |
| case JAVA_TYPE_FLOAT: |
| case JAVA_TYPE_BOOLEAN: |
| case JAVA_TYPE_BYTE: |
| case JAVA_TYPE_CHAR: |
| case JAVA_TYPE_SHORT: |
| case JAVA_TYPE_INT: |
| prevFrame.stack.push(); |
| prevFrame.stack.pick() = frame.stack.pick(); |
| break; |
| |
| case JAVA_TYPE_LONG: |
| case JAVA_TYPE_DOUBLE: |
| prevFrame.stack.push(2); |
| prevFrame.stack.pick(s0) = frame.stack.pick(s0); |
| prevFrame.stack.pick(s1) = frame.stack.pick(s1); |
| break; |
| |
| default: |
| LDIE(53, "Unexpected java type"); |
| } |
| setLastStackFrame(frame.prev); |
| DEBUG_TRACE("invoke_special }}}\n"); |
| } |
| |
| GenericFunctionPointer |
| interpreterGetNativeMethodAddr(Method* method) { |
| |
| assert(method->is_native()); |
| |
| if (method->get_state() == Method::ST_Linked ) { |
| return (GenericFunctionPointer) method->get_code_addr(); |
| } |
| |
| NativeCodePtr f = (NativeCodePtr)interp_find_native(method); |
| |
| hythread_suspend_enable(); |
| jvmti_process_native_method_bind_event( (jmethodID) method, f, &f); |
| hythread_suspend_disable(); |
| |
| // TODO: check if we need synchronization here |
| if( f ) { |
| method->set_code_addr(f); |
| method->set_state( Method::ST_Linked ); |
| } |
| |
| return (GenericFunctionPointer)f; |
| } |