📄 sparcjitcodegen.java
字号:
Opcode opc; // Opcode for instruction int lvi; // Local variable index MethodRef mr; // MethodRef for operand VariableRef vr; // VariableRef for operand FieldRef fr; // FieldRef for operand Constant cn; // Constant for operand Class c; // Class for m Field f; // Field for m in c int aw; // Number of argwords long adr; // Generic address value String opdtype; // Type of operand int iv; // Intermediate int value long lv; // Intermediate long value ClassRef cr; // Class reference value char tychar; // Type character, from Field.FT_* int boffs; // Branch offset, for local backpatching int boffs2; // Another branch offset, for local backpatching int boffs3; // Another branch offset, for local backpatching BackpatchInfo bpi; // Backpatch info structure created i = m.instrs [idx];// System.out.println (i.toString()); /* Mark where code related to this instruction starts. */ code.instrToByteOffs [idx] = code.nextByteOffs (); /* If we're doing exception handling, we need to update the pc * variable so we can tell where the exception was raised. */ if (0 < m.handlers.length) { code.SETHI (i.pc, "%o7"); code.SetLo (i.pc, "%o7"); code.ST ("%o7", "%fp", excOheadOffs [ARLV_pc]); } /* If instrumentation is enabled, increment the counter for this * instruction. */ if (null != instrcounts) { code.SETHI ((int) (icaddr + 4 * i.opcode.code), "%o7"); code.SetLo ((int) (icaddr + 4 * i.opcode.code), "%o7"); code.LD ("%o7", 0, "%l0"); code.ADD ("%l0", 1, "%l0"); code.ST ("%l0", "%o7", 0); } /* We can often deal with a bunch of instructions at once, so * we switch on the opcode kind, rather than the exact opcode. */ opc = i.opcode; switch (opc.kind) { case Opcode.CONST: /* Tconst_#, aconst_null, bipush, sipush */ opdtype = opc.push; if ('x' == opdtype.charAt (0)) { /* Two-word constant. Either a long or a double. */ if ('d' == opdtype.charAt (1)) { lv = Double.doubleToLongBits ((double)(opc.var + i.val)); } else { lv = (long) (opc.var + i.val); } code.SETHI ((int) (lv >>> 32), "%o7"); code.SetLo ((int) (lv >>> 32), "%o7"); code.pushES ("%o7"); code.SETHI ((int) (lv & 0xFFFFFFFF), "%o7"); code.SetLo ((int) (lv & 0xFFFFFFFF), "%o7"); code.pushES ("%o7"); } else { /* One-word constant. Either floating point or integral */ if ('f' == opdtype.charAt (0)) { iv = Float.floatToIntBits ((float)(opc.var + i.val)); } else { iv = (int) (opc.var + i.val); } code.SETHI (iv, "%o7"); code.SetLo (iv, "%o7"); code.pushES ("%o7"); } break; case Opcode.LDC: /* ldc, ldc_w, ldc2_w */ cn = i.con; /* Load the constants through immediates; at the moment, * every constant can be interpreted as immediates, even * floating point, so we don't need a data area. */ switch (cn.tag) { case Constant.INTEGER: case Constant.FLOAT: /* Integer values can be loaded directly. */ if (Constant.FLOAT == cn.tag) { iv = Float.floatToIntBits (((Float)cn.value).floatValue()); } else { iv = ((Integer)cn.value).intValue(); } code.SETHI (iv, "%o7"); code.SetLo (iv, "%o7"); code.pushES ("%o7"); break; case Constant.STRING: /* Strings (i.e., references to java.lang.string) * don't need to be stored in a data area, but we * do need to convert from the reference to an * integral value. */ iv = (int) code.getNativeObjectAddr ((Object)cn.value); code.SETHI (iv, "%o7"); code.SetLo (iv, "%o7"); code.pushES ("%o7"); break; case Constant.LONG: case Constant.DOUBLE: /* Long values can be loaded directly. */ if (Constant.DOUBLE == cn.tag) { lv = Double.doubleToLongBits (((Double)cn.value).doubleValue()); } else { lv = ((Long)cn.value).longValue(); } code.SETHI ((int) (lv >>> 32), "%o7"); code.SetLo ((int) (lv >>> 32), "%o7"); code.pushES ("%o7"); code.SETHI ((int) (lv & 0xFFFFFFFF), "%o7"); code.SetLo ((int) (lv & 0xFFFFFFFF), "%o7"); code.pushES ("%o7"); break; } break; case Opcode.LOAD: /* [ilfda]load{,_[0123]} */ /* It appears that Toba will guarantee that the val field * of the Opcode will be zero if this is a ?LOAD_x variant, * so we can get the local variable number by adding the * val and var fields. */ lvi = opc.var + i.val; /* Pull the value out of the local variable area and push * it onto the eval stack. If it's a double-word type with * the high word in lvi, do the high word first, then * the low word. */ if ('x' == opc.push.charAt (0)) { code.LD ("%fp", LVOffs (lvi), "%o7"); code.pushES ("%o7"); lvi++; } code.LD ("%fp", LVOffs (lvi), "%o7"); code.pushES ("%o7"); break; case Opcode.STORE: /* [ilfda]store{,_[0123]} */ lvi = opc.var + i.val; /* Pop the value off the stack and stuff it into the local * variable area */ code.popES ("%o7"); /* If this is a double word type, it lives at the local vars * lvi and lvi+1. However, the high word is at lvi, and the * low at lvi+1, so we've got to store into lvi+1 first. */ if (2 == opc.pop) { code.ST ("%o7", "%fp", LVOffs (lvi+1)); code.popES ("%o7"); } code.ST ("%o7", "%fp", LVOffs (lvi)); break; case Opcode.IINC: code.LD ("%fp", LVOffs (i.val), "%o7"); code.ADD ("%o7", i.more[0], "%o7"); code.ST ("%o7", "%fp", LVOffs (i.val)); break; case Opcode.GETS: /* getstatic */ vr = (VariableRef) i.con.value; /*!! UNFINISHED -- check access, existence !!*/ /* Emit code to call the class initializer if necessary */ emitClassInit (i, (Object) vr); /* Reserve space for code that will load the address of the * variable into %l6. Address may not known until link time. */ code.reserveCode (CodeBlock.brLOAD, i, "%l6", vr); /* Load the whosis from the %l6 area */ pushFromMemory ("%l6", vr.signature.charAt (0)); break; case Opcode.PUTS: /* putstatic */ vr = (VariableRef) i.con.value; /*!! UNFINISHED -- check access, existence, type !!*/ /* Emit code to call the class initializer if necessary */ emitClassInit (i, (Object) vr); /* Reserve space for code that will load the address of the * variable into %l6. Address may not known until link time. */ code.reserveCode (CodeBlock.brLOAD, i, "%l6", vr); /* Store the whosis into the %l6 area */ popIntoMemory ("%l6", vr.signature.charAt (0)); break; case Opcode.GETF: /* getfield */ vr = (VariableRef) i.con.value; /* Verify that the instance object is not null. */ checkObjectRef (0, "%l1", i); /* Make like we popped it instead of just peeked */ code.tossES (1); /* %l1 is now a pointer to an instance structure. First field * of the instance structure is a pointer to the C class of * the object. 128 bytes into that is the pointer to the * array of instance variable specs (struct vt_generics). *///!! REQUIRE: 124 == offsetof (struct class, ivars)//!! REQUIRE: 0 == offsetof (struct vt_generic, offset) code.LD ("%l1", 0, "%o0"); code.LD ("%o0", 124, "%o0"); /* Now: what we're interested in is the n'th element in the * array of vt_generic structures which follows the class structure * that's pointed to by %esi. Unfortunately, we don't know * what n is yet. Load that into %o1 at link time. */ code.reserveCode (CodeBlock.brFIELDLOAD, i, "%o1", vr); /* Now access the offset field of the n'th vt_generic in the * array that starts at %o0; the offset field is the first * field in the structure. We add that to the address of * the instance variable to get the address of the field. *///!! REQUIRE: 24 == sizeof (struct vt_generic) code.SLL ("%o1", 3, "%o1");// *8 code.ADD ("%o1", "%o1", "%o2"); // *2*8 code.ADD ("%o2", "%o1", "%o1"); // *3*8 = 24 code.LD ("%o0", "%o1", "%o2"); code.ADD ("%o2", "%l1", "%l1"); /* Push from memory */ pushFromMemory ("%l1", vr.signature.charAt (0)); break; case Opcode.PUTF: /* putfield */ vr = (VariableRef) i.con.value; /* Verify that the instance object is not null. The object * is n words down the stack, where n is the size of the value * to store. */ if ((Field.FT_long == vr.signature.charAt(0)) || (Field.FT_double == vr.signature.charAt(0))) { checkObjectRef (2, "%l1", i); aw = 3; } else { checkObjectRef (1, "%l1", i); aw = 2; } /* %l1 is now a pointer to an instance structure. First field * of the instance structure is a pointer to the C class of * the object. 128 bytes into that is the pointer to the * array of instance variable specs (struct vt_generics). *///!! REQUIRE: 124 == offsetof (struct class, ivars)//!! REQUIRE: 0 == offsetof (struct vt_generic, offset) code.LD ("%l1", 0, "%o0"); code.LD ("%o0", 124, "%o0"); /* Now: what we're interested in is the n'th element in the * array of vt_generic structures which follows the class structure * that's pointed to by %esi. Unfortunately, we don't know * what n is yet. Load that into %o1 at link time. */ code.reserveCode (CodeBlock.brFIELDLOAD, i, "%o1", vr); /* Now access the offset field of the n'th vt_generic in the * array that starts at %o0; the offset field is the first * field in the structure. We add that to the address of * the instance variable to get the address of the field. *///!! REQUIRE: 24 == sizeof (struct vt_generic) code.SLL ("%o1", 3, "%o1");// *8 code.ADD ("%o1", "%o1", "%o2"); // *2*8 code.ADD ("%o2", "%o1", "%o1"); // *3*8 = 24 code.LD ("%o0", "%o1", "%o2"); code.ADD ("%o2", "%l1", "%l1"); /* Pop result into memory */ popIntoMemory ("%l1", vr.signature.charAt (0)); /* Throw away the object ref we don't need any more */ code.tossES (1); break; case Opcode.NEW: /* new */ /* Backpatch load struct class reference into %o0 */ cr = (ClassRef) i.con.value; code.reserveCode (CodeBlock.brLOADNatCl, i, "%o0", cr); /* Now, with C class structure, call the routine that allocates * an instance method */ code.reserveCode (CodeBlock.brACALL, i, "noreg", getFuncAddr (FID_new)); code.NOP (); // fill delay slot /* Push the instance reference onto the stack */ code.pushES ("%o0"); break; case Opcode.ACAST: /* checkcast */ /* Look at the top element, without popping it. */ code.peekES (0, "%o0"); /* If it's null, we're OK. */ code.TST ("%o0"); boffs = code.nextByteOffs (); code.BE (0); code.NOP (); // fill delay slot /* Otherwise, see if it can be cast to the required type */ EmitCkInstance (i, (ClassRef)i.con.value); /* If %o0 is zero, throw a ClassCastException. */ code.TST ("%o0"); boffs2 = code.nextByteOffs (); code.BNE (0); code.NOP (); // fill delay slot code.reserveCode (CodeBlock.brACALL, i, "noreg", getFuncAddr (FID_throwCCE)); code.NOP (); // fill delay slot code.PatchDisp22 (boffs, (code.nextByteOffs() - boffs) >>> 2); code.PatchDisp22 (boffs2, (code.nextByteOffs() - boffs2) >>> 2); break; case Opcode.INSTC: /* instanceof */ /* Pop the object off the stack; instanceof consumes the ref */ code.popES ("%o0"); /* If it's null, we're going to push 0. */ code.TST ("%o0"); boffs = code.nextByteOffs (); code.BE (0); code.NOP (); // fill delay slot /* Otherwise, see if it can be cast to the required type */ EmitCkInstance (i, (ClassRef)i.con.value); /* Here %o0 is 0 or 1 relative to whether the cast is legal. */ code.PatchDisp22 (boffs, (code.nextByteOffs() - boffs) >>> 2); /* Push the result. */ code.pushES ("%o0"); break; case Opcode.NEWA: /* newarray */ /* Allocate a new array. Element type
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -