From 9275f0e079e325678bd40e1ad14405558398d313 Mon Sep 17 00:00:00 2001
From: Falk Howar <falk.howar@gmail.com>
Date: Wed, 13 Sep 2023 21:33:03 +0200
Subject: [PATCH 1/8] remove string models, springboot examples work

---
 .../com/oracle/truffle/espresso/nodes/BytecodeNode.java  | 9 +++++----
 .../espresso/substitutions/Target_java_lang_String.java  | 2 +-
 .../substitutions/Target_java_lang_StringBuffer.java     | 5 +++--
 .../substitutions/Target_java_lang_StringBuilder.java    | 5 +++--
 .../espresso/substitutions/Target_java_net_Socket.java   | 2 +-
 5 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
index 8295b5c7982e..ef28557145f2 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
@@ -2136,11 +2136,12 @@ private void putPoolConstant(VirtualFrame frame, int top, char cpi, int opcode)
         } else if (constant instanceof StringConstant) {
             assert opcode == LDC || opcode == LDC_W;
             StaticObject internedString = pool.resolvedStringAt(cpi);
-            Meta meta = getMeta();
-            StaticObject obj = meta.toGuestString(meta.toHostString(internedString));
-            SPouT.markObjectWithIFTaint(obj);
+            // todo: if we do this as we did below then springboot will fail to start with IncompleteAnnotation exceptions
+            //Meta meta = getMeta();
+            //StaticObject obj = meta.toGuestString(meta.toHostString(internedString));
+            //SPouT.markObjectWithIFTaint(obj);
             //TODO: (annotate string and maybe clone?)
-            putObject(frame, top, obj);
+            putObject(frame, top, internedString);
         } else if (constant instanceof ClassConstant) {
             assert opcode == LDC || opcode == LDC_W;
             Klass klass = pool.resolvedKlassAt(getDeclaringKlass(), cpi);
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java
index c7f143f40715..fe5e9c393d37 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java
@@ -8,7 +8,7 @@
 
 import java.util.Locale;
 
-@EspressoSubstitutions
+//@EspressoSubstitutions
 public final class Target_java_lang_String {
     @Substitution(hasReceiver = true)
     public static @JavaType(internalName = "Z") Object contains(@JavaType(String.class) StaticObject self,
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java
index e2c3baa75e44..3404607d2234 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java
@@ -5,7 +5,7 @@
 import com.oracle.truffle.espresso.runtime.StaticObject;
 import tools.aqua.spout.SPouT;
 
-@EspressoSubstitutions
+//@EspressoSubstitutions
 public final class Target_java_lang_StringBuffer {
 
 
@@ -13,7 +13,8 @@ public final class Target_java_lang_StringBuffer {
      * If we do not intercept the constructor, we get side effects from the length comparison in the trace that are
      * irrelevant for the symbolic encoding.
      */
-    @Substitution(hasReceiver = true, methodName = "<init>")
+    //todo: leads to segfault when starting springboot
+    //@Substitution(hasReceiver = true, methodName = "<init>")
     public static void init_string(
             @JavaType(StringBuilder.class) StaticObject self,
             @JavaType(String.class) StaticObject other,
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java
index 94a3e1c5edd2..a95ee2bb558c 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java
@@ -5,7 +5,7 @@
 import tools.aqua.spout.AnnotatedValue;
 import tools.aqua.spout.SPouT;
 
-@EspressoSubstitutions
+//@EspressoSubstitutions
 public final class Target_java_lang_StringBuilder {
 
 
@@ -13,7 +13,8 @@ public final class Target_java_lang_StringBuilder {
      * If we do not intercept the constructor, we get side effects from the length comparison in the trace that are
      * irrelevant for the symbolic encoding.
      */
-    @Substitution(hasReceiver = true, methodName = "<init>")
+    //todo: leads to segfault when starting springboot
+    //@Substitution(hasReceiver = true, methodName = "<init>")
     public static void init_string(
             @JavaType(StringBuilder.class) StaticObject self,
             @JavaType(String.class) StaticObject other,
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java
index 6f40ea123325..bfcd06f1f069 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java
@@ -5,7 +5,7 @@
 
 @EspressoSubstitutions
 public final class Target_java_net_Socket {
-    @Substitution(methodName = "<init>")
+    //@Substitution(methodName = "<init>")
     public static void __init(@JavaType(String.class) Object server, @JavaType(internalName = "I") Object port, @Inject Meta meta) {
         SPouT.stopRecording("Networking not supported yet.", meta);
     }

From 1c4f056cdcda12fc1b2954fbbbe037ca17148198 Mon Sep 17 00:00:00 2001
From: Falk Howar <falk.howar@gmail.com>
Date: Tue, 3 Oct 2023 19:17:34 +0200
Subject: [PATCH 2/8] fix imoplementation of String.equals()

---
 .../truffle/espresso/descriptors/Symbol.java  |  2 +
 .../oracle/truffle/espresso/meta/Meta.java    |  2 +
 .../Target_java_lang_String.java              |  2 +-
 .../Target_java_lang_StringBuffer.java        |  2 +-
 .../Target_java_lang_StringBuilder.java       |  2 +-
 .../src/tools/aqua/spout/SPouT.java           | 54 ++++++++++++++-----
 6 files changed, 49 insertions(+), 15 deletions(-)

diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java
index 2d55af44fea8..373424cdf4c8 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/descriptors/Symbol.java
@@ -1117,6 +1117,8 @@ public static void ensureInitialized() {
 
         public static final Symbol<Signature> String_byte_array_int_int = StaticSymbols.putSignature(Type.java_lang_String, Type._byte_array, Type._int, Type._int);
 
+        public static final Symbol<Signature> _boolean_byte_array_byte_array = StaticSymbols.putSignature(Type._boolean, Type._byte_array, Type._byte_array);
+
         public static final Symbol<Signature> _void_int_int_char_array_int = StaticSymbols.putSignature(Type._void, Type._int, Type._int, Type._char_array, Type._int);
     }
 }
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java
index 5d88847061ae..6d52dc494f3f 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java
@@ -838,6 +838,7 @@ public Meta(EspressoContext context) {
 
         java_lang_StringLatin1 = knownKlass(Type.java_lang_StringLatin1);
         java_lang_StringLatin1_newString = java_lang_StringLatin1.lookupMethod(getNames().getOrCreate("newString"), Signature.String_byte_array_int_int);
+        java_lang_StringLatin1_equals = java_lang_StringLatin1.lookupMethod(getNames().getOrCreate("equals"), Signature._boolean_byte_array_byte_array);
 
         java_lang_StringUTF16 = knownKlass(Type.java_lang_StringUTF16);
         java_lang_StringUTF16_newString = java_lang_StringUTF16.lookupMethod(getNames().getOrCreate("newString"), Signature.String_byte_array_int_int);
@@ -1454,6 +1455,7 @@ private DiffVersionLoadHelper diff() {
     public final ObjectKlass java_lang_StringLatin1;
 
     public final Method java_lang_StringLatin1_newString;
+    public final Method java_lang_StringLatin1_equals;
 
     public final ObjectKlass java_lang_StringUTF16;
 
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java
index fe5e9c393d37..c7f143f40715 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java
@@ -8,7 +8,7 @@
 
 import java.util.Locale;
 
-//@EspressoSubstitutions
+@EspressoSubstitutions
 public final class Target_java_lang_String {
     @Substitution(hasReceiver = true)
     public static @JavaType(internalName = "Z") Object contains(@JavaType(String.class) StaticObject self,
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java
index 3404607d2234..4da881108556 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java
@@ -5,7 +5,7 @@
 import com.oracle.truffle.espresso.runtime.StaticObject;
 import tools.aqua.spout.SPouT;
 
-//@EspressoSubstitutions
+@EspressoSubstitutions
 public final class Target_java_lang_StringBuffer {
 
 
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java
index a95ee2bb558c..bef080496966 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java
@@ -5,7 +5,7 @@
 import tools.aqua.spout.AnnotatedValue;
 import tools.aqua.spout.SPouT;
 
-//@EspressoSubstitutions
+@EspressoSubstitutions
 public final class Target_java_lang_StringBuilder {
 
 
diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
index c202d8be86cf..b83415112a43 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
@@ -1566,20 +1566,50 @@ public static StaticObject stringConcat(StaticObject self, StaticObject other, M
 
     }
 
+    // this is a faithful re-implementation of String.equals()
+    private static boolean stringEqualsConcrete(StaticObject self, StaticObject other, Meta meta) {
+        if (self == other) {
+            return true;
+        }
+
+        if (!other.isString()) {
+            return false;
+        }
+
+        boolean COMPACT_STRINGS = meta.java_lang_String_COMPACT_STRINGS.getBoolean(meta.java_lang_String.getStatics());
+        Object this_coder = meta.java_lang_String_coder.getValue(self);
+        Object other_coder = meta.java_lang_String_coder.getValue(other);
+
+        if (COMPACT_STRINGS && this_coder != other_coder) {
+            return false;
+        }
+
+        Object this_value = meta.java_lang_String_value.getValue(self);
+        Object other_value = meta.java_lang_String_value.getValue(other);
+        return (boolean) meta.java_lang_StringLatin1_equals.invokeMethod(null, new Object[] {this_value, other_value});
+
+    }
+
     @CompilerDirectives.TruffleBoundary
     public static Object stringEquals(StaticObject self, StaticObject other, Meta meta) {
-        String cSelf = meta.toHostString(self);
-        String cOther = meta.toHostString(other);
-        boolean areEqual = cSelf.equals(cOther);
-        if (!analyze || !self.hasAnnotations() && !other.hasAnnotations()) {
-            return areEqual;
-        }
-        Annotations a = analysis.stringEquals(cSelf,
-                cOther,
-                getStringAnnotations(self),
-                getStringAnnotations(other));
-        if(a != null) return new AnnotatedValue(areEqual, a);
-        else return areEqual;
+        boolean areEqual = stringEqualsConcrete(self, other, meta);
+        if (!analyze) return areEqual;
+        if (self.hasAnnotations() || (!StaticObject.isNull(other) && other.hasAnnotations())) {
+            String cSelf = meta.toHostString(self);
+            String cOther = meta.toHostString(other);
+            Annotations a = analysis.stringEquals(cSelf,
+                    cOther,
+                    getStringAnnotations(self),
+                    getStringAnnotations(other));
+            if(a != null) {
+                return new AnnotatedValue(areEqual, a);
+            }
+        }
+        // todo: maybe this can be encoded?
+        if (self.hasAnnotations() && StaticObject.isNull(other)) {
+            log("not recording string == null");
+        }
+        return areEqual;
     }
 
     @CompilerDirectives.TruffleBoundary

From d365d6bd24cb239f63901f74fae94f12d5374f7f Mon Sep 17 00:00:00 2001
From: Falk Howar <falk.howar@gmail.com>
Date: Tue, 3 Oct 2023 19:29:13 +0200
Subject: [PATCH 3/8] reversing changes from bug hunt

---
 .../com/oracle/truffle/espresso/nodes/BytecodeNode.java  | 9 ++++-----
 .../substitutions/Target_java_lang_StringBuffer.java     | 3 +--
 .../substitutions/Target_java_lang_StringBuilder.java    | 3 +--
 .../espresso/substitutions/Target_java_net_Socket.java   | 2 +-
 4 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
index ef28557145f2..a0fe6d7339a3 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
@@ -2136,11 +2136,10 @@ private void putPoolConstant(VirtualFrame frame, int top, char cpi, int opcode)
         } else if (constant instanceof StringConstant) {
             assert opcode == LDC || opcode == LDC_W;
             StaticObject internedString = pool.resolvedStringAt(cpi);
-            // todo: if we do this as we did below then springboot will fail to start with IncompleteAnnotation exceptions
-            //Meta meta = getMeta();
-            //StaticObject obj = meta.toGuestString(meta.toHostString(internedString));
-            //SPouT.markObjectWithIFTaint(obj);
-            //TODO: (annotate string and maybe clone?)
+            //TODO: (this is definitively not correct! Maybe clone properly and annotate?)
+            Meta meta = getMeta();
+            StaticObject obj = meta.toGuestString(meta.toHostString(internedString));
+            SPouT.markObjectWithIFTaint(obj);
             putObject(frame, top, internedString);
         } else if (constant instanceof ClassConstant) {
             assert opcode == LDC || opcode == LDC_W;
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java
index 4da881108556..e2c3baa75e44 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuffer.java
@@ -13,8 +13,7 @@ public final class Target_java_lang_StringBuffer {
      * If we do not intercept the constructor, we get side effects from the length comparison in the trace that are
      * irrelevant for the symbolic encoding.
      */
-    //todo: leads to segfault when starting springboot
-    //@Substitution(hasReceiver = true, methodName = "<init>")
+    @Substitution(hasReceiver = true, methodName = "<init>")
     public static void init_string(
             @JavaType(StringBuilder.class) StaticObject self,
             @JavaType(String.class) StaticObject other,
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java
index bef080496966..94a3e1c5edd2 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_StringBuilder.java
@@ -13,8 +13,7 @@ public final class Target_java_lang_StringBuilder {
      * If we do not intercept the constructor, we get side effects from the length comparison in the trace that are
      * irrelevant for the symbolic encoding.
      */
-    //todo: leads to segfault when starting springboot
-    //@Substitution(hasReceiver = true, methodName = "<init>")
+    @Substitution(hasReceiver = true, methodName = "<init>")
     public static void init_string(
             @JavaType(StringBuilder.class) StaticObject self,
             @JavaType(String.class) StaticObject other,
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java
index bfcd06f1f069..6f40ea123325 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_net_Socket.java
@@ -5,7 +5,7 @@
 
 @EspressoSubstitutions
 public final class Target_java_net_Socket {
-    //@Substitution(methodName = "<init>")
+    @Substitution(methodName = "<init>")
     public static void __init(@JavaType(String.class) Object server, @JavaType(internalName = "I") Object port, @Inject Meta meta) {
         SPouT.stopRecording("Networking not supported yet.", meta);
     }

From b309ddb75f402e2c7655fddf2ec3ad6722c5324c Mon Sep 17 00:00:00 2001
From: Falk Howar <falk.howar@gmail.com>
Date: Tue, 3 Oct 2023 19:36:35 +0200
Subject: [PATCH 4/8] add check for active iflow analysis

---
 .../oracle/truffle/espresso/nodes/BytecodeNode.java | 13 +++++++++----
 .../src/tools/aqua/spout/SPouT.java                 |  4 ++++
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
index a0fe6d7339a3..0081fd2a13ab 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
@@ -2137,10 +2137,15 @@ private void putPoolConstant(VirtualFrame frame, int top, char cpi, int opcode)
             assert opcode == LDC || opcode == LDC_W;
             StaticObject internedString = pool.resolvedStringAt(cpi);
             //TODO: (this is definitively not correct! Maybe clone properly and annotate?)
-            Meta meta = getMeta();
-            StaticObject obj = meta.toGuestString(meta.toHostString(internedString));
-            SPouT.markObjectWithIFTaint(obj);
-            putObject(frame, top, internedString);
+            if (SPouT.generateIFTaint()) {
+                Meta meta = getMeta();
+                StaticObject obj = meta.toGuestString(meta.toHostString(internedString));
+                SPouT.markObjectWithIFTaint(obj);
+                putObject(frame, top, obj);
+            }
+            else {
+                putObject(frame, top, internedString);
+            }
         } else if (constant instanceof ClassConstant) {
             assert opcode == LDC || opcode == LDC_W;
             Klass klass = pool.resolvedKlassAt(getDeclaringKlass(), cpi);
diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
index b83415112a43..3f15d5dad26b 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
@@ -529,6 +529,10 @@ public static void markWithIFTaint(VirtualFrame frame, int top){
         AnnotatedVM.putAnnotations(frame, top, a);
     }
 
+    public static boolean generateIFTaint() {
+        return (analyze && config.analyzeControlFlowTaint());
+    }
+
     public static void markObjectWithIFTaint(StaticObject obj) {
         if(!analyze || !config.analyzeControlFlowTaint()) return;
         if (obj == StaticObject.NULL) return;

From dd694ea5300103047605ff26cb0754c48fedc639 Mon Sep 17 00:00:00 2001
From: Falk Howar <falk.howar@gmail.com>
Date: Wed, 11 Oct 2023 09:53:17 +0200
Subject: [PATCH 5/8] bugfixes and more implementation of heap walker

---
 .../src/tools/aqua/spout/HeapWalker.java              | 10 ++++++++--
 .../src/tools/aqua/spout/SPouT.java                   |  7 ++++---
 .../src/tools/aqua/spout/Trace.java                   |  2 +-
 .../src/tools/aqua/taint/TaintAction.java             | 11 ++++++++++-
 .../src/tools/aqua/taint/TaintCheckAction.java        |  9 +++++++--
 5 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/HeapWalker.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/HeapWalker.java
index c171ee7bd028..44a1b15b0773 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/HeapWalker.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/HeapWalker.java
@@ -71,6 +71,10 @@ public void walk(EspressoLanguage lang) {
         visited.add(origin);
         while (!queue.isEmpty()) {
             StaticObject current = queue.poll();
+            if (current.isString()) {
+                action.applyToString(current);
+                continue;
+            }
             action.applyToObject(current);
             //SPouT.log("Analyzing " + current.getKlass().getNameAsString() + " . " + current.toString());
             ObjectKlass oClass = (ObjectKlass) current.getKlass();
@@ -113,18 +117,19 @@ private void processArray(StaticObject arr, EspressoLanguage lang,
         assert arr.isArray();
         action.applyToArray(arr);
         Klass eClass = arr.getKlass().getElementalType();
-        Object[] data = arr.unwrap(lang);
         if (eClass.isPrimitive()) {
-            for (int i=0; i<data.length; i++) {
+            for (int i=0; i<arr.length(lang); i++) {
                 action.applyToPrimitiveArrayElement(arr, i);
             }
         }
         else if (eClass.getType() == Symbol.Type.java_lang_String) {
+            Object[] data = arr.unwrap(lang);
             for (Object e : data) {
                 StaticObject str = (StaticObject) e;
                 action.applyToString(str);
             }
         } else if (eClass.isArray()) {
+            Object[] data = arr.unwrap(lang);
             for (Object e : data) {
                 StaticObject arr2 = (StaticObject) e;
                 if (visited.contains(arr2)) continue;
@@ -132,6 +137,7 @@ else if (eClass.getType() == Symbol.Type.java_lang_String) {
                 processArray( arr2, lang, nextQueue, visited);
             }
         } else {
+            Object[] data = arr.unwrap(lang);
             for (Object e : data) {
                 StaticObject obj2 = (StaticObject) e;
                 if (visited.contains(obj2)) continue;
diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
index 3f15d5dad26b..98b7cf4991e1 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
@@ -67,7 +67,7 @@
 
 public class SPouT {
 
-    public static final boolean DEBUG = false;
+    public static final boolean DEBUG = true;
 
     private static boolean analyze = false, oldAnalyze = analyze;
 
@@ -113,8 +113,8 @@ public static void endPath() {
             trace.printTrace();
         }
         log("======================== END PATH [END].");
-        log("[ENDOFTRACE]");
-        //System.out.flush();
+        System.out.println("[ENDOFTRACE]");
+        System.out.flush();
     }
 
     private static void stopAnalysis() {
@@ -445,6 +445,7 @@ private static void checkTaintOnCall(Object[] args, Method method, Taint t, Espr
     }
 
     private static Object[] analyzeTaint(Object[] args, Method method, Taint t, EspressoLanguage lang) {
+        log("analyze taint on method " + method.getName());
         int receiver = 0 + (method.isStatic() ? 0 : 1);
         KlassRef[] argTypes = method.getParameters();
         int argCount = argTypes.length;
diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Trace.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Trace.java
index 4f1069ae591e..15e557d3d973 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Trace.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Trace.java
@@ -63,7 +63,7 @@ public void addElement(TraceElement tNew) {
     public void printTrace() {
         TraceElement cur = traceHead;
         while (cur != null) {
-            SPouT.log(cur.toString());
+            System.out.println(cur.toString());
             cur = cur.getNext();
         }
     }
diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintAction.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintAction.java
index d91bb565c16a..c884dc935cab 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintAction.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintAction.java
@@ -43,7 +43,16 @@ public void applyToPrimitiveArrayElement(StaticObject obj, int i) {
 
     @Override
     public void applyToString(StaticObject obj) {
-        SPouT.log("currently not tainting strings s on heap");
+        if (!config.hasTaintAnalysis()) return;
+        Annotations a = Annotations.objectAnnotation(obj);
+        Taint tOld = Annotations.annotation(a, config.getTaintIdx());
+        if (a == null) {
+            a = Annotations.create();
+        }
+        Taint tNew = ColorUtil.joinColors(tOld, taint);
+        SPouT.log("tainting string with " + tNew);
+        a.set(config.getTaintIdx(), tNew);
+        Annotations.setObjectAnnotation(obj, a);
     }
 
     @Override
diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintCheckAction.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintCheckAction.java
index 809ec663903e..0f436a756184 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintCheckAction.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/taint/TaintCheckAction.java
@@ -30,13 +30,13 @@ public TaintCheckAction(Config config, Taint taint) {
     @Override
     public void applyToPrimitiveField(StaticObject obj, Field f) {
         if (!config.hasTaintAnalysis()) return;
+        Annotations a = AnnotatedVM.getFieldAnnotation(obj, f);
         for (int color : ColorUtil.colorsIn(taint)) {
             SPouT.log("checking " + color + " taint on " +
                     f.getKind().toString() + "-field " +
                     f.getNameAsString() + " of " +
                     obj.getKlass().getNameAsString() + " [" +
                     obj.toString() + "]");
-            Annotations a = AnnotatedVM.getFieldAnnotation(obj, f);
         taintAnalysis.checkTaint(a, color);
         }
     }
@@ -48,7 +48,12 @@ public void applyToPrimitiveArrayElement(StaticObject obj, int i) {
 
     @Override
     public void applyToString(StaticObject obj) {
-        SPouT.log("currently not checking taint on strings s on heap");
+        if (!config.hasTaintAnalysis()) return;
+        Annotations a = Annotations.objectAnnotation(obj);
+        for (int color : ColorUtil.colorsIn(taint)) {
+            SPouT.log("checking string for taint with color " + color);
+            taintAnalysis.checkTaint(a, color);
+        }
     }
 
     @Override

From e68ae6db007c5278866f95243f83625b464e70f3 Mon Sep 17 00:00:00 2001
From: Falk Howar <falk.howar@gmail.com>
Date: Tue, 17 Oct 2023 21:43:33 +0200
Subject: [PATCH 6/8] hook for methods invoked by reflection

---
 ...get_sun_reflect_NativeMethodAccessorImpl.java |  7 +++++++
 .../src/tools/aqua/spout/Annotations.java        |  3 ++-
 .../src/tools/aqua/spout/SPouT.java              | 16 +++++++++++++---
 3 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java
index 0b568e087119..e7909785956f 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_reflect_NativeMethodAccessorImpl.java
@@ -34,6 +34,7 @@
 import com.oracle.truffle.espresso.meta.Meta;
 import com.oracle.truffle.espresso.runtime.EspressoException;
 import com.oracle.truffle.espresso.runtime.StaticObject;
+import tools.aqua.spout.SPouT;
 
 /**
  * This substitution is merely for performance reasons, to avoid the deep-dive to native. libjava
@@ -340,7 +341,13 @@ public static Object checkAndWiden(Meta meta, StaticObject arg, Klass targetKlas
 
         Object result;
         try {
+            if (method.isPartOfAnalysis()) {
+                adjustedArgs = SPouT.processMethodCall(adjustedArgs, method, meta);
+            }
             result = method.invokeDirect(receiver, adjustedArgs);
+//            if (method.isPartOfAnalysis()) {
+//                result = SPouT.processReturnValue(result, method, meta);
+//            }
         } catch (EspressoException e) {
             throw meta.throwExceptionWithCause(meta.java_lang_reflect_InvocationTargetException, e.getGuestException());
         }
diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Annotations.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Annotations.java
index ccfb027b5b6a..c86179b53413 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Annotations.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/Annotations.java
@@ -61,7 +61,8 @@ public Object[] getAnnotations() {
 
     @SuppressWarnings("unchecked")
     public static <T> T annotation(Annotations a, int i) {
-        return a != null ? (T) a.annotations[i] : null;
+        if (a == null || i < 0 || a.annotations.length <= i) return null;
+        return (T) a.annotations[i];
     }
 
     @SuppressWarnings("unchecked")
diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
index 98b7cf4991e1..a818fd6c3697 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
@@ -139,6 +139,11 @@ public static boolean isPartOfAnalysis(Method method) {
         }
     }
 
+    @CompilerDirectives.TruffleBoundary
+    public static Object[] processMethodCall(Object[] args, Method method, Meta meta) {
+        return processMethodCall(args, method, meta.getLanguage(), meta.getSubstitutions().get(method));
+    }
+
     @CompilerDirectives.TruffleBoundary
     public static Object[] processMethodCall(Object[] args, Method method, EspressoLanguage lang, RootNode rn) {
         if (!analyze) return args;
@@ -162,6 +167,11 @@ public static Object[] processMethodCall(Object[] args, Method method, EspressoL
         return args;
     }
 
+    @CompilerDirectives.TruffleBoundary
+    public static Object processReturnValue(Object result, Method method, Meta meta) {
+        return processReturnValue(result, method, meta.getLanguage(), meta.getSubstitutions().get(method));
+    }
+
     public static Object processReturnValue(Object result, Method method, EspressoLanguage lang, RootNode rn) {
         if (!analyze) return result;
 
@@ -303,7 +313,7 @@ private static Object makeConcolic(Object obj, Symbol<Symbol.Type> type, Espress
     }
 
     private static Object[] analyzeConcolically(Object[] args, Method method, EspressoLanguage lang, RootNode rn) {
-        int receiver = 0 + (method.isStatic() ? 0 : 1);
+        int receiver = 0 + (method.isStatic() || args.length == method.getParameterCount() ? 0 : 1);
         Symbol<Symbol.Type>[] methodSignature = method.getParsedSignature();
         int argCount = Signatures.parameterCount(methodSignature);
         CompilerAsserts.partialEvaluationConstant(argCount);
@@ -425,7 +435,7 @@ private static Object sanitizeReturnValue(Object result, Method method, Taint t,
 
     @CompilerDirectives.TruffleBoundary
     private static void checkTaintOnCall(Object[] args, Method method, Taint t, EspressoLanguage lang) {
-        int receiver = 0 + (method.isStatic() ? 0 : 1);
+        int receiver = 0 + (method.isStatic() || args.length == method.getParameterCount() ? 0 : 1);
         KlassRef[] argTypes = method.getParameters();
         int argCount = argTypes.length;
         CompilerAsserts.partialEvaluationConstant(argCount);
@@ -446,7 +456,7 @@ private static void checkTaintOnCall(Object[] args, Method method, Taint t, Espr
 
     private static Object[] analyzeTaint(Object[] args, Method method, Taint t, EspressoLanguage lang) {
         log("analyze taint on method " + method.getName());
-        int receiver = 0 + (method.isStatic() ? 0 : 1);
+        int receiver = 0 + (method.isStatic() || args.length == method.getParameterCount() ? 0 : 1);
         KlassRef[] argTypes = method.getParameters();
         int argCount = argTypes.length;
         CompilerAsserts.partialEvaluationConstant(argCount);

From 9baf08ca87c83df3008d421aadfd22acc4e724a2 Mon Sep 17 00:00:00 2001
From: Falk Howar <falk.howar@gmail.com>
Date: Sun, 22 Oct 2023 18:48:16 +0300
Subject: [PATCH 7/8] more generic proposal for methods with concolic/taint
 models

---
 .../oracle/truffle/espresso/meta/Meta.java    |  5 +-
 .../truffle/espresso/nodes/BytecodeNode.java  |  6 +-
 .../concolic/ConcolicInvokeVirtualNode.java   | 75 +++++++++++++++++++
 .../Target_java_lang_String.java              |  4 +-
 .../src/tools/aqua/spout/SPouT.java           | 33 ++------
 5 files changed, 91 insertions(+), 32 deletions(-)
 create mode 100644 espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java

diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java
index 6d52dc494f3f..4b219e28ca80 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java
@@ -57,7 +57,6 @@
 import com.oracle.truffle.espresso.runtime.StaticObject;
 import com.oracle.truffle.espresso.substitutions.JavaType;
 import com.oracle.truffle.espresso.vm.InterpreterToVM;
-import tools.aqua.spout.SPouT;
 
 /**
  * Introspection API to access the guest world from the host. Provides seamless conversions from
@@ -840,6 +839,8 @@ public Meta(EspressoContext context) {
         java_lang_StringLatin1_newString = java_lang_StringLatin1.lookupMethod(getNames().getOrCreate("newString"), Signature.String_byte_array_int_int);
         java_lang_StringLatin1_equals = java_lang_StringLatin1.lookupMethod(getNames().getOrCreate("equals"), Signature._boolean_byte_array_byte_array);
 
+        java_lang_String_equals = java_lang_String.lookupMethod(getNames().getOrCreate("equals"), Signature._boolean_Object);
+
         java_lang_StringUTF16 = knownKlass(Type.java_lang_StringUTF16);
         java_lang_StringUTF16_newString = java_lang_StringUTF16.lookupMethod(getNames().getOrCreate("newString"), Signature.String_byte_array_int_int);
     }
@@ -1456,7 +1457,7 @@ private DiffVersionLoadHelper diff() {
 
     public final Method java_lang_StringLatin1_newString;
     public final Method java_lang_StringLatin1_equals;
-
+    public final Method java_lang_String_equals;
     public final ObjectKlass java_lang_StringUTF16;
 
     public final Method java_lang_StringUTF16_newString;
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
index 0081fd2a13ab..8f438c5594fd 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
@@ -229,7 +229,6 @@
 import static com.oracle.truffle.espresso.bytecode.Bytecodes.TABLESWITCH;
 import static com.oracle.truffle.espresso.bytecode.Bytecodes.WIDE;
 
-import java.lang.invoke.SwitchPoint;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
@@ -298,6 +297,7 @@
 import com.oracle.truffle.espresso.meta.ExceptionHandler;
 import com.oracle.truffle.espresso.meta.JavaKind;
 import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.nodes.concolic.ConcolicInvokeVirtualNode;
 import com.oracle.truffle.espresso.nodes.helper.EspressoReferenceArrayStoreNode;
 import com.oracle.truffle.espresso.nodes.quick.BaseQuickNode;
 import com.oracle.truffle.espresso.nodes.quick.CheckCastQuickNode;
@@ -342,7 +342,6 @@
 
 import tools.aqua.spout.*;
 import tools.aqua.taint.PostDominatorAnalysis;
-import tools.aqua.taint.TaintAnalysis;
 
 /**
  * Bytecode interpreter loop.
@@ -2493,6 +2492,9 @@ private BaseQuickNode dispatchQuickened(int top, int curBCI, char cpi, int opcod
             }
             // @formatter:on
         }
+        if (resolved == getMeta().java_lang_String_equals) {
+            invoke = new ConcolicInvokeVirtualNode.StringEquals(resolved, top, curBCI, getMeta());
+        }
         return invoke;
     }
 
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java
new file mode 100644
index 000000000000..ed91255aa438
--- /dev/null
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java
@@ -0,0 +1,75 @@
+package com.oracle.truffle.espresso.nodes.concolic;
+
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.espresso.descriptors.Signatures;
+import com.oracle.truffle.espresso.descriptors.Types;
+import com.oracle.truffle.espresso.impl.Method;
+import com.oracle.truffle.espresso.meta.Meta;
+import com.oracle.truffle.espresso.nodes.BytecodeNode;
+import com.oracle.truffle.espresso.nodes.bytecodes.InvokeVirtual;
+import com.oracle.truffle.espresso.nodes.bytecodes.InvokeVirtualNodeGen;
+import com.oracle.truffle.espresso.nodes.quick.QuickNode;
+import com.oracle.truffle.espresso.runtime.StaticObject;
+import tools.aqua.spout.SPouT;
+
+public abstract class ConcolicInvokeVirtualNode extends QuickNode {
+
+    final Method.MethodVersion method;
+    final int resultAt;
+    final boolean returnsPrimitiveType;
+    @Child InvokeVirtual.WithoutNullCheck invokeVirtual;
+
+    abstract Object concolicAnalysis(Object concreteResult, Object[] args);
+
+    public ConcolicInvokeVirtualNode(Method method, int top, int curBCI) {
+        super(top, curBCI);
+        assert !method.isStatic();
+        this.method = method.getMethodVersion();
+        this.resultAt = top - Signatures.slotsForParameters(method.getParsedSignature()) - 1; // -receiver
+        this.returnsPrimitiveType = Types.isPrimitive(Signatures.returnType(method.getParsedSignature()));
+        this.invokeVirtual = InvokeVirtualNodeGen.WithoutNullCheckNodeGen.create(method);
+    }
+
+    @Override
+    public int execute(VirtualFrame frame) {
+        Object[] args = BytecodeNode.popArguments(frame, top, true, method.getMethod().getParsedSignature());
+        nullCheck((StaticObject) args[0]);
+        Object result = invokeVirtual.execute(args);
+        result = concolicAnalysis(result, args);
+        if (!returnsPrimitiveType) {
+            getBytecodeNode().checkNoForeignObjectAssumption((StaticObject) result);
+        }
+        return (getResultAt() - top) + BytecodeNode.putKind(frame, getResultAt(), result, method.getMethod().getReturnKind());
+    }
+
+    @Override
+    public boolean removedByRedefintion() {
+        if (method.getRedefineAssumption().isValid()) {
+            return false;
+        } else {
+            return method.getMethod().isRemovedByRedefition();
+        }
+    }
+
+    private int getResultAt() {
+        return resultAt;
+    }
+
+
+    public static final class StringEquals extends ConcolicInvokeVirtualNode {
+
+        private final Meta meta;
+
+        public StringEquals(Method method, int top, int curBCI, Meta meta) {
+            super(method, top, curBCI);
+            this.meta = meta;
+        }
+        @Override
+        Object concolicAnalysis(Object concreteResult, Object[] args) {
+            SPouT.log("concolic virtual node");
+            return SPouT.stringEquals( (StaticObject) args[0], (StaticObject) args[1], (boolean) concreteResult, meta);
+        }
+    }
+
+
+}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java
index c7f143f40715..dbfdee8d43b2 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_java_lang_String.java
@@ -31,7 +31,7 @@ public static void init(@JavaType(String.class) StaticObject self, @JavaType(Str
                                                                  @Inject Meta meta) {
         return SPouT.stringCompareTo(self, other, meta);
     }
-
+/*
     @Substitution(hasReceiver = true)
     public static @JavaType(internalName = "Z") Object equals(
             @JavaType(String.class) StaticObject self,
@@ -39,7 +39,7 @@ public static void init(@JavaType(String.class) StaticObject self, @JavaType(Str
             @Inject Meta meta) {
         return SPouT.stringEquals(self, other, meta);
     }
-
+*/
     @Substitution(hasReceiver = true)
     public static @JavaType(internalName = "C") Object charAt(@JavaType(String.class) StaticObject self,
                                                                     @JavaType(internalName = "I") Object index,
diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
index a818fd6c3697..5e3118e86ca0 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
@@ -125,6 +125,10 @@ private static void stopAnalysis() {
         }
     }
 
+    public static boolean doAnalyze() {
+        return analyze;
+    }
+
     // --------------------------------------------------------------------------
     //
     // interception of method invocations
@@ -1581,33 +1585,10 @@ public static StaticObject stringConcat(StaticObject self, StaticObject other, M
 
     }
 
-    // this is a faithful re-implementation of String.equals()
-    private static boolean stringEqualsConcrete(StaticObject self, StaticObject other, Meta meta) {
-        if (self == other) {
-            return true;
-        }
-
-        if (!other.isString()) {
-            return false;
-        }
-
-        boolean COMPACT_STRINGS = meta.java_lang_String_COMPACT_STRINGS.getBoolean(meta.java_lang_String.getStatics());
-        Object this_coder = meta.java_lang_String_coder.getValue(self);
-        Object other_coder = meta.java_lang_String_coder.getValue(other);
-
-        if (COMPACT_STRINGS && this_coder != other_coder) {
-            return false;
-        }
-
-        Object this_value = meta.java_lang_String_value.getValue(self);
-        Object other_value = meta.java_lang_String_value.getValue(other);
-        return (boolean) meta.java_lang_StringLatin1_equals.invokeMethod(null, new Object[] {this_value, other_value});
-
-    }
-
+    // TODO: the concrete result may have annotations!!!
+    // TODO: these methods should work like the other entrypoints and distribute / integrate analyses!
     @CompilerDirectives.TruffleBoundary
-    public static Object stringEquals(StaticObject self, StaticObject other, Meta meta) {
-        boolean areEqual = stringEqualsConcrete(self, other, meta);
+    public static Object stringEquals(StaticObject self, StaticObject other, boolean areEqual, Meta meta) {
         if (!analyze) return areEqual;
         if (self.hasAnnotations() || (!StaticObject.isNull(other) && other.hasAnnotations())) {
             String cSelf = meta.toHostString(self);

From 943ce39fab9056646abc692d5afe46ec33945583 Mon Sep 17 00:00:00 2001
From: Falk Howar <falk.howar@gmail.com>
Date: Tue, 16 Jan 2024 07:57:45 +0100
Subject: [PATCH 8/8] some more invoke aspects

---
 .../oracle/truffle/espresso/impl/Method.java  | 14 +++++++++++
 .../truffle/espresso/nodes/BytecodeNode.java  |  7 ++++--
 .../concolic/ConcolicInvokeVirtualNode.java   | 12 +++++-----
 .../src/tools/aqua/spout/SPouT.java           | 23 +++++++++++++++++++
 4 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java
index 53f00f7b1f6a..80f37965367b 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java
@@ -1586,7 +1586,9 @@ public CodeAttribute getCodeAttribute() {
     }
     // endregion jdwp-specific
 
+    // spout
     private Boolean partOfAnalysis = null;
+    private Integer modelId = null;
 
     public boolean isPartOfAnalysis() {
         if (partOfAnalysis == null) {
@@ -1594,4 +1596,16 @@ public boolean isPartOfAnalysis() {
         }
         return partOfAnalysis;
     }
+
+    public boolean hasModel(Meta meta) {
+        if (modelId == null) {
+            modelId = SPouT.getModelId(this, meta);
+        }
+        return modelId != -1;
+    }
+
+    public int getModelId() {
+        return modelId;
+    }
+
 }
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
index 8f438c5594fd..0ff4e7018b3d 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
@@ -2492,9 +2492,12 @@ private BaseQuickNode dispatchQuickened(int top, int curBCI, char cpi, int opcod
             }
             // @formatter:on
         }
-        if (resolved == getMeta().java_lang_String_equals) {
-            invoke = new ConcolicInvokeVirtualNode.StringEquals(resolved, top, curBCI, getMeta());
+
+        Meta meta = getMeta();
+        if (resolved.hasModel(meta)) {
+            invoke = SPouT.injectModel(resolved, meta, top, curBCI);
         }
+
         return invoke;
     }
 
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java
index ed91255aa438..2e2a87281e5f 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/concolic/ConcolicInvokeVirtualNode.java
@@ -14,6 +14,7 @@
 
 public abstract class ConcolicInvokeVirtualNode extends QuickNode {
 
+    final Meta meta;
     final Method.MethodVersion method;
     final int resultAt;
     final boolean returnsPrimitiveType;
@@ -21,13 +22,14 @@ public abstract class ConcolicInvokeVirtualNode extends QuickNode {
 
     abstract Object concolicAnalysis(Object concreteResult, Object[] args);
 
-    public ConcolicInvokeVirtualNode(Method method, int top, int curBCI) {
+    public ConcolicInvokeVirtualNode(Method method, int top, int curBCI, Meta meta) {
         super(top, curBCI);
         assert !method.isStatic();
         this.method = method.getMethodVersion();
         this.resultAt = top - Signatures.slotsForParameters(method.getParsedSignature()) - 1; // -receiver
         this.returnsPrimitiveType = Types.isPrimitive(Signatures.returnType(method.getParsedSignature()));
         this.invokeVirtual = InvokeVirtualNodeGen.WithoutNullCheckNodeGen.create(method);
+        this.meta = meta;
     }
 
     @Override
@@ -58,12 +60,10 @@ private int getResultAt() {
 
     public static final class StringEquals extends ConcolicInvokeVirtualNode {
 
-        private final Meta meta;
-
-        public StringEquals(Method method, int top, int curBCI, Meta meta) {
-            super(method, top, curBCI);
-            this.meta = meta;
+        public StringEquals(int top, int curBCI, Meta meta) {
+            super(meta.java_lang_String_equals, top, curBCI, meta);
         }
+
         @Override
         Object concolicAnalysis(Object concreteResult, Object[] args) {
             SPouT.log("concolic virtual node");
diff --git a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
index 5e3118e86ca0..38cb228c54e3 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/tools/aqua/spout/SPouT.java
@@ -40,6 +40,8 @@
 import com.oracle.truffle.espresso.meta.EspressoError;
 import com.oracle.truffle.espresso.meta.Meta;
 import com.oracle.truffle.espresso.nodes.BytecodeNode;
+import com.oracle.truffle.espresso.nodes.concolic.ConcolicInvokeVirtualNode;
+import com.oracle.truffle.espresso.nodes.quick.QuickNode;
 import com.oracle.truffle.espresso.runtime.EspressoContext;
 import com.oracle.truffle.espresso.runtime.StaticObject;
 import tools.aqua.concolic.ConcolicAnnotationAction;
@@ -143,6 +145,27 @@ public static boolean isPartOfAnalysis(Method method) {
         }
     }
 
+    @CompilerDirectives.TruffleBoundary
+    public static int getModelId(Method method, Meta meta) {
+        Klass clazz = method.getDeclaringKlass();
+        if (clazz == meta.java_lang_String) {
+            if (method == meta.java_lang_String_equals) {
+                return 0;
+            }
+        }
+        return -1;
+    }
+
+    public static QuickNode injectModel(Method method, Meta meta, int top, int curBCI) {
+        switch (method.getModelId()) {
+            case 0: return new ConcolicInvokeVirtualNode.StringEquals(top, curBCI, getMeta());
+        }
+        stopRecordingWithoutMeta("unknown model");
+        // will not be reached
+        return null;
+    }
+
+
     @CompilerDirectives.TruffleBoundary
     public static Object[] processMethodCall(Object[] args, Method method, Meta meta) {
         return processMethodCall(args, method, meta.getLanguage(), meta.getSubstitutions().get(method));