summaryrefslogtreecommitdiff
path: root/java/field.c
diff options
context:
space:
mode:
authorRodrigo Arias Mallo <rodarima@gmail.com>2024-12-10 22:30:12 +0100
committerRodrigo Arias Mallo <rodarima@gmail.com>2024-12-10 22:30:12 +0100
commit429d5f88b94ff28416cbfc6420b6389fa284df97 (patch)
treefb6fdaf7731de1ef396f98b748c56f3149801c84 /java/field.c
Import RTFL 0.1.1v0.1.1
Diffstat (limited to 'java/field.c')
-rw-r--r--java/field.c156
1 files changed, 156 insertions, 0 deletions
diff --git a/java/field.c b/java/field.c
new file mode 100644
index 0000000..3427218
--- /dev/null
+++ b/java/field.c
@@ -0,0 +1,156 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include "field.h"
+#include "config.h"
+#include "misc.h"
+
+/* ----------------------------------------------------------------------
+
+ A sketch on how field modifications could be processed:
+
+ A field modification results in a "set" or in an "assoc"
+ command. Neither is the field name *necessarily* the name of the "set"
+ command (or "assoc", if it would support names), nor is the field
+ value necessarily the respective value. Instead, the following rules
+ are used to determine the structure of the fields.
+
+ (A) If the value type is "printable" (i. e. primitive, or a wrapper
+ class for a primitive type, or java.lang.String, or an enum (more
+ cases?)), then a set command is printed, with the name and the value
+ of the field.
+
+ (B) If the value is a visible object, and it is not configured as
+ sub-structure (see below), an "assoc" command is printed, between this
+ object and the value object. (As soon as associations get a name, the
+ field name is used for this.)
+
+ (C) If the value is an invisible object, or a visible object which is
+ configured as sub-structure, regard it as structured, according to the
+ rules which follow.
+
+ Structured values are divided into sub-values with sub-names; the
+ field name, followed by a dot, is used as base-name; all sub-values
+ and sub-names are processed recursively according to the same rules,
+ while the base-name is eventually prepended to all sub-names.
+
+ (C1) If the value is of type java.util.Map, and the keys are printable
+ (see (A)), use the keys as sub-names, the values as sub-values. ("The
+ keys are printable": does this mean that the type for the keys is a
+ class which is generally printable?)
+
+ (C2) If the value is of type java.util.Map, and the keys are not
+ printable (see also C1), regard the value as unsorted list of
+ elements, which are themselves structured sub-values
+ (java.util.Map.Entry?).
+
+ (C3) If the value is of type java.util.List, use the indices as
+ sub-names, and the elements as sub-values.
+
+ (C4) If the value is an unsorted collection, i. e. of type
+ java.util.Collection, but not of java.util.Map or java.util.List,
+ apply a random order and proceed as in (C4). (Unsorted collections are
+ not really supported in RTFL.)
+
+ The rules (C1) to (C4) apply not when configured otherwise ("do not
+ show logical structure").
+
+ (C5) Otherwise (not of type java.util.Collection or java.util.Map),
+ examine fields of the value; regard the names of its fields as
+ sub-names; their values as sub-values;
+
+ (Alternative: Java Beans?)
+
+ For simplification, ignore C1 to C4 in the first place and focus on
+ C5; then implement C1 to C4 by and by.
+
+ ---------------------------------------------------------------------- */
+
+static void print_field (jvmtiEnv *jvmti, JNIEnv* jni, jclass field_klass,
+ jobject object, jfieldID field, jvalue value,
+ char *base_name);
+static void print_string_field (jvmtiEnv *jvmti, JNIEnv* jni, char *object_str,
+ char *base_name, char *field_name,
+ jstring string);
+
+void JNICALL field_modification (jvmtiEnv *jvmti, JNIEnv* jni, jthread thread,
+ jmethodID method, jlocation location,
+ jclass field_klass, jobject object,
+ jfieldID field, char signature_type,
+ jvalue new_value)
+{
+ // The class name is irrelevant here, since classes are already
+ // filtered inclass_prepare(), where SetFieldModificationWatch()
+ // is called.
+
+ print_field (jvmti, jni, field_klass, object, field, new_value, "");
+}
+
+void print_field (jvmtiEnv *jvmti, JNIEnv* jni, jclass field_klass,
+ jobject object, jfieldID field, jvalue value, char *base_name)
+{
+ jvmtiError error;
+ char object_buf1[SIZE_OBJECT_BUF], object_buf2[SIZE_OBJECT_BUF];
+ char *class_name = NULL, *field_name = NULL, *field_sig = NULL;
+
+ if ((error = (*jvmti)->GetFieldName (jvmti, field_klass, field, &field_name,
+ &field_sig, NULL))
+ != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error, "GetFieldName");
+ else {
+ //printf ("==> %s - %s\n", field_name, field_sig);
+
+ fill_object_buf (jni, object_buf1, object);
+
+ if ((class_name = get_class_name_from_sig (field_sig, FALSE))) {
+ if (include_class (class_name)) {
+ // The field represents an instance of a class which is also
+ // included: this is an association, not a simple field.
+ // ("field_name" could be used here, as soon as associations get
+ // a name.)
+
+ if (value.l) {
+ fill_object_buf (jni, object_buf2, value.l);
+ RTFL_OBJ_PRINT ("assoc", "s:s", object_buf1, object_buf2);
+ }
+ } else {
+ if (strcmp (class_name, "java.lang.String")) {
+ print_string_field (jvmti, jni, object_buf1, base_name,
+ field_name, (jstring)(value.l));
+
+ }
+ }
+ }
+ }
+
+ jvmti_dealloc (jvmti, field_name);
+ jvmti_dealloc (jvmti, field_sig);
+ simple_free (class_name);
+}
+
+void print_string_field (jvmtiEnv *jvmti, JNIEnv* jni, char *object_str,
+ char *base_name, char *field_name, jstring string)
+{
+ if (string == NULL)
+ RTFL_OBJ_PRINT ("set", "s:ss:s", object_str, base_name, field_name,
+ "null");
+ else {
+ // TODO: JNI calls somehow cause an abortion. Just some test
+ // code.
+
+ //jsize len = (*jni)->GetStringLength (jni, string);
+ //const jchar *chars = (*jni)->GetStringChars (jni, string, NULL);
+
+ //char *chars0 = (char*)malloc (len + 1);
+ //memcpy (chars0, chars, len);
+ //chars0[len] = 0;
+
+ char *chars0 = "?\"?\"?";
+
+ RTFL_OBJ_PRINT ("set", "s:ss:\"q\"", object_str, base_name, field_name,
+ chars0);
+
+ //free (chars0);
+ //(*jni)->ReleaseStringChars (jni, string, chars);
+ }
+}