List of usage examples for org.objectweb.asm.tree.analysis BasicValue UNINITIALIZED_VALUE
BasicValue UNINITIALIZED_VALUE
To view the source code for org.objectweb.asm.tree.analysis BasicValue UNINITIALIZED_VALUE.
Click Source Link
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); }//w w w . j a v a 2s . c om } // 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:co.paralleluniverse.fibers.instrument.InstrumentMethod.java
License:Open Source License
static boolean isNullType(BasicValue v) { return (v == BasicValue.UNINITIALIZED_VALUE) || (v.isReference() && v.getType().getInternalName().equals("null")); }
From source file:com.android.build.gradle.internal.incremental.ConstructorBuilder.java
License:Apache License
/** * Deconstruct a constructor into its components and adds the necessary code to link the components * later. This code is not valid java, but it can be expressed in bytecode. In essence for this constructor: * <pre>{@code// www. j ava2 s. com * <init>(int x) { * int a = 2; * super(int b = 3, x = 1, expr2() ? 3 : a++) * doSomething(x + a) * } * }</pre> * it creates two parts: * <pre>{@code * Object[] init$args(Clazz this, int x, Object[] locals) { // this is always null here * int a = locals[0]; * int b = 3; * Object[] args = new Object[3]; * args[0] = b; * args[1] = (x = 1) * args[2] = expr2() ? 3 : a++; * locals = new Object[3]; // The arguments + the locals * locals[0] = NULL; * locals[1] = x; * locals[2] = new Object[2]; * locals[2][0] = a; * locals[2][1] = b; * return new Object[] {locals, "myclass.<init>(I;I;)V", args}; * } * * void init$body(int x, Object[] locals) { * int a = locals[0]; * int b = locals[1]; * doSomething(x + a); * } * }</pre> * * @param owner the owning class. * @param method the constructor method. */ @NonNull public static Constructor build(@NonNull String owner, @NonNull MethodNode method) { // Basic interpreter uses BasicValue.REFERENCE_VALUE for all object types. However // we need to distinguish one in particular. The value of the local variable 0, ie. the // uninitialized this. By doing it this way we ensure that whenever there is a ALOAD_0 // a LocalValue instance will be on the stack. BasicInterpreter interpreter = new BasicInterpreter() { boolean done = false; @Override // newValue is called first to initialize the frame values of all the local variables // we intercept the first one to create our own special value. public BasicValue newValue(Type type) { if (type == null) { return BasicValue.UNINITIALIZED_VALUE; } else if (type.getSort() == Type.VOID) { return null; } else { // If this is the first value created (i.e. the first local variable) // we use a special marker. BasicValue ret = done ? super.newValue(type) : new LocalValue(type); done = true; return ret; } } }; Analyzer analyzer = new Analyzer(interpreter); AbstractInsnNode[] instructions = method.instructions.toArray(); try { Frame[] frames = analyzer.analyze(owner, method); if (frames.length != instructions.length) { // Should never happen. throw new IllegalStateException("The number of frames is not equals to the number of instructions"); } int stackAtThis = -1; boolean poppedThis = false; int firstLocal = 1; for (Type type : Type.getArgumentTypes(method.desc)) { firstLocal += type.getSize(); } LinkedHashSet<LocalVariable> variables = new LinkedHashSet<LocalVariable>(); VarInsnNode lastThis = null; int localsAtLastThis = 0; // Records the most recent line number encountered. For javac, there should always be // a line number node before the call of interest to this(...) or super(...). For robustness, // -1 is recorded as a sentinel to indicate this assumption didn't hold. Upstream consumers // should check for -1 and recover in a reasonable way (for example, don't set the line // number in generated code). int recentLine = -1; for (int i = 0; i < instructions.length; i++) { AbstractInsnNode insn = instructions[i]; Frame frame = frames[i]; if (frame.getStackSize() < stackAtThis) { poppedThis = true; } if (insn instanceof MethodInsnNode) { // TODO: Do we need to check that the stack is empty after this super call? MethodInsnNode methodhInsn = (MethodInsnNode) insn; Type[] types = Type.getArgumentTypes(methodhInsn.desc); Value value = frame.getStack(frame.getStackSize() - types.length - 1); if (value instanceof LocalValue && methodhInsn.name.equals("<init>")) { if (poppedThis) { throw new IllegalStateException("Unexpected constructor structure."); } return split(owner, method, lastThis, methodhInsn, recentLine, new ArrayList<LocalVariable>(variables), localsAtLastThis); } } else if (insn instanceof VarInsnNode) { VarInsnNode var = (VarInsnNode) insn; if (var.var == 0) { lastThis = var; localsAtLastThis = variables.size(); stackAtThis = frame.getStackSize(); poppedThis = false; } Type type = ByteCodeUtils.getTypeForStoreOpcode(var.getOpcode()); if (type != null && var.var >= firstLocal) { // Variables are equals based on their number, so they will be added // to the set only if they are new, and in the order they are seen. variables.add(new LocalVariable(type, var.var)); } } else if (insn instanceof LineNumberNode) { // Record the most recent line number encountered so that call to this(...) // or super(...) has line number information. Ultimately used to emit a line // number in the generated code. LineNumberNode lineNumberNode = (LineNumberNode) insn; recentLine = lineNumberNode.line; } } throw new IllegalStateException("Unexpected constructor structure."); } catch (AnalyzerException e) { throw new IllegalStateException(e); } }
From source file:com.android.build.gradle.internal.incremental.ConstructorDelegationDetector.java
License:Apache License
/** * Deconstruct a constructor into its components and adds the necessary code to link the components * later. The generated bytecode does not correspond exactly to this code, but in essence, for * a constructor of this form:/*from w ww . j av a2 s .c o m*/ * <p/> * <code> * <init>(int x) { * super(x = 1, expr2() ? 3 : 7) * doSomething(x) * } * </code> * <p/> * it creates the two parts: * <code> * Object[] init$args(Object[] locals, int x) { * Object[] args = new Object[2]; * args[0] = (x = 1) * args[1] = expr2() ? 3 : 7; * locals[0] = x; * return new Object[] {"myclass.<init>(I;I;)V", args}; * } * * void init$body(int x) { * doSomething(x); * } * </code> * * @param owner the owning class. * @param method the constructor method. */ @NonNull public static Constructor deconstruct(@NonNull String owner, @NonNull MethodNode method) { // Basic interpreter uses BasicValue.REFERENCE_VALUE for all object types. However // we need to distinguish one in particular. The value of the local variable 0, ie. the // uninitialized this. By doing it this way we ensure that whenever there is a ALOAD_0 // a LocalValue instance will be on the stack. BasicInterpreter interpreter = new BasicInterpreter() { boolean done = false; @Override // newValue is called first to initialize the frame values of all the local variables // we intercept the first one to create our own special value. public BasicValue newValue(Type type) { if (type == null) { return BasicValue.UNINITIALIZED_VALUE; } else if (type.getSort() == Type.VOID) { return null; } else { // If this is the first value created (i.e. the first local variable) // we use a special marker. BasicValue ret = done ? super.newValue(type) : new LocalValue(type); done = true; return ret; } } }; Analyzer analyzer = new Analyzer(interpreter); AbstractInsnNode[] instructions = method.instructions.toArray(); try { Frame[] frames = analyzer.analyze(owner, method); if (frames.length != instructions.length) { // Should never happen. throw new IllegalStateException("The number of frames is not equals to the number of instructions"); } VarInsnNode lastThis = null; int stackAtThis = -1; boolean poppedThis = false; // Records the most recent line number encountered. For javac, there should always be // a line number node before the call of interest to this(...) or super(...). For robustness, // -1 is recorded as a sentinel to indicate this assumption didn't hold. Upstream consumers // should check for -1 and recover in a reasonable way (for example, don't set the line // number in generated code). int recentLine = -1; for (int i = 0; i < instructions.length; i++) { AbstractInsnNode insn = instructions[i]; Frame frame = frames[i]; if (frame.getStackSize() < stackAtThis) { poppedThis = true; } if (insn instanceof MethodInsnNode) { // TODO: Do we need to check that the stack is empty after this super call? MethodInsnNode methodhInsn = (MethodInsnNode) insn; Type[] types = Type.getArgumentTypes(methodhInsn.desc); Value value = frame.getStack(frame.getStackSize() - types.length - 1); if (value instanceof LocalValue && methodhInsn.name.equals("<init>")) { if (poppedThis) { throw new IllegalStateException("Unexpected constructor structure."); } return split(owner, method, lastThis, methodhInsn, recentLine); } } else if (insn instanceof VarInsnNode) { VarInsnNode var = (VarInsnNode) insn; if (var.var == 0) { lastThis = var; stackAtThis = frame.getStackSize(); poppedThis = false; } } else if (insn instanceof LineNumberNode) { // Record the most recent line number encountered so that call to this(...) // or super(...) has line number information. Ultimately used to emit a line // number in the generated code. LineNumberNode lineNumberNode = (LineNumberNode) insn; recentLine = lineNumberNode.line; } } throw new IllegalStateException("Unexpected constructor structure."); } catch (AnalyzerException e) { throw new IllegalStateException(e); } }
From source file:com.android.build.gradle.internal2.incremental.ConstructorBuilder.java
License:Apache License
/** * Deconstruct a constructor into its components and adds the necessary code to link the components * later. This code is not valid java, but it can be expressed in bytecode. In essence for this constructor: * <pre>{@code/*from www . jav a 2 s . c om*/ * <init>(int x) { * int a = 2; * super(int b = 3, x = 1, expr2() ? 3 : a++) * doSomething(x + a) * } * }</pre> * it creates two parts: * <pre>{@code * Object[] init$args(Clazz this, int x, Object[] locals) { // this is always null here * int a = locals[0]; * int b = 3; * Object[] args = new Object[3]; * args[0] = b; * args[1] = (x = 1) * args[2] = expr2() ? 3 : a++; * locals = new Object[3]; // The arguments + the locals * locals[0] = NULL; * locals[1] = x; * locals[2] = new Object[2]; * locals[2][0] = a; * locals[2][1] = b; * return new Object[] {locals, "myclass.<init>(I;I;)V", args}; * } * * void init$body(int x, Object[] locals) { * int a = locals[0]; * int b = locals[1]; * doSomething(x + a); * } * }</pre> * * @param owner the owning class. * @param method the constructor method. */ @NonNull public static Constructor build(@NonNull String owner, @NonNull MethodNode method) { // Basic interpreter uses BasicValue.REFERENCE_VALUE for all object types. However // we need to distinguish one in particular. The value of the local variable 0, ie. the // uninitialized this. By doing it this way we ensure that whenever there is a ALOAD_0 // a LocalValue instance will be on the stack. BasicInterpreter interpreter = new BasicInterpreter() { boolean done = false; @Override // newValue is called first to initialize the frame values of all the local variables // we intercept the first one to create our own special value. public BasicValue newValue(Type type) { if (type == null) { return BasicValue.UNINITIALIZED_VALUE; } else if (type.getSort() == Type.VOID) { return null; } else { // If this is the first value created (i.e. the first local variable) // we use a special marker. BasicValue ret = done ? super.newValue(type) : new LocalValue(type); done = true; return ret; } } }; Analyzer analyzer = new Analyzer(interpreter); AbstractInsnNode[] instructions = method.instructions.toArray(); try { Frame[] frames = analyzer.analyze(owner, method); if (frames.length != instructions.length) { // Should never happen. throw new IllegalStateException("The number of frames is not equals to the number of instructions"); } int stackAtThis = -1; boolean poppedThis = false; int firstLocal = 1; for (Type type : Type.getArgumentTypes(method.desc)) { firstLocal += type.getSize(); } LinkedHashSet<LocalVariable> variables = new LinkedHashSet<LocalVariable>(); VarInsnNode lastThis = null; int localsAtLastThis = 0; // Records the most recent line number encountered. For javac, there should always be // a line number node before the call of interest to this(...) or super(...). For robustness, // -1 is recorded as a sentinel to indicate this assumption didn't hold. Upstream consumers // should check for -1 and recover in a reasonable way (for example, don't set the line // number in generated code). int recentLine = -1; for (int i = 0; i < instructions.length; i++) { AbstractInsnNode insn = instructions[i]; Frame frame = frames[i]; if (frame.getStackSize() < stackAtThis) { poppedThis = true; } if (insn instanceof MethodInsnNode) { // TODO: Do we need to check that the stack is empty after this super call? MethodInsnNode methodhInsn = (MethodInsnNode) insn; Type[] types = Type.getArgumentTypes(methodhInsn.desc); Value value = frame.getStack(frame.getStackSize() - types.length - 1); if (value instanceof LocalValue && methodhInsn.name.equals(ByteCodeUtils.CONSTRUCTOR)) { if (poppedThis) { throw new IllegalStateException("Unexpected constructor structure."); } return split(owner, method, lastThis, methodhInsn, recentLine, new ArrayList<LocalVariable>(variables), localsAtLastThis); } } else if (insn instanceof VarInsnNode) { VarInsnNode var = (VarInsnNode) insn; if (var.var == 0) { lastThis = var; localsAtLastThis = variables.size(); stackAtThis = frame.getStackSize(); poppedThis = false; } Type type = ByteCodeUtils.getTypeForStoreOpcode(var.getOpcode()); if (type != null && var.var >= firstLocal) { // Variables are equals based on their number, so they will be added // to the set only if they are new, and in the order they are seen. variables.add(new LocalVariable(type, var.var)); } } else if (insn instanceof LineNumberNode) { // Record the most recent line number encountered so that call to this(...) // or super(...) has line number information. Ultimately used to emit a line // number in the generated code. LineNumberNode lineNumberNode = (LineNumberNode) insn; recentLine = lineNumberNode.line; } } throw new IllegalStateException("Unexpected constructor structure."); } catch (AnalyzerException e) { throw new IllegalStateException(e); } }
From source file:com.android.tools.lint.checks.ViewTagDetector.java
License:Apache License
@Override public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode, @NonNull MethodNode method, @NonNull MethodInsnNode call) {// w w w. j av a 2 s . co m // The leak behavior is fixed in ICS: // http://code.google.com/p/android/issues/detail?id=18273 if (context.getMainProject().getMinSdk() >= 14) { return; } String owner = call.owner; String desc = call.desc; if (owner.equals("android/view/View") //$NON-NLS-1$ && desc.equals("(ILjava/lang/Object;)V")) { //$NON-NLS-1$ Analyzer analyzer = new Analyzer(new BasicInterpreter() { @Override public BasicValue newValue(Type type) { if (type == null) { return BasicValue.UNINITIALIZED_VALUE; } else if (type.getSort() == Type.VOID) { return null; } else { return new BasicValue(type); } } }); try { Frame[] frames = analyzer.analyze(classNode.name, method); InsnList instructions = method.instructions; Frame frame = frames[instructions.indexOf(call)]; if (frame.getStackSize() < 3) { return; } BasicValue stackValue = (BasicValue) frame.getStack(2); Type type = stackValue.getType(); if (type == null) { return; } String internalName = type.getInternalName(); String className = type.getClassName(); LintDriver driver = context.getDriver(); SdkInfo sdkInfo = context.getClient().getSdkInfo(context.getMainProject()); String objectType = null; while (className != null) { if (className.equals("android.view.View")) { //$NON-NLS-1$ objectType = "views"; break; } else if (className.endsWith("ViewHolder")) { //$NON-NLS-1$ objectType = "view holders"; break; } else if (className.endsWith("Cursor") //$NON-NLS-1$ && className.startsWith("android.")) { //$NON-NLS-1$ objectType = "cursors"; break; } // TBD: Bitmaps, drawables? That's tricky, because as explained in // http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html // apparently these are used along with nulling out the callbacks, // and that's harder to detect here String parent = sdkInfo.getParentViewClass(className); if (parent == null) { if (internalName == null) { internalName = className.replace('.', '/'); } assert internalName != null; parent = driver.getSuperClass(internalName); } className = parent; internalName = null; } if (objectType != null) { Location location = context.getLocation(call); String message = String.format("Avoid setting %1$s as values for setTag: " + "Can lead to memory leaks in versions older than Android 4.0", objectType); context.report(ISSUE, method, call, location, message, null); } } catch (AnalyzerException e) { context.log(e, null); } } }
From source file:com.dragome.callbackevictor.serverside.bytecode.transformation.asm.ContinuationMethodAdapter.java
License:Apache License
public void visitCode() { mv.visitCode();/*from w w w. j a v a 2s .com*/ 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.dragome.callbackevictor.serverside.bytecode.transformation.asm.ContinuationMethodAdapter.java
License:Apache License
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { mv.visitMethodInsn(opcode, owner, name, desc, itf); if (currentFrame != null) { Label fl = new Label(); mv.visitVarInsn(ALOAD, stackRecorderVar); mv.visitJumpInsn(IFNULL, fl);//from w ww .j a v a2 s . c o m mv.visitVarInsn(ALOAD, stackRecorderVar); mv.visitFieldInsn(GETFIELD, STACK_RECORDER, "isCapturing", "Z"); mv.visitJumpInsn(IFEQ, fl); // save stack Type returnType = Type.getReturnType(desc); boolean hasReturn = returnType != Type.VOID_TYPE; if (hasReturn) { mv.visitInsn(returnType.getSize() == 1 ? POP : POP2); } Type[] params = Type.getArgumentTypes(desc); int argSize = params.length; int ownerSize = opcode == INVOKESTATIC ? 0 : 1; // TODO int ssize = currentFrame.getStackSize() - argSize - ownerSize; for (int i = ssize - 1; i >= 0; i--) { BasicValue value = (BasicValue) currentFrame.getStack(i); if (isNull(value)) { mv.visitInsn(POP); } else if (value == BasicValue.UNINITIALIZED_VALUE) { // TODO ?? } else if (value.isReference()) { mv.visitVarInsn(ALOAD, stackRecorderVar); mv.visitInsn(SWAP); mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, PUSH_METHOD + "Object", "(Ljava/lang/Object;)V", false); } else { Type type = value.getType(); if (type.getSize() > 1) { mv.visitInsn(ACONST_NULL); // dummy stack entry mv.visitVarInsn(ALOAD, stackRecorderVar); mv.visitInsn(DUP2_X2); // swap2 for long/double mv.visitInsn(POP2); mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, getPushMethod(type), "(" + type.getDescriptor() + ")V", false); mv.visitInsn(POP); // remove dummy stack entry } else { mv.visitVarInsn(ALOAD, stackRecorderVar); mv.visitInsn(SWAP); mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, getPushMethod(type), "(" + type.getDescriptor() + ")V", false); } } } if (!isStatic) { //RS: if (canalyzer._continueReflection && name.equals("invoke") && owner.startsWith("java/lang/reflect/Method")) { mv.visitVarInsn(ALOAD, stackRecorderVar); ContinuationMethodAnalyzer.MyVariables vars = canalyzer._reflectMapping .get(nodes.get(currentIndex)); // System.out.println("Class:" + canalyzer.className + "method:" + stackRecorderVar + ":" + name + ":" + owner + ":" + desc + ":" + vars.methodVar()); mv.visitVarInsn(ALOAD, vars.methodVar()); //mv.visitVarInsn(ALOAD, 3); mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, "replace" + "Reference", "(Ljava/lang/Object;)V", false); } //RS: mv.visitVarInsn(ALOAD, stackRecorderVar); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, PUSH_METHOD + "Reference", "(Ljava/lang/Object;)V", false); } // save locals int fsize = currentFrame.getLocals(); for (int j = 0; j < fsize; j++) { BasicValue value = (BasicValue) currentFrame.getLocal(j); if (isNull(value)) { // no need to save null } else if (value == BasicValue.UNINITIALIZED_VALUE) { // no need to save uninitialized objects } else if (value.isReference()) { mv.visitVarInsn(ALOAD, stackRecorderVar); mv.visitVarInsn(ALOAD, j); mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, PUSH_METHOD + "Object", "(Ljava/lang/Object;)V", false); } else { mv.visitVarInsn(ALOAD, stackRecorderVar); Type type = value.getType(); mv.visitVarInsn(type.getOpcode(ILOAD), j); mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, getPushMethod(type), "(" + type.getDescriptor() + ")V", false); } } mv.visitVarInsn(ALOAD, stackRecorderVar); if (currentIndex >= 128) { // if > 127 then it's a SIPUSH, not a BIPUSH... mv.visitIntInsn(SIPUSH, currentIndex); } else { // TODO optimize to iconst_0... mv.visitIntInsn(BIPUSH, currentIndex); } mv.visitMethodInsn(INVOKEVIRTUAL, STACK_RECORDER, "pushInt", "(I)V", false); if (currentFrame instanceof MonitoringFrame) { int[] monitoredLocals = ((MonitoringFrame) currentFrame).getMonitored(); // System.out.println(System.identityHashCode(currentFrame)+" Monitored locals "+monitoredLocals.length); for (int monitoredLocal : monitoredLocals) { // System.out.println(System.identityHashCode(currentFrame)+" Monitored local "+monitoredLocals[j]); mv.visitVarInsn(ALOAD, monitoredLocal); mv.visitInsn(MONITOREXIT); } } Type methodReturnType = Type.getReturnType(methodDesc); pushDefault(methodReturnType); mv.visitInsn(methodReturnType.getOpcode(IRETURN)); mv.visitLabel(fl); currentIndex++; currentFrame = null; } }
From source file:dodola.anole.lib.ConstructorDelegationDetector.java
License:Apache License
/** * Deconstruct a constructor into its components and adds the necessary code to link the components * later. The generated bytecode does not correspond exactly to this code, but in essence, for * a constructor of this form:// w w w . ja v a 2 s. c om * <p/> * <code> * <init>(int x) { * super(x = 1, expr2() ? 3 : 7) * doSomething(x) * } * </code> * <p/> * it creates the two parts: * <code> * Object[] init$args(Object[] locals, int x) { * Object[] args = new Object[2]; * args[0] = (x = 1) * args[1] = expr2() ? 3 : 7; * locals[0] = x; * return new Object[] {"myclass.<init>(I;I;)V", args}; * } * <p> * void init$body(int x) { * doSomething(x); * } * </code> * * @param owner the owning class. * @param method the constructor method. */ public static Constructor deconstruct(String owner, MethodNode method) { // Basic interpreter uses BasicValue.REFERENCE_VALUE for all object types. However // we need to distinguish one in particular. The value of the local variable 0, ie. the // uninitialized this. By doing it this way we ensure that whenever there is a ALOAD_0 // a LocalValue instance will be on the stack. BasicInterpreter interpreter = new BasicInterpreter() { boolean done = false; @Override // newValue is called first to initialize the frame values of all the local variables // we intercept the first one to create our own special value. public BasicValue newValue(Type type) { if (type == null) { return BasicValue.UNINITIALIZED_VALUE; } else if (type.getSort() == Type.VOID) { return null; } else { // If this is the first value created (i.e. the first local variable) // we use a special marker. BasicValue ret = done ? super.newValue(type) : new LocalValue(type); done = true; return ret; } } }; Analyzer analyzer = new Analyzer(interpreter); AbstractInsnNode[] instructions = method.instructions.toArray(); try { Frame[] frames = analyzer.analyze(owner, method); if (frames.length != instructions.length) { // Should never happen. throw new IllegalStateException("The number of frames is not equals to the number of instructions"); } VarInsnNode lastThis = null; int stackAtThis = -1; boolean poppedThis = false; // Records the most recent line number encountered. For javac, there should always be // a line number node before the call of interest to this(...) or super(...). For robustness, // -1 is recorded as a sentinel to indicate this assumption didn't hold. Upstream consumers // should check for -1 and recover in a reasonable way (for example, don't set the line // number in generated code). int recentLine = -1; for (int i = 0; i < instructions.length; i++) { AbstractInsnNode insn = instructions[i]; Frame frame = frames[i]; if (frame.getStackSize() < stackAtThis) { poppedThis = true; } if (insn instanceof MethodInsnNode) { // TODO: Do we need to check that the stack is empty after this super call? MethodInsnNode methodhInsn = (MethodInsnNode) insn; Type[] types = Type.getArgumentTypes(methodhInsn.desc); Value value = frame.getStack(frame.getStackSize() - types.length - 1); if (value instanceof LocalValue && methodhInsn.name.equals("<init>")) { if (poppedThis) { throw new IllegalStateException("Unexpected constructor structure."); } return split(owner, method, lastThis, methodhInsn, recentLine); } } else if (insn instanceof VarInsnNode) { VarInsnNode var = (VarInsnNode) insn; if (var.var == 0) { lastThis = var; stackAtThis = frame.getStackSize(); poppedThis = false; } } else if (insn instanceof LineNumberNode) { // Record the most recent line number encountered so that call to this(...) // or super(...) has line number information. Ultimately used to emit a line // number in the generated code. LineNumberNode lineNumberNode = (LineNumberNode) insn; recentLine = lineNumberNode.line; } } throw new IllegalStateException("Unexpected constructor structure."); } catch (AnalyzerException e) { throw new IllegalStateException(e); } }
From source file:edu.ubc.mirrors.holograms.BetterVerifier.java
License:Open Source License
@Override public BasicValue merge(final BasicValue v, final BasicValue w) { if (!v.equals(w)) { Type t = v.getType();/*from w w w . j a v a 2 s . c o m*/ Type u = w.getType(); if (t != null && (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)) { if (u != null && (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY)) { if ("Lnull;".equals(t.getDescriptor())) { return w; } if ("Lnull;".equals(u.getDescriptor())) { return v; } if (isAssignableFrom(t, u)) { return v; } if (isAssignableFrom(u, t)) { return w; } if (t.getSort() == Type.ARRAY && u.getSort() == Type.ARRAY) { BasicValue vComp = new BasicValue( Reflection.makeArrayType(t.getDimensions() - 1, t.getElementType())); BasicValue wComp = new BasicValue( Reflection.makeArrayType(u.getDimensions() - 1, u.getElementType())); BasicValue mergedComp = merge(vComp, wComp); if (!mergedComp.equals(BasicValue.UNINITIALIZED_VALUE)) { Type mergedCompType = mergedComp.getType(); return new BasicValue(Reflection.makeArrayType(1, mergedCompType)); } } do { if (t == null || isInterface(t)) { return BasicValue.REFERENCE_VALUE; } t = getSuperClass(t); if (isAssignableFrom(t, u)) { return newValue(t); } } while (true); } } return BasicValue.UNINITIALIZED_VALUE; } return v; }