Commit 20abe127 authored by Vít Kabele's avatar Vít Kabele

Fixing #6.

Processor package merged.
parent 24f66146
Pipeline #3347 passed with stages
in 3 minutes and 42 seconds
......@@ -12,6 +12,7 @@
<classpathentry kind="src" path="disl/src/src-coderep"/>
<classpathentry kind="src" path="disl/src/src-util"/>
<classpathentry kind="src" path="disl/src/src-snippet"/>
<classpathentry kind="src" path="disl/src/src-processor"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="output/lib/disl-bypass.jar"/>
<classpathentry kind="lib" path="lib/disl/log4j.jar" sourcepath="lib/devel/log4j-source.jar"/>
......
......@@ -13,6 +13,7 @@ src.disl.resolver=src-resolver
src.disl.coderep=src-coderep
src.disl.util=src-util
src.disl.snippet=src-snippet
src.disl.processor=src-processor
src.disl.exception=src-exception
src.disl.bypass=src-disl-bypass
src.disl.agent=src-disl-agent
......
......@@ -481,6 +481,7 @@
<src path="${src.disl.prefix}/src/${src.disl.resolver}"/>
<src path="${src.disl.prefix}/src/${src.disl.coderep}"/>
<src path="${src.disl.prefix}/src/${src.disl.snippet}"/>
<src path="${src.disl.prefix}/src/${src.disl.processor}"/>
<src path="${src.disl.prefix}/src/${src.disl.util}"/>
<src path="${src.disl.prefix}/src/${src.disl.main}"/>
<classpath>
......
......@@ -17,9 +17,6 @@ import ch.usi.dag.disl.annotation.Guarded;
import ch.usi.dag.disl.annotation.ProcessAlso;
import ch.usi.dag.disl.guard.GuardHelper;
import ch.usi.dag.disl.localvar.LocalVars;
import ch.usi.dag.disl.processor.ArgProcessor;
import ch.usi.dag.disl.processor.ArgProcessorKind;
import ch.usi.dag.disl.processor.ArgProcessorMethod;
import ch.usi.dag.util.Strings;
......@@ -30,6 +27,12 @@ class ArgProcessorParser extends AbstractParser {
//
private final Map <Type, ArgProcessor> __processors = new HashMap <> ();
private final ClassLoader classLoader;
ArgProcessorParser(final ClassLoader classLoader){
this.classLoader = classLoader;
}
Map <Type, ArgProcessor> initProcessors (final LocalVars localVars) {
__processors.values ().stream ().unordered ()
......@@ -133,7 +136,7 @@ class ArgProcessorParser extends AbstractParser {
// and create a code template for the argument processor method.
//
final UnprocessedCode codeTemplate = new UnprocessedCode (
className, method
className, method, classLoader
);
return new ArgProcessorMethod (
......
......@@ -7,15 +7,11 @@
package ch.usi.dag.disl;
import ch.usi.dag.disl.annotation.ArgumentProcessor;
import ch.usi.dag.disl.localvar.LocalVars;
import ch.usi.dag.disl.processor.ArgProcessor;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
......@@ -24,7 +20,7 @@ import java.util.stream.Collectors;
*/
abstract class DislClasses {
final SnippetParser snippetParser;
final IsolatedSnippetParser snippetParser;
/**
......@@ -32,73 +28,10 @@ abstract class DislClasses {
*
* @param snippetParser SnippetParser.
*/
DislClasses(SnippetParser snippetParser){
DislClasses(IsolatedSnippetParser snippetParser){
this.snippetParser = snippetParser;
}
/**
* Initialization method common for all inherited classes.
*
* @param sp Snippet parser
* @param options Code options
* @param classNodes Class nodes.
* @throws InitializationException
* @throws ParserException
* @throws ProcessorException
* @throws ReflectionException
*/
static void InitMethod(
final SnippetParser sp,
final Set<DiSL.CodeOption> options,
List<ClassNode> classNodes
) throws
InitializationException,
ParserException,
ProcessorException,
ReflectionException
{
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 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);
}
}
/**
* Get all possible snippets.
* @return All snippets
......@@ -115,7 +48,10 @@ abstract class DislClasses {
* @return Matching snippets.
*/
List<Snippet> selectMatchingSnippets (
String className, String methodName, String methodDesc) {
final String className,
final String methodName,
final String methodDesc
) {
return snippetParser.getSnippets ().stream ().unordered ()
.filter (s -> s.getScope ().matches (className, methodName, methodDesc))
......@@ -132,7 +68,7 @@ abstract class DislClasses {
* @param classNode Class node.
* @return True, when class node is argument processor, false otherwise.
*/
private static boolean __isArgumentProcessor (final ClassNode classNode) {
boolean __isArgumentProcessor (final ClassNode classNode) {
if (classNode.invisibleAnnotations != null) {
final Type apType = Type.getType (ArgumentProcessor.class);
......
package ch.usi.dag.disl;
import ch.usi.dag.disl.DiSL.CodeOption;
import ch.usi.dag.util.asm.ClassNodeHelper;
import org.objectweb.asm.tree.ClassNode;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Parser for DiSL classes containing either snippets or method argument
* processors. This class is not meant for public use.
*/
public final class DislClassesImpl extends DislClasses {
/**
* Create new instance of {@link DislClassesImpl} class.
* @param _snippetParser Snippet parser.
*/
private DislClassesImpl (final SnippetParser _snippetParser) {
// not to be instantiated from outside
super(_snippetParser);
}
//
public static DislClasses load (
final Set <CodeOption> options,
final Stream <String> classNames
) throws
ParserException,
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 (DislClassesImpl::__createClassNode)
.collect (Collectors.toList ());
final SnippetParser sp = new SnippetParser ();
InitMethod (sp, options, classNodes);
return new DislClassesImpl (sp);
}
/**
* 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.
*
* @param className Class name.
* @return ClassNode
*/
private static ClassNode __createClassNode (final String className) {
try {
return ClassNodeHelper.SNIPPET.load (className);
} catch (final Exception e) {
throw new InitializationException (
e, "failed to load DiSL class %s", className
);
}
}
}
......@@ -8,9 +8,12 @@
*/
package ch.usi.dag.disl;
import ch.usi.dag.disl.localvar.LocalVars;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import java.util.List;
import java.util.Map;
import java.util.Set;
......@@ -42,7 +45,41 @@ class IsolatedDislClasses extends DislClasses {
super( new IsolatedSnippetParser ( allClasses, classLoader ) );
InitMethod (snippetParser, options, classNodes);
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 ArgProcessorParser app = new ArgProcessorParser (classLoader);
for (final ClassNode classNode : classNodes) {
if (__isArgumentProcessor (classNode)) {
app.parse (classNode);
} else {
snippetParser.parse (classNode);
}
}
//
// Collect all local variables and initialize the argument processor
// and snippets.
//
final LocalVars localVars = LocalVars.merge (
snippetParser.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! :-(
snippetParser.initSnippets (localVars, processors, options);
}
}
......@@ -6,14 +6,13 @@
package ch.usi.dag.disl;
import ch.usi.dag.disl.localvar.LocalVars;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
......@@ -48,6 +47,67 @@ class IsolatedSnippetParser extends SnippetParser {
}
//
// NOTE: this method can be called many times
void parse (final ClassNode dislClass) throws ParserException {
processLocalVars (dislClass);
//
try {
final String className = AsmHelper.typeName (dislClass);
snippets.addAll (
dislClass
.methods
.stream ()
.filter (this::__isSnippetCandidate)
.map (m -> __parseSnippetWrapper (className, m))
.collect (Collectors.toList ())
);
} catch (final ParserRuntimeException e) {
throw new ParserException (e.getMessage (), e.getCause ());
}
}
/**
* Initialize the snippets.
* @param localVars
* @param processors
* @param options
* @throws ProcessorException
* @throws ReflectionException
*/
void initSnippets(
final LocalVars localVars,
final Map<Type, ArgProcessor> processors,
final Set<DiSL.CodeOption> options
) throws
ProcessorException,
ReflectionException
{
for (final Snippet snippet : getSnippets ()) {
snippet.init (localVars, processors, options);
}
}
@Override
SnippetUnprocessedCode getUnprocessedCode (
final String className,
final MethodNode methodNode,
final boolean dynamicBypass
) {
return new SnippetUnprocessedCode (
className, methodNode, dynamicBypass, classLoader
);
}
/**
* Gets the guard by type.
*
......
......@@ -2,17 +2,12 @@ package ch.usi.dag.disl;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
import ch.usi.dag.disl.annotation.*;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import ch.usi.dag.disl.annotation.After;
import ch.usi.dag.disl.annotation.AfterReturning;
import ch.usi.dag.disl.annotation.AfterThrowing;
import ch.usi.dag.disl.annotation.Before;
import ch.usi.dag.disl.guard.GuardHelper;
import ch.usi.dag.disl.marker.Marker;
import ch.usi.dag.disl.marker.Parameter;
......@@ -25,45 +20,21 @@ import ch.usi.dag.util.logging.Logger;
* Parses annotated Java class files and converts them to {@link Snippet}
* instances which it collects.
*/
class SnippetParser extends AbstractParser {
abstract class SnippetParser extends AbstractParser {
private final Logger __log = Logging.getPackageInstance ();
//
private final List <Snippet> snippets = new LinkedList <> ();
final List <Snippet> snippets = new LinkedList <> ();
public List <Snippet> getSnippets () {
return snippets;
}
//
// NOTE: this method can be called many times
void parse (final ClassNode dislClass) throws ParserException {
processLocalVars (dislClass);
//
try {
final String className = AsmHelper.typeName (dislClass);
snippets.addAll (
dislClass
.methods
.stream ()
.filter (this::__isSnippetCandidate)
.map (m -> __parseSnippetWrapper (className, m))
.collect (Collectors.toList ())
);
} catch (final ParserRuntimeException e) {
throw new ParserException (e.getMessage (), e.getCause ());
}
}
private boolean __isSnippetCandidate (final MethodNode m) {
boolean __isSnippetCandidate (final MethodNode m) {
if (JavaNames.isConstructorName (m.name)) {
__log.trace ("ignoring %s (constructor)", m.name);
return false;
......@@ -82,7 +53,7 @@ class SnippetParser extends AbstractParser {
return true;
}
private Snippet __parseSnippetWrapper (
Snippet __parseSnippetWrapper (
final String className, final MethodNode method
) {
//
......@@ -122,9 +93,7 @@ class SnippetParser extends AbstractParser {
GuardHelper.snippetContextSet ()
);
final SnippetUnprocessedCode template = new SnippetUnprocessedCode (
className, method, data.dynamicBypass
);
final SnippetUnprocessedCode template = getUnprocessedCode (className, method, data.dynamicBypass);
//
......@@ -133,6 +102,21 @@ class SnippetParser extends AbstractParser {
);
}
/**
* Force the inherited classes to implement a method to get instance of {@link SnippetUnprocessedCode}
*
* @param className
* @param methodNode
* @param dynamicBypass
* @return
*/
abstract SnippetUnprocessedCode getUnprocessedCode(
final String className,
final MethodNode methodNode,
final boolean dynamicBypass
);
//
private void __ensureSnippetIsWellDefined (
......
......@@ -42,13 +42,17 @@ public class UnprocessedCode {
/** Method node containing the snippet code. */
private final MethodNode __method;
private final ClassLoader classLoader;
//
UnprocessedCode (
final String className, final MethodNode method
final String className,
final MethodNode method,
final ClassLoader classLoader
) {
__className = className;
__method = method;
this.classLoader = classLoader;
}
//
......@@ -87,7 +91,7 @@ public class UnprocessedCode {
// variables, and finally determine if there is any exception handler in
// the code that handles the exception and does not propagate it.
//
final ContextUsage ctxs = ContextUsage.forMethod (__method);
final ContextUsage ctxs = ContextUsage.forMethod (__method, classLoader);
final Set <StaticContextMethod> scms = __collectStaticContextMethods (
__method.instructions, ctxs.staticContextTypes ()
);
......@@ -234,7 +238,7 @@ public class UnprocessedCode {
private Class <?> __resolveClass (final MethodInsnNode insn) {
try {
return ReflectionHelper.resolveClass (Type.getObjectType (insn.owner));
return ReflectionHelper.resolveClass (Type.getObjectType (insn.owner), classLoader);
} catch (final ReflectionException e) {
throw new InvalidStaticContextInvocationException (e.getMessage (), insn);
......@@ -277,8 +281,8 @@ public class UnprocessedCode {
AbstractLocalVar.fqFieldNameFor (fi.owner, fi.name)
));
})
.filter (o -> o.isPresent ())
.map (o -> o.get ())
.filter (Optional::isPresent)
.map (Optional::get)
.collect (Collectors.toSet ());
}
......
......@@ -53,100 +53,6 @@ public final class DiSL {
private final ClassLoader __classLoader = new ClassLoader ();
/**
* Initializes a DiSL instance by loading transformers, exclusion lists, and
* DiSL classes.
* <p>
* <b>Note:</b> This constructor is deprecated and will be removed in later
* releases. Use the {@link #init()} static factory method to obtain a
* {@link DiSL} instance.
*
* @param useDynamicBypass
* determines whether to generate bypass code and whether to control
* the bypass dynamically.
*/
@Deprecated
public DiSL (final boolean useDynamicBypass) throws DiSLException {
final Properties properties = System.getProperties ();
__codeOptions = __codeOptionsFrom (
Objects.requireNonNull (properties)
);
// Add the necessary bypass options for backwards compatibility.
if (useDynamicBypass) {
__codeOptions.add (CodeOption.CREATE_BYPASS);
__codeOptions.add (CodeOption.DYNAMIC_BYPASS);
}
final ClassResources resources = ClassResources.discover (properties);
__transformers = TransformersImpl.load (resources.transformers ());
__excludedScopes = ExclusionSet.prepare (resources.instrumentationResources ());
__dislClasses = DislClassesImpl.load (__codeOptions, resources.dislClasses ());
}
/**
* Initializes a DiSL instance.
*/
private DiSL (
final Set <CodeOption> codeOptions, final Transformers transformers,
final Set <Scope> excludedScopes, final DislClasses dislClasses
) {
__codeOptions = codeOptions;
__transformers = transformers;
__excludedScopes = excludedScopes;
__dislClasses = dislClasses;
}
/**
* Creates a {@link DiSL} instance. This involves loading and parsing DiSL
* classes containing snippets, loading transformer classes, and setting up
* exclusion lists. This method uses the system properties to look for
* configuration settings.
*
* @return A {@link DiSL} instance.
* @throws DiSLException
* if the initialization failed.
*/
public static DiSL init () throws DiSLException {
return init (System.getProperties ());
}
/**
* Loads transformers, exclusion lists, and DiSL classes with snippets, and
* creates an instance of the {@link DiSL} class.
*
* @param properties
* the properties to use in place of system properties, may not be
* {@code null}
* @return A {@link DiSL} instance.
* @throws DiSLException
* if the initialization failed.
*/
private static DiSL init (final Properties properties) throws DiSLException {
final Set <CodeOption> codeOptions = __codeOptionsFrom (
Objects.requireNonNull (properties)
);
final ClassResources resources = ClassResources.discover (properties);
final Transformers transformers = TransformersImpl.load (resources.transformers ());
final Set <Scope> excludedScopes = ExclusionSet.prepare (resources.instrumentationResources ());
final DislClasses dislClasses = DislClassesImpl.load (codeOptions, resources.dislClasses ());
// TODO put checker here
// like After should catch normal and abnormal execution
// but if you are using After (AfterThrowing) with BasicBlockMarker
// or InstructionMarker that doesn't throw exception, then it is
// probably something, you don't want - so just warn the user
// also it can warn about unknown opcodes if you let user to
// specify this for InstructionMarker
return new DiSL (codeOptions, transformers, excludedScopes, dislClasses);
}
/**
* Initialize new instance of the {@link DiSL} class, using received instrumentaion jars.
*
......@@ -155,8 +61,7 @@ public final class DiSL {
*
* @param properties System properties.
* @param instrumentations Received instrumentation jars (maybe wrap to something like SessionContext)
* @return New instance of the {@link DiSL} class.
* @throws DiSLException
* @throws DiSLException Error while initializing Disl class
*/
public DiSL(
final Properties properties,
......@@ -566,11 +471,8 @@ public final class DiSL {
final byte [] classBytes, final String fileName
) {
try {
final FileOutputStream fos = new FileOutputStream (fileName);
try {
try (FileOutputStream fos = new FileOutputStream (fileName)) {
fos.write (classBytes);
} finally {
fos.close ();
}
} catch (final IOException ioe) {
__log.warn (
......@@ -647,9 +549,7 @@ public final class DiSL {
*/
public static Set <CodeOption> setOf (final CodeOption... options) {
final EnumSet <CodeOption> result = EnumSet.noneOf (CodeOption.class);
for (final CodeOption option : options) {
result.add (option);
}
Collections.addAll (result, options);
return result;
}
......
package ch.usi.dag.disl.processor;
package ch.usi.dag.disl;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import ch.usi.dag.disl.StaticContextMethod;
import ch.usi.dag.disl.localvar.LocalVars;
......@@ -24,7 +23,7 @@ public class ArgProcessor {
//
public ArgProcessor (final String name, final List <ArgProcessorMethod> methods) {
ArgProcessor (final String name, final List <ArgProcessorMethod> methods) {
__className = name;
__methods = methods;
}
......@@ -43,7 +42,7 @@ public class ArgProcessor {
}
public Set <StaticContextMethod> getReferencedSCMs () {