Commit ae81feb0 authored by Lubomir Bulej's avatar Lubomir Bulej

DynamicContext: added methods for reading static and instance field values.

WeavingCode: added support for DynamicContext methods to read static and instance field values.
WeavingCode: cleaned up the weaver to highlight opportunities for refactorization.
src-test: added a test suite for the new DynamicContext methods.
parent 1aa0d2c4
package ch.usi.dag.disl.test.suite.dynamiccontext.app;
import java.util.Random;
public class TargetClass {
static final Class <?> STATIC_TYPE = TargetClass.class;
static final String STATIC_NAME = STATIC_TYPE.getSimpleName ();
static final int STATIC_RAND = new Random (42).nextInt ();
static final double STATIC_MATH = Math.pow (Math.E, Math.PI);
final Class <?> instType = getClass ();
final String instName = instType.getSimpleName ();
final int instRand = new Random (42).nextInt ();
final double instMath = Math.pow (Math.PI, Math.E);
public static void printStaticFields () {
System.out.println ("app: STATIC_TYPE="+ STATIC_TYPE);
System.out.println ("app: STATIC_NAME="+ STATIC_NAME);
System.out.println ("app: STATIC_RAND="+ STATIC_RAND);
System.out.println ("app: STATIC_MATH="+ STATIC_MATH);
}
public void printInstanceFields () {
System.out.println ("app: instType="+ instType);
System.out.println ("app: instName="+ instName);
System.out.println ("app: instRand="+ instRand);
System.out.println ("app: instMath="+ instMath);
}
public static void main(final String[] args) {
printStaticFields ();
new TargetClass().printInstanceFields ();
}
}
package ch.usi.dag.disl.test.suite.dynamiccontext.instr;
import ch.usi.dag.disl.annotation.AfterReturning;
import ch.usi.dag.disl.dynamiccontext.DynamicContext;
import ch.usi.dag.disl.marker.BodyMarker;
import ch.usi.dag.disl.marker.BytecodeMarker;
import ch.usi.dag.disl.staticcontext.FieldAccessStaticContext;
import ch.usi.dag.disl.test.suite.dynamiccontext.app.TargetClass;
public class DiSLClass {
/**
* Prints the names and values of static fields of this class accessed
* by the test method.
*/
@AfterReturning(marker = BytecodeMarker.class, args = "GETSTATIC", scope = "TargetClass.printStaticFields", order = 0)
public static void printStaticFieldsRead (final FieldAccessStaticContext fasc, final DynamicContext dc) {
if ("ch/usi/dag/disl/test/suite/dynamiccontext/app/TargetClass".equals (fasc.getOwnerInternalName ())) {
System.out.printf ("disl: %s=%s\n", fasc.getName (), dc.getStaticFieldValue (
fasc.getOwnerInternalName (), fasc.getName (), fasc.getDescriptor (), Object.class
));
}
}
/**
* Prints the names and values of selected static fields of this class.
*/
@AfterReturning(marker = BodyMarker.class, scope = "TargetClass.printStaticFields", order = 1)
public static void printSpecificStaticFieldsTedious (final DynamicContext dc) {
final String format = "disl: tedious %s=%s\n";
//
final Class <?> staticType = dc.getStaticFieldValue (
"ch/usi/dag/disl/test/suite/dynamiccontext/app/TargetClass",
"STATIC_TYPE", "Ljava/lang/Class;", Class.class
);
System.out.printf (format, "STATIC_TYPE", staticType);
//
final String staticName = dc.getStaticFieldValue (
"ch/usi/dag/disl/test/suite/dynamiccontext/app/TargetClass",
"STATIC_NAME", "Ljava/lang/String;", String.class
);
System.out.printf (format, "STATIC_NAME", staticName);
//
final int staticRand = dc.getStaticFieldValue (
"ch/usi/dag/disl/test/suite/dynamiccontext/app/TargetClass",
"STATIC_RAND", "I", int.class
);
System.out.printf (format, "STATIC_RAND", staticRand);
//
final double staticMath = dc.getStaticFieldValue (
"ch/usi/dag/disl/test/suite/dynamiccontext/app/TargetClass",
"STATIC_MATH", "D", double.class
);
System.out.printf (format, "STATIC_MATH", staticMath);
}
/**
* Prints the names and values of selected static fields of this class.
*/
@AfterReturning(marker = BodyMarker.class, scope = "TargetClass.printStaticFields", order = 2)
public static void printSpecificStaticFieldConcise (final DynamicContext dc) {
final String format = "disl: concise %s=%s\n";
//
final Class <?> staticType = dc.getStaticFieldValue (
TargetClass.class, "STATIC_TYPE", Class.class
);
System.out.printf (format, "STATIC_TYPE", staticType);
//
final String staticName = dc.getStaticFieldValue (
TargetClass.class, "STATIC_NAME", String.class
);
System.out.printf (format, "STATIC_NAME", staticName);
//
final int staticRand = dc.getStaticFieldValue (
TargetClass.class, "STATIC_RAND", int.class
);
System.out.printf (format, "STATIC_RAND", staticRand);
//
final double staticMath = dc.getStaticFieldValue (
TargetClass.class, "STATIC_MATH", double.class
);
System.out.printf (format, "STATIC_MATH", staticMath);
}
//
/**
* Prints the names and values of instance fields of this class accessed
* by the test method.
*/
@AfterReturning(marker = BytecodeMarker.class, args = "GETFIELD", scope = "TargetClass.printInstanceFields", order = 0)
public static void printInstanceFieldsRead (final FieldAccessStaticContext fasc, final DynamicContext dc) {
if ("ch/usi/dag/disl/test/suite/dynamiccontext/app/TargetClass".equals (fasc.getOwnerInternalName ())) {
System.out.printf ("disl: %s=%s\n", fasc.getName (), dc.getInstanceFieldValue (
dc.getThis (), fasc.getOwnerInternalName (), fasc.getName (), fasc.getDescriptor (), Object.class
));
}
}
/**
* Prints the names and values of selected instance fields of this class.
*/
@AfterReturning(marker = BodyMarker.class, scope = "TargetClass.printInstanceFields", order = 1)
public static void printSpecificInstanceFieldsTedious (final DynamicContext dc) {
final String format = "disl: tedious %s=%s\n";
final Class <?> instType = dc.getInstanceFieldValue (
dc.getThis (),
"ch/usi/dag/disl/test/suite/dynamiccontext/app/TargetClass",
"instType", "Ljava/lang/Class;", Class.class
);
System.out.printf (format, "instType", instType);
//
final String instName = dc.getInstanceFieldValue (
dc.getThis (),
"ch/usi/dag/disl/test/suite/dynamiccontext/app/TargetClass",
"instName", "Ljava/lang/String;", String.class
);
System.out.printf (format, "instName", instName);
//
final int instRand = dc.getInstanceFieldValue (
dc.getThis (),
"ch/usi/dag/disl/test/suite/dynamiccontext/app/TargetClass",
"instRand", "I", int.class
);
System.out.printf (format, "instRand", instRand);
//
final double instMath= dc.getInstanceFieldValue (
dc.getThis (),
"ch/usi/dag/disl/test/suite/dynamiccontext/app/TargetClass",
"instMath", "D", double.class
);
System.out.printf (format, "instMath", instMath);
}
/**
* Prints the names and values of selected instance fields of this class.
*/
@AfterReturning(marker = BodyMarker.class, scope = "TargetClass.printInstanceFields", order = 2)
public static void printSpecificInstanceFieldsConcise (final DynamicContext dc) {
final String format = "disl: concise %s=%s\n";
final Class <?> instType = dc.getInstanceFieldValue (
dc.getThis (), TargetClass.class, "instType", Class.class
);
System.out.printf (format, "instType", instType);
//
final String instName = dc.getInstanceFieldValue (
dc.getThis (), TargetClass.class, "instName", String.class
);
System.out.printf (format, "instName", instName);
//
final int instRand = dc.getInstanceFieldValue (
dc.getThis (), TargetClass.class, "instRand", int.class
);
System.out.printf (format, "instRand", instRand);
//
final double instMath= dc.getInstanceFieldValue (
dc.getThis (), TargetClass.class, "instMath", double.class
);
System.out.printf (format, "instMath", instMath);
}
}
package ch.usi.dag.disl.test.suite.dynamiccontext.junit;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import ch.usi.dag.disl.test.utils.ClientServerRunner;
@RunWith(JUnit4.class)
public class DynamicContextTest {
ClientServerRunner r = new ClientServerRunner(this.getClass());
@Test
public void test()
throws Exception {
r.start();
r.waitFor();
r.assertIsFinished();
if(Boolean.parseBoolean(System.getProperty("disl.test.verbose"))) { r.destroyIfRunningAndFlushOutputs(); }
r.assertIsSuccessful();
r.assertClientOut("client.out.resource");
r.assertClientErrNull();
r.assertServerOutNull();
r.assertServerErrNull();
}
@After
public void cleanup() {
r.destroy();
}
}
disl: STATIC_TYPE=class ch.usi.dag.disl.test.suite.dynamiccontext.app.TargetClass
app: STATIC_TYPE=class ch.usi.dag.disl.test.suite.dynamiccontext.app.TargetClass
disl: STATIC_NAME=TargetClass
app: STATIC_NAME=TargetClass
disl: STATIC_RAND=-1170105035
app: STATIC_RAND=-1170105035
disl: STATIC_MATH=23.140692632779263
app: STATIC_MATH=23.140692632779263
disl: tedious STATIC_TYPE=class ch.usi.dag.disl.test.suite.dynamiccontext.app.TargetClass
disl: tedious STATIC_NAME=TargetClass
disl: tedious STATIC_RAND=-1170105035
disl: tedious STATIC_MATH=23.140692632779263
disl: concise STATIC_TYPE=class ch.usi.dag.disl.test.suite.dynamiccontext.app.TargetClass
disl: concise STATIC_NAME=TargetClass
disl: concise STATIC_RAND=-1170105035
disl: concise STATIC_MATH=23.140692632779263
disl: instType=class ch.usi.dag.disl.test.suite.dynamiccontext.app.TargetClass
app: instType=class ch.usi.dag.disl.test.suite.dynamiccontext.app.TargetClass
disl: instName=TargetClass
app: instName=TargetClass
disl: instRand=-1170105035
app: instRand=-1170105035
disl: instMath=22.45915771836104
app: instMath=22.45915771836104
disl: tedious instType=class ch.usi.dag.disl.test.suite.dynamiccontext.app.TargetClass
disl: tedious instName=TargetClass
disl: tedious instRand=-1170105035
disl: tedious instMath=22.45915771836104
disl: concise instType=class ch.usi.dag.disl.test.suite.dynamiccontext.app.TargetClass
disl: concise instName=TargetClass
disl: concise instRand=-1170105035
disl: concise instMath=22.45915771836104
package ch.usi.dag.disl.dynamiccontext;
import ch.usi.dag.disl.annotation.After;
import ch.usi.dag.disl.annotation.AfterThrowing;
import ch.usi.dag.disl.staticcontext.FieldAccessStaticContext;
/**
* <p>
* Provides access to dynamic information available at runtime at the location
* where the snippet is inlined.
*
* <p>
* <ul>
* <li>{@link #getThis()}</li>
* <li>{@link #getException()}</li>
* <li>{@link #getStackValue(int, Class)}</li>
* <li>{@link #getMethodArgumentValue(int, Class)}</li>
* <li>{@link #getLocalVariableValue(int, Class)}</li>
* </ul>
* Provides access to dynamic information available to a snippet at runtime.
* This includes the {@code this} reference, exceptions being caught in a catch
* block, values on the operand stack, method arguments, local variables, and
* static and instance fields.
*/
public interface DynamicContext {
/**
* <p>
* Returns {@code this} reference to snippets inlined in an instance method,
* {@code null} for snippets inlined in a static method.
*/
Object getThis();
Object getThis ();
/**
* <p>
* Returns the exception reference to snippets inlined in the @After or the @AfterThrowing
* context, {@code null} otherwise.
* Returns the exception reference to snippets inlined in the {@link After}
* the {@link AfterThrowing} context, {@code null} otherwise.
*/
Throwable getException();
Throwable getException ();
/**
* <p>
* Returns the value of a particular item on the JVM operand stack.
*
* <p>
* <b>Note:</b> Each item index corresponds to one operand on the stack.
* Both primitive and wide values are considered to be a single item, i.e.,
* the index of the corresponding stack slot is determined automatically.
*
* @param itemIndex
* <p>
* index of the item on the operand stack, must be positive and
* not exceed the number of items on the stack. Index {@code 0}
* refers to an item at the top of the stack.
* index of the item on the operand stack, must be positive and not
* exceed the number of items on the stack. Index {@code 0} refers to
* an item at the top of the stack.
* @param valueType
* <p>
* the expected type of the accessed value. Primitive types are
* boxed into corresponding reference types.
* @return
* <p>
* The value of the selected stack item. Primitive types are boxed
* the expected type of the accessed value. Primitive types are boxed
* into corresponding reference types.
* @return The value of the selected stack item. Primitive types are boxed
* into corresponding reference types.
*/
<T> T getStackValue(int itemIndex, Class<T> valueType);
<T> T getStackValue (int itemIndex, Class <T> valueType);
/**
* <p>
* Returns the value of a particular method argument.
*
* <p>
* <b>Note:</b> Each argument index corresponds to one method argument, be
* it primitive or wide, i.e., the index of the corresponding local variable
* slot is determined automatically.
*
* @param argumentIndex
* <p>
* index of the desired method argument, must be positive and not
* exceed the number of method arguments. Index {@code 0} refers
* to the first argument.
* index of the desired method argument, must be positive and not
* exceed the number of method arguments. Index {@code 0} refers to
* the first argument.
* @param valueType
* <p>
* the expected type of the accessed value.
* @return
* <p>
* The value of the selected method argument. Primitive types are
* the expected type of the accessed value.
* @return The value of the selected method argument. Primitive types are
* boxed into corresponding reference types.
*/
<T> T getMethodArgumentValue(int argumentIndex, Class<T> valueType);
<T> T getMethodArgumentValue (int argumentIndex, Class <T> valueType);
/**
* <p>
* Returns the value of a local variable occupying a particular local
* variable slot (or two slots, in case of wide types such as long and
* double).
*
* <p>
* <b>Note:</b> Each slot index corresponds to one local variable slot. The
* value of wide values is obtained from two consecutive local variable
* slots, starting with the given slot index.
*
* @param slotIndex
* <p>
* index of the desired local variable slot, must be positive and
* not exceed the number of local variable slots. Index {@code 0}
* refers to the first local variable slot.
* index of the desired local variable slot, must be positive and not
* exceed the number of local variable slots. Index {@code 0} refers
* to the first local variable slot.
* @param valueType
* <p>
* the expected type of the accessed value.
* @return
* <p>
* The value of the selected local variable slot. Primitive types
* the expected type of the accessed value.
* @return The value of the selected local variable slot. Primitive types
* are boxed into corresponding reference types.
*/
<T> T getLocalVariableValue(int slotIndex, Class<T> valueType);
// TODO enable when properly implemented
// <T> T getStaticFieldValue (
// String ownerClass,
// String fieldName, String fieldDesc, Class<T> fieldType
// );
// <T> T getInstanceFieldValue (
// Object instance, String ownerClass,
// String fieldName, String fieldDesc, Class<T> fieldType
// );
<T> T getLocalVariableValue (int slotIndex, Class <T> valueType);
/**
* Returns the value of a given static field in a given class. This method
* is intended for accessing fields of known types in known classes.
*
* @param ownerType
* the owner type class literal.
* @param fieldName
* the name of the field to read.
* @param fieldType
* the field type class literal.
* @return The value of the given static field. Primitive types are boxed
* into corresponding value types.
*/
<T> T getStaticFieldValue (
Class <?> ownerType, String fieldName, Class <T> fieldType
);
/**
* Returns the value of a given static field in a given class. This method
* is intended for accessing unknown fields in unknown classes, typically
* using a {@link FieldAccessStaticContext} when intercepting field
* accesses.
*
* @param ownerName
* the internal name of the owner class.
* @param fieldName
* the name of the field to read.
* @param fieldDesc
* the type descriptor of the field.
* @param valueType
* the expected type of the accessed value. This should be a
* superclass of the type described by the field descriptor. In case
* of primitive types, a superclass of the corresponding value type
* is allowed.
* @return The value of the given static field. Primitive types are boxed
* into corresponding value types.
*/
<T> T getStaticFieldValue (
String ownerName,
String fieldName, String fieldDesc, Class <T> valueType
);
<T> T getInstanceFieldValue (
Object instance, Class <?> ownerType,
String fieldName, Class <T> fieldType
);
/**
* Returns the value of a given instance field in a given object.
*
* @param instance
* the instance of the owner class to read the field value from.
* @param ownerClass
* the internal name of the owner class.
* @param fieldName
* the name of the field to read.
* @param fieldDesc
* the type descriptor of the field.
* @param valueType
* the expected type of the accessed value. This should be a
* superclass of the type described by the field descriptor. In case
* of primitive types, a superclass of the corresponding value type
* is allowed.
* @return The value of the given static field. Primitive types are boxed
* into corresponding value types.
*/
<T> T getInstanceFieldValue (
Object instance, String ownerClass,
String fieldName, String fieldDesc, Class <T> valueType
);
}
This diff is collapsed.
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