void Compiler::handle_ik_cf(const JInst& jinst) { switch(jinst.opcode) { case OPCODE_IFNULL: case OPCODE_IFNONNULL: case OPCODE_IFEQ: case OPCODE_IFNE: case OPCODE_IFLT: case OPCODE_IFGE: case OPCODE_IFGT: case OPCODE_IFLE: gen_if(jinst.opcode, jinst.get_target(0)); break; case OPCODE_IF_ACMPEQ: case OPCODE_IF_ACMPNE: case OPCODE_IF_ICMPEQ: case OPCODE_IF_ICMPNE: case OPCODE_IF_ICMPLT: case OPCODE_IF_ICMPGE: case OPCODE_IF_ICMPGT: case OPCODE_IF_ICMPLE: gen_if_icmp(jinst.opcode, jinst.get_target(0)); break; case OPCODE_GOTO: case OPCODE_GOTO_W: gen_goto(jinst.get_target(0)); break; case OPCODE_JSR: case OPCODE_JSR_W: gen_jsr(jinst.get_target(0)); break; case OPCODE_RET: gen_ret(jinst.op0); break; case OPCODE_TABLESWITCH: case OPCODE_LOOKUPSWITCH: gen_switch(jinst); break; default: assert(false); break; } }
void Compiler::gen_switch(const JInst & jinst) { assert(jinst.opcode == OPCODE_LOOKUPSWITCH || jinst.opcode == OPCODE_TABLESWITCH); Opnd val = vstack(0, true).as_opnd(); vpop(); rlock(val); gen_bb_leave(NOTHING); if (jinst.opcode == OPCODE_LOOKUPSWITCH) { unsigned n = jinst.get_num_targets(); for (unsigned i = 0; i < n; i++) { Opnd key(jinst.key(i)); unsigned pc = jinst.get_target(i); alu(alu_cmp, val, key); br(eq, pc, m_bbinfo->start); } runlock(val); br(cond_none, jinst.get_def_target(), m_bbinfo->start); return; } // // TABLESWITCH // alu(alu_cmp, val, jinst.high()); br(gt, jinst.get_def_target(), m_bbinfo->start); alu(alu_cmp, val, jinst.low()); br(lt, jinst.get_def_target(), m_bbinfo->start); AR gr_tabl = valloc(jobj); movp(gr_tabl, DATA_SWITCH_TABLE | m_curr_inst->pc, m_bbinfo->start); #ifdef _EM64T_ // On EM64T, we operate with I_32 value in a register, but the // register will be used as 64 bit in address form - have to extend sx(Opnd(i64, val.reg()), Opnd(i32, val.reg())); #endif // Here, we need to extract 'index-=low()' - can pack this into // complex address form: // [table + index*sizeof(void*) - low()*sizeof(void*)], // but only if low()*sizeof(void*) does fit into displacement ... int tmp = -jinst.low(); const int LO_BOUND = INT_MIN/(int)sizeof(void*); const int UP_BOUND = INT_MAX/(int)sizeof(void*); if (LO_BOUND<=tmp && tmp<=UP_BOUND) { ld(jobj, gr_tabl, gr_tabl, -jinst.low()*sizeof(void*), val.reg(), sizeof(void*)); } else { // ... otherwise subtract explicitly, but only if the register // is not used anywhere else if (rrefs(val.reg()) !=0) { Opnd vtmp(i32, valloc(i32)); mov(vtmp, val); // make a copy of val runlock(val); val = vtmp; rlock(val); } alu(alu_sub, val, jinst.low()); ld(jobj, gr_tabl, gr_tabl, 0, val.reg(), sizeof(void*)); } runlock(val); br(gr_tabl); }