Commit 3556f0a1 authored by Lukáš Marek's avatar Lukáš Marek

REDispatch now supports sending objects with or without additional data

Improved sendig of additional data for String and Thread
Fixed and improved dispatch test
parent 48ece151
......@@ -46,12 +46,6 @@ static int jvm_started = FALSE;
static volatile int no_tagging_work = FALSE;
static volatile int no_sending_work = FALSE;
// *** Accessed only by sending thread ***
// communication connection socket descriptor
// access must be protected by monitor
static int connection = 0;
// *** Sync queues ***
// !!! There should be enough buffers for initial class loading
......@@ -79,8 +73,7 @@ typedef struct {
static process_buffs pb_list[BQ_BUFFERS];
#define OT_OBJECT 1
#define OT_STRING 2
#define OT_CLASS 3
#define OT_DATA_OBJECT 2
typedef struct {
unsigned char obj_type;
......@@ -394,41 +387,17 @@ static void _fill_ot_rec(JNIEnv * jni_env, buffer * cmd_buff,
}
static void pack_object(JNIEnv * jni_env, buffer * buff, buffer * cmd_buff,
jobject to_send) {
// create entry for object tagging thread that will replace the null ref
if(to_send != NULL) {
_fill_ot_rec(jni_env, cmd_buff, OT_OBJECT, buff, to_send);
}
// pack null net reference
pack_long(buff, NULL_NET_REF);
}
static void pack_string_java(JNIEnv * jni_env, buffer * buff, buffer * cmd_buff,
jstring to_send) {
jobject to_send, unsigned char object_type) {
// create entry for object tagging thread that will replace the null ref
if(to_send != NULL) {
_fill_ot_rec(jni_env, cmd_buff, OT_STRING, buff, to_send);
_fill_ot_rec(jni_env, cmd_buff, object_type, buff, to_send);
}
// pack null net reference
pack_long(buff, NULL_NET_REF);
}
static void pack_class(JNIEnv * jni_env, buffer * buff, buffer * cmd_buff,
jclass to_send) {
// create entry for object tagging thread that will replace the null ref
if(to_send != NULL) {
_fill_ot_rec(jni_env, cmd_buff, OT_CLASS, buff, to_send);
}
// pack null class id
pack_long(buff, NULL_NET_REF);
}
static void buff_put_short(buffer * buff, size_t buff_pos, jshort to_put) {
// put the short at the position in network order
jshort nts = htons(to_put);
......@@ -489,8 +458,9 @@ static jshort register_method(
// new id for analysis method
pack_short(buff, new_analysis_id);
// method descriptor
// uses string case and additional message for string - bit unoptimized
pack_string_java(jni_env, buff, buffs->command_buff, analysis_method_desc);
// sends string as object with additional data - bit unoptimized but works
pack_object(jni_env, buff, buffs->command_buff, analysis_method_desc,
OT_DATA_OBJECT);
// send message
buffs_objtag(buffs);
......@@ -791,7 +761,10 @@ static void analysis_end(struct tldata * tld) {
// TODO add cache - ??
static void ot_pack_string_cache(JNIEnv * jni_env, buffer * buff,
static jclass THREAD_CLASS = NULL;
static jclass STRING_CLASS = NULL;
static void ot_pack_string_data(JNIEnv * jni_env, buffer * buff,
jstring to_send, jlong str_net_ref) {
// get string length
......@@ -818,45 +791,79 @@ static void ot_pack_string_cache(JNIEnv * jni_env, buffer * buff,
(*jni_env)->ReleaseStringUTFChars(jni_env, to_send, str);
}
static void ot_tag_object(JNIEnv * jni_env, buffer * buff, size_t buff_pos,
jobject to_send, buffer * new_objs_buff) {
static void ot_pack_thread_data(JNIEnv * jni_env, buffer * buff,
jstring to_send, jlong thr_net_ref) {
jvmtiThreadInfo info;
jvmtiError error = (*jvmti_env)->GetThreadInfo(jvmti_env, to_send, &info);
check_error(error != JVMTI_ERROR_NONE, "Cannot get tread info");
// get net reference and put it on proper position
buff_put_long(buff, buff_pos,
get_net_reference(jni_env, jvmti_env, new_objs_buff, to_send));
// pack thread info message
// msg id
pack_byte(buff, MSG_THREAD_INFO);
// thread object id
pack_long(buff, thr_net_ref);
// thread name
pack_string_utf8(buff, info.name, strlen(info.name));
// is daemon thread
pack_boolean(buff, info.is_daemon);
}
// NOTE: this tagging uses cache
static void ot_tag_string(JNIEnv * jni_env, buffer * buff, size_t buff_pos,
jobject to_send, buffer * new_objs_buff) {
static void update_send_status(jobject to_send, jlong * net_ref) {
jlong net_ref =
get_net_reference(jni_env, jvmti_env, new_objs_buff, to_send);
net_ref_set_spec(net_ref, TRUE);
update_net_reference(jvmti_env, to_send, *net_ref);
}
// test if the string was already sent to the server
// NOTE: we don't use lock here, so it is possible that multiple threads
// will send it, but this will not hurt (only performance)
if(net_ref_get_spec(net_ref) == FALSE) {
static void ot_pack_aditional_data(JNIEnv * jni_env, jlong * net_ref,
jobject to_send, unsigned char obj_type, buffer * new_objs_buff) {
// update the send status
net_ref_set_spec(&net_ref, TRUE);
update_net_reference(jvmti_env, to_send, net_ref);
// NOTE: we don't use lock for updating send status, so it is possible
// that multiple threads will send it, but this will hurt only performance
// add cached string to the buffer
ot_pack_string_cache(jni_env, new_objs_buff, to_send, net_ref);
// test if the data was already sent to the server
if(net_ref_get_spec(*net_ref) == TRUE) {
return;
}
buff_put_long(buff, buff_pos, net_ref);
// NOTE: Tests for class types could be done by buffering threads.
// It depends, where we want to have the load.
// String - pack data
if((*jni_env)->IsInstanceOf(jni_env, to_send, STRING_CLASS)) {
update_send_status(to_send, net_ref);
ot_pack_string_data(jni_env, new_objs_buff, to_send, *net_ref);
}
// Thread - pack data
if((*jni_env)->IsInstanceOf(jni_env, to_send, THREAD_CLASS)) {
update_send_status(to_send, net_ref);
ot_pack_thread_data(jni_env, new_objs_buff, to_send, *net_ref);
}
}
static void ot_tag_class(JNIEnv * jni_env, buffer * buff, size_t buff_pos,
jobject to_send, buffer * new_objs_buff) {
static void ot_tag_record(JNIEnv * jni_env, buffer * buff, size_t buff_pos,
jobject to_send, unsigned char obj_type, buffer * new_objs_buff) {
// get class net reference...
// get net reference
jlong net_ref =
get_net_reference(jni_env, jvmti_env, new_objs_buff, to_send);
// ... and put it on proper position
// send additional data
if(obj_type == OT_DATA_OBJECT) {
// NOTE: can update net reference (net_ref)
ot_pack_aditional_data(jni_env, &net_ref, to_send, obj_type,
new_objs_buff);
}
// update the net reference
buff_put_long(buff, buff_pos, net_ref);
}
......@@ -874,26 +881,8 @@ static void ot_tag_buff(JNIEnv * jni_env, buffer * anl_buff, buffer * cmd_buff,
buffer_read(cmd_buff, read, &ot_rec, sizeof(ot_rec));
read += sizeof(ot_rec);
// tag
switch(ot_rec.obj_type) {
case OT_OBJECT: {
ot_tag_object(jni_env, anl_buff, ot_rec.buff_pos, ot_rec.obj_to_tag,
new_objs_buff);
break;
}
case OT_STRING: {
ot_tag_string(jni_env, anl_buff, ot_rec.buff_pos, ot_rec.obj_to_tag,
new_objs_buff);
break;
}
case OT_CLASS: {
ot_tag_class(jni_env, anl_buff, ot_rec.buff_pos, ot_rec.obj_to_tag,
new_objs_buff);
break;
}
default:
check_error(TRUE, "Undefined type to pack.");
}
ot_tag_record(jni_env, anl_buff, ot_rec.buff_pos, ot_rec.obj_to_tag,
ot_rec.obj_type, new_objs_buff);
// free global reference
(*jni_env)->DeleteGlobalRef(jni_env, ot_rec.obj_to_tag);
......@@ -912,6 +901,14 @@ static void * objtag_thread_loop(void * obj) {
buffer * new_obj_buff = malloc(sizeof(buffer));
buffer_alloc(new_obj_buff);
// retrieve java types
STRING_CLASS = (*jni_env)->FindClass(jni_env, "java/lang/String");
check_error(STRING_CLASS == NULL, "String class not found");
THREAD_CLASS = (*jni_env)->FindClass(jni_env, "java/lang/Thread");
check_error(STRING_CLASS == NULL, "Thread class not found");
// exit when the jvm is terminated and there are no msg to process
while(! (no_tagging_work && bq_length(&objtag_q) == 0) ) {
......@@ -958,7 +955,7 @@ static void * objtag_thread_loop(void * obj) {
// ******************* Sending thread *******************
static void _send_buffer(buffer * b) {
static void _send_buffer(int connection, buffer * b) {
// send data
// NOTE: normally access the buffer using methods
......@@ -998,7 +995,7 @@ static void close_connection(int conn, jlong thread_id) {
pack_byte(buff, MSG_CLOSE);
// send buffer directly
_send_buffer(buff);
_send_buffer(conn, buff);
// release buffer
_buffs_release(buffs);
......@@ -1017,7 +1014,7 @@ static void attach_current_thread_to_jvm () {
}
static void * send_thread_loop(void * obj) {
connection = open_connection();
int connection = open_connection();
attach_current_thread_to_jvm ();
// exit when the jvm is terminated and there are no msg to process
......@@ -1034,9 +1031,9 @@ static void * send_thread_loop(void * obj) {
#endif
// first send command buffer - contains new class or object ids,...
_send_buffer(pb->command_buff);
_send_buffer(connection, pb->command_buff);
// send analysis buffer
_send_buffer(pb->analysis_buff);
_send_buffer(connection, pb->analysis_buff);
// release buffer
_buffs_release(pb);
......@@ -1468,7 +1465,6 @@ JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved)
&to_buff_lock);
check_jvmti_error(jvmti_env, error, "Cannot create raw monitor");
// read options (port/hostname)
parse_agent_options(options);
......@@ -1580,23 +1576,18 @@ JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendDoubleAsLong
pack_long(tld_get()->analysis_buff, to_send);
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendString
(JNIEnv * jni_env, jclass this_class, jstring to_send) {
struct tldata * tld = tld_get ();
pack_string_java(jni_env, tld->analysis_buff, tld->command_buff, to_send);
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendObject
(JNIEnv * jni_env, jclass this_class, jobject to_send) {
struct tldata * tld = tld_get ();
pack_object(jni_env, tld->analysis_buff, tld->command_buff, to_send);
pack_object(jni_env, tld->analysis_buff, tld->command_buff, to_send,
OT_OBJECT);
}
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendClass
(JNIEnv * jni_env, jclass this_class, jclass to_send) {
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendObjectPlusData
(JNIEnv * jni_env, jclass this_class, jobject to_send) {
struct tldata * tld = tld_get ();
pack_class(jni_env, tld->analysis_buff, tld->command_buff, to_send);
pack_object(jni_env, tld->analysis_buff, tld->command_buff, to_send,
OT_DATA_OBJECT);
}
......@@ -9,129 +9,6 @@ extern "C" {
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved);
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: registerMethod
* Signature: (Ljava/lang/String;)S
*/
JNIEXPORT jshort JNICALL Java_ch_usi_dag_dislre_REDispatch_registerMethod
(JNIEnv *, jclass, jstring);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: analysisStart
* Signature: (S)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_analysisStart__S
(JNIEnv *, jclass, jshort);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: analysisStart
* Signature: (SB)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_analysisStart__SB
(JNIEnv *, jclass, jshort, jbyte);
/*
* 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: sendFloatAsInt
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendFloatAsInt
(JNIEnv *, jclass, jint);
/*
* Class: ch_usi_dag_dislre_REDispatch
* Method: sendDoubleAsLong
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_ch_usi_dag_dislre_REDispatch_sendDoubleAsLong
(JNIEnv *, jclass, jlong);
/*
* 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
}
#endif
......
......@@ -22,10 +22,14 @@ static volatile jint avail_class_id;
// should be in sync with NetReference on the server
// format of net reference looks like this
// HIGHEST (1 bit spec, 23 bits class id, 40 bits object id)
// format of net reference looks like this (from HIGHEST)
// 1 bit data trans., 1 bit class instance, 23 bits class id, 40 bits object id
// bit field not used because there is no guarantee of alignment
// TODO rename SPEC
// SPEC flag is used to indicate if some additional data for this object where
// transfered to the server
static const uint8_t OBJECT_ID_POS = 0;
static const uint8_t CLASS_ID_POS = 40;
static const uint8_t CLASS_INSTANCE_POS = 62;
......@@ -141,15 +145,6 @@ static int _object_is_class(jvmtiEnv * jvmti_env, jobject obj) {
return TRUE;
}
static jvmtiError _try_get_threadinfo(jvmtiEnv * jvmti_env, jobject obj,
jvmtiThreadInfo *info_ptr) {
// TODO isn't there better way?
jvmtiError error = (*jvmti_env)->GetThreadInfo(jvmti_env, obj, info_ptr);
return error;
}
// does not increment any counter - just sets the values
static jlong _set_net_reference(jvmtiEnv * jvmti_env, jobject obj,
jlong object_id, jint class_id, unsigned char spec, unsigned char cbit) {
......@@ -193,24 +188,6 @@ static void _pack_class_info(buffer * buff, jlong class_net_ref,
}
static void _pack_thread_info(buffer * buff, jlong net_ref, const char *name,
jboolean isDaemon) {
// pack thread info message
// msg id
pack_byte(buff, MSG_THREAD_INFO);
// object id
pack_long(buff, net_ref);
// thread name
pack_string_utf8(buff, name, strlen(name));
// is daemon thread
pack_boolean(buff, isDaemon);
}
static jlong _set_net_reference_for_class(JNIEnv * jni_env,
jvmtiEnv * jvmti_env, buffer * buff, jclass klass) {
......@@ -311,14 +288,6 @@ static jlong _set_net_reference_for_object(JNIEnv * jni_env,
jlong net_ref =
_set_net_reference(jvmti_env, obj, avail_object_id, class_id, 0, 0);
jvmtiThreadInfo info;
jvmtiError error;
if ((error = _try_get_threadinfo(jvmti_env, obj, &info))
== JVMTI_ERROR_NONE) {
_pack_thread_info(buff, net_ref, info.name, info.is_daemon);
}
// increment object id counter
++avail_object_id;
......
......@@ -42,9 +42,8 @@ public class REDispatch {
public static native void sendLong(long longToSend);
public static native void sendFloatAsInt(int floatAsIntToSend);
public static native void sendDoubleAsLong(long doubleAsLongToSend);
public static native void sendString(String stringToSend);
public static native void sendObject(Object objToSend);
public static native void sendClass(Class<?> classToSend);
public static native void sendObjectPlusData(Object objToSend);
// helper methods for sending float and double
// for proper conversion, we would still need to call ...Bits methods
......
......@@ -4,6 +4,7 @@ import ch.usi.dag.dislreserver.remoteanalysis.RemoteAnalysis;
import ch.usi.dag.dislreserver.shadow.ShadowClass;
import ch.usi.dag.dislreserver.shadow.ShadowObject;
import ch.usi.dag.dislreserver.shadow.ShadowString;
import ch.usi.dag.dislreserver.shadow.ShadowThread;
// NOTE that this class is not static anymore
public class CodeExecuted extends RemoteAnalysis {
......@@ -50,27 +51,43 @@ public class CodeExecuted extends RemoteAnalysis {
}
}
public static void testingAdvanced(ShadowString s, ShadowObject o, ShadowClass c) {
public static void testingAdvanced(ShadowObject s, ShadowObject o, ShadowObject c, ShadowObject t) {
if(! s.toString().equals("Corect transfer of String")) {
throw new RuntimeException("Incorect transfer of String");
}
long objId = ((ShadowObject)o).getId();
if(! (s instanceof ShadowObject)) {
throw new RuntimeException("This string should be transfered as string");
}
// object id should be non 0
if(! (o instanceof ShadowObject) || objId == 0) {
throw new RuntimeException("Incorect transfer of Object");
if(o.getId() == 0) {
throw new RuntimeException("Object id should not be null");
}
System.out.println("Received object id: " + o.getId());
if(o instanceof ShadowString) {
throw new RuntimeException("This string should be transfered as object");
}
System.out.println("Received object id: " + objId);
if(! (c instanceof ShadowClass)) {
throw new RuntimeException("This class should be transfered as class");
}
// class id should be non 0
if(! (c instanceof ShadowClass) || c.getClassId() == 0) {
throw new RuntimeException("Incorect transfer of Class");
if(((ShadowClass) c).getClassId() == 0) {
throw new RuntimeException("Class id should not be null");
}
System.out.println("Received class id: " + ((ShadowClass) c).getClassId());
if(! (t instanceof ShadowThread)) {
throw new RuntimeException("This thread should be transfered as thread");
}
System.out.println("Received class id: " + c.getClassId());
System.out.println("Received thread: " + ((ShadowThread) t).getName() + " is deamon " + ((ShadowThread) t).isDaemon());
}
public static void printClassInfo(ShadowClass sc) {
......@@ -88,16 +105,16 @@ public class CodeExecuted extends RemoteAnalysis {
ShadowClass class2, ShadowClass class3, ShadowClass class4) {
System.out.println("* o1 class *");
printClassInfo(((ShadowObject)o1).getShadowClass());
printClassInfo(o1.getShadowClass());
System.out.println("* o2 class *");
printClassInfo(o2.getShadowClass());
System.out.println("* o3 class *");
printClassInfo(((ShadowObject)o3).getShadowClass());
printClassInfo(o3.getShadowClass());
System.out.println("* o4 class *");
printClassInfo(((ShadowObject)o4).getShadowClass());
printClassInfo(o4.getShadowClass());
System.out.println("* class 1 *");
printClassInfo(class1);
......
......@@ -52,21 +52,21 @@ public class CodeExecutedRE {
}
public static void testingAdvanced(String s, Object o, Class<?> c,
int classID) {
Thread t) {
REDispatch.analysisStart(taId);
REDispatch.sendString(s);
REDispatch.sendObjectPlusData(s);
REDispatch.sendObject(o);
REDispatch.sendClass(c);
// class_id ignored
REDispatch.sendObject(c);
REDispatch.sendObjectPlusData(t);
REDispatch.analysisEnd();
}
public static void testingAdvanced2(Object o1, Object o2, Object o3,
Object o4, Class<?> class1, int cid1, Class<?> class2, int cid2,
Class<?> class3, int cid3, Class<?> class4, int cid4) {
Object o4, Class<?> class1, Class<?> class2,
Class<?> class3, Class<?> class4) {
REDispatch.analysisStart(ta2Id);
......@@ -74,14 +74,10 @@ public class CodeExecutedRE {
REDispatch.sendObject(o2);
REDispatch.sendObject(o3);
REDispatch.sendObject(o4);
REDispatch.sendClass(class1);
// class_id ignored
REDispatch.sendClass(class2);
// class_id ignored
REDispatch.sendClass(class3);
// class_id ignored
REDispatch.sendClass(class4);
// class_id ignored