Commit 82c61c1d authored by Vít Kabele's avatar Vít Kabele

Extracted DiSLClasses interface.

parent c7143a43
......@@ -15,6 +15,7 @@ import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import ch.usi.dag.disl.classparser.DislClassesImpl;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
......@@ -90,7 +91,7 @@ public final class DiSL {
final ClassResources resources = ClassResources.discover (properties);
__transformers = TransformersImpl.load (resources.transformers ());
__excludedScopes = ExclusionSet.prepare (resources.instrumentationResources ());
__dislClasses = DislClasses.load (__codeOptions, resources.dislClasses ());
__dislClasses = DislClassesImpl.load (__codeOptions, resources.dislClasses ());
}
......@@ -142,7 +143,7 @@ public final class DiSL {
final ClassResources resources = ClassResources.discover (properties);
final Transformers transformers = TransformersImpl.load (resources.transformers ());
final Set <Scope> excludedScopes = ExclusionSet.prepare (resources.instrumentationResources ());
final DislClasses dislClasses = DislClasses.load (codeOptions, resources.dislClasses ());
final DislClasses dislClasses = DislClassesImpl.load (codeOptions, resources.dislClasses ());
// TODO put checker here
// like After should catch normal and abnormal execution
......
/**
* This file is part of disl project
* Provide an interface for getting snippets.
* Author: Vit Kabele <vit@kabele.me>
* Created on the 26/10/2018
*/
package ch.usi.dag.disl.classparser;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import ch.usi.dag.disl.DiSL.CodeOption;
import ch.usi.dag.disl.InitializationException;
import ch.usi.dag.disl.annotation.ArgumentProcessor;
import ch.usi.dag.disl.exception.ParserException;
import ch.usi.dag.disl.exception.ProcessorException;
import ch.usi.dag.disl.exception.ReflectionException;
import ch.usi.dag.disl.exception.StaticContextGenException;
import ch.usi.dag.disl.localvar.LocalVars;
import ch.usi.dag.disl.processor.ArgProcessor;
import ch.usi.dag.disl.snippet.Snippet;
import ch.usi.dag.util.asm.ClassNodeHelper;
import java.util.List;
/**
* Parser for DiSL classes containing either snippets or method argument
* processors. This class is not meant for public use.
* Provide an interface for getting snippets.
*/
public final class DislClasses {
private final SnippetParser __snippetParser;
//
private DislClasses (final SnippetParser snippetParser) {
// not to be instantiated from outside
__snippetParser = snippetParser;
}
//
public static DislClasses load (
final Set <CodeOption> options, final Stream <String> classNames
) throws ParserException, StaticContextGenException, ReflectionException,
ProcessorException {
//
// Get an ASM tree representation of the DiSL classes first, then
// parse them as snippets or argument processors depending on the
// annotations associated with each class.
//
final List <ClassNode> classNodes = classNames
.map (className -> __createClassNode (className))
.collect (Collectors.toList ());
if (classNodes.isEmpty ()) {
throw new InitializationException (
"No DiSL classes found. They must be explicitly specified "+
"using the disl.classes system property or the DiSL-Classes "+
"attribute in the instrumentation JAR manifest."
);
}
//
final SnippetParser sp = new SnippetParser ();
final ArgProcessorParser app = new ArgProcessorParser ();
for (final ClassNode classNode : classNodes) {
if (__isArgumentProcessor (classNode)) {
app.parse (classNode);
} else {
sp.parse (classNode);
}
}
//
// Collect all local variables and initialize the argument processor
// and snippets.
//
final LocalVars localVars = LocalVars.merge (
sp.getAllLocalVars (), app.getAllLocalVars ()
);
final Map <Type, ArgProcessor> processors = app.initProcessors (localVars);
// TODO LB: Consider whether we need to create the argument processor
// invocation map now -- we basically discard the argument processors
// and keep an invocation map keyed to instruction indices! :-(
// TODO LB: Move the loop to the SnippetParser class
for (final Snippet snippet : sp.getSnippets ()) {
snippet.init (localVars, processors, options);
}
return new DislClasses (sp);
}
private static ClassNode __createClassNode (final String className) {
//
// Parse input stream into a class node. Include debug information so
// that we can report line numbers in case of problems in DiSL classes.
// Re-throw any exceptions as DiSL initialization exceptions.
//
try {
return ClassNodeHelper.SNIPPET.load (className);
} catch (final Exception e) {
throw new InitializationException (
e, "failed to load DiSL class %s", className
);
}
}
private static boolean __isArgumentProcessor (final ClassNode classNode) {
//
// An argument processor must have an @ArgumentProcessor annotation
// associated with the class. DiSL instrumentation classes may have
// an @Instrumentation annotation. DiSL classes without annotations
// are by default considered to be instrumentation classes.
//
if (classNode.invisibleAnnotations != null) {
final Type apType = Type.getType (ArgumentProcessor.class);
for (final AnnotationNode annotation : classNode.invisibleAnnotations) {
final Type annotationType = Type.getType (annotation.desc);
if (apType.equals (annotationType)) {
return true;
}
}
}
// default: not an argument processor
return false;
}
//
public List <Snippet> getSnippets () {
return __snippetParser.getSnippets ();
}
public List <Snippet> selectMatchingSnippets (
final String className, final String methodName, final String methodDesc
) {
return __snippetParser.getSnippets ().stream ().unordered ()
.filter (s -> s.getScope ().matches (className, methodName, methodDesc))
.collect (Collectors.toList ());
}
public interface DislClasses {
/**
* Get all possible snippets.
* @return All snippets
*/
List<Snippet> getSnippets ();
/**
* Get matching snippets.
* @param className Name of class
* @param methodName Name of method
* @param methodDesc Description of the method
* @return Matching snippets.
*/
List<Snippet> selectMatchingSnippets (
String className, String methodName, String methodDesc
);
}
package ch.usi.dag.disl.classparser;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import ch.usi.dag.disl.DiSL.CodeOption;
import ch.usi.dag.disl.InitializationException;
import ch.usi.dag.disl.annotation.ArgumentProcessor;
import ch.usi.dag.disl.exception.ParserException;
import ch.usi.dag.disl.exception.ProcessorException;
import ch.usi.dag.disl.exception.ReflectionException;
import ch.usi.dag.disl.exception.StaticContextGenException;
import ch.usi.dag.disl.localvar.LocalVars;
import ch.usi.dag.disl.processor.ArgProcessor;
import ch.usi.dag.disl.snippet.Snippet;
import ch.usi.dag.util.asm.ClassNodeHelper;
/**
* Parser for DiSL classes containing either snippets or method argument
* processors. This class is not meant for public use.
*/
public final class DislClassesImpl implements DislClasses {
private final SnippetParser __snippetParser;
//
private DislClassesImpl (final SnippetParser snippetParser) {
// not to be instantiated from outside
__snippetParser = snippetParser;
}
//
public static DislClasses load (
final Set <CodeOption> options, final Stream <String> classNames
) throws ParserException, StaticContextGenException, ReflectionException,
ProcessorException {
//
// Get an ASM tree representation of the DiSL classes first, then
// parse them as snippets or argument processors depending on the
// annotations associated with each class.
//
final List <ClassNode> classNodes = classNames
.map (className -> __createClassNode (className))
.collect (Collectors.toList ());
if (classNodes.isEmpty ()) {
throw new InitializationException (
"No DiSL classes found. They must be explicitly specified "+
"using the disl.classes system property or the DiSL-Classes "+
"attribute in the instrumentation JAR manifest."
);
}
//
final SnippetParser sp = new SnippetParser ();
final ArgProcessorParser app = new ArgProcessorParser ();
for (final ClassNode classNode : classNodes) {
if (__isArgumentProcessor (classNode)) {
app.parse (classNode);
} else {
sp.parse (classNode);
}
}
//
// Collect all local variables and initialize the argument processor
// and snippets.
//
final LocalVars localVars = LocalVars.merge (
sp.getAllLocalVars (), app.getAllLocalVars ()
);
final Map <Type, ArgProcessor> processors = app.initProcessors (localVars);
// TODO LB: Consider whether we need to create the argument processor
// invocation map now -- we basically discard the argument processors
// and keep an invocation map keyed to instruction indices! :-(
// TODO LB: Move the loop to the SnippetParser class
for (final Snippet snippet : sp.getSnippets ()) {
snippet.init (localVars, processors, options);
}
return new DislClassesImpl (sp);
}
private static ClassNode __createClassNode (final String className) {
//
// Parse input stream into a class node. Include debug information so
// that we can report line numbers in case of problems in DiSL classes.
// Re-throw any exceptions as DiSL initialization exceptions.
//
try {
return ClassNodeHelper.SNIPPET.load (className);
} catch (final Exception e) {
throw new InitializationException (
e, "failed to load DiSL class %s", className
);
}
}
private static boolean __isArgumentProcessor (final ClassNode classNode) {
//
// An argument processor must have an @ArgumentProcessor annotation
// associated with the class. DiSL instrumentation classes may have
// an @Instrumentation annotation. DiSL classes without annotations
// are by default considered to be instrumentation classes.
//
if (classNode.invisibleAnnotations != null) {
final Type apType = Type.getType (ArgumentProcessor.class);
for (final AnnotationNode annotation : classNode.invisibleAnnotations) {
final Type annotationType = Type.getType (annotation.desc);
if (apType.equals (annotationType)) {
return true;
}
}
}
// default: not an argument processor
return false;
}
//
@Override public List <Snippet> getSnippets () {
return __snippetParser.getSnippets ();
}
@Override public List <Snippet> selectMatchingSnippets (
final String className, final String methodName, final String methodDesc
) {
return __snippetParser.getSnippets ().stream ().unordered ()
.filter (s -> s.getScope ().matches (className, methodName, methodDesc))
.collect (Collectors.toList ());
}
}
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