// This method is called while executing the raw bytecodes, so none of // the adjustments that BytecodeStream performs applies. void trace(methodHandle method, address bcp, uintptr_t tos, uintptr_t tos2) { MutexLocker ml(BytecodeTrace_lock); ResourceMark rm; if (_current_method != method()) { // Note 1: This code will not work as expected with true MT/MP. // Need an explicit lock or a different solution. tty->cr(); tty->print("[%d] ", (int) Thread::current()->osthread()->thread_id()); method->print_name(tty); tty->cr(); _current_method = method(); } Bytecodes::Code code; if (is_wide()) { // bcp wasn't advanced if previous bytecode was _wide. code = Bytecodes::cast(*(bcp+1)); } else { code = Bytecodes::cast(*bcp); } int bci = bcp - method->code_base(); tty->print("[%d] ", (int) Thread::current()->osthread()->thread_id()); if (Verbose) { tty->print("%8d %4d " INTPTR_FORMAT " " INTPTR_FORMAT " %s", BytecodeCounter::counter_value(), bci, tos, tos2, Bytecodes::name(code)); } else { tty->print("%8d %4d %s", BytecodeCounter::counter_value(), bci, Bytecodes::name(code)); } _next_pc = is_wide() ? bcp+2 : bcp+1; print_attributes(code, bci); // Set is_wide for the next one, since the caller of this doesn't skip // the next bytecode. _is_wide = (code == Bytecodes::_wide); }
void BaseBytecodeStream::assert_raw_index_size(int size) const { if (raw_code() == Bytecodes::_invokedynamic && is_raw()) { // in raw mode, pretend indy is "bJJ__" assert(size == 2, "raw invokedynamic instruction has 2-byte index only"); } else { bytecode()->assert_index_size(size, raw_code(), is_wide()); } }
// Used for methodOop::print_codes(). The input bcp comes from // BytecodeStream, which will skip wide bytecodes. void trace(methodHandle method, address bcp, outputStream* st) { _current_method = method(); ResourceMark rm; Bytecodes::Code code = Bytecodes::code_at(bcp); // Set is_wide _is_wide = (code == Bytecodes::_wide); if (is_wide()) { code = Bytecodes::code_at(bcp+1); } int bci = bcp - method->code_base(); // Print bytecode index and name if (is_wide()) { st->print("%d %s_w", bci, Bytecodes::name(code)); } else { st->print("%d %s", bci, Bytecodes::name(code)); } _next_pc = is_wide() ? bcp+2 : bcp+1; print_attributes(code, bci, st); bytecode_epilog(bci, st); }
// This method is called while executing the raw bytecodes, so none of // the adjustments that BytecodeStream performs applies. void trace(methodHandle method, address bcp, uintptr_t tos, uintptr_t tos2, outputStream* st) { ResourceMark rm; if (_current_method != method()) { // Note 1: This code will not work as expected with true MT/MP. // Need an explicit lock or a different solution. // It is possible for this block to be skipped, if a garbage // _current_method pointer happens to have the same bits as // the incoming method. We could lose a line of trace output. // This is acceptable in a debug-only feature. st->cr(); st->print("[%ld] ", (long) Thread::current()->osthread()->thread_id()); method->print_name(st); st->cr(); _current_method = method(); } Bytecodes::Code code; if (is_wide()) { // bcp wasn't advanced if previous bytecode was _wide. code = Bytecodes::code_at(method(), bcp+1); } else { code = Bytecodes::code_at(method(), bcp); } _code = code; int bci = bcp - method->code_base(); st->print("[%ld] ", (long) Thread::current()->osthread()->thread_id()); if (Verbose) { st->print("%8d %4d " INTPTR_FORMAT " " INTPTR_FORMAT " %s", BytecodeCounter::counter_value(), bci, tos, tos2, Bytecodes::name(code)); } else { st->print("%8d %4d %s", BytecodeCounter::counter_value(), bci, Bytecodes::name(code)); } _next_pc = is_wide() ? bcp+2 : bcp+1; print_attributes(bci); // Set is_wide for the next one, since the caller of this doesn't skip // the next bytecode. _is_wide = (code == Bytecodes::_wide); _code = Bytecodes::_illegal; }
void assert_index_size(int required_size) const { #ifdef ASSERT int isize = instruction_size() - (is_wide() ? 1 : 0) - 1; if (isize == 2 && cur_bc() == Bytecodes::_iinc) isize = 1; else if (isize <= 2) ; // no change else if (has_giant_index()) isize = 4; else isize = 2; assert(isize = required_size, "wrong index size"); #endif }
// ------------------------------------------------------------------ // ciBytecodeStream::next_wide_or_table // // Special handling for switch ops Bytecodes::Code ciBytecodeStream::next_wide_or_table(Bytecodes::Code bc) { switch (bc) { // Check for special bytecode handling case Bytecodes::_wide: // Special handling for the wide bytcode // Get following bytecode; do not return wide assert(Bytecodes::Code(_pc[0]) == Bytecodes::_wide, ""); bc = Bytecodes::java_code(_raw_bc = (Bytecodes::Code)_pc[1]); assert(Bytecodes::wide_length_for(bc) > 2, "must make progress"); _pc += Bytecodes::wide_length_for(bc); _was_wide = _pc; // Flag last wide bytecode found assert(is_wide(), "accessor works right"); break; case Bytecodes::_lookupswitch: _pc++; // Skip wide bytecode _pc += (_start-_pc)&3; // Word align _table_base = (jint*)_pc; // Capture for later usage // table_base[0] is default far_dest // Table has 2 lead elements (default, length), then pairs of u4 values. // So load table length, and compute address at end of table _pc = (address)&_table_base[2+ 2*Bytes::get_Java_u4((address)&_table_base[1])]; break; case Bytecodes::_tableswitch: { _pc++; // Skip wide bytecode _pc += (_start-_pc)&3; // Word align _table_base = (jint*)_pc; // Capture for later usage // table_base[0] is default far_dest int lo = Bytes::get_Java_u4((address)&_table_base[1]);// Low bound int hi = Bytes::get_Java_u4((address)&_table_base[2]);// High bound int len = hi - lo + 1; // Dense table size _pc = (address)&_table_base[3+len]; // Skip past table break; } default: fatal("unhandled bytecode"); } return bc; }
int get_index_special() { return (is_wide()) ? get_index_u2() : get_index_u1(); }
void BytecodePrinter::print_attributes(int bci, outputStream* st) { // Show attributes of pre-rewritten codes Bytecodes::Code code = Bytecodes::java_code(raw_code()); // If the code doesn't have any fields there's nothing to print. // note this is ==1 because the tableswitch and lookupswitch are // zero size (for some reason) and we want to print stuff out for them. if (Bytecodes::length_for(code) == 1) { st->cr(); return; } switch(code) { // Java specific bytecodes only matter. case Bytecodes::_bipush: st->print_cr(" " INT32_FORMAT, get_byte()); break; case Bytecodes::_sipush: st->print_cr(" " INT32_FORMAT, get_short()); break; case Bytecodes::_ldc: if (Bytecodes::uses_cp_cache(raw_code())) { print_constant(get_index_u1_cpcache(), st); } else { print_constant(get_index_u1(), st); } break; case Bytecodes::_ldc_w: case Bytecodes::_ldc2_w: if (Bytecodes::uses_cp_cache(raw_code())) { print_constant(get_index_u2_cpcache(), st); } else { print_constant(get_index_u2(), st); } break; case Bytecodes::_iload: case Bytecodes::_lload: case Bytecodes::_fload: case Bytecodes::_dload: case Bytecodes::_aload: case Bytecodes::_istore: case Bytecodes::_lstore: case Bytecodes::_fstore: case Bytecodes::_dstore: case Bytecodes::_astore: st->print_cr(" #%d", get_index_special()); break; case Bytecodes::_iinc: { int index = get_index_special(); jint offset = is_wide() ? get_short(): get_byte(); st->print_cr(" #%d " INT32_FORMAT, index, offset); } break; case Bytecodes::_newarray: { BasicType atype = (BasicType)get_index_u1(); const char* str = type2name(atype); if (str == NULL || atype == T_OBJECT || atype == T_ARRAY) { assert(false, "Unidentified basic type"); } st->print_cr(" %s", str); } break; case Bytecodes::_anewarray: { int klass_index = get_index_u2(); ConstantPool* constants = method()->constants(); Symbol* name = constants->klass_name_at(klass_index); st->print_cr(" %s ", name->as_C_string()); } break; case Bytecodes::_multianewarray: { int klass_index = get_index_u2(); int nof_dims = get_index_u1(); ConstantPool* constants = method()->constants(); Symbol* name = constants->klass_name_at(klass_index); st->print_cr(" %s %d", name->as_C_string(), nof_dims); } break; case Bytecodes::_ifeq: case Bytecodes::_ifnull: case Bytecodes::_iflt: case Bytecodes::_ifle: case Bytecodes::_ifne: case Bytecodes::_ifnonnull: case Bytecodes::_ifgt: case Bytecodes::_ifge: case Bytecodes::_if_icmpeq: case Bytecodes::_if_icmpne: case Bytecodes::_if_icmplt: case Bytecodes::_if_icmpgt: case Bytecodes::_if_icmple: case Bytecodes::_if_icmpge: case Bytecodes::_if_acmpeq: case Bytecodes::_if_acmpne: case Bytecodes::_goto: case Bytecodes::_jsr: st->print_cr(" %d", bci + get_short()); break; case Bytecodes::_goto_w: case Bytecodes::_jsr_w: st->print_cr(" %d", bci + get_int()); break; case Bytecodes::_ret: st->print_cr(" %d", get_index_special()); break; case Bytecodes::_tableswitch: { align(); int default_dest = bci + get_int(); int lo = get_int(); int hi = get_int(); int len = hi - lo + 1; jint* dest = NEW_RESOURCE_ARRAY(jint, len); for (int i = 0; i < len; i++) { dest[i] = bci + get_int(); } st->print(" %d " INT32_FORMAT " " INT32_FORMAT " ", default_dest, lo, hi); int first = true; for (int ll = lo; ll <= hi; ll++, first = false) { int idx = ll - lo; const char *format = first ? " %d:" INT32_FORMAT " (delta: %d)" : ", %d:" INT32_FORMAT " (delta: %d)"; st->print(format, ll, dest[idx], dest[idx]-bci); } st->cr(); } break; case Bytecodes::_lookupswitch: { align(); int default_dest = bci + get_int(); int len = get_int(); jint* key = NEW_RESOURCE_ARRAY(jint, len); jint* dest = NEW_RESOURCE_ARRAY(jint, len); for (int i = 0; i < len; i++) { key [i] = get_int(); dest[i] = bci + get_int(); }; st->print(" %d %d ", default_dest, len); bool first = true; for (int ll = 0; ll < len; ll++, first = false) { const char *format = first ? " " INT32_FORMAT ":" INT32_FORMAT : ", " INT32_FORMAT ":" INT32_FORMAT ; st->print(format, key[ll], dest[ll]); } st->cr(); } break; case Bytecodes::_putstatic: case Bytecodes::_getstatic: case Bytecodes::_putfield: case Bytecodes::_getfield: print_field_or_method(get_index_u2_cpcache(), st); break; case Bytecodes::_invokevirtual: case Bytecodes::_invokespecial: case Bytecodes::_invokestatic: print_field_or_method(get_index_u2_cpcache(), st); break; case Bytecodes::_invokeinterface: { int i = get_index_u2_cpcache(); int n = get_index_u1(); get_byte(); // ignore zero byte print_field_or_method(i, st); } break; case Bytecodes::_invokedynamic: print_field_or_method(get_index_u4(), st); break; case Bytecodes::_new: case Bytecodes::_checkcast: case Bytecodes::_instanceof: { int i = get_index_u2(); ConstantPool* constants = method()->constants(); Symbol* name = constants->klass_name_at(i); st->print_cr(" %d <%s>", i, name->as_C_string()); } break; case Bytecodes::_wide: // length is zero not one, but printed with no more info. break; default: ShouldNotReachHere(); break; } }
// Get a byte index following this bytecode. // If prefixed with a wide bytecode, get a wide index. int get_index() const { assert_index_size(is_wide() ? 2 : 1); return (_pc == _was_wide) // was widened? ? Bytes::get_Java_u2(_bc_start+2) // yes, return wide index : _bc_start[1]; // no, return narrow index }
//Dump LIR stmts stored in fu->lirList array. void dump_lir2(LIR * lir, DexFile * df, INT pos) { if (g_tfile == NULL || lir == NULL) return; if (pos < 0) { fprintf(g_tfile, "%s", LIR_name(lir)); } else { fprintf(g_tfile, "(%dth)%s", pos, LIR_name(lir)); } switch (LIR_opcode(lir)) { case LOP_NOP: break; case LOP_CONST: switch (LIR_dt(lir)) { case LIR_JDT_unknown: fprintf(g_tfile, ", INT"); if (is_s4(LIR_int_imm(lir)) && LIR_res(lir) < 16) { //AB fprintf(g_tfile, ", v%d <- %d", LIR_res(lir), (INT)LIR_int_imm(lir)); } else if (is_s16(LIR_int_imm(lir))) { //AABBBB fprintf(g_tfile, ", v%d <- %d", LIR_res(lir), (INT)LIR_int_imm(lir)); } else { //AABBBBBBBB fprintf(g_tfile, ", v%d <- %d", LIR_res(lir), (INT)LIR_int_imm(lir)); } break; case LIR_JDT_wide: fprintf(g_tfile, ", %s", get_dt_name(lir)); if (is_swide16(LIR_int_imm(lir))) { //AABBBB fprintf(g_tfile, ", (v%d,v%d) <- %d", LIR_res(lir), LIR_res(lir) + 1, (INT)LIR_int_imm(lir)); } else if (is_swide32(LIR_int_imm(lir))) { //AABBBBBBBB fprintf(g_tfile, ", (v%d,v%d) <- %d", LIR_res(lir), LIR_res(lir) + 1, (INT)LIR_int_imm(lir)); } else { //AABBBBBBBBBBBBBBBB fprintf(g_tfile, ", (v%d,v%d) <- %lld", LIR_res(lir), LIR_res(lir) + 1, LIR_int_imm(lir)); } break; default: /* It seems dex does not distinguish float and integer const. And regard float as 32bit integer, double will be 64bit integer. */ IS_TRUE0(0); } break; case LOP_RETURN: { switch (LIR_dt(lir)) { case LIR_JDT_unknown: //return preg. fprintf(g_tfile, ", INT"); fprintf(g_tfile, ", v%d", LIR_res(lir)); break; case LIR_JDT_void: //No return value. break; case LIR_JDT_object: //return object. fprintf(g_tfile, ", obj_ptr:v%d", LIR_res(lir)); break; case LIR_JDT_wide: fprintf(g_tfile, ", %s", get_dt_name(lir)); fprintf(g_tfile, ", (v%d,v%d)", LIR_res(lir), LIR_res(lir) + 1); break; default: IS_TRUE0(0); } } break; case LOP_THROW: //AA //Throws an exception object. //The reference of the exception object is in vx. fprintf(g_tfile, ", v%d", LIR_res(lir)); break; case LOP_MONITOR_ENTER : fprintf(g_tfile, ", v%d", LIR_res(lir)); break; case LOP_MONITOR_EXIT : break; case LOP_MOVE_RESULT : { //Move function return value to regisiter. //AA LIRAOp * p = (LIRAOp*)lir; switch (LIR_dt(lir)) { case LIR_JDT_unknown: //lexOpcode = lc_mov_result32; break; fprintf(g_tfile, ", INT"); fprintf(g_tfile, ", retval -> v%d", LIR_res(lir)); break; case LIR_JDT_wide: //lexOpcode = lc_mov_result64; break; fprintf(g_tfile, ", %s", get_dt_name(lir)); fprintf(g_tfile, ", retval -> (v%d,v%d)", LIR_res(lir), LIR_res(lir) + 1); break; case LIR_JDT_object: //lexOpcode = lc_mov_result_object; break; fprintf(g_tfile, ", obj-ptr"); fprintf(g_tfile, ", retval -> v%d", LIR_res(lir)); break; } } break; case LOP_MOVE_EXCEPTION : //AA fprintf(g_tfile, ", v%d", LIR_res(lir)); break; case LOP_GOTO : //AABBBBBBBB { LIRGOTOOp * p = (LIRGOTOOp*)lir; fprintf(g_tfile, ", (lirIdx)%dth", p->target); } break; case LOP_MOVE : switch (LIR_dt(lir)) { case LIR_JDT_unknown: fprintf(g_tfile, ", INT"); if ((LIR_op0(lir) | LIR_res(lir)) < 16) { //AB fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); } else if (LIR_res(lir) < 256) { //AABBBB fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); } else { //AAAABBBB fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); } break; case LIR_JDT_wide: fprintf(g_tfile, ", %s", get_dt_name(lir)); if ((LIR_op0(lir) | LIR_res(lir)) < 16) { //AB fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d)", LIR_res(lir), LIR_res(lir) + 1, LIR_op0(lir), LIR_op0(lir) + 1); } else if (LIR_res(lir) < 256) { //AABBBB fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d)", LIR_res(lir), LIR_res(lir) + 1, LIR_op0(lir), LIR_op0(lir) + 1); } else { //AAAABBBB fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d)", LIR_res(lir), LIR_res(lir) + 1, LIR_op0(lir), LIR_op0(lir) + 1); } break; case LIR_JDT_object: fprintf(g_tfile, ", obj-ptr"); if ((LIR_op0(lir) | LIR_res(lir)) < 16) { //AB fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); } else if (LIR_res(lir) < 256) { //AABBBB fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); } else { //AAAABBBB fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); } break; } break; case LOP_NEG : //AB case LOP_NOT : //AB fprintf(g_tfile, ", %s", get_dt_name(lir)); if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d)", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), LIR_op0(lir)+1); } else { fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); } break; case LOP_CONVERT : //AB switch (LIR_dt(lir)) { case LIR_convert_i2l: fprintf(g_tfile, ", INT->LONG"); fprintf(g_tfile, ", (v%d,v%d) <- v%d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir)); break; case LIR_convert_i2f: fprintf(g_tfile, ", INT->FLOAT"); break; case LIR_convert_i2d: fprintf(g_tfile, ", INT->DOUBLE"); fprintf(g_tfile, ", (v%d,v%d) <- v%d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir)); break; case LIR_convert_l2i: fprintf(g_tfile, ", LONG->INT"); fprintf(g_tfile, ", v%d <- (v%d,v%d)", LIR_res(lir), LIR_op0(lir), LIR_op0(lir)+1); break; case LIR_convert_l2f: fprintf(g_tfile, ", LONG->FLOAT"); fprintf(g_tfile, ", v%d <- (v%d,v%d)", LIR_res(lir), LIR_op0(lir), LIR_op0(lir)+1); break; case LIR_convert_l2d: fprintf(g_tfile, ", LONG->DOUBLE"); fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d)", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), LIR_op0(lir)+1); break; case LIR_convert_f2i: fprintf(g_tfile, ", FLOAT->INT"); break; case LIR_convert_f2l: fprintf(g_tfile, ", FLOAT->LONG"); fprintf(g_tfile, ", (v%d,v%d) <- v%d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir)); break; case LIR_convert_f2d: fprintf(g_tfile, ", FLOAT->DOUBLE"); fprintf(g_tfile, ", (v%d,v%d) <- v%d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir)); break; case LIR_convert_d2i: fprintf(g_tfile, ", DOUBLE->INT"); fprintf(g_tfile, ", v%d <- (v%d,v%d)", LIR_res(lir), LIR_op0(lir), LIR_op0(lir)+1); break; case LIR_convert_d2l: fprintf(g_tfile, ", DOUBLE->LONG"); fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d)", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), LIR_op0(lir)+1); break; case LIR_convert_d2f: fprintf(g_tfile, ", DOUBLE->FLOAT"); fprintf(g_tfile, ", v%d <- (v%d,v%d)", LIR_res(lir), LIR_op0(lir), LIR_op0(lir)+1); break; case LIR_convert_i2b: fprintf(g_tfile, ", INT->BOOL"); fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); break; case LIR_convert_i2c: fprintf(g_tfile, ", INT->CHAR"); fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); break; case LIR_convert_i2s: fprintf(g_tfile, ", INT->SHORT"); fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); break; default: IS_TRUE0(0); } break; case LOP_ADD_ASSIGN : case LOP_SUB_ASSIGN : case LOP_MUL_ASSIGN : case LOP_DIV_ASSIGN : case LOP_REM_ASSIGN : case LOP_AND_ASSIGN : case LOP_OR_ASSIGN : case LOP_XOR_ASSIGN : case LOP_SHL_ASSIGN : case LOP_SHR_ASSIGN : case LOP_USHR_ASSIGN: fprintf(g_tfile, ", %s", get_dt_name(lir)); if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d), (v%d,v%d)", LIR_res(lir), LIR_res(lir)+1, LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), LIR_op0(lir)+1); } else { fprintf(g_tfile, ", v%d <- v%d, v%d", LIR_res(lir), LIR_res(lir), LIR_op0(lir)); } break; case LOP_ARRAY_LENGTH: //AABBBB //Calculates the number of elements of the array referenced by vy //and puts the length value into vx. fprintf(g_tfile, ", v%d <- v%d", LIR_res(lir), LIR_op0(lir)); break; case LOP_IFZ : //AABBBB switch (LIR_dt(lir)) { case LIR_cond_EQ: fprintf(g_tfile, ", =="); break; case LIR_cond_NE: fprintf(g_tfile, ", !="); break; case LIR_cond_LT: fprintf(g_tfile, ", <"); break; case LIR_cond_GE: fprintf(g_tfile, ", >="); break; case LIR_cond_GT: fprintf(g_tfile, ", >"); break; case LIR_cond_LE: fprintf(g_tfile, ", <="); break; } if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d), 0, (lirIdx)%dth", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir)); } else { fprintf(g_tfile, ", v%d, 0, (lirIdx)%dth", LIR_res(lir), LIR_op0(lir)); } break; case LOP_NEW_INSTANCE: //AABBBB //LIR_op0(lir) is class-type-id, not class-declaration-id. IS_TRUE0(df); fprintf(g_tfile, ", (obj_ptr)v%d <- (clsname<%d>)%s", LIR_res(lir), LIR_op0(lir), get_class_name(df, LIR_op0(lir))); break; case LOP_CONST_STRING: //AABBBB or AABBBBBBBB IS_TRUE0(df); fprintf(g_tfile, ", v%d <- (strofst<%d>)\"%s\"", LIR_res(lir), LIR_op0(lir), dexStringById(df, LIR_op0(lir))); break; case LOP_CONST_CLASS : //AABBBB //const-class vx,type_id //Moves the class object of a class identified by //type_id (e.g. Object.class) into vx. fprintf(g_tfile, ", v%d <- (clsname<%d>)%s", LIR_res(lir), LIR_op0(lir), dexStringByTypeIdx(df, LIR_op0(lir))); break; case LOP_SGET : //AABBBB fprintf(g_tfile, ", %s", get_dt_name(lir)); IS_TRUE0(df); fprintf(g_tfile, ", v%d <- (ofst<%d>)%s::%s", LIR_res(lir), LIR_op0(lir), get_field_class_name(df, LIR_op0(lir)), get_field_name(df, LIR_op0(lir))); break; case LOP_CHECK_CAST : //AABBBB IS_TRUE0(df); fprintf(g_tfile, ", v%d '%s'", LIR_res(lir), dexStringByTypeIdx(df, LIR_op0(lir))); break; case LOP_SPUT : { //AABBBB LIRABOp * p = (LIRABOp*)lir; fprintf(g_tfile, ", %s", get_dt_name(lir)); IS_TRUE0(df); if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) -> %s::%s", LIR_res(lir), LIR_res(lir)+1, get_field_class_name(df, LIR_op0(lir)), get_field_name(df, LIR_op0(lir))); } else { fprintf(g_tfile, ", v%d -> %s::%s", LIR_res(lir), get_field_class_name(df, LIR_op0(lir)), get_field_name(df, LIR_op0(lir))); } } break; case LOP_APUT : //AABBCC fprintf(g_tfile, ", %s", get_dt_name(lir)); IS_TRUE0(df); if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) -> (array_base_ptr)v%d, (array_elem)v%d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), (UINT)LIR_op1(lir)); } else { fprintf(g_tfile, ", v%d -> (array_base_ptr)v%d, (array_elem)v%d", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir)); } break; case LOP_AGET : //AABBCC fprintf(g_tfile, ", %s", get_dt_name(lir)); IS_TRUE0(df); if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) <- (array_base_ptr)v%d, (array_elem)v%d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), (UINT)LIR_op1(lir)); } else { fprintf(g_tfile, ", v%d <- (array_base_ptr)v%d, (array_elem)v%d", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir)); } break; case LOP_CMPL : case LOP_CMP_LONG : //AABBCC IS_TRUE0(df); switch (LIR_dt(lir)) { case LIR_CMP_float: fprintf(g_tfile, ", FLOAT"); fprintf(g_tfile, ", v%d, v%d, %d", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir)); break; case LIR_CMP_double: fprintf(g_tfile, ", DOUBLE"); fprintf(g_tfile, ", (v%d,v%d), (v%d,v%d), %d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), LIR_op0(lir)+1, (UINT)LIR_op1(lir)); break; default: IS_TRUE0(0); } break; case LOP_ADD : case LOP_SUB : case LOP_MUL : case LOP_DIV : case LOP_REM : case LOP_AND : case LOP_OR : case LOP_XOR : case LOP_SHL : case LOP_SHR : case LOP_USHR : { fprintf(g_tfile, ", %s", get_dt_name(lir)); LIRABCOp * p = (LIRABCOp*)lir; if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d), (v%d,v%d)", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), LIR_op0(lir)+1, (UINT)LIR_op1(lir), (UINT)LIR_op1(lir)+1); } else { fprintf(g_tfile, ", v%d <- v%d, v%d", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir)); } } break; case LOP_IF : //ABCCCC switch (LIR_dt(lir)) { case LIR_cond_EQ: fprintf(g_tfile, ", =="); break; case LIR_cond_NE: fprintf(g_tfile, ", !="); break; case LIR_cond_LT: fprintf(g_tfile, ", <"); break; case LIR_cond_GE: fprintf(g_tfile, ", >="); break; case LIR_cond_GT: fprintf(g_tfile, ", >"); break; case LIR_cond_LE: fprintf(g_tfile, ", <="); break; } fprintf(g_tfile, ", v%d, v%d, (lirIdx)%dth", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir)); break; case LOP_ADD_LIT : //AABBCC, AABBCCCC case LOP_SUB_LIT : //AABBCC, AABBCCCC case LOP_MUL_LIT : //AABBCC, AABBCCCC case LOP_DIV_LIT : //AABBCC, AABBCCCC case LOP_REM_LIT : //AABBCC, AABBCCCC case LOP_AND_LIT : //AABBCC, AABBCCCC case LOP_OR_LIT : //AABBCC, AABBCCCC case LOP_XOR_LIT : //AABBCC, AABBCCCC case LOP_SHL_LIT : //AABBCC case LOP_SHR_LIT : //AABBCC case LOP_USHR_LIT : //AABBCC { fprintf(g_tfile, ", %s", get_dt_name(lir)); LIRABCOp * p = (LIRABCOp*)lir; if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) <- (v%d,v%d),", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), LIR_op0(lir)+1); } else { fprintf(g_tfile, ", v%d <- v%d,", LIR_res(lir), LIR_op0(lir)); } if (is_s8((INT)LIR_op1(lir))) { //8bit imm fprintf(g_tfile, "(lit8)%d", (INT)LIR_op1(lir)); } else if (is_s16((INT)LIR_op1(lir))) { //16bit imm fprintf(g_tfile, "(lit16)%d", (INT)LIR_op1(lir)); } else { IS_TRUE0(0); } } break; case LOP_IPUT : fprintf(g_tfile, ", %s", get_dt_name(lir)); //ABCCCC IS_TRUE0(df); if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) -> (obj_ptr)v%d, (ofst<%d>)%s::%s", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), (UINT)LIR_op1(lir), get_field_class_name(df, (UINT)LIR_op1(lir)), get_field_name(df, (UINT)LIR_op1(lir))); } else { fprintf(g_tfile, ", v%d -> (obj_ptr)v%d, (ofst<%d>)%s::%s", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir), get_field_class_name(df, (UINT)LIR_op1(lir)), get_field_name(df, (UINT)LIR_op1(lir))); } break; case LOP_IGET : fprintf(g_tfile, ", %s", get_dt_name(lir)); //ABCCCC IS_TRUE0(df); if (is_wide(lir)) { fprintf(g_tfile, ", (v%d,v%d) <- (obj_ptr)v%d, (ofst<%d>)%s::%s", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), (UINT)LIR_op1(lir), get_field_class_name(df, (UINT)LIR_op1(lir)), get_field_name(df, (UINT)LIR_op1(lir))); } else { fprintf(g_tfile, ", v%d <- (obj_ptr)v%d, (ofst<%d>)%s::%s", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir), get_field_class_name(df, (UINT)LIR_op1(lir)), get_field_name(df, (UINT)LIR_op1(lir))); } break; case LOP_INSTANCE_OF: fprintf(g_tfile, ", (pred)v%d <- v%d, (clsname<%d>)'%s'", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir), dexStringByTypeIdx(df, (UINT)LIR_op1(lir))); break; case LOP_NEW_ARRAY : //ABCCCC //new-array v%d(res) <- v%d(op0), LCAnimal(op1) fprintf(g_tfile, ", %s", get_dt_name(lir)); //ABCCCC IS_TRUE0(df); fprintf(g_tfile, ", v%d <- (num_of_elem)v%d, (elem_type<%d>)'%s'", LIR_res(lir), LIR_op0(lir), (UINT)LIR_op1(lir), dexStringByTypeIdx(df, (UINT)LIR_op1(lir))); break; case LOP_TABLE_SWITCH: { LIRSwitchOp * p = (LIRSwitchOp*)lir; IS_TRUE0(LIR_dt(p) == 0x1); fprintf(g_tfile, ", v%d", p->value); USHORT * pdata = p->data; //data[0]: flag to indicate switch-table type: // 0x1 TABLE_SWITCH, 0x2 LOOKUP_SWITCH USHORT f = pdata[0]; IS_TRUE0(f == 0x100); //data[1]: the number of CASE entry. USHORT num_of_case = pdata[1]; //data[2..3]: the base value of case-table UINT base_val = *((UINT*)(&pdata[2])); fprintf(g_tfile, ", basev:%d", base_val); //((BYTE*)data)[4..num_of_case*4]: // the position of the index table is at current instruction. if (num_of_case > 0) { UINT * pcase_entry = (UINT*)&pdata[4]; fprintf(g_tfile, " tgtidx:"); for (USHORT i = 0; i < num_of_case; i++) { UINT idx_of_insn = pcase_entry[i]; fprintf(g_tfile, "%d", idx_of_insn); if (i != num_of_case - 1) { fprintf(g_tfile, ","); } } } } break; case LOP_LOOKUP_SWITCH: { LIRSwitchOp * p = (LIRSwitchOp*)lir; IS_TRUE0(LIR_dt(p) == 0x2); fprintf(g_tfile, ", v%d", p->value); USHORT * pdata = p->data; //pdata[0]: flag to indicate switch-table type: // 0x1 TABLE_SWITCH, 0x2 LOOKUP_SWITCH UINT f = pdata[0]; IS_TRUE0(f == 0x200); //pdata[1]: the number of CASE entry. UINT num_of_case = pdata[1]; if (num_of_case > 0) { BYTE * tp = (BYTE*)pdata; //((BYTE*)pdata)[4..4+num_of_case*4-1]: the case-value buffer. UINT * pcase_value = (UINT*)&tp[4]; //((BYTE*)pdata)[4+num_of_case*4, 4+num_of_case*8-1]: // the position of the index table is at current instruction. UINT * pcase_entry = (UINT*)&tp[4 + num_of_case * 4]; fprintf(g_tfile, " val2idx("); for (UINT i = 0; i < num_of_case; i++) { UINT idx_of_insn = pcase_entry[i]; fprintf(g_tfile, "%d:%d", pcase_value[i], idx_of_insn); if (i != num_of_case - 1) { fprintf(g_tfile, ","); } } fprintf(g_tfile, ")"); } } break; case LOP_FILL_ARRAY_DATA: { fprintf(g_tfile, ", %s", get_dt_name(lir)); //AABBBBBBBB //pdata[0]: the magic number of code //0x100 PACKED_SWITCH, 0x200 SPARSE_SWITCH, 0x300 FILL_ARRAY_DATA LIRSwitchOp * r = (LIRSwitchOp*)lir; UInt16 const* pdata = (UInt16 const*)r->data; IS_TRUE0(pdata[0] == 0x300); //pdata[1]: size of each element. //pdata[2]: the number of element. UINT size_of_elem = pdata[1]; UINT num_of_elem = pdata[2]; UINT data_size = num_of_elem * size_of_elem; //fprintf(g_tfile, ", (elem_sz<%d>), (elem_num<%d>), (data_ptr)0x%x", fprintf(g_tfile, ", (elem_sz<%d>), (elem_num<%d>)", size_of_elem, num_of_elem); } break; case LOP_INVOKE: { /* ABCCCCDDDD the layout clarifies: A(p4), B(argc), CCCC(method_id), DDDD(p0, p1, p2, p3) where p0,p1,p2,p3,p4 are five parameters. AABBBBCCCC the layout clarifies: AA(argc), BBBB(method_id), CCCC(p0,p1,...p(argc-1)) */ LIRInvokeOp * r = (LIRInvokeOp*)lir; UINT flags = LIR_dt(lir); UINT flag1 = flags & 0x0F; UINT flag2 = flags & 0xF0; IS_TRUE(flag1 != 0, ("means LIR is LOP_FILLED_NEW_ARRAY")); DexMethodId const* method_id = dexGetMethodId(df, r->ref); IS_TRUE0(method_id); CHAR const* method_name = dexStringById(df, method_id->nameIdx); CHAR const* class_name = dexStringByTypeIdx(df, method_id->classIdx); IS_TRUE0(method_name); DexProtoId const* proto_id = dexGetProtoId(df, method_id->protoIdx); CHAR const* shorty_name = dexStringById(df, proto_id->shortyIdx); fprintf(g_tfile, ", %s::%s", class_name, method_name); UINT k = LIR_dt(lir); bool is_range = HAVE_FLAG((k & 0xf0), LIR_Range); if (is_range) { switch (k & 0x0f) { case LIR_invoke_unknown: IS_TRUE0(0); break; case LIR_invoke_virtual: fprintf(g_tfile, ", virtual-range"); break; case LIR_invoke_direct: fprintf(g_tfile, ", direct-range"); break; case LIR_invoke_super: fprintf(g_tfile, ", super-range"); break; case LIR_invoke_interface: fprintf(g_tfile, ", interface-range"); break; case LIR_invoke_static: fprintf(g_tfile, ", static-range"); break; default: IS_TRUE0(0); } } else { switch (k & 0x0f) { case LIR_invoke_unknown: IS_TRUE0(0); break; case LIR_invoke_virtual: fprintf(g_tfile, ", virtual"); break; case LIR_invoke_direct: fprintf(g_tfile, ", direct"); break; case LIR_invoke_super: fprintf(g_tfile, ", super"); break; case LIR_invoke_interface: fprintf(g_tfile, ", interface"); break; case LIR_invoke_static: fprintf(g_tfile, ", static"); break; default: IS_TRUE0(0); } } if (r->argc != 0) { fprintf(g_tfile, ", arg("); for (USHORT i = 0; i < r->argc; i++) { fprintf(g_tfile, "v%d", r->args[i]); if (i != r->argc-1) { fprintf(g_tfile, ","); } } fprintf(g_tfile, ")"); } } break; case LOP_FILLED_NEW_ARRAY: { /* AABBBBCCCC or ABCCCCDEFG e.g: A(argc), B,D,E,F,G(parampters), CCCC(class_tyid) */ LIRInvokeOp * r = (LIRInvokeOp*)lir; UINT flags = LIR_dt(lir); CHAR const* class_name = dexStringByTypeIdx(df, r->ref); IS_TRUE0(class_name); fprintf(g_tfile, ", %s", class_name); if (r->argc != 0) { fprintf(g_tfile, ", arg("); for (USHORT i = 0; i < r->argc; i++) { fprintf(g_tfile, "v%d", r->args[i]); if (i != r->argc-1) { fprintf(g_tfile, ","); } } fprintf(g_tfile, ")"); } } break; case LOP_CMPG: //AABBCC IS_TRUE0(df); switch (LIR_dt(lir)) { case LIR_CMP_float: fprintf(g_tfile, ", FLOAT"); fprintf(g_tfile, ", v%d, v%d, %d", LIR_res(lir), LIR_op0(lir), (INT)LIR_op1(lir)); break; case LIR_CMP_double: fprintf(g_tfile, ", DOUBLE"); fprintf(g_tfile, ", (v%d,v%d), v%d, %d", LIR_res(lir), LIR_res(lir)+1, LIR_op0(lir), (INT)LIR_op1(lir)); break; default: IS_TRUE0(0); } break; case LOP_PHI: IS_TRUE0(0); break; default: IS_TRUE0(0); } //end switch fflush(g_tfile); }
int get_index_special() { return (is_wide()) ? get_big_index() : get_index(); }
void assert_wide(bool require_wide) const { if (require_wide) { assert(is_wide(), "must be a wide instruction"); } else { assert(!is_wide(), "must not be a wide instruction"); } }