Commit 59816375 authored by Lukáš Marek's avatar Lukáš Marek

Added ProcessAlso annotation

Improved processor test
Added build.properties for test
Added support for some static analyses in guards
parent 50423e2e
......@@ -2,4 +2,3 @@ asm.path=lib/asm-debug-all-4.0_RC1.jar
jborat.path=lib/jborat.jar
jborat-runtime.path=lib/jborat-runtime.jar
instr.jar.name=dislinstr.jar
user.runtime.jar.name=test-runtime.jar
\ No newline at end of file
package ch.usi.dag.disl.dislclass.annotation;
public @interface ProcessAlso {
// NOTE if you want to change names, you need to change
// ProcessorParser.ProcessAlsoAnnotationData class
// NOTE because of implementation of annotations in java the defaults
// are not retrieved from here but from class mentioned above
public enum Type {
BOOLEAN,
BYTE,
SHORT
}
Type[] types();
}
......@@ -148,14 +148,15 @@ public abstract class AbstractParser {
}
// parse annotation data
SLAnnotaionData slad = ParserHelper.parseAnnotation(annotation,
new SLAnnotaionData());
SLAnnotaionData slad = new SLAnnotaionData();
ParserHelper.parseAnnotation(slad, annotation);
// default val for init
SyntheticLocal.Initialize slvInit = SyntheticLocal.Initialize.ALWAYS;
if(slad.initialize != null) {
// initialize array
// enum is converted to array
// - first value is class name
// - second value is value name
slvInit = SyntheticLocal.Initialize.valueOf(slad.initialize[1]);
......
......@@ -24,13 +24,15 @@ public abstract class ParserHelper {
return ReflectionHelper.createInstance(guardClass);
}
public static <T> T parseAnnotation(AnnotationNode annotation,
T parsedDataObject) {
// NOTE: first parameter is modified by this function
public static <T> void parseAnnotation(T parsedDataObject,
AnnotationNode annotation) {
try {
// nothing to do
if(annotation.values == null) {
return parsedDataObject;
return;
}
Iterator<?> it = annotation.values.iterator();
......@@ -61,7 +63,5 @@ public abstract class ParserHelper {
throw new DiSLFatalException(
"Reflection error wihle parsing annotation", e);
}
return parsedDataObject;
}
}
package ch.usi.dag.disl.dislclass.parser;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedList;
......@@ -13,6 +14,7 @@ import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import ch.usi.dag.disl.dislclass.annotation.Guarded;
import ch.usi.dag.disl.dislclass.annotation.ProcessAlso;
import ch.usi.dag.disl.dislclass.code.UnprocessedCode;
import ch.usi.dag.disl.dislclass.processor.Proc;
import ch.usi.dag.disl.dislclass.processor.ProcArgType;
......@@ -53,8 +55,8 @@ public class ProcessorParser extends AbstractParser {
(AnnotationNode) classNode.invisibleAnnotations.get(0);
// parse processor annotation
ProcessorAnnotationData pad = ParserHelper.parseAnnotation(annotation,
new ProcessorAnnotationData());
ProcessorAnnotationData pad = new ProcessorAnnotationData();
ParserHelper.parseAnnotation(pad, annotation);
// ** guard **
ProcessorGuard guard =
......@@ -118,13 +120,19 @@ public class ProcessorParser extends AbstractParser {
ProcArgType methodArgType = parseProcMethodArgs(
className + "." + method.name, method.desc);
EnumSet<ProcArgType> allTypes = EnumSet.of(methodArgType);
// all processed types - add method type
EnumSet<ProcArgType> allProcessedTypes = EnumSet.of(methodArgType);
// ** parse processor method annotation **
ProcMethodAnnotationsData pmad =
parseMethodAnnotations(fullMethodName, method.invisibleAnnotations);
// TODO ! add process also
// check if process also annotation contains only valid types
checkProcessAlsoSetValidity(fullMethodName, methodArgType,
pmad.processAlsoTypes);
// add types from process also annotation
allProcessedTypes.addAll(pmad.processAlsoTypes);
// ** guard **
ProcessorMethodGuard guard =
......@@ -136,7 +144,7 @@ public class ProcessorParser extends AbstractParser {
method.tryCatchBlocks);
// return whole processor method
return new ProcMethod(allTypes, guard, ucd);
return new ProcMethod(allProcessedTypes, guard, ucd);
}
......@@ -183,47 +191,77 @@ public class ProcessorParser extends AbstractParser {
// data holder for parseMethodAnnotation methods
private static class ProcMethodAnnotationsData {
public EnumSet<ProcArgType> processAlsoTypes =
EnumSet.noneOf(ProcArgType.class);
public Type guard = null;
}
private ProcMethodAnnotationsData parseMethodAnnotations(String fullMethodName,
private ProcMethodAnnotationsData parseMethodAnnotations(
String fullMethodName,
List<AnnotationNode> invisibleAnnotations)
throws ProcessorParserException {
// TODO ! add process also
ProcMethodAnnotationsData pmad = new ProcMethodAnnotationsData();
// check annotation
// check no annotation
if (invisibleAnnotations == null) {
return new ProcMethodAnnotationsData();
return pmad;
}
for(AnnotationNode annotation : invisibleAnnotations) {
Type annotationType = Type.getType(annotation.desc);
// check only one annotation
if (invisibleAnnotations.size() > 1) {
// guarded annotation
if (annotationType.equals(Type.getType(Guarded.class))) {
parseGuardedAnnotation(pmad, annotation);
continue;
}
// process also annotation
if (annotationType.equals(Type.getType(ProcessAlso.class))) {
parseProcessAlsoAnnotation(pmad, annotation);
continue;
}
// unknown annotation
throw new ProcessorParserException("Method " + fullMethodName
+ " can have only one DiSL anottation");
+ " has unsupported DiSL annotation");
}
AnnotationNode annotation = invisibleAnnotations.get(0);
return pmad;
}
// NOTE: pmad is modified by this function
private void parseGuardedAnnotation(
ProcMethodAnnotationsData pmad, AnnotationNode annotation) {
ParserHelper.parseAnnotation(pmad, annotation);
Type annotationType = Type.getType(annotation.desc);
if(pmad.guard == null) {
// after annotation
if (annotationType.equals(Type.getType(Guarded.class))) {
return parseMethodAnnotFields(annotation);
throw new DiSLFatalException("Missing attribute in annotation "
+ Type.getType(annotation.desc).toString()
+ ". This may happen if annotation class is changed but"
+ " data holder class is not.");
}
// unknown annotation
throw new ProcessorParserException("Method " + fullMethodName
+ " has unsupported DiSL annotation");
}
private ProcMethodAnnotationsData parseMethodAnnotFields(
private static class ProcessAlsoAnnotationData {
public Collection<String[]> types = null;
}
// NOTE: pmad is modified by this function
private void parseProcessAlsoAnnotation(ProcMethodAnnotationsData pmad,
AnnotationNode annotation) {
ProcMethodAnnotationsData pmad = ParserHelper.parseAnnotation(
annotation, new ProcMethodAnnotationsData());
ProcessAlsoAnnotationData paData = new ProcessAlsoAnnotationData();
if(pmad.guard == null) {
ParserHelper.parseAnnotation(paData, annotation);
if(paData.types == null) {
throw new DiSLFatalException("Missing attribute in annotation "
+ Type.getType(annotation.desc).toString()
......@@ -231,6 +269,79 @@ public class ProcessorParser extends AbstractParser {
+ " data holder class is not.");
}
return pmad;
// array is converted to collection
for(String[] enumType : paData.types) {
// enum is converted to array
// - first value is class name
// - second value is value name
ProcessAlso.Type paType = ProcessAlso.Type.valueOf(enumType[1]);
pmad.processAlsoTypes.add(ProcArgType.valueOf(paType));
}
}
private void checkProcessAlsoSetValidity(String fullMethodName,
ProcArgType methodArgType,
EnumSet<ProcArgType> processAlsoTypes)
throws ProcessorParserException {
EnumSet<ProcArgType> validSet;
// valid sets for types
switch(methodArgType) {
case INT: {
validSet = EnumSet.of(
ProcArgType.BOOLEAN,
ProcArgType.BYTE,
ProcArgType.SHORT);
break;
}
case SHORT: {
validSet = EnumSet.of(
ProcArgType.BOOLEAN,
ProcArgType.BYTE);
break;
}
case BYTE: {
validSet = EnumSet.of(
ProcArgType.BOOLEAN);
break;
}
default: {
// for other types empty set
validSet = EnumSet.noneOf(ProcArgType.class);
}
}
// create set of non valid types
EnumSet<ProcArgType> nonValidTypes = processAlsoTypes.clone();
nonValidTypes.removeAll(validSet);
if(! nonValidTypes.isEmpty()) {
StringBuilder strNonValidTypes = new StringBuilder();
final String STR_DELIM = ", ";
for(ProcArgType paType : nonValidTypes) {
strNonValidTypes.append(paType.toString() + STR_DELIM);
}
// remove last STR_DELIM
int delimSize = STR_DELIM.length();
strNonValidTypes.delete(strNonValidTypes.length() - delimSize,
strNonValidTypes.length());
throw new ProcessorParserException(methodArgType.toString()
+ " processor in method "
+ fullMethodName
+ " cannot process "
+ strNonValidTypes.toString());
}
}
}
......@@ -205,8 +205,8 @@ public class SnippetParser extends AbstractParser {
private SnippetAnnotationData parseMethodAnnotFields(Class<?> type,
AnnotationNode annotation) {
SnippetAnnotationData sad = ParserHelper.parseAnnotation(annotation,
new SnippetAnnotationData(type));
SnippetAnnotationData sad = new SnippetAnnotationData(type);
ParserHelper.parseAnnotation(sad, annotation);
if (sad.marker == null || sad.scope == null) {
......
......@@ -2,6 +2,7 @@ package ch.usi.dag.disl.dislclass.processor;
import org.objectweb.asm.Type;
import ch.usi.dag.disl.dislclass.annotation.ProcessAlso;
import ch.usi.dag.disl.exception.DiSLFatalException;
public enum ProcArgType {
......@@ -97,7 +98,26 @@ public enum ProcArgType {
return OBJECT;
}
throw new DiSLFatalException("Conversion from " + type.getClassName() +
" not defined");
throw new DiSLFatalException("Conversion from " + type.getClassName()
+ " not defined");
}
public static ProcArgType valueOf(ProcessAlso.Type type) {
if(type == null) {
throw new DiSLFatalException("Conversion from null not defined");
}
switch(type) {
case BOOLEAN:
return BOOLEAN;
case BYTE:
return BYTE;
case SHORT:
return SHORT;
default:
throw new DiSLFatalException("Conversion from " + type.toString()
+ " not defined");
}
}
}
......@@ -4,6 +4,11 @@ import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import ch.usi.dag.disl.dislclass.snippet.Snippet;
import ch.usi.dag.disl.dislclass.snippet.marker.MarkedRegion;
import ch.usi.dag.disl.exception.ReflectionException;
import ch.usi.dag.disl.exception.StaticInfoException;
import ch.usi.dag.disl.staticinfo.analysis.cache.StaticAnalysisCache;
......@@ -15,6 +20,26 @@ abstract public class AbstractStaticAnalysis implements StaticAnalysis {
private Map<String, StaticAnalysisCache> retValCache =
new HashMap<String, StaticAnalysisCache>();
// this is standard constructor for static analysis
// add registerCache calls to the subclass constructor
protected AbstractStaticAnalysis() {
}
// the subclass may optionally override this constructor - enables to use
// the static analysis in guards
// NOTE: static analysis should not use markings because they are not
// visible in guards and will not be set
// NOTE: if you include this constructor, you should also include
// constructor without parameters, otherwise, the static analysis will not
// be usable normally
public AbstractStaticAnalysis(ClassNode classNode, MethodNode methodNode,
Snippet snippet, MarkedRegion markedRegion) {
staticAnalysisData = new StaticAnalysisData(classNode, methodNode,
snippet, null, markedRegion);
}
protected <T extends StaticAnalysisData> void registerCache(
String methodName, Class<T> keyCacheClass) {
......
......@@ -3,11 +3,24 @@ package ch.usi.dag.disl.staticinfo.analysis;
import java.util.List;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import ch.usi.dag.disl.dislclass.snippet.Snippet;
import ch.usi.dag.disl.dislclass.snippet.marker.MarkedRegion;
import ch.usi.dag.disl.util.cfg.CtrlFlowGraph;
public class BasicBlockAnalysis extends AbstractStaticAnalysis {
public BasicBlockAnalysis() {
super();
}
public BasicBlockAnalysis(ClassNode classNode, MethodNode methodNode,
Snippet snippet, MarkedRegion markedRegion) {
super(classNode, methodNode, snippet, markedRegion);
}
public int getBBSize() {
int count = 1;
......
package ch.usi.dag.disl.staticinfo.analysis;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import ch.usi.dag.disl.dislclass.snippet.Snippet;
import ch.usi.dag.disl.dislclass.snippet.marker.MarkedRegion;
public class BytecodeAnalysis extends AbstractStaticAnalysis {
public BytecodeAnalysis() {
super();
}
public BytecodeAnalysis(ClassNode classNode, MethodNode methodNode,
Snippet snippet, MarkedRegion markedRegion) {
super(classNode, methodNode, snippet, markedRegion);
}
public int getBytecodeNumber() {
return staticAnalysisData.getMarkedRegion().getStart().getOpcode();
......
package ch.usi.dag.disl.staticinfo.analysis;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import ch.usi.dag.disl.dislclass.snippet.Snippet;
import ch.usi.dag.disl.dislclass.snippet.marker.MarkedRegion;
import ch.usi.dag.disl.staticinfo.analysis.cache.ClassCache;
import ch.usi.dag.disl.staticinfo.analysis.cache.MethodCache;
import ch.usi.dag.disl.util.Constants;
public class StaticContext extends AbstractStaticAnalysis {
public StaticContext(ClassNode classNode, MethodNode methodNode,
Snippet snippet, MarkedRegion markedRegion) {
super(classNode, methodNode, snippet, markedRegion);
}
public StaticContext() {
registerCache("thisClassName", ClassCache.class);
......@@ -41,7 +50,7 @@ public class StaticContext extends AbstractStaticAnalysis {
registerCache("isMethodStatic", MethodCache.class);
registerCache("isMethodSynchronized", MethodCache.class);
registerCache("isMethodVarArgs", MethodCache.class);
}
}
// *** Class ***
......
......@@ -99,8 +99,9 @@ public class ClassParser {
+ " declared as ThreadLocal but is not static");
}
TLAnnotationData tlad = ParserHelper.parseAnnotation(annotation,
new TLAnnotationData());
// parse annotation
TLAnnotationData tlad = new TLAnnotationData();
ParserHelper.parseAnnotation(tlad, annotation);
Type fieldType = Type.getType(field.desc);
......
user.runtime.jar.name=test-runtime.jar
\ No newline at end of file
......@@ -2,6 +2,7 @@
<property file="../disl.version"/>
<property file="../build.properties"/>
<property file="build.properties"/>
<property name="disl.jar.path" value="../build/disl-${disl.version}.jar"/>
<path id="buildpath">
......
package ch.usi.dag.disl.test.processor;
import ch.usi.dag.disl.dislclass.annotation.ProcessAlso;
import ch.usi.dag.disl.dislclass.annotation.ProcessAlso.Type;
import ch.usi.dag.disl.dislclass.annotation.Processor;
import ch.usi.dag.disl.dislclass.annotation.SyntheticLocal;
......@@ -23,6 +25,7 @@ public class ProcessorTest {
System.out.println("processor for object 2");
}
@ProcessAlso(types={Type.SHORT, Type.BYTE, Type.BOOLEAN})
public static void intPM(int a, int b, int c) {
System.out.println("processor for int");
System.out.println(a);
......
......@@ -21,6 +21,10 @@ public class TargetClass {
public void method4(String[] sa, int[] ia) {
System.out.println("This is the body of TargetClass.method4");
}
public void method5(boolean z, byte b, short s) {
System.out.println("This is the body of TargetClass.method5");
}
public static void main(String[] args) {
TargetClass t = new TargetClass();
......@@ -29,5 +33,8 @@ public class TargetClass {
t.method3("object", "string");
t.method3(1, 2, "object");
t.method4(new String[1], new int[1]);
byte b = 2;
short s = 3;
t.method5(true, b, s);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment