Table类
Interpreter类,
class Interpreter: public CC_INTERP_ONLY(CppInterpreter) NOT_CC_INTERP(TemplateInterpreter) { public: // Debugging/printing static InterpreterCodelet* codelet_containing(address pc) { return (InterpreterCodelet*)_code->stub_containing(pc); } #ifdef TARGET_ARCH_x86 # include "interpreter_x86.hpp" #endif };
看这俩个宏
#ifdef CC_INTERP #define CC_INTERP_ONLY(code) code #define NOT_CC_INTERP(code) #else #define CC_INTERP_ONLY(code) #define NOT_CC_INTERP(code) code #endif // CC_INTERP
啥也没干就是继承了,俩个类 CppInterpreter 和 TemplateInterpreter
说起来有点逗,java 是子类实现接口,这c++可好,子类继承了两个父类
class DispatchTable VALUE_OBJ_CLASS_SPEC { public: enum { length = 1 << BitsPerByte }; // an entry point for each byte value (also for undefined bytecodes) private: address _table[number_of_states][length]; // dispatch tables, indexed by tosca and bytecode public: // Attributes EntryPoint entry(int i) const; // return entry point for a given bytecode i void set_entry(int i, EntryPoint& entry); // set entry point for a given bytecode i address* table_for(TosState state) { return _table[state]; } address* table_for() { return table_for((TosState)0); } int distance_from(address *table) { return table - table_for(); } int distance_from(TosState state) { return distance_from(table_for(state)); } // Comparison bool operator == (DispatchTable& y); // for debugging only }; class TemplateInterpreter: public AbstractInterpreter { friend class VMStructs; friend class InterpreterMacroAssembler; friend class TemplateInterpreterGenerator; friend class InterpreterGenerator; friend class TemplateTable; // friend class Interpreter; public: enum MoreConstants { number_of_return_entries = number_of_states, // number of return entry points number_of_deopt_entries = number_of_states, // number of deoptimization entry points number_of_return_addrs = number_of_states // number of return addresses }; protected: static address _throw_ArrayIndexOutOfBoundsException_entry; static address _throw_ArrayStoreException_entry; static address _throw_ArithmeticException_entry; static address _throw_ClassCastException_entry; static address _throw_WrongMethodType_entry; static address _throw_NullPointerException_entry; static address _throw_exception_entry; static address _throw_StackOverflowError_entry; static address _remove_activation_entry; // continuation address if an exception is not handled by current frame #ifdef HOTSWAP static address _remove_activation_preserving_args_entry; // continuation address when current frame is being popped #endif // HOTSWAP #ifndef PRODUCT static EntryPoint _trace_code; #endif // !PRODUCT static EntryPoint _return_entry[number_of_return_entries]; // entry points to return to from a call static EntryPoint _earlyret_entry; // entry point to return early from a call static EntryPoint _deopt_entry[number_of_deopt_entries]; // entry points to return to from a deoptimization static EntryPoint _continuation_entry; static EntryPoint _safept_entry; static address _return_3_addrs_by_index[number_of_return_addrs]; // for invokevirtual return entries static address _return_5_addrs_by_index[number_of_return_addrs]; // for invokeinterface return entries static DispatchTable _active_table; // the active dispatch table (used by the interpreter for dispatch) static DispatchTable _normal_table; // the normal dispatch table (used to set the active table in normal mode) static DispatchTable _safept_table; // the safepoint dispatch table (used to set the active table for safepoints) static address _wentry_point[DispatchTable::length]; // wide instructions only (vtos tosca always) public: // Initialization/debugging static void initialize(); // this only returns whether a pc is within generated code for the interpreter. static bool contains(address pc) { return _code != NULL && _code->contains(pc); } public: static address remove_activation_early_entry(TosState state) { return _earlyret_entry.entry(state); } #ifdef HOTSWAP static address remove_activation_preserving_args_entry() { return _remove_activation_preserving_args_entry; } #endif // HOTSWAP static address remove_activation_entry() { return _remove_activation_entry; } static address throw_exception_entry() { return _throw_exception_entry; } static address throw_ArithmeticException_entry() { return _throw_ArithmeticException_entry; } static address throw_WrongMethodType_entry() { return _throw_WrongMethodType_entry; } static address throw_NullPointerException_entry() { return _throw_NullPointerException_entry; } static address throw_StackOverflowError_entry() { return _throw_StackOverflowError_entry; } // Code generation #ifndef PRODUCT static address trace_code (TosState state) { return _trace_code.entry(state); } #endif // !PRODUCT static address continuation (TosState state) { return _continuation_entry.entry(state); } static address* dispatch_table(TosState state) { return _active_table.table_for(state); } static address* dispatch_table() { return _active_table.table_for(); } static int distance_from_dispatch_table(TosState state){ return _active_table.distance_from(state); } static address* normal_table(TosState state) { return _normal_table.table_for(state); } static address* normal_table() { return _normal_table.table_for(); } // Support for invokes static address* return_3_addrs_by_index_table() { return _return_3_addrs_by_index; } static address* return_5_addrs_by_index_table() { return _return_5_addrs_by_index; } static int TosState_as_index(TosState state); // computes index into return_3_entry_by_index table static address return_entry (TosState state, int length); static address deopt_entry (TosState state, int length); // Safepoint support static void notice_safepoints(); // stops the thread when reaching a safepoint static void ignore_safepoints(); // ignores safepoints // Deoptimization support // Compute the entry address for continuation after static address deopt_continue_after_entry(methodOop method, address bcp, int callee_parameters, bool is_top_frame); // Deoptimization should reexecute this bytecode static bool bytecode_should_reexecute(Bytecodes::Code code); // Compute the address for reexecution static address deopt_reexecute_entry(methodOop method, address bcp); };
这里就看到真身了, jmp(Address(rscratch1, rbx, Address::times_8));
bind(no_safepoint);
lea(rscratch1, ExternalAddress((address)table));
bind(dispatch);
jmp(Address(rscratch1, rbx, Address::times_8));
这里将table地址给了 rscratch1
先看下执行一个add的字节码指令
private static int add(int a, int b) { int c=a+b; int d=c+9; return d; } 0 iload_0 1 iload_1 2 iadd 3 istore_2 4 iload_2 5 bipush 9 7 iadd 8 istore_3 9 iload_3 10 ireturn
执行流程是 先得到
iload_0 ==>
iload_1==>
iadd
那就先取iload_0的指令地址,在dispatch_table表的某项,都值 jmp *(读到的值), 就跳到了 iload_1 对应的汇编指令去执行
形成了一个table表,从这个地址开始偏移00 代表 nop 这个指令的汇编指令地址
*table==>开始
*table+0x00
地址 | 内容 | |
*table+0x00 |
0x0000000002cb6f40 |
nop |
*table+0x8 |
0x0000000002cb6fc0 |
aconst_null |
*table+0x10 |
0x0000000002cb7040 |
iconst_m1 |
*table+0x18 |
0x0000000002cb70c0 |
iconst_0 |
---------------------------------------------------------------------- nop 0 nop [0x0000000002cb6f40, 0x0000000002cb6fa0] 96 bytes 0x0000000002cb6f40: push %rax 0x0000000002cb6f41: jmpq 0x0000000002cb6f70 0x0000000002cb6f46: sub $0x8,%rsp 0x0000000002cb6f4a: vmovss %xmm0,(%rsp) 0x0000000002cb6f4f: jmpq 0x0000000002cb6f70 0x0000000002cb6f54: sub $0x10,%rsp 0x0000000002cb6f58: vmovsd %xmm0,(%rsp) 0x0000000002cb6f5d: jmpq 0x0000000002cb6f70 0x0000000002cb6f62: sub $0x10,%rsp 0x0000000002cb6f66: mov %rax,(%rsp) 0x0000000002cb6f6a: jmpq 0x0000000002cb6f70 0x0000000002cb6f6f: push %rax 0x0000000002cb6f70: movzbl 0x1(%r13),%ebx 0x0000000002cb6f75: inc %r13 0x0000000002cb6f78: movabs $0x667c43f0,%r10 0x0000000002cb6f82: jmpq *(%r10,%rbx,8) 0x0000000002cb6f86: xchg %ax,%ax 0x0000000002cb6f88: add %al,(%rax) 0x0000000002cb6f8a: add %al,(%rax) 0x0000000002cb6f8c: add %al,(%rax) 0x0000000002cb6f8e: add %al,(%rax) 0x0000000002cb6f90: add %al,(%rax) 0x0000000002cb6f92: add %al,(%rax) 0x0000000002cb6f94: add %al,(%rax) 0x0000000002cb6f96: add %al,(%rax) 0x0000000002cb6f98: add %al,(%rax) 0x0000000002cb6f9a: add %al,(%rax) 0x0000000002cb6f9c: add %al,(%rax) 0x0000000002cb6f9e: add %al,(%rax) ---------------------------------------------------------------------- aconst_null 1 aconst_null [0x0000000002cb6fc0, 0x0000000002cb7020] 96 bytes 0x0000000002cb6fc0: push %rax 0x0000000002cb6fc1: jmpq 0x0000000002cb6ff0 0x0000000002cb6fc6: sub $0x8,%rsp 0x0000000002cb6fca: vmovss %xmm0,(%rsp) 0x0000000002cb6fcf: jmpq 0x0000000002cb6ff0 0x0000000002cb6fd4: sub $0x10,%rsp 0x0000000002cb6fd8: vmovsd %xmm0,(%rsp) 0x0000000002cb6fdd: jmpq 0x0000000002cb6ff0 0x0000000002cb6fe2: sub $0x10,%rsp 0x0000000002cb6fe6: mov %rax,(%rsp) 0x0000000002cb6fea: jmpq 0x0000000002cb6ff0 0x0000000002cb6fef: push %rax 0x0000000002cb6ff0: xor %eax,%eax 0x0000000002cb6ff2: movzbl 0x1(%r13),%ebx 0x0000000002cb6ff7: inc %r13 0x0000000002cb6ffa: movabs $0x667c3bf0,%r10 0x0000000002cb7004: jmpq *(%r10,%rbx,8) 0x0000000002cb7008: add %al,(%rax) 0x0000000002cb700a: add %al,(%rax) 0x0000000002cb700c: add %al,(%rax) 0x0000000002cb700e: add %al,(%rax) 0x0000000002cb7010: add %al,(%rax) 0x0000000002cb7012: add %al,(%rax) 0x0000000002cb7014: add %al,(%rax) 0x0000000002cb7016: add %al,(%rax) 0x0000000002cb7018: add %al,(%rax) 0x0000000002cb701a: add %al,(%rax) 0x0000000002cb701c: add %al,(%rax) 0x0000000002cb701e: add %al,(%rax) ---------------------------------------------------------------------- iconst_m1 2 iconst_m1 [0x0000000002cb7040, 0x0000000002cb70a0] 96 bytes 0x0000000002cb7040: push %rax 0x0000000002cb7041: jmpq 0x0000000002cb7070 0x0000000002cb7046: sub $0x8,%rsp 0x0000000002cb704a: vmovss %xmm0,(%rsp) 0x0000000002cb704f: jmpq 0x0000000002cb7070 0x0000000002cb7054: sub $0x10,%rsp 0x0000000002cb7058: vmovsd %xmm0,(%rsp) 0x0000000002cb705d: jmpq 0x0000000002cb7070 0x0000000002cb7062: sub $0x10,%rsp 0x0000000002cb7066: mov %rax,(%rsp) 0x0000000002cb706a: jmpq 0x0000000002cb7070 0x0000000002cb706f: push %rax 0x0000000002cb7070: mov $0xffffffff,%eax 0x0000000002cb7075: movzbl 0x1(%r13),%ebx 0x0000000002cb707a: inc %r13 0x0000000002cb707d: movabs $0x667c1bf0,%r10 0x0000000002cb7087: jmpq *(%r10,%rbx,8) 0x0000000002cb708b: nopl 0x0(%rax,%rax,1) 0x0000000002cb7090: add %al,(%rax) 0x0000000002cb7092: add %al,(%rax) 0x0000000002cb7094: add %al,(%rax) 0x0000000002cb7096: add %al,(%rax) 0x0000000002cb7098: add %al,(%rax) 0x0000000002cb709a: add %al,(%rax) 0x0000000002cb709c: add %al,(%rax) 0x0000000002cb709e: add %al,(%rax) ---------------------------------------------------------------------- iconst_0 3 iconst_0 [0x0000000002cb70c0, 0x0000000002cb7120] 96 bytes 0x0000000002cb70c0: push %rax 0x0000000002cb70c1: jmpq 0x0000000002cb70f0 0x0000000002cb70c6: sub $0x8,%rsp 0x0000000002cb70ca: vmovss %xmm0,(%rsp) 0x0000000002cb70cf: jmpq 0x0000000002cb70f0 0x0000000002cb70d4: sub $0x10,%rsp 0x0000000002cb70d8: vmovsd %xmm0,(%rsp) 0x0000000002cb70dd: jmpq 0x0000000002cb70f0 0x0000000002cb70e2: sub $0x10,%rsp 0x0000000002cb70e6: mov %rax,(%rsp) 0x0000000002cb70ea: jmpq 0x0000000002cb70f0 0x0000000002cb70ef: push %rax 0x0000000002cb70f0: xor %eax,%eax 0x0000000002cb70f2: movzbl 0x1(%r13),%ebx 0x0000000002cb70f7: inc %r13 0x0000000002cb70fa: movabs $0x667c1bf0,%r10 0x0000000002cb7104: jmpq *(%r10,%rbx,8) 0x0000000002cb7108: add %al,(%rax) 0x0000000002cb710a: add %al,(%rax) 0x0000000002cb710c: add %al,(%rax) 0x0000000002cb710e: add %al,(%rax) 0x0000000002cb7110: add %al,(%rax) 0x0000000002cb7112: add %al,(%rax) 0x0000000002cb7114: add %al,(%rax) 0x0000000002cb7116: add %al,(%rax) 0x0000000002cb7118: add %al,(%rax) 0x0000000002cb711a: add %al,(%rax) 0x0000000002cb711c: add %al,(%rax) 0x0000000002cb711e: add %al,(%rax)
这样就解释清楚了,这个table是什么为什么通过dispatch_table 取指_表 能获得指令