0001: /*
0002: * Copyright 2004 Brian S O'Neill
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.cojen.classfile;
0018:
0019: import org.cojen.classfile.attribute.CodeAttr;
0020: import org.cojen.classfile.constant.ConstantClassInfo;
0021: import org.cojen.classfile.constant.ConstantFieldInfo;
0022:
0023: /**
0024: * This class is used as an aid in generating code for a method.
0025: * It controls the max stack, local variable allocation, labels and bytecode.
0026: *
0027: * @author Brian S O'Neill
0028: */
0029: public class CodeBuilder extends AbstractCodeAssembler implements
0030: CodeBuffer, CodeAssembler {
0031: private final CodeAttr mCodeAttr;
0032: private final ClassFile mClassFile;
0033: private final ConstantPool mCp;
0034:
0035: private final InstructionList mInstructions;
0036:
0037: private final LocalVariable mThisReference;
0038: private final LocalVariable[] mParameters;
0039:
0040: private final int mTarget;
0041:
0042: private final boolean mSaveLineNumberInfo;
0043: private final boolean mSaveLocalVariableInfo;
0044:
0045: /**
0046: * Construct a CodeBuilder for the CodeAttr of the given MethodInfo. The
0047: * CodeBuffer for the CodeAttr is automatically set to this CodeBuilder.
0048: */
0049: public CodeBuilder(MethodInfo info) {
0050: this (info, true, false);
0051: }
0052:
0053: /**
0054: * Construct a CodeBuilder for the CodeAttr of the given MethodInfo. The
0055: * CodeBuffer for the CodeAttr is automatically set to this CodeBuilder.
0056: *
0057: * @param saveLineNumberInfo When set false, all calls to mapLineNumber
0058: * are ignored. By default, this value is true.
0059: * @param saveLocalVariableInfo When set true, all local variable
0060: * usage information is saved in the ClassFile. By default, this value
0061: * is false.
0062: * @see #mapLineNumber
0063: */
0064: public CodeBuilder(MethodInfo info, boolean saveLineNumberInfo,
0065: boolean saveLocalVariableInfo) {
0066:
0067: String target = info.getClassFile().getTarget();
0068: if ("1.0".equals(target)) {
0069: mTarget = 0x00010000;
0070: } else if ("1.1".equals(target)) {
0071: mTarget = 0x00010001;
0072: } else if ("1.2".equals(target)) {
0073: mTarget = 0x00010002;
0074: } else if ("1.3".equals(target)) {
0075: mTarget = 0x00010003;
0076: } else if ("1.4".equals(target)) {
0077: mTarget = 0x00010004;
0078: } else if ("1.5".equals(target)) {
0079: mTarget = 0x00010005;
0080: } else if ("1.6".equals(target)) {
0081: mTarget = 0x00010006;
0082: } else {
0083: mTarget = 0x00010000;
0084: }
0085:
0086: mCodeAttr = info.getCodeAttr();
0087: mClassFile = info.getClassFile();
0088: mCp = mClassFile.getConstantPool();
0089: mInstructions = new InstructionList();
0090:
0091: mCodeAttr.setCodeBuffer(this );
0092:
0093: mSaveLineNumberInfo = saveLineNumberInfo;
0094: mSaveLocalVariableInfo = saveLocalVariableInfo;
0095:
0096: // Create LocalVariable references for "this" reference and other
0097: // passed in parameters.
0098:
0099: LocalVariable localVar;
0100:
0101: if (info.getModifiers().isStatic()) {
0102: mThisReference = null;
0103: } else {
0104: localVar = mInstructions.createLocalParameter("this",
0105: mClassFile.getType());
0106: mThisReference = localVar;
0107:
0108: if (saveLocalVariableInfo) {
0109: mCodeAttr.localVariableUse(localVar);
0110: }
0111: }
0112:
0113: TypeDesc[] paramTypes = info.getMethodDescriptor()
0114: .getParameterTypes();
0115: int paramSize = paramTypes.length;
0116:
0117: mParameters = new LocalVariable[paramSize];
0118:
0119: for (int i = 0; i < paramTypes.length; i++) {
0120: localVar = mInstructions.createLocalParameter(null,
0121: paramTypes[i]);
0122: mParameters[i] = localVar;
0123: if (saveLocalVariableInfo) {
0124: mCodeAttr.localVariableUse(localVar);
0125: }
0126: }
0127: }
0128:
0129: public int getMaxStackDepth() {
0130: return mInstructions.getMaxStackDepth();
0131: }
0132:
0133: public int getMaxLocals() {
0134: return mInstructions.getMaxLocals();
0135: }
0136:
0137: public byte[] getByteCodes() {
0138: return mInstructions.getByteCodes();
0139: }
0140:
0141: public ExceptionHandler[] getExceptionHandlers() {
0142: return mInstructions.getExceptionHandlers();
0143: }
0144:
0145: private void addCode(int stackAdjust, byte opcode) {
0146: mInstructions.new CodeInstruction(stackAdjust,
0147: new byte[] { opcode });
0148: }
0149:
0150: private void addCode(int stackAdjust, byte opcode, byte operand) {
0151: mInstructions.new CodeInstruction(stackAdjust, new byte[] {
0152: opcode, operand });
0153: }
0154:
0155: private void addCode(int stackAdjust, byte opcode, short operand) {
0156: mInstructions.new CodeInstruction(stackAdjust, new byte[] {
0157: opcode, (byte) (operand >> 8), (byte) operand });
0158: }
0159:
0160: private void addCode(int stackAdjust, byte opcode, int operand) {
0161: byte[] bytes = new byte[5];
0162:
0163: bytes[0] = opcode;
0164: bytes[1] = (byte) (operand >> 24);
0165: bytes[2] = (byte) (operand >> 16);
0166: bytes[3] = (byte) (operand >> 8);
0167: bytes[4] = (byte) operand;
0168:
0169: mInstructions.new CodeInstruction(stackAdjust, bytes);
0170: }
0171:
0172: private void addCode(int stackAdjust, byte opcode, ConstantInfo info) {
0173: // The zeros get filled in later, when the ConstantInfo index
0174: // is resolved.
0175: mInstructions.new ConstantOperandInstruction(stackAdjust,
0176: new byte[] { opcode, (byte) 0, (byte) 0 }, info);
0177: }
0178:
0179: private String getClassName(TypeDesc classDesc)
0180: throws IllegalArgumentException {
0181: if (classDesc.isPrimitive()) {
0182: throw new IllegalArgumentException(
0183: "Primitive type not allowed");
0184: }
0185: if (classDesc.isArray()) {
0186: throw new IllegalArgumentException("Array type not allowed");
0187: }
0188: return classDesc.getRootName();
0189: }
0190:
0191: public int getParameterCount() {
0192: return mParameters.length;
0193: }
0194:
0195: public LocalVariable getParameter(int index) {
0196: return mParameters[index];
0197: }
0198:
0199: public LocalVariable createLocalVariable(String name, TypeDesc type) {
0200: LocalVariable localVar = mInstructions.createLocalVariable(
0201: name, type);
0202:
0203: if (mSaveLocalVariableInfo) {
0204: mCodeAttr.localVariableUse(localVar);
0205: }
0206:
0207: return localVar;
0208: }
0209:
0210: public Label createLabel() {
0211: return mInstructions.new LabelInstruction();
0212: }
0213:
0214: public void exceptionHandler(Location startLocation,
0215: Location endLocation, String catchClassName) {
0216: Location catchLocation = createLabel().setLocation();
0217:
0218: ConstantClassInfo catchClass;
0219: if (catchClassName == null) {
0220: catchClass = null;
0221: } else {
0222: catchClass = mCp.addConstantClass(catchClassName);
0223: }
0224:
0225: ExceptionHandler handler = new ExceptionHandler(startLocation,
0226: endLocation, catchLocation, catchClass);
0227:
0228: mInstructions.addExceptionHandler(handler);
0229: }
0230:
0231: public void mapLineNumber(int lineNumber) {
0232: if (mSaveLineNumberInfo) {
0233: mCodeAttr.mapLineNumber(createLabel().setLocation(),
0234: lineNumber);
0235: }
0236: }
0237:
0238: // load-constant-to-stack style instructions
0239:
0240: public void loadNull() {
0241: addCode(1, Opcode.ACONST_NULL);
0242: }
0243:
0244: public void loadConstant(String value) {
0245: if (value == null) {
0246: loadNull();
0247: return;
0248: }
0249:
0250: int strlen = value.length();
0251:
0252: if (strlen <= (65535 / 3)) {
0253: // Guaranteed to fit in a Java UTF encoded string.
0254: ConstantInfo info = mCp.addConstantString(value);
0255: mInstructions.new LoadConstantInstruction(1, info);
0256: return;
0257: }
0258:
0259: // Compute actual UTF length.
0260:
0261: int utflen = 0;
0262:
0263: for (int i = 0; i < strlen; i++) {
0264: int c = value.charAt(i);
0265: if ((c >= 0x0001) && (c <= 0x007F)) {
0266: utflen++;
0267: } else if (c > 0x07FF) {
0268: utflen += 3;
0269: } else {
0270: utflen += 2;
0271: }
0272: }
0273:
0274: if (utflen <= 65535) {
0275: ConstantInfo info = mCp.addConstantString(value);
0276: mInstructions.new LoadConstantInstruction(1, info);
0277: return;
0278: }
0279:
0280: // Break string up into chunks and construct in a StringBuffer.
0281:
0282: TypeDesc stringBufferDesc;
0283: if (mTarget >= 0x00010005) {
0284: stringBufferDesc = TypeDesc
0285: .forClass("java.lang.StringBuilder");
0286: } else {
0287: stringBufferDesc = TypeDesc.forClass(StringBuffer.class);
0288: }
0289:
0290: TypeDesc intDesc = TypeDesc.INT;
0291: TypeDesc stringDesc = TypeDesc.STRING;
0292: TypeDesc[] stringParam = new TypeDesc[] { stringDesc };
0293:
0294: newObject(stringBufferDesc);
0295: dup();
0296: loadConstant(strlen);
0297: invokeConstructor(stringBufferDesc, new TypeDesc[] { intDesc });
0298:
0299: int beginIndex;
0300: int endIndex = 0;
0301:
0302: while (endIndex < strlen) {
0303: beginIndex = endIndex;
0304:
0305: // Make each chunk as large as possible.
0306: utflen = 0;
0307: for (; endIndex < strlen; endIndex++) {
0308: int c = value.charAt(endIndex);
0309: int size;
0310: if ((c >= 0x0001) && (c <= 0x007F)) {
0311: size = 1;
0312: } else if (c > 0x07FF) {
0313: size = 3;
0314: } else {
0315: size = 2;
0316: }
0317:
0318: if ((utflen + size) > 65535) {
0319: break;
0320: } else {
0321: utflen += size;
0322: }
0323: }
0324:
0325: String substr = value.substring(beginIndex, endIndex);
0326:
0327: ConstantInfo info = mCp.addConstantString(substr);
0328: mInstructions.new LoadConstantInstruction(1, info);
0329:
0330: invokeVirtual(stringBufferDesc, "append", stringBufferDesc,
0331: stringParam);
0332: }
0333:
0334: invokeVirtual(stringBufferDesc, "toString", stringDesc, null);
0335: }
0336:
0337: public void loadConstant(TypeDesc type)
0338: throws IllegalStateException {
0339: if (type == null) {
0340: loadNull();
0341: return;
0342: }
0343:
0344: if (type.isPrimitive()) {
0345: if (mTarget < 0x00010001) {
0346: throw new IllegalStateException(
0347: "Loading constant primitive classes not supported below target version 1.1");
0348: }
0349: loadStaticField(type.toObjectType(), "TYPE", TypeDesc
0350: .forClass(Class.class));
0351: } else {
0352: if (mTarget < 0x00010005) {
0353: throw new IllegalStateException(
0354: "Loading constant object classes not supported below target version 1.5");
0355: }
0356: ConstantInfo info = mCp.addConstantClass(type);
0357: mInstructions.new LoadConstantInstruction(1, info);
0358: }
0359: }
0360:
0361: public void loadConstant(boolean value) {
0362: loadConstant(value ? 1 : 0);
0363: }
0364:
0365: public void loadConstant(int value) {
0366: if (-1 <= value && value <= 5) {
0367: byte op;
0368:
0369: switch (value) {
0370: case -1:
0371: op = Opcode.ICONST_M1;
0372: break;
0373: case 0:
0374: op = Opcode.ICONST_0;
0375: break;
0376: case 1:
0377: op = Opcode.ICONST_1;
0378: break;
0379: case 2:
0380: op = Opcode.ICONST_2;
0381: break;
0382: case 3:
0383: op = Opcode.ICONST_3;
0384: break;
0385: case 4:
0386: op = Opcode.ICONST_4;
0387: break;
0388: case 5:
0389: op = Opcode.ICONST_5;
0390: break;
0391: default:
0392: op = Opcode.NOP;
0393: }
0394:
0395: addCode(1, op);
0396: } else if (-128 <= value && value <= 127) {
0397: addCode(1, Opcode.BIPUSH, (byte) value);
0398: } else if (-32768 <= value && value <= 32767) {
0399: addCode(1, Opcode.SIPUSH, (short) value);
0400: } else {
0401: ConstantInfo info = mCp.addConstantInteger(value);
0402: mInstructions.new LoadConstantInstruction(1, info);
0403: }
0404: }
0405:
0406: public void loadConstant(long value) {
0407: if (value == 0) {
0408: addCode(2, Opcode.LCONST_0);
0409: } else if (value == 1) {
0410: addCode(2, Opcode.LCONST_1);
0411: } else {
0412: ConstantInfo info = mCp.addConstantLong(value);
0413: mInstructions.new LoadConstantInstruction(2, info, true);
0414: }
0415: }
0416:
0417: public void loadConstant(float value) {
0418: if (value == 0) {
0419: addCode(1, Opcode.FCONST_0);
0420: } else if (value == 1) {
0421: addCode(1, Opcode.FCONST_1);
0422: } else if (value == 2) {
0423: addCode(1, Opcode.FCONST_2);
0424: } else {
0425: ConstantInfo info = mCp.addConstantFloat(value);
0426: mInstructions.new LoadConstantInstruction(1, info);
0427: }
0428: }
0429:
0430: public void loadConstant(double value) {
0431: if (value == 0) {
0432: addCode(2, Opcode.DCONST_0);
0433: } else if (value == 1) {
0434: addCode(2, Opcode.DCONST_1);
0435: } else {
0436: ConstantInfo info = mCp.addConstantDouble(value);
0437: mInstructions.new LoadConstantInstruction(2, info, true);
0438: }
0439: }
0440:
0441: // load-local-to-stack style instructions
0442:
0443: public void loadLocal(LocalVariable local) {
0444: if (local == null) {
0445: throw new IllegalArgumentException(
0446: "No local variable specified");
0447: }
0448: int stackAdjust = local.getType().isDoubleWord() ? 2 : 1;
0449: mInstructions.new LoadLocalInstruction(stackAdjust, local);
0450: }
0451:
0452: public void loadThis() {
0453: if (mThisReference != null) {
0454: loadLocal(mThisReference);
0455: } else {
0456: throw new IllegalStateException(
0457: "Attempt to load \"this\" reference in a static method");
0458: }
0459: }
0460:
0461: // store-from-stack-to-local style instructions
0462:
0463: public void storeLocal(LocalVariable local) {
0464: if (local == null) {
0465: throw new IllegalArgumentException(
0466: "No local variable specified");
0467: }
0468: int stackAdjust = local.getType().isDoubleWord() ? -2 : -1;
0469: mInstructions.new StoreLocalInstruction(stackAdjust, local);
0470: }
0471:
0472: // load-to-stack-from-array style instructions
0473:
0474: public void loadFromArray(TypeDesc type) {
0475: byte op;
0476: int stackAdjust = -1;
0477:
0478: switch (type.getTypeCode()) {
0479: case TypeDesc.INT_CODE:
0480: op = Opcode.IALOAD;
0481: break;
0482: case TypeDesc.BOOLEAN_CODE:
0483: case TypeDesc.BYTE_CODE:
0484: op = Opcode.BALOAD;
0485: break;
0486: case TypeDesc.SHORT_CODE:
0487: op = Opcode.SALOAD;
0488: break;
0489: case TypeDesc.CHAR_CODE:
0490: op = Opcode.CALOAD;
0491: break;
0492: case TypeDesc.FLOAT_CODE:
0493: op = Opcode.FALOAD;
0494: break;
0495: case TypeDesc.LONG_CODE:
0496: stackAdjust = 0;
0497: op = Opcode.LALOAD;
0498: break;
0499: case TypeDesc.DOUBLE_CODE:
0500: stackAdjust = 0;
0501: op = Opcode.DALOAD;
0502: break;
0503: default:
0504: op = Opcode.AALOAD;
0505: break;
0506: }
0507:
0508: addCode(stackAdjust, op);
0509: }
0510:
0511: // store-to-array-from-stack style instructions
0512:
0513: public void storeToArray(TypeDesc type) {
0514: byte op;
0515: int stackAdjust = -3;
0516:
0517: switch (type.getTypeCode()) {
0518: case TypeDesc.INT_CODE:
0519: op = Opcode.IASTORE;
0520: break;
0521: case TypeDesc.BOOLEAN_CODE:
0522: case TypeDesc.BYTE_CODE:
0523: op = Opcode.BASTORE;
0524: break;
0525: case TypeDesc.SHORT_CODE:
0526: op = Opcode.SASTORE;
0527: break;
0528: case TypeDesc.CHAR_CODE:
0529: op = Opcode.CASTORE;
0530: break;
0531: case TypeDesc.FLOAT_CODE:
0532: op = Opcode.FASTORE;
0533: break;
0534: case TypeDesc.LONG_CODE:
0535: stackAdjust = -4;
0536: op = Opcode.LASTORE;
0537: break;
0538: case TypeDesc.DOUBLE_CODE:
0539: stackAdjust = -4;
0540: op = Opcode.DASTORE;
0541: break;
0542: default:
0543: op = Opcode.AASTORE;
0544: break;
0545: }
0546:
0547: addCode(stackAdjust, op);
0548: }
0549:
0550: // load-field-to-stack style instructions
0551:
0552: public void loadField(String fieldName, TypeDesc type) {
0553: getfield(0, Opcode.GETFIELD, constantField(fieldName, type),
0554: type);
0555: }
0556:
0557: public void loadField(String className, String fieldName,
0558: TypeDesc type) {
0559:
0560: getfield(0, Opcode.GETFIELD, mCp.addConstantField(className,
0561: fieldName, type), type);
0562: }
0563:
0564: public void loadField(TypeDesc classDesc, String fieldName,
0565: TypeDesc type) {
0566:
0567: loadField(getClassName(classDesc), fieldName, type);
0568: }
0569:
0570: public void loadStaticField(String fieldName, TypeDesc type) {
0571:
0572: getfield(1, Opcode.GETSTATIC, constantField(fieldName, type),
0573: type);
0574: }
0575:
0576: public void loadStaticField(String className, String fieldName,
0577: TypeDesc type) {
0578:
0579: getfield(1, Opcode.GETSTATIC, mCp.addConstantField(className,
0580: fieldName, type), type);
0581: }
0582:
0583: public void loadStaticField(TypeDesc classDesc, String fieldName,
0584: TypeDesc type) {
0585:
0586: loadStaticField(getClassName(classDesc), fieldName, type);
0587: }
0588:
0589: private void getfield(int stackAdjust, byte opcode,
0590: ConstantInfo info, TypeDesc type) {
0591: if (type.isDoubleWord()) {
0592: stackAdjust++;
0593: }
0594: addCode(stackAdjust, opcode, info);
0595: }
0596:
0597: private ConstantFieldInfo constantField(String fieldName,
0598: TypeDesc type) {
0599: return mCp.addConstantField(mClassFile.getClassName(),
0600: fieldName, type);
0601: }
0602:
0603: // store-to-field-from-stack style instructions
0604:
0605: public void storeField(String fieldName, TypeDesc type) {
0606:
0607: putfield(-1, Opcode.PUTFIELD, constantField(fieldName, type),
0608: type);
0609: }
0610:
0611: public void storeField(String className, String fieldName,
0612: TypeDesc type) {
0613:
0614: putfield(-1, Opcode.PUTFIELD, mCp.addConstantField(className,
0615: fieldName, type), type);
0616: }
0617:
0618: public void storeField(TypeDesc classDesc, String fieldName,
0619: TypeDesc type) {
0620:
0621: storeField(getClassName(classDesc), fieldName, type);
0622: }
0623:
0624: public void storeStaticField(String fieldName, TypeDesc type) {
0625:
0626: putfield(0, Opcode.PUTSTATIC, constantField(fieldName, type),
0627: type);
0628: }
0629:
0630: public void storeStaticField(String className, String fieldName,
0631: TypeDesc type) {
0632:
0633: putfield(0, Opcode.PUTSTATIC, mCp.addConstantField(className,
0634: fieldName, type), type);
0635: }
0636:
0637: public void storeStaticField(TypeDesc classDesc, String fieldName,
0638: TypeDesc type) {
0639:
0640: storeStaticField(getClassName(classDesc), fieldName, type);
0641: }
0642:
0643: private void putfield(int stackAdjust, byte opcode,
0644: ConstantInfo info, TypeDesc type) {
0645: if (type.isDoubleWord()) {
0646: stackAdjust -= 2;
0647: } else {
0648: stackAdjust--;
0649: }
0650: addCode(stackAdjust, opcode, info);
0651: }
0652:
0653: // return style instructions
0654:
0655: public void returnVoid() {
0656: addCode(0, Opcode.RETURN);
0657: }
0658:
0659: public void returnValue(TypeDesc type) {
0660: int stackAdjust = -1;
0661: byte op;
0662:
0663: switch (type.getTypeCode()) {
0664: case TypeDesc.INT_CODE:
0665: case TypeDesc.BOOLEAN_CODE:
0666: case TypeDesc.BYTE_CODE:
0667: case TypeDesc.SHORT_CODE:
0668: case TypeDesc.CHAR_CODE:
0669: op = Opcode.IRETURN;
0670: break;
0671: case TypeDesc.FLOAT_CODE:
0672: op = Opcode.FRETURN;
0673: break;
0674: case TypeDesc.LONG_CODE:
0675: stackAdjust = -2;
0676: op = Opcode.LRETURN;
0677: break;
0678: case TypeDesc.DOUBLE_CODE:
0679: stackAdjust = -2;
0680: op = Opcode.DRETURN;
0681: break;
0682: case TypeDesc.VOID_CODE:
0683: stackAdjust = 0;
0684: op = Opcode.RETURN;
0685: break;
0686: default:
0687: op = Opcode.ARETURN;
0688: break;
0689: }
0690:
0691: addCode(stackAdjust, op);
0692: }
0693:
0694: // numerical conversion style instructions
0695:
0696: public void convert(TypeDesc fromType, TypeDesc toType) {
0697: convert(fromType, toType, CONVERT_FP_NORMAL);
0698: }
0699:
0700: public void convert(TypeDesc fromType, TypeDesc toType,
0701: int fpConvertMode) {
0702: if (fpConvertMode < 0 || fpConvertMode > CONVERT_FP_RAW_BITS) {
0703: throw new IllegalArgumentException(
0704: "Illegal floating point conversion mode");
0705: }
0706:
0707: if (toType == TypeDesc.OBJECT) {
0708: if (fromType.isPrimitive()) {
0709: toType = fromType.toObjectType();
0710: } else {
0711: return;
0712: }
0713: }
0714:
0715: if (fromType == toType) {
0716: return;
0717: }
0718:
0719: TypeDesc fromPrimitiveType = fromType.toPrimitiveType();
0720: if (fromPrimitiveType == null) {
0721: if (!toType.isPrimitive()) {
0722: Class fromClass = fromType.toClass();
0723: if (fromClass != null) {
0724: Class toClass = toType.toClass();
0725: if (toClass != null
0726: && toClass.isAssignableFrom(fromClass)) {
0727: return;
0728: }
0729: }
0730: }
0731: throw invalidConversion(fromType, toType);
0732: }
0733: int fromTypeCode = fromPrimitiveType.getTypeCode();
0734:
0735: if (toType.toClass() == Number.class) {
0736: switch (fromTypeCode) {
0737: case TypeDesc.INT_CODE:
0738: case TypeDesc.BYTE_CODE:
0739: case TypeDesc.SHORT_CODE:
0740: case TypeDesc.LONG_CODE:
0741: case TypeDesc.FLOAT_CODE:
0742: case TypeDesc.DOUBLE_CODE:
0743: if (fromType.isPrimitive()) {
0744: toType = fromType.toObjectType();
0745: } else {
0746: return;
0747: }
0748: }
0749: }
0750:
0751: TypeDesc toPrimitiveType = toType.toPrimitiveType();
0752: if (toPrimitiveType == null) {
0753: throw invalidConversion(fromType, toType);
0754: }
0755: int toTypeCode = toPrimitiveType.getTypeCode();
0756:
0757: // Location is set at end, after doConversion.
0758: Label end = createLabel();
0759:
0760: doConversion: {
0761: int stackAdjust = 0;
0762: byte op;
0763:
0764: switch (fromTypeCode) {
0765: case TypeDesc.INT_CODE:
0766: case TypeDesc.BYTE_CODE:
0767: case TypeDesc.SHORT_CODE:
0768: case TypeDesc.CHAR_CODE:
0769: case TypeDesc.BOOLEAN_CODE:
0770: switch (toTypeCode) {
0771: case TypeDesc.BYTE_CODE:
0772: op = (fromTypeCode == TypeDesc.BYTE_CODE) ? Opcode.NOP
0773: : Opcode.I2B;
0774: break;
0775: case TypeDesc.SHORT_CODE:
0776: op = (fromTypeCode == TypeDesc.SHORT_CODE) ? Opcode.NOP
0777: : Opcode.I2S;
0778: break;
0779: case TypeDesc.CHAR_CODE:
0780: op = (fromTypeCode == TypeDesc.CHAR_CODE) ? Opcode.NOP
0781: : Opcode.I2C;
0782: break;
0783: case TypeDesc.FLOAT_CODE:
0784: op = Opcode.I2F;
0785: break;
0786: case TypeDesc.LONG_CODE:
0787: stackAdjust = 1;
0788: op = Opcode.I2L;
0789: break;
0790: case TypeDesc.DOUBLE_CODE:
0791: stackAdjust = 1;
0792: op = Opcode.I2D;
0793: break;
0794: case TypeDesc.INT_CODE:
0795: op = Opcode.NOP;
0796: break;
0797: case TypeDesc.BOOLEAN_CODE:
0798: if (!fromType.isPrimitive()) {
0799: if (!toType.isPrimitive()) {
0800: nullConvert(end);
0801: }
0802: unbox(fromType, fromPrimitiveType);
0803: }
0804: toBoolean(!toType.isPrimitive());
0805: break doConversion;
0806: default:
0807: throw invalidConversion(fromType, toType);
0808: }
0809: break;
0810:
0811: case TypeDesc.LONG_CODE:
0812: switch (toTypeCode) {
0813: case TypeDesc.INT_CODE:
0814: stackAdjust = -1;
0815: op = Opcode.L2I;
0816: break;
0817: case TypeDesc.FLOAT_CODE:
0818: stackAdjust = -1;
0819: op = Opcode.L2F;
0820: break;
0821: case TypeDesc.DOUBLE_CODE:
0822: op = Opcode.L2D;
0823: break;
0824: case TypeDesc.BYTE_CODE:
0825: case TypeDesc.CHAR_CODE:
0826: case TypeDesc.SHORT_CODE:
0827: addCode(-1, Opcode.L2I);
0828: convert(TypeDesc.INT, toPrimitiveType);
0829: // fall through
0830: case TypeDesc.LONG_CODE:
0831: op = Opcode.NOP;
0832: break;
0833: case TypeDesc.BOOLEAN_CODE:
0834: if (!fromType.isPrimitive()) {
0835: if (!toType.isPrimitive()) {
0836: nullConvert(end);
0837: }
0838: unbox(fromType, fromPrimitiveType);
0839: }
0840: loadConstant(0L);
0841: math(Opcode.LCMP);
0842: toBoolean(!toType.isPrimitive());
0843: break doConversion;
0844: default:
0845: throw invalidConversion(fromType, toType);
0846: }
0847: break;
0848:
0849: case TypeDesc.FLOAT_CODE:
0850: switch (toTypeCode) {
0851: case TypeDesc.INT_CODE:
0852: op = Opcode.F2I;
0853: break;
0854: case TypeDesc.LONG_CODE:
0855: stackAdjust = 1;
0856: op = Opcode.F2L;
0857: break;
0858: case TypeDesc.DOUBLE_CODE:
0859: stackAdjust = 1;
0860: op = Opcode.F2D;
0861: break;
0862: case TypeDesc.BYTE_CODE:
0863: case TypeDesc.CHAR_CODE:
0864: case TypeDesc.SHORT_CODE:
0865: addCode(0, Opcode.F2I);
0866: convert(TypeDesc.INT, toPrimitiveType);
0867: // fall through
0868: case TypeDesc.FLOAT_CODE:
0869: op = Opcode.NOP;
0870: break;
0871: case TypeDesc.BOOLEAN_CODE:
0872: if (!fromType.isPrimitive()) {
0873: if (!toType.isPrimitive()) {
0874: nullConvert(end);
0875: }
0876: unbox(fromType, fromPrimitiveType);
0877: }
0878: loadConstant(0.0f);
0879: math(Opcode.FCMPG);
0880: toBoolean(!toType.isPrimitive());
0881: break doConversion;
0882: default:
0883: throw invalidConversion(fromType, toType);
0884: }
0885: break;
0886:
0887: case TypeDesc.DOUBLE_CODE:
0888: switch (toTypeCode) {
0889: case TypeDesc.INT_CODE:
0890: stackAdjust = -1;
0891: op = Opcode.D2I;
0892: break;
0893: case TypeDesc.FLOAT_CODE:
0894: stackAdjust = -1;
0895: op = Opcode.D2F;
0896: break;
0897: case TypeDesc.LONG_CODE:
0898: op = Opcode.D2L;
0899: break;
0900: case TypeDesc.BYTE_CODE:
0901: case TypeDesc.CHAR_CODE:
0902: case TypeDesc.SHORT_CODE:
0903: addCode(-1, Opcode.D2I);
0904: convert(TypeDesc.INT, toPrimitiveType);
0905: // fall through
0906: case TypeDesc.DOUBLE_CODE:
0907: op = Opcode.NOP;
0908: break;
0909: case TypeDesc.BOOLEAN_CODE:
0910: if (!fromType.isPrimitive()) {
0911: if (!toType.isPrimitive()) {
0912: nullConvert(end);
0913: }
0914: unbox(fromType, fromPrimitiveType);
0915: }
0916: loadConstant(0.0d);
0917: math(Opcode.DCMPG);
0918: toBoolean(!toType.isPrimitive());
0919: break doConversion;
0920: default:
0921: throw invalidConversion(fromType, toType);
0922: }
0923: break;
0924:
0925: default:
0926: throw invalidConversion(fromType, toType);
0927: }
0928:
0929: if (!fromType.isPrimitive()) {
0930: if (!toType.isPrimitive()) {
0931: nullConvert(end);
0932: }
0933: unbox(fromType, fromPrimitiveType);
0934: }
0935:
0936: if (toType.isPrimitive()) {
0937: if (op != Opcode.NOP) {
0938: convertPrimitive(stackAdjust, op, fpConvertMode);
0939: }
0940: } else {
0941: if (op == Opcode.NOP) {
0942: prebox(toPrimitiveType, toType);
0943: } else if (!fromPrimitiveType.isDoubleWord()
0944: && toPrimitiveType.isDoubleWord()) {
0945: // Slight optimization here. Perform prebox on single word value,
0946: // depending on what conversion is being applied.
0947: prebox(fromPrimitiveType, toType);
0948: convertPrimitive(stackAdjust, op, fpConvertMode);
0949: } else {
0950: convertPrimitive(stackAdjust, op, fpConvertMode);
0951: prebox(toPrimitiveType, toType);
0952: }
0953: box(toPrimitiveType, toType);
0954: }
0955: }
0956:
0957: end.setLocation();
0958: }
0959:
0960: /**
0961: * @param from must be an object type
0962: * @param to must be a primitive type
0963: */
0964: private void unbox(TypeDesc from, TypeDesc to) {
0965: String methodName;
0966:
0967: switch (to.getTypeCode()) {
0968: case TypeDesc.BOOLEAN_CODE:
0969: methodName = "booleanValue";
0970: break;
0971: case TypeDesc.CHAR_CODE:
0972: methodName = "charValue";
0973: break;
0974: case TypeDesc.FLOAT_CODE:
0975: methodName = "floatValue";
0976: break;
0977: case TypeDesc.DOUBLE_CODE:
0978: methodName = "doubleValue";
0979: break;
0980: case TypeDesc.BYTE_CODE:
0981: methodName = "byteValue";
0982: break;
0983: case TypeDesc.SHORT_CODE:
0984: methodName = "shortValue";
0985: break;
0986: case TypeDesc.INT_CODE:
0987: methodName = "intValue";
0988: break;
0989: case TypeDesc.LONG_CODE:
0990: methodName = "longValue";
0991: break;
0992: default:
0993: return;
0994: }
0995:
0996: invokeVirtual(from.getRootName(), methodName, to, null);
0997: }
0998:
0999: /**
1000: * @param from must be a primitive type
1001: * @param to must be an object type
1002: */
1003: private void prebox(TypeDesc from, TypeDesc to) {
1004: if (mTarget >= 0x00010005) {
1005: // No need to prebox since static valueOf method can be called
1006: // instead.
1007: return;
1008: }
1009:
1010: // Wouldn't it be cool if I could walk backwards in the instruction
1011: // list and insert the new-dup pair before the value to box was even
1012: // put on the stack?
1013:
1014: switch (from.getTypeCode()) {
1015: default:
1016: break;
1017: case TypeDesc.BOOLEAN_CODE:
1018: if (to.toPrimitiveType().getTypeCode() == TypeDesc.BOOLEAN_CODE) {
1019: break;
1020: }
1021: // fall through
1022: case TypeDesc.CHAR_CODE:
1023: case TypeDesc.FLOAT_CODE:
1024: case TypeDesc.BYTE_CODE:
1025: case TypeDesc.SHORT_CODE:
1026: case TypeDesc.INT_CODE:
1027: newObject(to);
1028: dupX1();
1029: swap();
1030: break;
1031: case TypeDesc.DOUBLE_CODE:
1032: case TypeDesc.LONG_CODE:
1033: newObject(to);
1034: dupX2();
1035: dupX2();
1036: pop();
1037: break;
1038: }
1039: }
1040:
1041: /**
1042: * @param from must be a primitive type
1043: * @param to must be an object type
1044: */
1045: private void box(TypeDesc from, TypeDesc to) {
1046: if (mTarget >= 0x00010005) {
1047: // Call the new valueOf method.
1048: invokeStatic(to.getRootName(), "valueOf", to,
1049: new TypeDesc[] { from });
1050: return;
1051: }
1052:
1053: switch (from.getTypeCode()) {
1054: case TypeDesc.BOOLEAN_CODE:
1055: toBoolean(true);
1056: break;
1057: case TypeDesc.CHAR_CODE:
1058: case TypeDesc.FLOAT_CODE:
1059: case TypeDesc.BYTE_CODE:
1060: case TypeDesc.SHORT_CODE:
1061: case TypeDesc.INT_CODE:
1062: case TypeDesc.DOUBLE_CODE:
1063: case TypeDesc.LONG_CODE:
1064: invokeConstructor(to.getRootName(), new TypeDesc[] { from });
1065: break;
1066: }
1067: }
1068:
1069: // Converts an int on the stack to a boolean.
1070: private void toBoolean(boolean box) {
1071: if (box && mTarget >= 0x00010004) {
1072: // Call the new valueOf method.
1073: invokeStatic("java.lang.Boolean", "valueOf",
1074: TypeDesc.BOOLEAN.toObjectType(),
1075: new TypeDesc[] { TypeDesc.BOOLEAN });
1076: return;
1077: }
1078:
1079: Label nonZero = createLabel();
1080: Label done = createLabel();
1081: ifZeroComparisonBranch(nonZero, "!=");
1082: if (box) {
1083: TypeDesc newType = TypeDesc.BOOLEAN.toObjectType();
1084: loadStaticField(newType.getRootName(), "FALSE", newType);
1085: branch(done);
1086: nonZero.setLocation();
1087: loadStaticField(newType.getRootName(), "TRUE", newType);
1088: } else {
1089: loadConstant(false);
1090: branch(done);
1091: nonZero.setLocation();
1092: loadConstant(true);
1093: }
1094: done.setLocation();
1095: }
1096:
1097: private void convertPrimitive(int stackAdjust, byte op,
1098: int fpConvertMode) {
1099: if (fpConvertMode != CONVERT_FP_NORMAL) {
1100: switch (op) {
1101: case Opcode.I2F:
1102: invokeStatic("java.lang.Float", "intBitsToFloat",
1103: TypeDesc.FLOAT, new TypeDesc[] { TypeDesc.INT });
1104: return;
1105:
1106: case Opcode.L2D:
1107: invokeStatic("java.lang.Double", "longBitsToDouble",
1108: TypeDesc.DOUBLE,
1109: new TypeDesc[] { TypeDesc.LONG });
1110: return;
1111:
1112: case Opcode.F2I:
1113: if (fpConvertMode == CONVERT_FP_RAW_BITS) {
1114: invokeStatic("java.lang.Float",
1115: "floatToRawIntBits", TypeDesc.INT,
1116: new TypeDesc[] { TypeDesc.FLOAT });
1117: } else {
1118: invokeStatic("java.lang.Float", "floatToIntBits",
1119: TypeDesc.INT,
1120: new TypeDesc[] { TypeDesc.FLOAT });
1121: }
1122: return;
1123:
1124: case Opcode.D2L:
1125: if (fpConvertMode == CONVERT_FP_RAW_BITS) {
1126: invokeStatic("java.lang.Double",
1127: "doubleToRawLongBits", TypeDesc.LONG,
1128: new TypeDesc[] { TypeDesc.DOUBLE });
1129: } else {
1130: invokeStatic("java.lang.Double",
1131: "doubleToLongBits", TypeDesc.LONG,
1132: new TypeDesc[] { TypeDesc.DOUBLE });
1133: }
1134: return;
1135: }
1136: }
1137:
1138: addCode(stackAdjust, op);
1139: }
1140:
1141: // Check if from object is null. If so, no need to convert, and don't throw
1142: // a NullPointerException. Assumes that from type and to type are objects.
1143: private void nullConvert(Label end) {
1144: LocalVariable temp = createLocalVariable("temp",
1145: TypeDesc.OBJECT);
1146: storeLocal(temp);
1147: loadLocal(temp);
1148: Label notNull = createLabel();
1149: ifNullBranch(notNull, false);
1150: loadNull();
1151: branch(end);
1152: notNull.setLocation();
1153: loadLocal(temp);
1154: }
1155:
1156: private IllegalArgumentException invalidConversion(TypeDesc from,
1157: TypeDesc to) {
1158: throw new IllegalArgumentException("Invalid conversion: "
1159: + from.getFullName() + " to " + to.getFullName());
1160: }
1161:
1162: // invocation style instructions
1163:
1164: public void invokeVirtual(String methodName, TypeDesc ret,
1165: TypeDesc[] params) {
1166:
1167: ConstantInfo info = mCp.addConstantMethod(mClassFile
1168: .getClassName(), methodName, ret, params);
1169:
1170: int stackAdjust = returnSize(ret) - 1;
1171: if (params != null) {
1172: stackAdjust -= argSize(params);
1173: }
1174:
1175: addCode(stackAdjust, Opcode.INVOKEVIRTUAL, info);
1176: }
1177:
1178: public void invokeVirtual(String className, String methodName,
1179: TypeDesc ret, TypeDesc[] params) {
1180: ConstantInfo info = mCp.addConstantMethod(className,
1181: methodName, ret, params);
1182:
1183: int stackAdjust = returnSize(ret) - 1;
1184: if (params != null) {
1185: stackAdjust -= argSize(params);
1186: }
1187:
1188: addCode(stackAdjust, Opcode.INVOKEVIRTUAL, info);
1189: }
1190:
1191: public void invokeVirtual(TypeDesc classDesc, String methodName,
1192: TypeDesc ret, TypeDesc[] params) {
1193:
1194: invokeVirtual(getClassName(classDesc), methodName, ret, params);
1195: }
1196:
1197: public void invokeStatic(String methodName, TypeDesc ret,
1198: TypeDesc[] params) {
1199: ConstantInfo info = mCp.addConstantMethod(mClassFile
1200: .getClassName(), methodName, ret, params);
1201:
1202: int stackAdjust = returnSize(ret) - 0;
1203: if (params != null) {
1204: stackAdjust -= argSize(params);
1205: }
1206:
1207: addCode(stackAdjust, Opcode.INVOKESTATIC, info);
1208: }
1209:
1210: public void invokeStatic(String className, String methodName,
1211: TypeDesc ret, TypeDesc[] params) {
1212: ConstantInfo info = mCp.addConstantMethod(className,
1213: methodName, ret, params);
1214:
1215: int stackAdjust = returnSize(ret) - 0;
1216: if (params != null) {
1217: stackAdjust -= argSize(params);
1218: }
1219:
1220: addCode(stackAdjust, Opcode.INVOKESTATIC, info);
1221: }
1222:
1223: public void invokeStatic(TypeDesc classDesc, String methodName,
1224: TypeDesc ret, TypeDesc[] params) {
1225:
1226: invokeStatic(getClassName(classDesc), methodName, ret, params);
1227: }
1228:
1229: public void invokeInterface(String className, String methodName,
1230: TypeDesc ret, TypeDesc[] params) {
1231:
1232: ConstantInfo info = mCp.addConstantInterfaceMethod(className,
1233: methodName, ret, params);
1234:
1235: int paramCount = 1;
1236: if (params != null) {
1237: paramCount += argSize(params);
1238: }
1239:
1240: int stackAdjust = returnSize(ret) - paramCount;
1241:
1242: byte[] bytes = new byte[5];
1243:
1244: bytes[0] = Opcode.INVOKEINTERFACE;
1245: //bytes[1] = (byte)0;
1246: //bytes[2] = (byte)0;
1247: bytes[3] = (byte) paramCount;
1248: //bytes[4] = (byte)0;
1249:
1250: mInstructions.new ConstantOperandInstruction(stackAdjust,
1251: bytes, info);
1252: }
1253:
1254: public void invokeInterface(TypeDesc classDesc, String methodName,
1255: TypeDesc ret, TypeDesc[] params) {
1256:
1257: invokeInterface(getClassName(classDesc), methodName, ret,
1258: params);
1259: }
1260:
1261: public void invokePrivate(String methodName, TypeDesc ret,
1262: TypeDesc[] params) {
1263: ConstantInfo info = mCp.addConstantMethod(mClassFile
1264: .getClassName(), methodName, ret, params);
1265:
1266: int stackAdjust = returnSize(ret) - 1;
1267: if (params != null) {
1268: stackAdjust -= argSize(params);
1269: }
1270:
1271: addCode(stackAdjust, Opcode.INVOKESPECIAL, info);
1272: }
1273:
1274: public void invokeSuper(String super ClassName, String methodName,
1275: TypeDesc ret, TypeDesc[] params) {
1276: ConstantInfo info = mCp.addConstantMethod(super ClassName,
1277: methodName, ret, params);
1278:
1279: int stackAdjust = returnSize(ret) - 1;
1280: if (params != null) {
1281: stackAdjust -= argSize(params);
1282: }
1283:
1284: addCode(stackAdjust, Opcode.INVOKESPECIAL, info);
1285: }
1286:
1287: public void invokeSuper(TypeDesc super ClassDesc, String methodName,
1288: TypeDesc ret, TypeDesc[] params) {
1289:
1290: invokeSuper(getClassName(super ClassDesc), methodName, ret,
1291: params);
1292: }
1293:
1294: public void invokeConstructor(TypeDesc[] params) {
1295: ConstantInfo info = mCp.addConstantConstructor(mClassFile
1296: .getClassName(), params);
1297:
1298: int stackAdjust = -1;
1299: if (params != null) {
1300: stackAdjust -= argSize(params);
1301: }
1302:
1303: addCode(stackAdjust, Opcode.INVOKESPECIAL, info);
1304: }
1305:
1306: public void invokeConstructor(String className, TypeDesc[] params) {
1307: ConstantInfo info = mCp.addConstantConstructor(className,
1308: params);
1309:
1310: int stackAdjust = -1;
1311: if (params != null) {
1312: stackAdjust -= argSize(params);
1313: }
1314:
1315: addCode(stackAdjust, Opcode.INVOKESPECIAL, info);
1316: }
1317:
1318: public void invokeConstructor(TypeDesc classDesc, TypeDesc[] params) {
1319: invokeConstructor(getClassName(classDesc), params);
1320: }
1321:
1322: public void invokeSuperConstructor(TypeDesc[] params) {
1323: invokeConstructor(mClassFile.getSuperClassName(), params);
1324: }
1325:
1326: private int returnSize(TypeDesc ret) {
1327: if (ret == null || ret == TypeDesc.VOID) {
1328: return 0;
1329: }
1330: if (ret.isDoubleWord()) {
1331: return 2;
1332: }
1333: return 1;
1334: }
1335:
1336: private int argSize(TypeDesc[] params) {
1337: int size = 0;
1338: if (params != null) {
1339: for (int i = 0; i < params.length; i++) {
1340: size += returnSize(params[i]);
1341: }
1342: }
1343: return size;
1344: }
1345:
1346: // creation style instructions
1347:
1348: public void newObject(TypeDesc type) {
1349: if (type.isArray()) {
1350: newObject(type, 1);
1351: } else {
1352: ConstantInfo info = mCp.addConstantClass(type);
1353: addCode(1, Opcode.NEW, info);
1354: }
1355: }
1356:
1357: public void newObject(TypeDesc type, int dimensions) {
1358: if (dimensions <= 0) {
1359: // If type refers to an array, then this code is bogus.
1360: ConstantInfo info = mCp.addConstantClass(type);
1361: addCode(1, Opcode.NEW, info);
1362: return;
1363: }
1364:
1365: TypeDesc componentType = type.getComponentType();
1366:
1367: if (dimensions == 1) {
1368: if (componentType.isPrimitive()) {
1369: addCode(0, Opcode.NEWARRAY, (byte) componentType
1370: .getTypeCode());
1371: return;
1372: }
1373: addCode(0, Opcode.ANEWARRAY, mCp
1374: .addConstantClass(componentType));
1375: return;
1376: }
1377:
1378: int stackAdjust = -(dimensions - 1);
1379: ConstantInfo info = mCp.addConstantClass(type);
1380: byte[] bytes = new byte[4];
1381:
1382: bytes[0] = Opcode.MULTIANEWARRAY;
1383: //bytes[1] = (byte)0;
1384: //bytes[2] = (byte)0;
1385: bytes[3] = (byte) dimensions;
1386:
1387: mInstructions.new ConstantOperandInstruction(stackAdjust,
1388: bytes, info);
1389: }
1390:
1391: // stack operation style instructions
1392:
1393: public void dup() {
1394: addCode(1, Opcode.DUP);
1395: }
1396:
1397: public void dupX1() {
1398: addCode(1, Opcode.DUP_X1);
1399: }
1400:
1401: public void dupX2() {
1402: addCode(1, Opcode.DUP_X2);
1403: }
1404:
1405: public void dup2() {
1406: addCode(2, Opcode.DUP2);
1407: }
1408:
1409: public void dup2X1() {
1410: addCode(2, Opcode.DUP2_X1);
1411: }
1412:
1413: public void dup2X2() {
1414: addCode(2, Opcode.DUP2_X2);
1415: }
1416:
1417: public void pop() {
1418: addCode(-1, Opcode.POP);
1419: }
1420:
1421: public void pop2() {
1422: addCode(-2, Opcode.POP2);
1423: }
1424:
1425: public void swap() {
1426: addCode(0, Opcode.SWAP);
1427: }
1428:
1429: public void swap2() {
1430: dup2X2();
1431: pop2();
1432: }
1433:
1434: // flow control instructions
1435:
1436: private void branch(int stackAdjust, Location location, byte opcode) {
1437: mInstructions.new BranchInstruction(stackAdjust, opcode,
1438: location);
1439: }
1440:
1441: public void branch(Location location) {
1442: branch(0, location, Opcode.GOTO);
1443: }
1444:
1445: public void ifNullBranch(Location location, boolean choice) {
1446: branch(-1, location, choice ? Opcode.IFNULL : Opcode.IFNONNULL);
1447: }
1448:
1449: public void ifEqualBranch(Location location, boolean choice) {
1450: branch(-2, location, choice ? Opcode.IF_ACMPEQ
1451: : Opcode.IF_ACMPNE);
1452: }
1453:
1454: public void ifZeroComparisonBranch(Location location, String choice)
1455: throws IllegalArgumentException {
1456:
1457: choice = choice.intern();
1458:
1459: byte opcode;
1460: if (choice == "==") {
1461: opcode = Opcode.IFEQ;
1462: } else if (choice == "!=") {
1463: opcode = Opcode.IFNE;
1464: } else if (choice == "<") {
1465: opcode = Opcode.IFLT;
1466: } else if (choice == ">=") {
1467: opcode = Opcode.IFGE;
1468: } else if (choice == ">") {
1469: opcode = Opcode.IFGT;
1470: } else if (choice == "<=") {
1471: opcode = Opcode.IFLE;
1472: } else {
1473: throw new IllegalArgumentException(
1474: "Invalid comparision choice: " + choice);
1475: }
1476:
1477: branch(-1, location, opcode);
1478: }
1479:
1480: public void ifComparisonBranch(Location location, String choice)
1481: throws IllegalArgumentException {
1482:
1483: choice = choice.intern();
1484:
1485: byte opcode;
1486: if (choice == "==") {
1487: opcode = Opcode.IF_ICMPEQ;
1488: } else if (choice == "!=") {
1489: opcode = Opcode.IF_ICMPNE;
1490: } else if (choice == "<") {
1491: opcode = Opcode.IF_ICMPLT;
1492: } else if (choice == ">=") {
1493: opcode = Opcode.IF_ICMPGE;
1494: } else if (choice == ">") {
1495: opcode = Opcode.IF_ICMPGT;
1496: } else if (choice == "<=") {
1497: opcode = Opcode.IF_ICMPLE;
1498: } else {
1499: throw new IllegalArgumentException(
1500: "Invalid comparision choice: " + choice);
1501: }
1502:
1503: branch(-2, location, opcode);
1504: }
1505:
1506: public void switchBranch(int[] cases, Location[] locations,
1507: Location defaultLocation) {
1508:
1509: mInstructions.new SwitchInstruction(cases, locations,
1510: defaultLocation);
1511: }
1512:
1513: public void jsr(Location location) {
1514: // Adjust the stack by one to make room for the return address.
1515: branch(1, location, Opcode.JSR);
1516: }
1517:
1518: public void ret(LocalVariable local) {
1519: if (local == null) {
1520: throw new IllegalArgumentException(
1521: "No local variable specified");
1522: }
1523:
1524: mInstructions.new RetInstruction(local);
1525: }
1526:
1527: // math instructions
1528:
1529: public void math(byte opcode) {
1530: int stackAdjust;
1531:
1532: switch (opcode) {
1533: case Opcode.INEG:
1534: case Opcode.LNEG:
1535: case Opcode.FNEG:
1536: case Opcode.DNEG:
1537: stackAdjust = 0;
1538: break;
1539: case Opcode.IADD:
1540: case Opcode.ISUB:
1541: case Opcode.IMUL:
1542: case Opcode.IDIV:
1543: case Opcode.IREM:
1544: case Opcode.IAND:
1545: case Opcode.IOR:
1546: case Opcode.IXOR:
1547: case Opcode.ISHL:
1548: case Opcode.ISHR:
1549: case Opcode.IUSHR:
1550: case Opcode.FADD:
1551: case Opcode.FSUB:
1552: case Opcode.FMUL:
1553: case Opcode.FDIV:
1554: case Opcode.FREM:
1555: case Opcode.FCMPG:
1556: case Opcode.FCMPL:
1557: case Opcode.LSHL:
1558: case Opcode.LSHR:
1559: case Opcode.LUSHR:
1560: stackAdjust = -1;
1561: break;
1562: case Opcode.LADD:
1563: case Opcode.LSUB:
1564: case Opcode.LMUL:
1565: case Opcode.LDIV:
1566: case Opcode.LREM:
1567: case Opcode.LAND:
1568: case Opcode.LOR:
1569: case Opcode.LXOR:
1570: case Opcode.DADD:
1571: case Opcode.DSUB:
1572: case Opcode.DMUL:
1573: case Opcode.DDIV:
1574: case Opcode.DREM:
1575: stackAdjust = -2;
1576: break;
1577: case Opcode.LCMP:
1578: case Opcode.DCMPG:
1579: case Opcode.DCMPL:
1580: stackAdjust = -3;
1581: break;
1582: default:
1583: throw new IllegalArgumentException("Not a math opcode: "
1584: + Opcode.getMnemonic(opcode));
1585: }
1586:
1587: addCode(stackAdjust, opcode);
1588: }
1589:
1590: // miscellaneous instructions
1591:
1592: public void arrayLength() {
1593: addCode(0, Opcode.ARRAYLENGTH);
1594: }
1595:
1596: public void throwObject() {
1597: addCode(-1, Opcode.ATHROW);
1598: }
1599:
1600: public void checkCast(TypeDesc type) {
1601: ConstantInfo info = mCp.addConstantClass(type);
1602: addCode(0, Opcode.CHECKCAST, info);
1603: }
1604:
1605: public void instanceOf(TypeDesc type) {
1606: ConstantInfo info = mCp.addConstantClass(type);
1607: addCode(0, Opcode.INSTANCEOF, info);
1608: }
1609:
1610: public void integerIncrement(LocalVariable local, int amount) {
1611: if (local == null) {
1612: throw new IllegalArgumentException(
1613: "No local variable specified");
1614: }
1615:
1616: if (-32768 <= amount && amount <= 32767) {
1617: mInstructions.new ShortIncrementInstruction(local,
1618: (short) amount);
1619: } else {
1620: // Amount can't possibly fit in a 16-bit value, so use regular
1621: // instructions instead.
1622:
1623: loadLocal(local);
1624: loadConstant(amount);
1625: math(Opcode.IADD);
1626: storeLocal(local);
1627: }
1628: }
1629:
1630: public void monitorEnter() {
1631: addCode(-1, Opcode.MONITORENTER);
1632: }
1633:
1634: public void monitorExit() {
1635: addCode(-1, Opcode.MONITOREXIT);
1636: }
1637:
1638: public void nop() {
1639: addCode(0, Opcode.NOP);
1640: }
1641:
1642: public void breakpoint() {
1643: addCode(0, Opcode.BREAKPOINT);
1644: }
1645: }
|