Commit 5c376d0e authored by Lubomir Bulej's avatar Lubomir Bulej

NetReferenceHelper: add getUniqueId() method that will return a net reference...

NetReferenceHelper: add getUniqueId() method that will return a net reference with the special payload bit masked.
ShadowObject: add (package private) getUniqueId() method.
ShadowObject: add (package private) isSpecial() method.
ShadowObject, ShadowClass: move (package private) getClassId() method from ShadowClass to ShadowObject.
ShadowObject: remove the getNetRef() method to (sort of) keep a lid on the raw net reference.
ShadowObject: test equality using getUniqueId() instead of raw net reference, so that objects with the same it but one containing special payload are considered equal.
ShadowObjectTable: only call updateFrom() on an existing object when the other object is "special", i.e., it contains special payload.
ShadowClassTable: avoid using net reference directly, use isSpecial() and getClassId() on the shadow object.
parent 294bf36d
......@@ -21,13 +21,19 @@ final class NetReferenceHelper {
private static final long CBIT_MASK = (1L << 1) - 1;
/**
* 1-bit special flag at bit 63 (used internally in the agent).
* 1-bit special payload flag at bit 63. Indicates that the object has
* extra payload attached.
*/
private static final short SPEC_POS = 63;
private static final long SPEC_MASK = (1L << 1) - 1;
//
static long getUniqueId (final long netReference) {
return netReference & ~SPEC_MASK;
}
static long getObjectId (final long netReference) {
return __bits (netReference, OBJECT_ID_POS, OBJECT_ID_MASK);
}
......
......@@ -42,12 +42,6 @@ public abstract class ShadowClass extends ShadowObject {
//
// No need to expose the interface to user. getId() should be sufficient
protected final int _classId () {
return NetReferenceHelper.getClassId (getNetRef ());
}
protected final Type _type () {
return __type;
}
......@@ -92,7 +86,7 @@ public abstract class ShadowClass extends ShadowObject {
// Use the 22 bits of the class identifier padded with 10 bits of the
// class loader object identifier.
//
return (_classId () << 22) ^ (int) (__classLoaderId () & ((1 << 10) - 1));
return (getClassId () << 22) ^ (int) (__classLoaderId () & ((1 << 10) - 1));
}
......
......@@ -206,10 +206,8 @@ public final class ShadowClassTable {
static void freeShadowObject (final ShadowObject object) {
final long netReference = object.getNetRef ();
if (NetReferenceHelper.isClassInstance (netReference)) {
final int classId = NetReferenceHelper.getClassId (netReference);
shadowClasses.remove (classId);
if (object.isClassInstance ()) {
shadowClasses.remove (object.getClassId ());
} else if (classLoaderMap.containsKey (object)) {
classLoaderMap.remove (object);
......
......@@ -30,11 +30,30 @@ public class ShadowObject implements Formattable {
}
//
// These methods are meant to be only used internally, so that we avoid
// exposing the net reference.
//
final long getUniqueId () {
return NetReferenceHelper.getUniqueId (__netReference);
}
final int getClassId () {
return NetReferenceHelper.getClassId (__netReference);
}
final long getNetRef () {
return __netReference;
final boolean isClassInstance () {
return NetReferenceHelper.isClassInstance (__netReference);
}
final boolean isSpecial () {
return NetReferenceHelper.isSpecial (__netReference);
}
//
public final long getId () {
return NetReferenceHelper.getObjectId (__netReference);
......@@ -150,12 +169,15 @@ public class ShadowObject implements Formattable {
private boolean __equals (final ShadowObject other) {
//
// The equality of shadow objects should be based purely on
// the equality of the net reference. The value of some special
// shadow objects can be updated lazily, so we should not really
// compare the values.
// The equality of shadow objects should be based purely on the equality of
// the net reference, without taking into account the special bit which
// indicates whether the object has been sent with additional data.
//
// The value of some special shadow objects can be updated lazily, so we
// should not really compare their values unless we can make sure that
// the comparison makes sense at all times.
//
return this.__netReference == other.__netReference;
return this.getUniqueId () == other.getUniqueId ();
}
//
......@@ -163,7 +185,9 @@ public class ShadowObject implements Formattable {
final void updateFrom (final ShadowObject other) {
//
// When updating value from another shadow object, the net reference
// of this and the other object must be the same.
// of this and the other object (without the special bit) must be the same.
// The other object must have the SPECIAL bit set (this is checked by the
// caller of this method).
//
if (this.__equals (other)) {
_updateFrom (other);
......@@ -178,10 +202,12 @@ public class ShadowObject implements Formattable {
/**
* This method is intended to be override by the subclasses to implement
* updating of a shadow object's state. The caller of this method guarantees
* that the net reference of the object to update from will be the same
* as the net reference of this shadow object.
* This method is intended to be overriden by subclasses to update shadow
* object's internal values. The caller of this method guarantees that the
* unique id part of the net reference of the object to update from will be
* the same as that of this shadow object. In addition, the other object
* will have the special bit of the net reference set, indicating that it
* contains additional payload specific to that object.
*
* @param object
* the {@link ShadowObject} instance to update from.
......
......@@ -34,7 +34,7 @@ public final class ShadowObjectTable {
final long objectId = object.getId ();
final ShadowObject existing = shadowObjects.putIfAbsent (objectId, object);
if (existing != null) {
if (existing != null && object.isSpecial ()) {
if (__log.traceIsLoggable ()) {
__log.trace ("updating shadow object 0x%x", objectId);
}
......
package ch.usi.dag.disl.test.suite.sendspecial.app;
import ch.usi.dag.dislre.REDispatch;
public class TargetClass {
private static short __stringEventId__ = REDispatch.registerMethod (
"ch.usi.dag.disl.test.suite.sendspecial.instr.Analysis.stringEvent"
);
static void sendString (final boolean isSpecial, final String string) {
REDispatch.analysisStart (__stringEventId__);
__sendObject (isSpecial, string);
REDispatch.analysisEnd ();
}
//
private static short __threadEventId__ = REDispatch.registerMethod (
"ch.usi.dag.disl.test.suite.sendspecial.instr.Analysis.threadEvent"
);
static void sendThread (final boolean isSpecial, final Thread thread) {
REDispatch.analysisStart (__threadEventId__);
__sendObject (isSpecial, thread);
REDispatch.analysisEnd ();
}
//
private static void __sendObject (final boolean isSpecial, final Object object) {
REDispatch.sendBoolean (isSpecial);
if (isSpecial) {
REDispatch.sendObjectPlusData (object);
} else {
REDispatch.sendObject (object);
}
}
//
public static void main (final String [] args) throws InterruptedException {
final String string = "Hello, World!";
sendString (false, string);
sendString (true, string);
final Thread thread = new Thread ("Newly Thread");
sendThread (false, thread);
sendThread (true, thread);
}
}
package ch.usi.dag.disl.test.suite.sendspecial.instr;
import ch.usi.dag.dislreserver.remoteanalysis.RemoteAnalysis;
import ch.usi.dag.dislreserver.shadow.ShadowObject;
import ch.usi.dag.dislreserver.shadow.ShadowString;
import ch.usi.dag.dislreserver.shadow.ShadowThread;
public class Analysis extends RemoteAnalysis {
public void threadEvent (final boolean isSpecial, final ShadowThread thread) {
System.out.printf ("thread, is special: %s, name: %s, daemon: %s\n", isSpecial, thread.getName (), thread.isDaemon ());
}
public void stringEvent (final boolean isSpecial, final ShadowString string) {
System.out.printf ("string, is special: %s, value: %s\n", isSpecial, string.toString ());
}
@Override
public void atExit () {
// do nothing
}
@Override
public void objectFree (final ShadowObject netRef) {
// do nothing
}
}
package ch.usi.dag.disl.test.suite.sendspecial.junit;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import ch.usi.dag.disl.test.suite.ShadowVmOnlyTest;
@RunWith (JUnit4.class)
public class SendSpecialTest extends ShadowVmOnlyTest {
}
string, is special: false, value: Hello, World!
string, is special: true, value: Hello, World!
thread, is special: false, name: Newly Thread, daemon: false
thread, is special: true, name: Newly Thread, daemon: false
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