
com.sun.btrace.compiler.Postprocessor Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2008-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.btrace.compiler;
import com.sun.btrace.org.objectweb.asm.AnnotationVisitor;
import com.sun.btrace.org.objectweb.asm.Attribute;
import com.sun.btrace.org.objectweb.asm.ClassVisitor;
import com.sun.btrace.org.objectweb.asm.FieldVisitor;
import com.sun.btrace.org.objectweb.asm.Label;
import com.sun.btrace.org.objectweb.asm.MethodVisitor;
import com.sun.btrace.org.objectweb.asm.Opcodes;
import com.sun.btrace.org.objectweb.asm.Type;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
/**
*
* @author Jaroslav Bachorik
*/
public class Postprocessor extends ClassVisitor {
private List fields = new ArrayList();
private boolean shortSyntax = false;
private String className = "";
public Postprocessor(ClassVisitor cv) {
super(Opcodes.ASM4, cv);
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
if (((access & Opcodes.ACC_PUBLIC) |
(access & Opcodes.ACC_PROTECTED) |
(access & Opcodes.ACC_PRIVATE)) == 0)
{
shortSyntax = true; // specifying "class " rather than "public class " means using short syntax
access |= Opcodes.ACC_PUBLIC; // force the public modifier on the btrace class
}
className = name;
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (!shortSyntax) return super.visitMethod(access, name, desc, signature, exceptions);
if ((access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE)) == 0) {
access &= ~Opcodes.ACC_PROTECTED;
access |= Opcodes.ACC_PUBLIC;
}
final int localVarOffset = ((access & Opcodes.ACC_STATIC) == 0) ? -1 : 0;
access |= Opcodes.ACC_STATIC;
boolean isconstructor = false;
if ("".equals(name)) {
name = "";
isconstructor = true;
}
MethodVisitor mv = new MethodConvertor(localVarOffset, isconstructor, super.visitMethod(access, name, desc, signature, exceptions));
return mv;
}
@Override
public FieldVisitor visitField(final int access, final String name, final String desc, final String signature, final Object value) {
if (!shortSyntax) return super.visitField(access, name, desc, signature, value);
final List attrs = new ArrayList();
return new FieldVisitor(Opcodes.ASM4) {
public AnnotationVisitor visitAnnotation(String string, boolean bln) {
return new AnnotationVisitor(Opcodes.ASM4){
};
}
public void visitAttribute(Attribute atrbt) {
attrs.add(atrbt);
}
public void visitEnd() {
FieldDescriptor fd = new FieldDescriptor(access, name, desc,
signature, value, attrs);
fields.add(fd);
}
};
}
@Override
public void visitEnd() {
if (shortSyntax) {
addFields();
}
}
private void addFields() {
for (FieldDescriptor fd : fields) {
String fieldName = fd.name;
int fieldAccess = fd.access;
String fieldDesc = fd.desc;
String fieldSignature = fd.signature;
Object fieldValue = fd.value;
fieldAccess &= ~Opcodes.ACC_PRIVATE;
fieldAccess &= ~Opcodes.ACC_PROTECTED;
fieldAccess |= Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC;
FieldVisitor fv = super.visitField(fieldAccess,
fieldName,
fieldDesc, fieldSignature, fieldValue);
for (Attribute attr : fd.attributes) {
fv.visitAttribute(attr);
}
fv.visitEnd();
}
}
private class MethodConvertor extends MethodVisitor {
private Deque simulatedStack = new ArrayDeque();
private int localVarOffset = 0;
private boolean isConstructor;
private boolean copyEnabled = false;
public MethodConvertor(int localVarOffset, boolean isConstructor, MethodVisitor mv) {
super(Opcodes.ASM4, mv);
this.localVarOffset = localVarOffset;
this.isConstructor = isConstructor;
this.copyEnabled = !isConstructor; // copy is enabled by default for all methods except constructor
}
@Override
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
if (index + localVarOffset < 0 || !copyEnabled) {
return;
}
super.visitLocalVariable(name, desc, signature, start, end, index + localVarOffset);
}
@Override
public void visitVarInsn(int opcode, int var) {
boolean delegate = true;
switch (opcode) {
case Opcodes.ALOAD: {
delegate = (var + localVarOffset) >= 0;
simulatedStack.push(!delegate);
break;
}
case Opcodes.LLOAD:
case Opcodes.DLOAD: {
simulatedStack.push(Boolean.FALSE);
// long and double occoupy 2 stack slots; fall through
}
case Opcodes.ILOAD:
case Opcodes.FLOAD:
{
simulatedStack.push(Boolean.FALSE);
break;
}
case Opcodes.LSTORE:
case Opcodes.DSTORE: {
simulatedStack.poll();
// long and double occoupy 2 stack slots; fall through
}
case Opcodes.ASTORE:
case Opcodes.ISTORE:
case Opcodes.FSTORE: {
simulatedStack.poll();
break;
}
}
if (delegate && copyEnabled) super.visitVarInsn(opcode, var + localVarOffset);
}
@Override
public void visitInsn(int opcode) {
switch(opcode) {
case Opcodes.POP: {
if (simulatedStack.pop()) {
return;
}
break;
}
case Opcodes.POP2: {
Boolean[] vals = new Boolean[2];
vals[0] = simulatedStack.poll();
vals[1] = simulatedStack.poll();
if (vals[0] && vals[1]) {
return;
} else if (vals[0] || vals[1]) {
opcode = Opcodes.POP;
}
break;
}
case Opcodes.DUP: {
Boolean val = simulatedStack.peek();
val = val != null ? val : Boolean.FALSE;
simulatedStack.push(val);
if (val) return;
break;
}
case Opcodes.DUP_X1: {
if (simulatedStack.size() < 2) return;
Boolean[] vals = new Boolean[2];
int cntr = vals.length - 1;
while (cntr >= 0) {
vals[cntr--] = simulatedStack.pop();
}
simulatedStack.push(vals[vals.length - 1]);
simulatedStack.addAll(Arrays.asList(vals));
if (vals[1]) {
return;
} else if (vals[0]) {
opcode = Opcodes.DUP;
}
break;
}
case Opcodes.DUP_X2: {
if (simulatedStack.size() < 3) return;
Boolean[] vals = new Boolean[3];
int cntr = vals.length - 1;
while (cntr >= 0) {
vals[cntr--] = simulatedStack.pop();
}
simulatedStack.push(vals[vals.length - 1]);
simulatedStack.addAll(Arrays.asList(vals));
if (vals[2]) {
return;
} else if (vals[0] && vals[1]) {
opcode = Opcodes.DUP;
} else {
opcode = Opcodes.DUP_X1;
}
break;
}
case Opcodes.DUP2: {
if (simulatedStack.size() < 2) return;
Boolean[] vals = new Boolean[2];
int cntr = vals.length - 1;
while (cntr >= 0) {
vals[cntr--] = simulatedStack.pop();
}
simulatedStack.addAll(Arrays.asList(vals));
if (vals[0] && vals[1]) {
return;
} else if(vals[0] || vals[1]) {
opcode = Opcodes.DUP;
}
break;
}
case Opcodes.DUP2_X1: {
if (simulatedStack.size() < 3) return;
Boolean[] vals = new Boolean[3];
int cntr = vals.length - 1;
while (cntr >= 0) {
vals[cntr--] = simulatedStack.pop();
}
simulatedStack.push(vals[vals.length - 2]);
simulatedStack.push(vals[vals.length - 1]);
simulatedStack.addAll(Arrays.asList(vals));
if (vals[1] && vals[2]) {
return;
}
if (vals[0]) {
if (vals[1] || vals[2]) {
opcode = Opcodes.DUP;
} else {
opcode = Opcodes.DUP2;
}
} else {
if (vals[1] || vals[2]) {
opcode = Opcodes.DUP_X1;
}
}
break;
}
case Opcodes.DUP2_X2: {
Boolean[] vals = new Boolean[]{Boolean.FALSE, Boolean.FALSE, Boolean.FALSE, Boolean.FALSE};
Iterator iter = simulatedStack.descendingIterator();
int cntr = 0;
while (cntr < vals.length && iter.hasNext()) {
vals[cntr++] = iter.next();
}
simulatedStack.push(vals[vals.length - 2]);
simulatedStack.push(vals[vals.length - 1]);
simulatedStack.addAll(Arrays.asList(vals));
break;
}
case Opcodes.SWAP: {
if (simulatedStack.size() < 2) return;
Boolean[] vals = new Boolean[2];
int cntr = vals.length - 1;
while (cntr >= 0) {
vals[cntr--] = simulatedStack.pop();
}
if (vals[0] || vals[1]) {
return;
}
simulatedStack.push(vals[1]);
simulatedStack.push(vals[0]);
}
// zero operand instructions
case Opcodes.LCONST_0:
case Opcodes.LCONST_1:
case Opcodes.DCONST_0:
case Opcodes.DCONST_1: {
simulatedStack.push(Boolean.FALSE);
}
case Opcodes.ICONST_0:
case Opcodes.ICONST_1:
case Opcodes.ICONST_2:
case Opcodes.ICONST_3:
case Opcodes.ICONST_4:
case Opcodes.ICONST_5:
case Opcodes.ICONST_M1:
case Opcodes.FCONST_0:
case Opcodes.FCONST_1:
case Opcodes.FCONST_2:
case Opcodes.ACONST_NULL:
case Opcodes.MONITORENTER:
case Opcodes.MONITOREXIT: {
simulatedStack.push(Boolean.FALSE);
break;
}
// one operand instructions
case Opcodes.INEG:
case Opcodes.FNEG:
case Opcodes.DNEG:
case Opcodes.LNEG:
case Opcodes.I2B:
case Opcodes.I2C:
case Opcodes.I2F:
case Opcodes.I2S:
case Opcodes.L2D:
case Opcodes.D2L:
case Opcodes.F2I:
case Opcodes.CHECKCAST:
case Opcodes.ARRAYLENGTH: {
// nothing changes in regard to the simulated stack
break;
}
case Opcodes.I2L:
case Opcodes.I2D: {
simulatedStack.push(Boolean.FALSE); // extending the original value by one slot
break;
}
// two operand instructions
case Opcodes.LADD:
case Opcodes.DADD:
case Opcodes.LSUB:
case Opcodes.DSUB:
case Opcodes.LMUL:
case Opcodes.DMUL:
case Opcodes.LDIV:
case Opcodes.DDIV:
case Opcodes.LREM:
case Opcodes.DREM:
case Opcodes.LSHL:
case Opcodes.LSHR:
case Opcodes.LUSHR:
case Opcodes.LAND:
case Opcodes.LOR:
case Opcodes.LXOR:
case Opcodes.LALOAD:
case Opcodes.DALOAD: {
simulatedStack.pop();
simulatedStack.pop();
// remove 4 slots == 2 long/double operands and add 2 slots == 1 long/double result
break;
}
case Opcodes.LCMP:
case Opcodes.DCMPL:
case Opcodes.DCMPG: {
simulatedStack.pop();
simulatedStack.pop();
simulatedStack.pop();
// remove 4 slots == 2 long/double operands and add 1 slot == 1 int result
break;
}
case Opcodes.IADD:
case Opcodes.FADD:
case Opcodes.ISUB:
case Opcodes.FSUB:
case Opcodes.IMUL:
case Opcodes.IDIV:
case Opcodes.FDIV:
case Opcodes.IREM:
case Opcodes.FREM:
case Opcodes.ISHL:
case Opcodes.ISHR:
case Opcodes.IUSHR:
case Opcodes.IAND:
case Opcodes.IOR:
case Opcodes.IXOR:
case Opcodes.FCMPL:
case Opcodes.FCMPG:
case Opcodes.BALOAD:
case Opcodes.SALOAD:
case Opcodes.CALOAD:
case Opcodes.IALOAD:
case Opcodes.FALOAD:
{
simulatedStack.poll();
// remove 2 slots == 2 intoperands and add 1 slot == 1 int result
break;
}
// three operand instructions
case Opcodes.LASTORE:
case Opcodes.DASTORE: {
simulatedStack.pop();
// LASTORE, DSTORE occupy one more slot compared to BASTORE etc.; falling through
}
case Opcodes.BASTORE:
case Opcodes.CASTORE:
case Opcodes.SASTORE:
case Opcodes.IASTORE:
case Opcodes.FASTORE: {
simulatedStack.pop();
simulatedStack.pop();
simulatedStack.pop();
}
}
if (copyEnabled) {
super.visitInsn(opcode);
}
}
@Override
public void visitIntInsn(int opcode, int index) {
switch (opcode) {
case Opcodes.BIPUSH:
case Opcodes.SIPUSH: {
simulatedStack.push(Boolean.FALSE);
break;
}
}
if (copyEnabled) {
super.visitIntInsn(opcode, index);
}
}
@Override
public void visitJumpInsn(int opcode, Label label) {
switch (opcode) {
case Opcodes.IFEQ:
case Opcodes.IFNE:
case Opcodes.IFLE:
case Opcodes.IFGE:
case Opcodes.IFGT:
case Opcodes.IFLT:
case Opcodes.IFNULL:
case Opcodes.IFNONNULL: {
simulatedStack.poll();
break;
}
case Opcodes.IF_ICMPEQ:
case Opcodes.IF_ICMPGE:
case Opcodes.IF_ICMPGT:
case Opcodes.IF_ICMPLE:
case Opcodes.IF_ICMPLT:
case Opcodes.IF_ICMPNE: {
simulatedStack.poll();
simulatedStack.poll();
break;
}
}
if (copyEnabled) {
super.visitJumpInsn(opcode, label);
}
}
@Override
public void visitTableSwitchInsn(int i, int i1, Label label, Label[] labels) {
simulatedStack.poll();
if (copyEnabled) {
super.visitTableSwitchInsn(i, i1, label, labels);
}
}
@Override
public void visitLookupSwitchInsn(Label label, int[] ints, Label[] labels) {
simulatedStack.poll();
if (copyEnabled) {
super.visitLookupSwitchInsn(label, ints, labels);
}
}
@Override
public void visitLdcInsn(Object o) {
simulatedStack.push(Boolean.FALSE);
if (o instanceof Long || o instanceof Double) {
simulatedStack.push(Boolean.FALSE);
}
if (copyEnabled) {
super.visitLdcInsn(o);
}
}
@Override
public void visitMaxs(int maxStack, int maxLocals) {
super.visitMaxs(maxStack, (maxLocals + localVarOffset > 0 ? maxLocals + localVarOffset : 0));
}
@Override
public void visitIincInsn(int var, int increment) {
if (copyEnabled) {
super.visitIincInsn(var + localVarOffset, increment);
}
}
@Override
public void visitFieldInsn(int i, String clazz, String name, String desc) {
if (i == Opcodes.GETFIELD) {
Boolean opTarget = simulatedStack.poll();
opTarget = opTarget != null ? opTarget : Boolean.FALSE;
if (opTarget) {
i = Opcodes.GETSTATIC;
}
} else if (i == Opcodes.PUTFIELD) {
simulatedStack.pop();
simulatedStack.pop();
if (desc.equals("J") || desc.equals("D")) {
simulatedStack.pop();
}
if (clazz.equals(className)) { // all local fields are static
i = Opcodes.PUTSTATIC;
}
}
switch (i) {
case Opcodes.GETFIELD:
case Opcodes.GETSTATIC: {
simulatedStack.push(Boolean.FALSE);
if (desc.equals("J") || desc.equals("D")) {
simulatedStack.push(Boolean.FALSE);
}
break;
}
}
if (copyEnabled) {
super.visitFieldInsn(i, clazz, name, desc);
}
}
@Override
public void visitMethodInsn(int opcode, String clazz, String method, String desc) {
int origOpcode = opcode;
Type[] args = Type.getArgumentTypes(desc);
for(Type t : args) {
for(int i=0;i attributes;
int var = -1;
boolean initialized;
FieldDescriptor(int acc, String n, String d,
String sig, Object val, List attrs) {
access = acc;
name = n;
desc = d;
signature = sig;
value = val;
attributes = attrs;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy