/*
* Copyright (c) 2014, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.btrace.util.templates;
import com.sun.btrace.org.objectweb.asm.AnnotationVisitor;
import com.sun.btrace.org.objectweb.asm.Attribute;
import com.sun.btrace.org.objectweb.asm.Handle;
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 com.sun.btrace.org.objectweb.asm.TypePath;
import com.sun.btrace.runtime.Assembler;
import com.sun.btrace.util.LocalVariableHelper;
import com.sun.btrace.util.MethodID;
import com.sun.btrace.util.templates.impl.MethodTrackingExpander;
import java.util.ArrayList;
import java.util.Collection;
/**
* An ASM visitor providing customized template expansion
* @author Jaroslav Bachorik
* @since 1.3
*/
public class TemplateExpanderVisitor extends MethodVisitor implements LocalVariableHelper {
final private LocalVariableHelper lvs;
final private Collection<TemplateExpander> expanders = new ArrayList<>();
final private String className, methodName, desc;
final private Assembler asm;
private TemplateExpander.Result lastResult = TemplateExpander.Result.IGNORED;
public TemplateExpanderVisitor(LocalVariableHelper lvs,
String className, String methodName,
String desc) {
super(Opcodes.ASM5, (MethodVisitor)lvs);
this.lvs = lvs;
this.expanders.add(new MethodTrackingExpander(MethodID.getMethodId(className, methodName, desc)));
this.className = className;
this.methodName = methodName;
this.desc = desc;
this.asm = new Assembler((MethodVisitor)lvs);
}
public Assembler asm() {
return asm;
}
@Override
public int storeNewLocal(Type type) {
expandTemplate(null);
return lvs.storeNewLocal(type);
}
@Override
public void visitCode() {
super.visitCode();
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isIface) {
Template t = BTraceTemplates.getTemplate(owner, name, desc);
if (expandTemplate(t) == TemplateExpander.Result.IGNORED) {
super.visitMethodInsn(opcode, owner, name, desc, isIface);
}
}
@Override
public void visitVarInsn(int opcode, int var) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitVarInsn(opcode, var);
}
}
@Override
public void visitMultiANewArrayInsn(String string, int i) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitMultiANewArrayInsn(string, i);
}
}
@Override
public void visitLookupSwitchInsn(Label label, int[] ints, Label[] labels) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitLookupSwitchInsn(label, ints, labels);
}
}
@Override
public void visitTableSwitchInsn(int i, int i1, Label label, Label... labels) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitTableSwitchInsn(i, i1, label, labels);
}
}
@Override
public void visitIincInsn(int i, int i1) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitIincInsn(i, i1);
}
}
@Override
public void visitLdcInsn(Object o) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitLdcInsn(o);
}
}
@Override
public void visitJumpInsn(int i, Label label) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitJumpInsn(i, label);
}
}
@Override
public void visitInvokeDynamicInsn(String string, String string1, Handle handle, Object... os) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitInvokeDynamicInsn(string, string1, handle, os);
}
}
@Override
public void visitFieldInsn(int i, String string, String string1, String string2) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitFieldInsn(i, string, string1, string2);
}
}
@Override
public void visitTypeInsn(int i, String string) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitTypeInsn(i, string);
}
}
@Override
public void visitIntInsn(int i, int i1) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitIntInsn(i, i1);
}
}
@Override
public void visitInsn(int i) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
switch (i) {
case Opcodes.RETURN:
case Opcodes.LRETURN:
case Opcodes.DRETURN:
case Opcodes.FRETURN:
case Opcodes.ARETURN:
case Opcodes.ATHROW:
resetState();
break;
}
super.visitInsn(i);
}
}
@Override
public void visitLineNumber(int i, Label label) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitLineNumber(i, label);
}
}
@Override
public AnnotationVisitor visitLocalVariableAnnotation(int i, TypePath tp, Label[] labels, Label[] labels1, int[] ints, String string, boolean bln) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
return super.visitLocalVariableAnnotation(i, tp, labels, labels1, ints, string, bln);
}
return null;
}
@Override
public void visitLocalVariable(String string, String string1, String string2, Label label, Label label1, int i) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitLocalVariable(string, string1, string2, label, label1, i);
}
}
@Override
public AnnotationVisitor visitTryCatchAnnotation(int i, TypePath tp, String string, boolean bln) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
return super.visitTryCatchAnnotation(i, tp, string, bln);
}
return null;
}
@Override
public void visitTryCatchBlock(Label label, Label label1, Label label2, String string) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitTryCatchBlock(label, label1, label2, string);
}
}
@Override
public AnnotationVisitor visitInsnAnnotation(int i, TypePath tp, String string, boolean bln) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
return super.visitInsnAnnotation(i, tp, string, bln);
}
return null;
}
@Override
public void visitLabel(Label label) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitLabel(label);
}
}
@Override
public void visitAttribute(Attribute atrbt) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitAttribute(atrbt);
}
}
@Override
public AnnotationVisitor visitParameterAnnotation(int i, String string, boolean bln) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
return super.visitParameterAnnotation(i, string, bln);
}
return null;
}
@Override
public AnnotationVisitor visitTypeAnnotation(int i, TypePath tp, String string, boolean bln) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
return super.visitTypeAnnotation(i, tp, string, bln);
}
return null;
}
@Override
public AnnotationVisitor visitAnnotation(String string, boolean bln) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
return super.visitAnnotation(string, bln);
}
return null;
}
@Override
public AnnotationVisitor visitAnnotationDefault() {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
return super.visitAnnotationDefault();
}
return null;
}
@Override
public void visitParameter(String string, int i) {
if (expandTemplate(null) == TemplateExpander.Result.IGNORED) {
super.visitParameter(string, i);
}
}
@Override
public void visitEnd() {
expandTemplate(null);
super.visitEnd();
}
@Override
public void visitMaxs(int stack, int locals) {
expandTemplate(null);
super.visitMaxs(stack, locals);
}
public String getClassName() {
return className;
}
public String getMethodName() {
return methodName;
}
public String getDesc() {
return desc;
}
private boolean expanding = false;
private TemplateExpander.Result expandTemplate(Template newTemplate) {
if (expanding) {
return TemplateExpander.Result.IGNORED;
}
if (newTemplate == null && lastResult == TemplateExpander.Result.IGNORED) {
return TemplateExpander.Result.IGNORED;
}
for(TemplateExpander exp : expanders) {
TemplateExpander.Result r = exp.expand(this, newTemplate);
if (r != TemplateExpander.Result.IGNORED) {
lastResult = r;
return r;
}
}
lastResult = TemplateExpander.Result.IGNORED;
return TemplateExpander.Result.IGNORED;
}
private void resetState() {
for(TemplateExpander exp : expanders) {
exp.resetState();
}
}
public void expand(
TemplateExpander.Consumer<TemplateExpanderVisitor> f) {
try {
if (!expanding) {
expanding = true;
f.consume(this);
}
} finally {
expanding = false;
}
}
}