List of usage examples for org.objectweb.asm.tree.analysis Frame getLocals
public int getLocals()
From source file:co.paralleluniverse.fibers.instrument.InstrumentMethod.java
License:Open Source License
private void emitStoreState(MethodVisitor mv, int idx, FrameInfo fi, int numArgsToPreserve) { Frame f = frames[fi.endInstruction]; if (fi.lBefore != null) fi.lBefore.accept(mv);/*w ww .ja v a2 s. c o m*/ mv.visitVarInsn(Opcodes.ALOAD, lvarStack); emitConst(mv, idx); emitConst(mv, fi.numSlots); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "pushMethod", "(II)V"); // store operand stack for (int i = f.getStackSize(); i-- > 0;) { BasicValue v = (BasicValue) f.getStack(i); if (!isOmitted(v)) { if (!isNullType(v)) { int slotIdx = fi.stackSlotIndices[i]; assert slotIdx >= 0 && slotIdx < fi.numSlots; emitStoreValue(mv, v, lvarStack, slotIdx, -1); } else { db.log(LogLevel.DEBUG, "NULL stack entry: type=%s size=%d", v.getType(), v.getSize()); mv.visitInsn(Opcodes.POP); } } } // store local vars for (int i = firstLocal; i < f.getLocals(); i++) { BasicValue v = (BasicValue) f.getLocal(i); if (!isNullType(v)) { mv.visitVarInsn(v.getType().getOpcode(Opcodes.ILOAD), i); int slotIdx = fi.localSlotIndices[i]; assert slotIdx >= 0 && slotIdx < fi.numSlots; emitStoreValue(mv, v, lvarStack, slotIdx, i); } } // restore last numArgsToPreserve operands for (int i = f.getStackSize() - numArgsToPreserve; i < f.getStackSize(); i++) { BasicValue v = (BasicValue) f.getStack(i); if (!isOmitted(v)) { if (!isNullType(v)) { int slotIdx = fi.stackSlotIndices[i]; assert slotIdx >= 0 && slotIdx < fi.numSlots; emitRestoreValue(mv, v, lvarStack, slotIdx, -1); } else { mv.visitInsn(Opcodes.ACONST_NULL); } } } }
From source file:co.paralleluniverse.fibers.instrument.InstrumentMethod.java
License:Open Source License
private void emitRestoreState(MethodVisitor mv, int idx, FrameInfo fi, int numArgsPreserved) { Frame f = frames[fi.endInstruction]; // restore local vars for (int i = firstLocal; i < f.getLocals(); i++) { BasicValue v = (BasicValue) f.getLocal(i); if (!isNullType(v)) { int slotIdx = fi.localSlotIndices[i]; assert slotIdx >= 0 && slotIdx < fi.numSlots; emitRestoreValue(mv, v, lvarStack, slotIdx, i); mv.visitVarInsn(v.getType().getOpcode(Opcodes.ISTORE), i); } else if (v != BasicValue.UNINITIALIZED_VALUE) { mv.visitInsn(Opcodes.ACONST_NULL); mv.visitVarInsn(Opcodes.ASTORE, i); }/*from ww w .j a va2 s. c o m*/ } // restore operand stack for (int i = 0; i < f.getStackSize() - numArgsPreserved; i++) { BasicValue v = (BasicValue) f.getStack(i); if (!isOmitted(v)) { if (!isNullType(v)) { int slotIdx = fi.stackSlotIndices[i]; assert slotIdx >= 0 && slotIdx < fi.numSlots; emitRestoreValue(mv, v, lvarStack, slotIdx, -1); } else { mv.visitInsn(Opcodes.ACONST_NULL); } } } if (fi.lAfter != null) { fi.lAfter.accept(mv); } }
From source file:com.dragome.callbackevictor.serverside.bytecode.transformation.asm.ContinuationMethodAdapter.java
License:Apache License
public void visitCode() { mv.visitCode();/*from ww w .j a va 2s. c om*/ int fsize = labels.size(); Label[] restoreLabels = new Label[fsize]; for (int i = 0; i < restoreLabels.length; i++) { restoreLabels[i] = new Label(); } // verify if restoring Label l0 = new Label(); // PC: StackRecorder stackRecorder = StackRecorder.get(); mv.visitMethodInsn(INVOKESTATIC, STACK_RECORDER, "get", "()L" + STACK_RECORDER + ";", false); mv.visitInsn(DUP); mv.visitVarInsn(ASTORE, stackRecorderVar); mv.visitLabel(startLabel); // PC: if (stackRecorder != null && !stackRecorder.isRestoring) { mv.visitJumpInsn(IFNULL, l0); mv.visitVarInsn(ALOAD, stackRecorderVar); mv.visitFieldInsn(GETFIELD, STACK_RECORDER, "isRestoring", "Z"); mv.visitJumpInsn(IFEQ, l0); mv.visitVarInsn(ALOAD, stackRecorderVar); // PC: stackRecorder.popInt(); mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, POP_METHOD + "Int", "()I", false); mv.visitTableSwitchInsn(0, fsize - 1, l0, restoreLabels); // switch cases for (int i = 0; i < fsize; i++) { Label frameLabel = labels.get(i); mv.visitLabel(restoreLabels[i]); MethodInsnNode mnode = nodes.get(i); Frame frame = analyzer.getFrames()[canalyzer.getIndex(mnode)]; // for each local variable store the value in locals popping it from the stack! // locals int lsize = frame.getLocals(); for (int j = lsize - 1; j >= 0; j--) { BasicValue value = (BasicValue) frame.getLocal(j); if (isNull(value)) { mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, j); } else if (value == BasicValue.UNINITIALIZED_VALUE) { // TODO ?? } else if (value == BasicValue.RETURNADDRESS_VALUE) { // TODO ?? } else { mv.visitVarInsn(ALOAD, stackRecorderVar); Type type = value.getType(); if (value.isReference()) { mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, POP_METHOD + "Object", "()Ljava/lang/Object;", false); Type t = value.getType(); String desc = t.getDescriptor(); if (desc.charAt(0) == '[') { mv.visitTypeInsn(CHECKCAST, desc); } else { mv.visitTypeInsn(CHECKCAST, t.getInternalName()); } mv.visitVarInsn(ASTORE, j); } else { mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, getPopMethod(type), "()" + type.getDescriptor(), false); mv.visitVarInsn(type.getOpcode(ISTORE), j); } } } if (frame instanceof MonitoringFrame) { int[] monitoredLocals = ((MonitoringFrame) frame).getMonitored(); // System.out.println(System.identityHashCode(frame)+" AMonitored locals "+monitoredLocals.length); for (int monitoredLocal : monitoredLocals) { // System.out.println(System.identityHashCode(frame)+" AMonitored local "+monitoredLocals[j]); mv.visitVarInsn(ALOAD, monitoredLocal); mv.visitInsn(MONITORENTER); } } // stack int argSize = Type.getArgumentTypes(mnode.desc).length; int ownerSize = mnode.getOpcode() == INVOKESTATIC ? 0 : 1; // TODO int initSize = mnode.name.equals("<init>") ? 2 : 0; int ssize = frame.getStackSize(); for (int j = 0; j < ssize - argSize - ownerSize - initSize; j++) { BasicValue value = (BasicValue) frame.getStack(j); if (isNull(value)) { mv.visitInsn(ACONST_NULL); } else if (value == BasicValue.UNINITIALIZED_VALUE) { // TODO ?? } else if (value == BasicValue.RETURNADDRESS_VALUE) { // TODO ?? } else if (value.isReference()) { mv.visitVarInsn(ALOAD, stackRecorderVar); mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, POP_METHOD + "Object", "()Ljava/lang/Object;", false); mv.visitTypeInsn(CHECKCAST, value.getType().getInternalName()); } else { Type type = value.getType(); mv.visitVarInsn(ALOAD, stackRecorderVar); mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, getPopMethod(type), "()" + type.getDescriptor(), false); } } boolean hasMethodRef = false; if (mnode.getOpcode() != INVOKESTATIC) { // Load the object whose method we are calling BasicValue value = ((BasicValue) frame.getStack(ssize - argSize - 1)); if (isNull(value)) { // If user code causes NPE, then we keep this behavior: load null to get NPE at runtime mv.visitInsn(ACONST_NULL); } else { hasMethodRef = true; mv.visitVarInsn(ALOAD, stackRecorderVar); mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, POP_METHOD + "Reference", "()Ljava/lang/Object;", false); mv.visitTypeInsn(CHECKCAST, value.getType().getInternalName()); } } // Create null types for the parameters of the method invocation // RS: if (hasMethodRef && canalyzer._continueReflection && mnode.name.contains("invoke") && mnode.owner.contains("java/lang/reflect/Method")) { ContinuationMethodAnalyzer.MyVariables vars = canalyzer._reflectMapping.get(mnode); mv.visitVarInsn(ALOAD, vars.objectVar()); mv.visitVarInsn(ALOAD, vars.argsVar()); //mv.visitVarInsn(ALOAD, 2); //mv.visitVarInsn(ALOAD, 4); } //RS: else { for (Type paramType : Type.getArgumentTypes(mnode.desc)) { pushDefault(paramType); } } // continue to the next method mv.visitJumpInsn(GOTO, frameLabel); } // PC: } // end of start block mv.visitLabel(l0); }
From source file:com.googlecode.dex2jar.test.TestUtils.java
License:Apache License
static void printAnalyzerResult(MethodNode method, Analyzer a, final PrintWriter pw) throws IllegalArgumentException, IllegalAccessException { Frame[] frames = a.getFrames(); Textifier t = new Textifier(); TraceMethodVisitor mv = new TraceMethodVisitor(t); String format = "%05d %-" + (method.maxStack + method.maxLocals + 6) + "s|%s"; for (int j = 0; j < method.instructions.size(); ++j) { method.instructions.get(j).accept(mv); StringBuffer s = new StringBuffer(); Frame f = frames[j]; if (f == null) { s.append('?'); } else {//from w ww . jav a2 s.co m for (int k = 0; k < f.getLocals(); ++k) { s.append(getShortName(f.getLocal(k).toString())); } s.append(" : "); for (int k = 0; k < f.getStackSize(); ++k) { s.append(getShortName(f.getStack(k).toString())); } } pw.printf(format, j, s, buf.get(t)); // mv.text.get(j)); } for (int j = 0; j < method.tryCatchBlocks.size(); ++j) { ((TryCatchBlockNode) method.tryCatchBlocks.get(j)).accept(mv); pw.print(" " + buf.get(t)); } pw.println(); pw.flush(); }
From source file:com.googlecode.dex2jar.tools.AsmVerify.java
License:Apache License
static void printAnalyzerResult(MethodNode method, Analyzer a, final PrintWriter pw) throws IllegalArgumentException { Frame[] frames = a.getFrames(); Textifier t = new Textifier(); TraceMethodVisitor mv = new TraceMethodVisitor(t); String format = "%05d %-" + (method.maxStack + method.maxLocals + 6) + "s|%s"; for (int j = 0; j < method.instructions.size(); ++j) { method.instructions.get(j).accept(mv); StringBuffer s = new StringBuffer(); Frame f = frames[j]; if (f == null) { s.append('?'); } else {// w w w .j a v a 2 s . c o m for (int k = 0; k < f.getLocals(); ++k) { s.append(getShortName(f.getLocal(k).toString())); } s.append(" : "); for (int k = 0; k < f.getStackSize(); ++k) { s.append(getShortName(f.getStack(k).toString())); } } try { pw.printf(format, j, s, buf.get(t)); // mv.text.get(j)); } catch (IllegalAccessException e) { e.printStackTrace(); } } for (TryCatchBlockNode tryCatchBlockNode : method.tryCatchBlocks) { tryCatchBlockNode.accept(mv); try { pw.print(" " + buf.get(t)); } catch (IllegalAccessException e) { e.printStackTrace(); } } pw.println(); pw.flush(); }
From source file:com.offbynull.coroutines.instrumenter.asm.InstructionUtils.java
License:Open Source License
/** * Generates instructions to load the local variables table from an object array. * * @param arrayLocalsVar variable that the object array containing local variables table is stored * @param tempObjectVar variable to use for temporary objects * @param frame execution frame at the instruction for which the local variables table is to be restored * @return instructions to load the local variables table from an array * @throws NullPointerException if any argument is {@code null} * @throws IllegalArgumentException if variables have the same index, or if variables have been released, or if variables are of wrong * type//from w w w . j a v a 2 s. co m */ public static InsnList loadLocalVariableTable(Variable arrayLocalsVar, Variable tempObjectVar, Frame<BasicValue> frame) { Validate.notNull(arrayLocalsVar); Validate.notNull(tempObjectVar); Validate.notNull(frame); Validate.isTrue(arrayLocalsVar.getType().equals(Type.getType(Object[].class))); Validate.isTrue(tempObjectVar.getType().equals(Type.getType(Object.class))); validateLocalIndicies(arrayLocalsVar.getIndex(), tempObjectVar.getIndex()); InsnList ret = new InsnList(); // Load the locals for (int i = 0; i < frame.getLocals(); i++) { BasicValue basicValue = frame.getLocal(i); Type type = basicValue.getType(); // If type == null, basicValue is pointing to uninitialized var -- basicValue.toString() will return ".". This means that this // slot contains nothing to load. So, skip this slot if we encounter it (such that it will remain uninitialized). if (type == null) { continue; } // If type is 'Lnull;', this means that the slot has been assigned null and that "there has been no merge yet that would 'raise' // the type toward some class or interface type" (from ASM mailing list). We know this slot will always contain null at this // point in the code so there's no specific value to load up from the array. Instead we push a null in to that slot, thereby // keeping the same 'Lnull;' type originally assigned to that slot (it doesn't make sense to do a CHECKCAST because 'null' is // not a real class and can never be a real class -- null is a reserved word in Java). if (type.getSort() == Type.OBJECT && "Lnull;".equals(type.getDescriptor())) { ret.add(new InsnNode(Opcodes.ACONST_NULL)); ret.add(new VarInsnNode(Opcodes.ASTORE, i)); continue; } // Load item from locals storage array ret.add(new VarInsnNode(Opcodes.ALOAD, arrayLocalsVar.getIndex())); ret.add(new LdcInsnNode(i)); ret.add(new InsnNode(Opcodes.AALOAD)); // Convert the item from an object stores it in local vars table. switch (type.getSort()) { case Type.BOOLEAN: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Boolean")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false)); ret.add(new VarInsnNode(Opcodes.ISTORE, i)); break; case Type.BYTE: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Byte")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false)); ret.add(new VarInsnNode(Opcodes.ISTORE, i)); break; case Type.SHORT: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Short")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false)); ret.add(new VarInsnNode(Opcodes.ISTORE, i)); break; case Type.CHAR: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Character")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false)); ret.add(new VarInsnNode(Opcodes.ISTORE, i)); break; case Type.INT: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Integer")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false)); ret.add(new VarInsnNode(Opcodes.ISTORE, i)); break; case Type.FLOAT: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Float")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false)); ret.add(new VarInsnNode(Opcodes.FSTORE, i)); break; case Type.LONG: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Long")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false)); ret.add(new VarInsnNode(Opcodes.LSTORE, i)); break; case Type.DOUBLE: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/Double")); ret.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false)); ret.add(new VarInsnNode(Opcodes.DSTORE, i)); break; case Type.ARRAY: case Type.OBJECT: ret.add(new TypeInsnNode(Opcodes.CHECKCAST, basicValue.getType().getInternalName())); ret.add(new VarInsnNode(Opcodes.ASTORE, i)); break; case Type.METHOD: case Type.VOID: default: throw new IllegalStateException(); } } return ret; }
From source file:com.offbynull.coroutines.instrumenter.asm.InstructionUtils.java
License:Open Source License
/** * Generates instructions to save the local variables table to an object array. * * @param arrayLocalsVar variable that the object array containing local variables table is stored * @param tempObjectVar variable to use for temporary objects * @param frame execution frame at the instruction where the local variables table is to be saved * @return instructions to save the local variables table in to an array * @throws NullPointerException if any argument is {@code null} * @throws IllegalArgumentException if variables have the same index, or if variables have been released, or if variables are of wrong * type/*from w ww . j av a 2 s .c om*/ */ public static InsnList saveLocalVariableTable(Variable arrayLocalsVar, Variable tempObjectVar, Frame<BasicValue> frame) { Validate.notNull(arrayLocalsVar); Validate.notNull(tempObjectVar); Validate.notNull(frame); Validate.isTrue(arrayLocalsVar.getType().equals(Type.getType(Object[].class))); Validate.isTrue(tempObjectVar.getType().equals(Type.getType(Object.class))); validateLocalIndicies(arrayLocalsVar.getIndex(), tempObjectVar.getIndex()); InsnList ret = new InsnList(); // Create array and save it in local vars table ret.add(new LdcInsnNode(frame.getLocals())); ret.add(new TypeInsnNode(Opcodes.ANEWARRAY, "java/lang/Object")); ret.add(new VarInsnNode(Opcodes.ASTORE, arrayLocalsVar.getIndex())); // Save the locals for (int i = 0; i < frame.getLocals(); i++) { BasicValue basicValue = frame.getLocal(i); Type type = basicValue.getType(); // If type == null, basicValue is pointing to uninitialized var -- basicValue.toString() will return '.'. This means that this // slot contains nothing to save. So, skip this slot if we encounter it. if (type == null) { continue; } // If type is 'Lnull;', this means that the slot has been assigned null and that "there has been no merge yet that would 'raise' // the type toward some class or interface type" (from ASM mailing list). We know this slot will always contain null at this // point in the code so we can avoid saving it. When we load it back up, we can simply push a null in to that slot, thereby // keeping the same 'Lnull;' type. if ("Lnull;".equals(type.getDescriptor())) { continue; } // Convert the item to an object (if not already an object) and stores it in array. switch (type.getSort()) { case Type.BOOLEAN: ret.add(new VarInsnNode(Opcodes.ILOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;")); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.BYTE: ret.add(new VarInsnNode(Opcodes.ILOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.SHORT: ret.add(new VarInsnNode(Opcodes.ILOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.CHAR: ret.add(new VarInsnNode(Opcodes.ILOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.INT: ret.add(new VarInsnNode(Opcodes.ILOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.FLOAT: ret.add(new VarInsnNode(Opcodes.FLOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.LONG: ret.add(new VarInsnNode(Opcodes.LLOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.DOUBLE: ret.add(new VarInsnNode(Opcodes.DLOAD, i)); ret.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.ARRAY: case Type.OBJECT: ret.add(new VarInsnNode(Opcodes.ALOAD, i)); ret.add(new VarInsnNode(Opcodes.ASTORE, tempObjectVar.getIndex())); break; case Type.METHOD: case Type.VOID: default: throw new IllegalStateException(); } // Store item in to locals storage array ret.add(new VarInsnNode(Opcodes.ALOAD, arrayLocalsVar.getIndex())); ret.add(new LdcInsnNode(i)); ret.add(new VarInsnNode(Opcodes.ALOAD, tempObjectVar.getIndex())); ret.add(new InsnNode(Opcodes.AASTORE)); } return ret; }
From source file:com.offbynull.coroutines.instrumenter.LocalsStateGenerators.java
License:Open Source License
/** * Generates instructions to load the local variables table. * @param markerType debug marker type/*from w ww. j a va 2 s . c om*/ * @param storageVars variables to load locals from * @param frame execution frame at the instruction for which the local variables table is to be restored * @return instructions to load the local variables table from an array * @throws NullPointerException if any argument is {@code null} */ public static InsnList loadLocals(MarkerType markerType, StorageVariables storageVars, Frame<BasicValue> frame) { Validate.notNull(markerType); Validate.notNull(storageVars); Validate.notNull(frame); Variable intsVar = storageVars.getIntStorageVar(); Variable floatsVar = storageVars.getFloatStorageVar(); Variable longsVar = storageVars.getLongStorageVar(); Variable doublesVar = storageVars.getDoubleStorageVar(); Variable objectsVar = storageVars.getObjectStorageVar(); int intsCounter = 0; int floatsCounter = 0; int longsCounter = 0; int doublesCounter = 0; int objectsCounter = 0; InsnList ret = new InsnList(); // Load the locals ret.add(debugMarker(markerType, "Loading locals")); for (int i = 0; i < frame.getLocals(); i++) { BasicValue basicValue = frame.getLocal(i); Type type = basicValue.getType(); // If type == null, basicValue is pointing to uninitialized var -- basicValue.toString() will return ".". This means that this // slot contains nothing to load. So, skip this slot if we encounter it (such that it will remain uninitialized). if (type == null) { ret.add(debugMarker(markerType, "Skipping uninitialized value at " + i)); continue; } // If type is 'Lnull;', this means that the slot has been assigned null and that "there has been no merge yet that would 'raise' // the type toward some class or interface type" (from ASM mailing list). We know this slot will always contain null at this // point in the code so there's no specific value to load up from the array. Instead we push a null in to that slot, thereby // keeping the same 'Lnull;' type originally assigned to that slot (it doesn't make sense to do a CHECKCAST because 'null' is // not a real class and can never be a real class -- null is a reserved word in Java). if (type.getSort() == Type.OBJECT && "Lnull;".equals(type.getDescriptor())) { ret.add(debugMarker(markerType, "Putting null value at " + i)); ret.add(new InsnNode(Opcodes.ACONST_NULL)); ret.add(new VarInsnNode(Opcodes.ASTORE, i)); continue; } // Load the locals switch (type.getSort()) { case Type.BOOLEAN: case Type.BYTE: case Type.SHORT: case Type.CHAR: case Type.INT: ret.add(debugMarker(markerType, "Loading int to LVT index " + i + " from storage index " + intsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, intsVar.getIndex())); // [int[]] ret.add(new LdcInsnNode(intsCounter)); // [int[], idx] ret.add(new InsnNode(Opcodes.IALOAD)); // [val] ret.add(new VarInsnNode(Opcodes.ISTORE, i)); // [] intsCounter++; break; case Type.FLOAT: ret.add(debugMarker(markerType, "Loading float to LVT index " + i + " from storage index " + floatsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, floatsVar.getIndex())); // [float[]] ret.add(new LdcInsnNode(floatsCounter)); // [float[], idx] ret.add(new InsnNode(Opcodes.FALOAD)); // [val] ret.add(new VarInsnNode(Opcodes.FSTORE, i)); // [] floatsCounter++; break; case Type.LONG: ret.add(debugMarker(markerType, "Loading long to LVT index " + i + " from storage index " + longsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, longsVar.getIndex())); // [long[]] ret.add(new LdcInsnNode(longsCounter)); // [long[], idx] ret.add(new InsnNode(Opcodes.LALOAD)); // [val_PART1, val_PART2] ret.add(new VarInsnNode(Opcodes.LSTORE, i)); // [] longsCounter++; break; case Type.DOUBLE: ret.add(debugMarker(markerType, "Loading double to LVT index " + i + " from storage index " + doublesCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, doublesVar.getIndex())); // [double[]] ret.add(new LdcInsnNode(doublesCounter)); // [double[], idx] ret.add(new InsnNode(Opcodes.DALOAD)); // [val_PART1, val_PART2] ret.add(new VarInsnNode(Opcodes.DSTORE, i)); // [] doublesCounter++; break; case Type.ARRAY: case Type.OBJECT: ret.add(debugMarker(markerType, "Loading object to LVT index " + i + " from storage index " + objectsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, objectsVar.getIndex())); // [Object[]] ret.add(new LdcInsnNode(objectsCounter)); // [Object[], idx] ret.add(new InsnNode(Opcodes.AALOAD)); // [val] // must cast, otherwise the jvm won't know the type that's in the localvariable slot and it'll fail when the code tries // to access a method/field on it ret.add(new TypeInsnNode(Opcodes.CHECKCAST, basicValue.getType().getInternalName())); ret.add(new VarInsnNode(Opcodes.ASTORE, i)); // [] objectsCounter++; break; case Type.METHOD: case Type.VOID: default: throw new IllegalStateException(); } } return ret; }
From source file:com.offbynull.coroutines.instrumenter.LocalsStateGenerators.java
License:Open Source License
/** * Generates instructions to save the local variables table. * @param markerType debug marker type/*w w w. jav a2 s . c o m*/ * @param storageVars variables to store locals in to * @param frame execution frame at the instruction where the local variables table is to be saved * @return instructions to save the local variables table in to an array * @throws NullPointerException if any argument is {@code null} */ public static InsnList saveLocals(MarkerType markerType, StorageVariables storageVars, Frame<BasicValue> frame) { Validate.notNull(markerType); Validate.notNull(storageVars); Validate.notNull(frame); Variable intsVar = storageVars.getIntStorageVar(); Variable floatsVar = storageVars.getFloatStorageVar(); Variable longsVar = storageVars.getLongStorageVar(); Variable doublesVar = storageVars.getDoubleStorageVar(); Variable objectsVar = storageVars.getObjectStorageVar(); int intsCounter = 0; int floatsCounter = 0; int longsCounter = 0; int doublesCounter = 0; int objectsCounter = 0; StorageSizes storageSizes = computeSizes(frame); InsnList ret = new InsnList(); // Create storage arrays and save them in respective storage vars ret.add(merge(debugMarker(markerType, "Saving locals"), mergeIf(intsVar != null, () -> new Object[] { debugMarker(markerType, "Generating ints container (" + storageSizes.getIntsSize() + ")"), new LdcInsnNode(storageSizes.getIntsSize()), new IntInsnNode(Opcodes.NEWARRAY, Opcodes.T_INT), new VarInsnNode(Opcodes.ASTORE, intsVar.getIndex()) }), mergeIf(floatsVar != null, () -> new Object[] { debugMarker(markerType, "Generating floats container (" + storageSizes.getFloatsSize() + ")"), new LdcInsnNode(storageSizes.getFloatsSize()), new IntInsnNode(Opcodes.NEWARRAY, Opcodes.T_FLOAT), new VarInsnNode(Opcodes.ASTORE, floatsVar.getIndex()) }), mergeIf(longsVar != null, () -> new Object[] { debugMarker(markerType, "Generating longs container (" + storageSizes.getLongsSize() + ")"), new LdcInsnNode(storageSizes.getLongsSize()), new IntInsnNode(Opcodes.NEWARRAY, Opcodes.T_LONG), new VarInsnNode(Opcodes.ASTORE, longsVar.getIndex()) }), mergeIf(doublesVar != null, () -> new Object[] { debugMarker(markerType, "Generating doubles container (" + storageSizes.getDoublesSize() + ")"), new LdcInsnNode(storageSizes.getDoublesSize()), new IntInsnNode(Opcodes.NEWARRAY, Opcodes.T_DOUBLE), new VarInsnNode(Opcodes.ASTORE, doublesVar.getIndex()) }), mergeIf(objectsVar != null, () -> new Object[] { debugMarker(markerType, "Generating objects container (" + storageSizes.getObjectsSize() + ")"), new LdcInsnNode(storageSizes.getObjectsSize()), new TypeInsnNode(Opcodes.ANEWARRAY, "java/lang/Object"), new VarInsnNode(Opcodes.ASTORE, objectsVar.getIndex()) }))); // Save the locals for (int i = 0; i < frame.getLocals(); i++) { BasicValue basicValue = frame.getLocal(i); Type type = basicValue.getType(); // If type == null, basicValue is pointing to uninitialized var -- basicValue.toString() will return '.'. This means that this // slot contains nothing to save. So, skip this slot if we encounter it. if (type == null) { ret.add(debugMarker(markerType, "Skipping uninitialized value at " + i)); continue; } // If type is 'Lnull;', this means that the slot has been assigned null and that "there has been no merge yet that would 'raise' // the type toward some class or interface type" (from ASM mailing list). We know this slot will always contain null at this // point in the code so we can avoid saving it. When we load it back up, we can simply push a null in to that slot, thereby // keeping the same 'Lnull;' type. if ("Lnull;".equals(type.getDescriptor())) { ret.add(debugMarker(markerType, "Skipping null value at " + i)); continue; } // Place item in to appropriate storage array switch (type.getSort()) { case Type.BOOLEAN: case Type.BYTE: case Type.SHORT: case Type.CHAR: case Type.INT: ret.add(debugMarker(markerType, "Inserting int at LVT index " + i + " to storage index " + intsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, intsVar.getIndex())); // [int[]] ret.add(new LdcInsnNode(intsCounter)); // [int[], idx] ret.add(new VarInsnNode(Opcodes.ILOAD, i)); // [int[], idx, val] ret.add(new InsnNode(Opcodes.IASTORE)); // [] intsCounter++; break; case Type.FLOAT: ret.add(debugMarker(markerType, "Inserting float at LVT index " + i + " to storage index " + floatsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, floatsVar.getIndex())); // [float[]] ret.add(new LdcInsnNode(floatsCounter)); // [float[], idx] ret.add(new VarInsnNode(Opcodes.FLOAD, i)); // [float[], idx, val] ret.add(new InsnNode(Opcodes.FASTORE)); // [] floatsCounter++; break; case Type.LONG: ret.add(debugMarker(markerType, "Inserting long at LVT index " + i + " to storage index " + longsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, longsVar.getIndex())); // [long[]] ret.add(new LdcInsnNode(longsCounter)); // [long[], idx] ret.add(new VarInsnNode(Opcodes.LLOAD, i)); // [long[], idx, val] ret.add(new InsnNode(Opcodes.LASTORE)); // [] longsCounter++; break; case Type.DOUBLE: ret.add(debugMarker(markerType, "Inserting double at LVT index " + i + " to storage index " + doublesCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, doublesVar.getIndex())); // [double[]] ret.add(new LdcInsnNode(doublesCounter)); // [double[], idx] ret.add(new VarInsnNode(Opcodes.DLOAD, i)); // [double[], idx, val] ret.add(new InsnNode(Opcodes.DASTORE)); // [] doublesCounter++; break; case Type.ARRAY: case Type.OBJECT: ret.add(debugMarker(markerType, "Inserting object at LVT index " + i + " to storage index " + objectsCounter)); ret.add(new VarInsnNode(Opcodes.ALOAD, objectsVar.getIndex())); // [Object[]] ret.add(new LdcInsnNode(objectsCounter)); // [Object[], idx] ret.add(new VarInsnNode(Opcodes.ALOAD, i)); // [Object[], idx, val] ret.add(new InsnNode(Opcodes.AASTORE)); // [] objectsCounter++; break; case Type.METHOD: case Type.VOID: default: throw new IllegalStateException(); } } return ret; }
From source file:com.offbynull.coroutines.instrumenter.LocalsStateGenerators.java
License:Open Source License
/** * Compute sizes required for the storage arrays that will contain the local variables table at this frame. * @param frame frame to compute for//w w w. j a va2 s. c om * @return size required by each storage array * @throws NullPointerException if any argument is {@code null} */ public static StorageSizes computeSizes(Frame<BasicValue> frame) { Validate.notNull(frame); // Count size required for each storage array int intsSize = 0; int longsSize = 0; int floatsSize = 0; int doublesSize = 0; int objectsSize = 0; for (int i = 0; i < frame.getLocals(); i++) { BasicValue basicValue = frame.getLocal(i); Type type = basicValue.getType(); // If type == null, basicValue is pointing to uninitialized var -- basicValue.toString() will return '.'. This means that this // slot contains nothing to save. So, skip this slot if we encounter it. if (type == null) { continue; } // If type is 'Lnull;', this means that the slot has been assigned null and that "there has been no merge yet that would 'raise' // the type toward some class or interface type" (from ASM mailing list). We know this slot will always contain null at this // point in the code so we can avoid saving it. When we load it back up, we can simply push a null in to that slot, thereby // keeping the same 'Lnull;' type. if ("Lnull;".equals(type.getDescriptor())) { continue; } switch (type.getSort()) { case Type.BOOLEAN: case Type.BYTE: case Type.SHORT: case Type.CHAR: case Type.INT: intsSize++; break; case Type.FLOAT: floatsSize++; break; case Type.LONG: longsSize++; break; case Type.DOUBLE: doublesSize++; break; case Type.ARRAY: case Type.OBJECT: objectsSize++; break; case Type.METHOD: case Type.VOID: default: throw new IllegalStateException(); } } return new StorageSizes(intsSize, longsSize, floatsSize, doublesSize, objectsSize); }