Commit edf4cb2c authored by Lukáš Marek's avatar Lukáš Marek

Dispatch test working

parent a016d51c
......@@ -59,7 +59,7 @@
</javac>
</target>
<target name="compile-test" depends="compile-disl">
<target name="compile-test" depends="compile-disl,compile-dislre-server,compile-dislre-dispatch">
<javac srcdir="${src.test}" destdir="bin" debug="true" includeAntRuntime="false">
<classpath refid="buildpath" />
</javac>
......
......@@ -39,6 +39,7 @@ static int connection = 0;
// closing connection
static const jint MSG_CLOSE = 0;
static const jint MSG_ANALYZE = 1;
// TODO unify in header - helper
// ******************* Helper routines *******************
......@@ -422,7 +423,13 @@ static void JNICALL jvmti_callback_class_file_load_hook( jvmtiEnv *jvmti_env,
static void JNICALL jvmti_callback_class_vm_death_hook(jvmtiEnv *jvmti_env, JNIEnv* jni_env) {
close_connection(connection);
enter_critical_section(jvmti_env, global_lock);
{
close_connection(connection);
}
exit_critical_section(jvmti_env, global_lock);
}
// ******************* JVMTI entry method *******************
......@@ -488,12 +495,99 @@ JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved)
return 0;
}
// ******************* REDispatch helper methods *******************
// TODO if you add buffer as param it can server for other functions also
void send_int(jint to_send) {
// TODO should go to the buffer
jint nts = htonl(to_send);
send_data(connection, &nts, sizeof(jint));
}
void analysis_start(jint analysis_method_id) {
// TODO should go to the buffer
// send analysis msg
send_int(MSG_ANALYZE);
// send method id
send_int(analysis_method_id);
}
void analysis_end() {
// TODO should send the buffer with critical section
}
// ******************* REDispatch methods *******************
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_analyse
(JNIEnv * jni_env, jclass this_class, jint objID, jint methodID, jobjectArray args) {
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_analysisStart
(JNIEnv * jni_env, jclass this_class, jint analysis_method_id) {
// TODO create send method for each basic type
printf("I'm here\n");
analysis_start(analysis_method_id);
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_analysisEnd
(JNIEnv * jni_env, jclass this_class) {
analysis_end();
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendBoolean
(JNIEnv * jni_env, jclass this_class, jboolean to_send) {
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendByte
(JNIEnv * jni_env, jclass this_class, jbyte to_send) {
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendChar
(JNIEnv * jni_env, jclass this_class, jchar to_send) {
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendShort
(JNIEnv * jni_env, jclass this_class, jshort to_send) {
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendInt
(JNIEnv * jni_env, jclass this_class, jint to_send) {
send_int(to_send);
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendLong
(JNIEnv * jni_env, jclass this_class, jlong to_send) {
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendFloat
(JNIEnv * jni_env, jclass this_class, jfloat to_send) {
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendDouble
(JNIEnv * jni_env, jclass this_class, jdouble to_send) {
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendString
(JNIEnv * jni_env, jclass this_class, jstring to_send) {
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendObject
(JNIEnv * jni_env, jclass this_class, jobject to_send) {
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendClass
(JNIEnv * jni_env, jclass this_class, jclass to_send) {
}
......@@ -20,11 +20,107 @@ extern "C" {
#endif
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: analyse
* Signature: (II[Ljava/lang/Object;)V
* Method: analysisStart
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_analyse
(JNIEnv *, jclass, jint, jint, jobjectArray);
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_analysisStart
(JNIEnv *, jclass, jint);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: analysisEnd
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_analysisEnd
(JNIEnv *, jclass);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendBoolean
* Signature: (Z)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendBoolean
(JNIEnv *, jclass, jboolean);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendByte
* Signature: (B)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendByte
(JNIEnv *, jclass, jbyte);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendChar
* Signature: (C)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendChar
(JNIEnv *, jclass, jchar);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendShort
* Signature: (S)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendShort
(JNIEnv *, jclass, jshort);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendInt
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendInt
(JNIEnv *, jclass, jint);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendLong
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendLong
(JNIEnv *, jclass, jlong);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendFloat
* Signature: (F)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendFloat
(JNIEnv *, jclass, jfloat);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendDouble
* Signature: (D)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendDouble
(JNIEnv *, jclass, jdouble);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendString
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendString
(JNIEnv *, jclass, jstring);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendObject
* Signature: (Ljava/lang/Object;)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendObject
(JNIEnv *, jclass, jobject);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendClass
* Signature: (Ljava/lang/Class;)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendClass
(JNIEnv *, jclass, jclass);
#ifdef __cplusplus
}
......
......@@ -2,13 +2,30 @@ package ch.usi.dag.dislre;
public class REDispatch {
// TODO remove
public static native void analyse(int analysisID, int methodID, Object ... args);
// TODO uncomment
/*
public static native void analyse(int analysisID, int methodID);
// TODO all basic types in jni
/**
* Announce start of an analysis transmission
*
* @param analysisID remote analysis id
* @param methodID remote method id
*/
// TODO re - allow strings with remote string cache support?
public static native void analysisStart(int analysisMethodID);
/**
* Announce end of an analysis transmission
*/
public static native void analysisEnd();
// allows transmitting types
public static native void sendBoolean(boolean booleanToSend);
public static native void sendByte(byte byteToSend);
public static native void sendChar(char charToSend);
public static native void sendShort(short shortToSend);
public static native void sendInt(int intToSend);
*/
public static native void sendLong(long longToSend);
public static native void sendFloat(float floatToSend);
public static native void sendDouble(double doubleToSend);
public static native void sendString(String stringToSend);
public static native void sendObject(Object objToSend);
public static native void sendClass(Class<?> classToSend);
}
package ch.usi.dag.dislreserver.msg.analyze;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
import ch.usi.dag.dislreserver.DiSLREServerException;
import ch.usi.dag.dislreserver.msg.analyze.AnalysisResolver.AnalysisMethodHolder;
import ch.usi.dag.dislreserver.objectid.InvalidClass;
import ch.usi.dag.dislreserver.objectid.ObjectId;
import ch.usi.dag.dislreserver.reqdispatch.RequestHandler;
public class AnalysisHandler implements RequestHandler {
public void handle(DataInputStream is, DataOutputStream os, boolean debug)
throws DiSLREServerException {
try {
// *** retrieve method ***
// read method id from network
int analysisMethodId = is.readInt();
// retrieve method
AnalysisMethodHolder amh = AnalysisResolver.getMethod(analysisMethodId);
if(debug) {
System.out.println("Processing analysis "
+ amh.getAnalysisInstance().getClass().getName()
+ "."
+ amh.getAnalysisMethod().getName()
+ "()");
}
// *** retrieve method argument values ***
Method analysisMethod = amh.getAnalysisMethod();
// prepare argument value list
List<Object> args = new LinkedList<Object>();
// read data according to argument types
for(Class<?> argClass : analysisMethod.getParameterTypes()) {
Object argValue = readType(is, argClass);
if(argValue == null) {
throw new DiSLREServerException(
"Unsupported data type "
+ argClass.toString()
+ " in analysis method "
+ analysisMethod.getDeclaringClass().toString()
+ "."
+ analysisMethod.toString());
}
args.add(argValue);
}
// *** invoke method ***
analysisMethod.invoke(amh.getAnalysisInstance(), args.toArray());
} catch (IOException e) {
throw new DiSLREServerException(e);
} catch (IllegalAccessException e) {
throw new DiSLREServerException(e);
} catch (IllegalArgumentException e) {
throw new DiSLREServerException(e);
} catch (InvocationTargetException e) {
throw new DiSLREServerException(e);
}
}
private Object readType(DataInputStream is, Class<?> argClass)
throws IOException {
if(argClass.equals(boolean.class)) {
return is.readBoolean();
}
if(argClass.equals(char.class)) {
return is.readChar();
}
if(argClass.equals(byte.class)) {
return is.readByte();
}
if(argClass.equals(short.class)) {
return is.readShort();
}
if(argClass.equals(int.class)) {
return is.readInt();
}
if(argClass.equals(long.class)) {
return is.readLong();
}
if(argClass.equals(float.class)) {
return is.readFloat();
}
if(argClass.equals(double.class)) {
return is.readDouble();
}
// read string
if(argClass.equals(String.class)) {
// read the length of the string
int stringLength = is.readInt();
// read the string bytes
byte byteBuffer[] = new byte[stringLength];
is.readFully(byteBuffer);
// return string
return new String(byteBuffer);
}
// read id only
if(argClass.equals(Object.class)) {
return new ObjectId(is.readInt());
}
// return "invalid" class object
if(argClass.equals(Class.class)) {
return InvalidClass.class;
}
return null;
}
}
package ch.usi.dag.dislreserver.msg.analyze;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import ch.usi.dag.disl.test.dispatch.CodeExecuted;
import ch.usi.dag.dislreserver.remoteanalysis.RemoteAnalysis;
public class AnalysisResolver {
private static final Map<Integer, AnalysisMethodHolder> methodMap =
new HashMap<Integer, AnalysisMethodHolder>();
private static final Set<RemoteAnalysis> analysisSet =
new HashSet<RemoteAnalysis>();
public static class AnalysisMethodHolder {
RemoteAnalysis analysisInstance;
Method analysisMethod;
public AnalysisMethodHolder(RemoteAnalysis analysisInstance,
Method analysisMethod) {
super();
this.analysisInstance = analysisInstance;
this.analysisMethod = analysisMethod;
}
public RemoteAnalysis getAnalysisInstance() {
return analysisInstance;
}
public Method getAnalysisMethod() {
return analysisMethod;
}
}
public static AnalysisMethodHolder getMethod(int methodId) {
AnalysisMethodHolder result = methodMap.get(methodId);
if(result == null) {
// TODO re - different except
throw new RuntimeException("Unknow method id");
}
return result;
}
public static Set<RemoteAnalysis> getAllAnalyses() {
return analysisSet;
}
public static void registerMethod(int methodId,
AnalysisMethodHolder analysisMethod) {
// register method
methodMap.put(methodId, analysisMethod);
// register analysis instance
analysisSet.add(analysisMethod.getAnalysisInstance());
}
static {
// TODO re - should not be hardcoded
try {
Method m = CodeExecuted.class.getMethod("bytecodesExecuted", int.class);
Object i = CodeExecuted.class.newInstance();
registerMethod(1, new AnalysisMethodHolder((RemoteAnalysis)i, m));
} catch (Exception e) {
e.printStackTrace();
}
}
}
......@@ -2,13 +2,22 @@ package ch.usi.dag.dislreserver.msg.close;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.util.Set;
import ch.usi.dag.dislreserver.msg.analyze.AnalysisResolver;
import ch.usi.dag.dislreserver.remoteanalysis.RemoteAnalysis;
import ch.usi.dag.dislreserver.reqdispatch.RequestHandler;
public class CloseHandler implements RequestHandler {
public void handle(DataInputStream is, DataOutputStream os, boolean debug) {
// Nothing to do
// invoke all atExit on registered analyses
Set<RemoteAnalysis> raSet = AnalysisResolver.getAllAnalyses();
for(RemoteAnalysis ra : raSet) {
ra.atExit();
}
}
}
package ch.usi.dag.dislreserver.objectid;
public abstract class InvalidClass {
}
package ch.usi.dag.dislreserver.objectid;
public class ObjectId {
int id;
public ObjectId(int id) {
super();
this.id = id;
}
public int getId() {
return id;
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ObjectId other = (ObjectId) obj;
if (id != other.id)
return false;
return true;
}
}
package ch.usi.dag.dislreserver.remoteanalysis;
/**
* Each analysis evaluated remotely have to implement this interface.
*
* The method arguments can be only basic types, String, Object and Class.
* See additional restrictions below.
*
* There is a special handling for class literals. If the class literal should
* be transmitted for evaluation, then the analysis method has to contain
* int argument after Class argument representing class id.
*
* On the server, the Class argument will contain InvalidClass.class and the
* class id argument will hold proper id value.
*
* On the client, the int argument should not be transmitted (should be ignored).
* Valid only in the case, that transmission is done manually.
*
* Object argument on the client will contain ObjectId instnace.
*/
public abstract class RemoteAnalysis {
public abstract void atExit();
}
......@@ -6,6 +6,7 @@ import java.util.HashMap;
import java.util.Map;
import ch.usi.dag.dislreserver.DiSLREServerException;
import ch.usi.dag.dislreserver.msg.analyze.AnalysisHandler;
import ch.usi.dag.dislreserver.msg.close.CloseHandler;
public class RequestDispatcher {
......@@ -19,7 +20,8 @@ public class RequestDispatcher {
// close
requestMap.put(0, new CloseHandler());
// TODO analysis eval
// analyze
requestMap.put(1, new AnalysisHandler());
}
public static boolean dispatch(int requestNo, DataInputStream is,
......@@ -28,6 +30,10 @@ public class RequestDispatcher {
// request handler
RequestHandler rh = requestMap.get(requestNo);
if(debug) {
System.out.println("Dispatching " + rh.getClass().getName());
}
// process request
rh.handle(is, os, debug);
......
package ch.usi.dag.disl.test.dispatch;
import ch.usi.dag.dislreserver.remoteanalysis.RemoteAnalysis;
// NOTE that this class is not static anymore
public class CodeExecuted extends RemoteAnalysis {
long totalExecutedBytecodes = 0;
public void bytecodesExecuted(int count) {
totalExecutedBytecodes += count;
}
public void atExit() {
System.out.println("Total number of executed bytecodes: "
+ totalExecutedBytecodes);
}
}
package ch.usi.dag.disl.test.dispatch;
import ch.usi.dag.dislre.REDispatch;
// Optimally, this class is automatically created on analysis machine
// and redefines during loading the CodeExecuted class on the client vm
// Even more optimally, this is automatically generated native class with same
// functionality
public class CodeExecutedRE {
public static void bytecodesExecuted(int count) {
REDispatch.analysisStart(1);
REDispatch.sendInt(count);
REDispatch.analysisEnd();
}
}