?? intel86jitcodegen.java
字號:
break; case Opcode.F2D: /* NOP */ break; /* Double operands: %f2 -> %f0 */ case Opcode.DNEG: code.FCHS (); break; /* D2I: see F2I */ case Opcode.D2F: /* NOP */ break; /* D2L: see F2L */ default: throw new InternalError ("Unop code " + i.opcode + " not supported in JIT"); } /* Store the result back on the execution stack, unless we did it * already (e.g., for float-to-int conversions) */ if (! donestore) { if (opdtype.equals ("i")) { /* stack: %l0 -> val */ code.pushES (R_eax); } else if (opdtype.equals ("f")) { /* stack: %f0 -> val */ code.FpushES (); } else if (opdtype.equals ("xl")) { /* stack: %l0 -> val.w1 val.w2 */ code.LpushES (R_edx, R_eax); } else if (opdtype.equals ("xd")) { /* stack: %f0 -> val.w1 val.w2 */ code.DpushES (); } else { throw new InternalError ("Bad type in unop."); } } return; } /** Emit code for a binary operation * @param i instruction for codegen */ private void EmitBinOp (Instr i) { String opdtype; // Type of operands of instruction opdtype = i.opcode.push; /* Load the operands into their registers. Fortunately, no * binary operators are cast operators, so the output and input * types are the same. Um, except for long shifts. */ if (opdtype.equals ("i")) { /* stack: op1 op2 -> %eax %ecx */ code.popES (R_ecx); code.popES (R_eax); } else if (opdtype.equals ("f")) { /* stack: op1 op2 -> ST(0) ST(1) */ code.FpopES (); code.FpopES (); } else if (opdtype.equals ("xl")) { if ((Opcode.LSHL == i.opcode.code) || (Opcode.LSHR == i.opcode.code) || (Opcode.LUSHR == i.opcode.code)) { /* stack: op1.w1 op1.w2 op2 -> %o0 %o2 */ /* We're going to call a function to do these, so pop * right into the outgoing args. */ code.popES (R_ecx); code.LpopES (R_edx, R_eax); } else { /* stack: op1.w1 op1.w2 op2.w1 op2.w2 -> %l2 %l4 */ code.LpopES (R_ebx, R_ecx); code.LpopES (R_edx, R_eax); } } else if (opdtype.equals ("xd")) { /* stack: op1.w1 op1.w2 op2.w1 op2.w2 -> ST(0) ST(1) */ code.DpopES (); code.DpopES (); } else { throw new InternalError ("Bad type in binop."); } /* Emit the code to operate on the results */ switch (i.opcode.code) { /* int operands: %eax op %ecx -> %eax */ case Opcode.IADD: code.ADD (R_ecx, R_eax); break; case Opcode.ISUB: code.NEG (R_ecx); code.ADD (R_ecx, R_eax); break; case Opcode.IMUL: code.IMUL (R_ecx); break; case Opcode.IREM: code.CWD (); /* DIV and REM generate the wrong answer for MIN_VALUE/-1, * which is unrepresentable. In fact, on Linux, this * throws an FPE. We'd have to special-case that. */ code.IDIV (R_ecx); code.MOV (R_edx, R_eax); break; case Opcode.IDIV: code.CWD (); code.IDIV (R_ecx); break; case Opcode.IAND: code.AND (R_ecx, R_eax); break; case Opcode.IOR: code.OR (R_ecx, R_eax); break; case Opcode.IXOR: code.XOR (R_ecx, R_eax); break; case Opcode.ISHL: code.SHL (R_cl, R_eax); break; case Opcode.ISHR: code.SAR (R_cl, R_eax); break; case Opcode.IUSHR: code.SHR (R_cl, R_eax); break; /* long operands: %edx:%eax op %ebx:%ecx -> %edx:%eax */ case Opcode.LADD: code.ADD (R_ecx, R_eax); code.ADC (R_ebx, R_edx); break; case Opcode.LSUB: code.SUB (R_ecx, R_eax); code.SBB (R_ebx, R_edx); break; case Opcode.LMUL: case Opcode.LREM: case Opcode.LDIV: /* Everybody else does this with a function call; let's * do it that way too. */ code.PUSH (R_ebx); code.PUSH (R_ecx); code.PUSH (R_edx); code.PUSH (R_eax); code.reserveCode (CodeBlock.brACALL, i, null, getFuncAddr ((Opcode.LREM == i.opcode.code) ? FID_longrem : (Opcode.LDIV == i.opcode.code) ? FID_longdiv : FID_longmul)); code.ADD (IMM_16, R_esp); break; case Opcode.LAND: code.AND (R_ecx, R_eax); code.AND (R_ebx, R_edx); break; case Opcode.LOR: code.OR (R_ecx, R_eax); code.OR (R_ebx, R_edx); break; case Opcode.LXOR: code.XOR (R_ecx, R_eax); code.XOR (R_ebx, R_edx); break; case Opcode.LSHL: case Opcode.LSHR: case Opcode.LUSHR: /* Already have op1 and op2 into %o0, %o1, %o2, so put in * the operator type, and call the function. */ code.PUSH (new Immediate (i.opcode.code)); code.PUSH (R_ecx); code.PUSH (R_edx); code.PUSH (R_eax); code.reserveCode (CodeBlock.brACALL, i, null, FA_longshift); code.ADD (IMM_16, R_esp); break; /* Float operands: %f2 op %f3 -> %f0 */ case Opcode.DADD: case Opcode.FADD: code.FADDP (R_ST1); break; case Opcode.FSUB: code.FSUBRP (R_ST1); break; case Opcode.DMUL: case Opcode.FMUL: code.FMULP (R_ST1); break; case Opcode.DDIV: case Opcode.FDIV: /*!! UNFINISHED -- check for divbyzero !!*/ code.FDIVRP (R_ST1); break; case Opcode.DREM: case Opcode.FREM: /*!! UNFINISHED -- is this correct? !!*/ /* Convert from single to double precision, and call * the remdr function in toba */ code.SUB (IMM_16, R_esp); code.FSTP (new MemoryRef (R_esp).setRefSize (8)); code.FSTP (new MemoryRef (IMM_8, R_esp).setRefSize (8)); code.reserveCode (CodeBlock.brACALL, i, null, FA_remdr); code.ADD (IMM_16, R_esp); break; /* Double operands: same as single prec */ default: throw new InternalError ("Binop code " + i.opcode + " not supported in JIT"); } /* Store the result back on the execution stack */ if (opdtype.equals ("i")) { /* stack: %l0 -> val */ code.pushES (R_eax); } else if (opdtype.equals ("f")) { /* stack: %f0 -> val */ code.FpushES (); } else if (opdtype.equals ("xl")) { /* stack: %l0 -> val.w1 val.w2 */ code.LpushES (R_edx, R_eax); } else if (opdtype.equals ("xd")) { /* stack: %f0 -> val.w1 val.w2 */ code.DpushES (); } else { throw new InternalError ("Bad type in binop."); } return; } /** Assuming we just got back from a call to the given method, push * the return value onto the evaluation stack. * @param mr MethodRef of called method (FieldRef if interface method) */ private void EmitRetvalStore (FieldRef mr) { String s = mr.signature; switch (s.charAt (s.indexOf (')') + 1)) { case Field.FT_byte: case Field.FT_char: case Field.FT_int: case Field.FT_object: case Field.FT_short: case Field.FT_boolean: case Field.FT_array: code.pushES (R_eax); break; case Field.FT_float: code.FpushES (); break; case Field.FT_long: code.LpushES (R_edx, R_eax); break; case Field.FT_double: code.DpushES (); break; case Field.FT_void: break; default: throw new InternalError ("WTF in " + s + " from " + mr); } return; } /** Load the pointer to the C class for type into register * @param i instruction inducing the load * @param cr ClassRef to type we're looking for; not necessarily resolved * @param getArray If nonzero, want the array-of-type instead of base type * @param reg Register pointer should go into */ private void loadClassPointer (Instr i, // Instruction inducing load ClassRef cr, // Reference to class int getArray, // Get array, or base type? Register reg) // Name of target register { int cp; // Integer representation of pointer int arank; /* We have here the name of a primitive or reference type. * We need to get the pointer to the struct class that defines * it. */ arank = 0; while (Field.FT_array == cr.name.charAt(arank)) { arank++; } cp = 0; switch (cr.name.charAt (arank)) { case Field.FT_byte: cp = (int) getNPprimclass (Opcode.T_BYTE, getArray); break; case Field.FT_char: cp = (int) getNPprimclass (Opcode.T_CHAR, getArray); break; case Field.FT_double: cp = (int) getNPprimclass (Opcode.T_DOUBLE, getArray); break; case Field.FT_float: cp = (int) getNPprimclass (Opcode.T_FLOAT, getArray); break; case Field.FT_int: cp = (int) getNPprimclass (Opcode.T_INT, getArray); break; case Field.FT_long: cp = (int) getNPprimclass (Opcode.T_LONG, getArray); break; case Field.FT_short: cp = (int) getNPprimclass (Opcode.T_SHORT, getArray); break; case Field.FT_boolean: cp = (int) getNPprimclass (Opcode.T_BOOLEAN, getArray); break; default: /* Something not a primitive class. We should just be able * to load the native class. We'd better not want an * array version of it, though. */ if (0 != getArray) { throw new InternalError ("Don't support loadClassPointer of array non-primitives"); } code.reserveCode (CodeBlock.brLOADNatCl, i, reg, cr); cp = 0;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -