Commit 15f47fd9 authored by Lubomir Bulej's avatar Lubomir Bulej

Snippet: stop exposing marker, provide selectApplicableSnippets() instead.

UnprocessedCode: move rewriting of accesses to thread-local variables to
Weaver.
Weaver: rewrite accesses to thread-local variables at the end of the weaving
phase.
DiSL: updated to reflect the changes in Snippet and UnprocessedCode.
RewriteThreadLocalVarAccessesCodeTransformer: moved to the weaver package
for now.
parent bd2321ef
This diff is collapsed.
......@@ -116,15 +116,13 @@ public class UnprocessedCode {
// Clone the method code so that we can transform it, then:
//
// - replace all RETURN instructions with a GOTO to the end of a method
// - rewrite accesses to thread-local variables
//
// Finally create an instance of processed code.
//
final MethodNode method = AsmHelper.cloneMethod (__method);
CodeTransformer.apply (method.instructions,
new ReplaceReturnsWithGotoCodeTransformer (),
new RewriteThreadLocalVarAccessesCodeTransformer (tlvs)
new ReplaceReturnsWithGotoCodeTransformer ()
);
return new Code (
......
package ch.usi.dag.disl.snippet;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import ch.usi.dag.disl.DiSL.CodeOption;
import ch.usi.dag.disl.exception.MarkerException;
import ch.usi.dag.disl.exception.ProcessorException;
import ch.usi.dag.disl.exception.ReflectionException;
import ch.usi.dag.disl.guard.GuardHelper;
import ch.usi.dag.disl.localvar.LocalVars;
import ch.usi.dag.disl.marker.Marker;
import ch.usi.dag.disl.processor.ArgProcessor;
......@@ -92,10 +98,37 @@ public class Snippet implements Comparable <Snippet> {
/**
* @return The marker associated with the snippet.
* Applies the marker associated with this snippet to the given
* class and method, so as to provide a list of {@link Shadow}
* instances representing individual instances of a snippet.
*
* @throws MarkerException
*/
public final List <Shadow> selectApplicableShadows (
final ClassNode classNode, final MethodNode methodNode
) throws MarkerException {
return __guardedShadows (marker.mark (classNode, methodNode, this));
}
/**
* Selects shadows passing the guard associated with this snippet.
*
* @param shadows
* the list of {@link Shadow} instances to filter.
* @return A list of {@link Shadow} instances passing the guard.
*/
public Marker getMarker () {
return marker;
private List <Shadow> __guardedShadows (
final List <Shadow> shadows
) {
if (guard == null) {
return shadows;
}
return shadows.stream ()
// potentially .parallel(), needs thread-safe static context
.filter (shadow -> GuardHelper.guardApplicable (guard, shadow))
.collect (Collectors.toList ());
}
......
package ch.usi.dag.disl.coderep;
package ch.usi.dag.disl.weaver;
import java.util.List;
import java.util.Set;
......@@ -6,16 +6,23 @@ import java.util.stream.Collectors;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import ch.usi.dag.disl.localvar.ThreadLocalVar;
import ch.usi.dag.disl.util.AsmHelper;
import ch.usi.dag.disl.util.CodeTransformer;
import ch.usi.dag.disl.util.AsmHelper.Insns;
import ch.usi.dag.disl.util.CodeTransformer;
import ch.usi.dag.disl.util.Insn;
/**
* Replaces accesses to static variables representing thread-local variable
* accesses with actual field accesses to the {@link Thread} class.
*/
final class RewriteThreadLocalVarAccessesCodeTransformer implements CodeTransformer {
private final Set <String> __tlvIds;
......@@ -39,8 +46,8 @@ final class RewriteThreadLocalVarAccessesCodeTransformer implements CodeTransfor
public void transform (final InsnList insns) {
//
// Scan the method code for GETSTATIC/PUTSTATIC instructions accessing
// the static fields marked to be thread locals. Replace all the
// static accesses with thread variable accesses.
// the static fields marked to be thread locals. Replace all accesses
// to such static fields with access to a field in the Thread class.
//
// First select the instructions, then modify the instruction list.
//
......@@ -66,42 +73,59 @@ final class RewriteThreadLocalVarAccessesCodeTransformer implements CodeTransfor
private static void __rewriteThreadLocalVarAccess (
final FieldInsnNode fieldInsn, final InsnList insns
) {
//
// Issue a call to Thread.currentThread() and access a field
// in the current thread corresponding to the thread-local
// variable.
//
insns.insertBefore (fieldInsn, AsmHelper.invokeStatic (
threadType, currentThreadName, currentThreadType
));
if (Insn.GETSTATIC.matches (fieldInsn)) {
//
// Issue a call to Thread.currentThread() and access a field
// in the current thread corresponding to the thread-local
// variable.
//
insns.insertBefore (fieldInsn, __currentThread ());
insns.insertBefore (fieldInsn, AsmHelper.getField (
threadType, fieldInsn.name, fieldInsn.desc
));
} else if (Insn.PUTSTATIC.matches (fieldInsn)) {
//
// We need to execute a PUTFIELD instruction, which requires
// two operands, but the current thread reference that we
// currently have on the top of the stack needs to come after
// the value that is to be stored.
// We need to execute a PUTFIELD instruction, which requires two
// operands, with the value to be stored on the top of the stack
// and the current-thread reference below it.
//
// In general, we do not know the value to be stored comes from,
// so we push the current-thread reference on the stack (using an
// invocation of the currentThread() method) and swap the two
// operands on the stack.
//
// We therefore need to swap the two operands on the stack.
// There is no easier way, unless we want to track where the
// There is no easier way, unless we could track where the
// value to be stored was pushed on the stack and put the
// currentThread() method invocation before it.
//
// For primitive operands, we just swap the values. For wide
// operands, we need to rearrange 3 slots in total, with the
// slot 0 becoming slot 2, and slots 1 and 2 becoming 0 and 1.
//
// As an optimization, if the instruction preceding PUTSTATIC
// is a simple load (scalar local variable, a constant, a literal,
// or even GETSTATIC), then we can place the invocation of the
// currentThread() method before the load to avoid the swap.
//
if (Type.getType (fieldInsn.desc).getSize () == 1) {
insns.insertBefore (fieldInsn, new InsnNode (Opcodes.SWAP));
final AbstractInsnNode prevInsn = Insns.REVERSE.nextRealInsn (fieldInsn);
if (__isSimpleLoad (prevInsn)) {
insns.insertBefore (prevInsn, __currentThread ());
} else {
insns.insertBefore (fieldInsn, new InsnNode (Opcodes.DUP_X2));
insns.insertBefore (fieldInsn, new InsnNode (Opcodes.POP));
//
// Otherwise for primitive operands, we just swap the values.
// For wide operands, we need to rearrange 3 slots in total,
// with the slot 0 becoming slot 2, and slots 1 and 2 becoming 0
// and 1.
//
insns.insertBefore (fieldInsn, __currentThread ());
if (Type.getType (fieldInsn.desc).getSize () == 1) {
insns.insertBefore (fieldInsn, new InsnNode (Opcodes.SWAP));
} else {
insns.insertBefore (fieldInsn, new InsnNode (Opcodes.DUP_X2));
insns.insertBefore (fieldInsn, new InsnNode (Opcodes.POP));
}
}
......@@ -110,7 +134,7 @@ final class RewriteThreadLocalVarAccessesCodeTransformer implements CodeTransfor
));
} else {
throw new AssertionError ("field insn is GETSTATIC/PUTSTATIC");
throw new AssertionError ("field insn is not GETSTATIC/PUTSTATIC");
}
//
......@@ -119,4 +143,16 @@ final class RewriteThreadLocalVarAccessesCodeTransformer implements CodeTransfor
insns.remove (fieldInsn);
}
private static boolean __isSimpleLoad (final AbstractInsnNode prevInsn) {
return Insn.isConstLoad (prevInsn) || Insn.isScalarLoad (prevInsn) || Insn.GETSTATIC.matches (prevInsn);
}
//
private static MethodInsnNode __currentThread () {
return AsmHelper.invokeStatic (
threadType, currentThreadName, currentThreadType
);
}
}
......@@ -2,6 +2,7 @@ package ch.usi.dag.disl.weaver;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
......@@ -21,6 +22,7 @@ import ch.usi.dag.disl.annotation.Before;
import ch.usi.dag.disl.annotation.SyntheticLocal.Initialize;
import ch.usi.dag.disl.exception.InvalidContextUsageException;
import ch.usi.dag.disl.localvar.SyntheticLocalVar;
import ch.usi.dag.disl.localvar.ThreadLocalVar;
import ch.usi.dag.disl.processor.generator.PIResolver;
import ch.usi.dag.disl.snippet.Shadow;
import ch.usi.dag.disl.snippet.Shadow.WeavingRegion;
......@@ -29,6 +31,7 @@ import ch.usi.dag.disl.snippet.SnippetCode;
import ch.usi.dag.disl.staticcontext.generator.SCGenerator;
import ch.usi.dag.disl.util.AsmHelper;
import ch.usi.dag.disl.util.AsmHelper.Insns;
import ch.usi.dag.disl.util.CodeTransformer;
// The weaver instruments byte-codes into java class.
public class Weaver {
......@@ -42,7 +45,7 @@ public class Weaver {
*/
private static void static2Local (
final MethodNode methodNode,
final List<SyntheticLocalVar> syntheticLocalVars
final Set <SyntheticLocalVar> syntheticLocalVars
) {
final InsnList instructions = methodNode.instructions;
final AbstractInsnNode first = instructions.getFirst ();
......@@ -245,7 +248,8 @@ public class Weaver {
public static void instrument (
final ClassNode classNode, final MethodNode methodNode,
final Map <Snippet, List <Shadow>> snippetShadows,
final List <SyntheticLocalVar> syntheticLocalVars,
final Set <SyntheticLocalVar> syntheticLocalVars,
final Set <ThreadLocalVar> threadLocalVars,
final SCGenerator staticInfoHolder, final PIResolver piResolver
) throws InvalidContextUsageException {
......@@ -260,8 +264,10 @@ public class Weaver {
}
// Instrument
//
// TODO LB: Extract transformations for individual annotation types.
//
// For @Before snippets, insert the snippet code just before the
// region entry.
//
......@@ -370,6 +376,11 @@ public class Weaver {
}
static2Local(methodNode, syntheticLocalVars);
CodeTransformer.apply (
methodNode.instructions,
new RewriteThreadLocalVarAccessesCodeTransformer (threadLocalVars)
);
AdvancedSorter.sort(methodNode);
}
......
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