From 48632e51c78cdda61a789e5781244eff3cf6eb9b Mon Sep 17 00:00:00 2001
From: Goetz Lindenmaier <goetz@openjdk.org>
Date: Thu, 27 Apr 2023 10:32:13 +0000
Subject: [PATCH] 8301491: C2: java.lang.StringUTF16::indexOfChar intrinsic
 called with negative character argument

Backport-of: 47ca5773a54743244a9b28f877246d260b90a408
---
 src/hotspot/share/opto/library_call.cpp       | 13 +++-
 .../TestStringIndexOfCharIntrinsics.java      | 74 +++++++++++++++++++
 2 files changed, 85 insertions(+), 2 deletions(-)
 create mode 100644 test/hotspot/jtreg/compiler/intrinsics/string/TestStringIndexOfCharIntrinsics.java

diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp
index 8fa250d9268..ea483750181 100644
--- a/src/hotspot/share/opto/library_call.cpp
+++ b/src/hotspot/share/opto/library_call.cpp
@@ -1220,7 +1220,7 @@ bool LibraryCallKit::inline_string_indexOfChar(StrIntrinsicNode::ArgEnc ae) {
   }
   assert(callee()->signature()->size() == 4, "String.indexOfChar() has 4 arguments");
   Node* src         = argument(0); // byte[]
-  Node* tgt         = argument(1); // tgt is int ch
+  Node* int_ch      = argument(1);
   Node* from_index  = argument(2);
   Node* max         = argument(3);
 
@@ -1232,6 +1232,15 @@ bool LibraryCallKit::inline_string_indexOfChar(StrIntrinsicNode::ArgEnc ae) {
 
   // Range checks
   generate_string_range_check(src, src_offset, src_count, ae == StrIntrinsicNode::U);
+
+  // Check for int_ch >= 0
+  Node* int_ch_cmp = _gvn.transform(new CmpINode(int_ch, intcon(0)));
+  Node* int_ch_bol = _gvn.transform(new BoolNode(int_ch_cmp, BoolTest::ge));
+  {
+    BuildCutout unless(this, int_ch_bol, PROB_MAX);
+    uncommon_trap(Deoptimization::Reason_intrinsic,
+                  Deoptimization::Action_maybe_recompile);
+  }
   if (stopped()) {
     return true;
   }
@@ -1239,7 +1248,7 @@ bool LibraryCallKit::inline_string_indexOfChar(StrIntrinsicNode::ArgEnc ae) {
   RegionNode* region = new RegionNode(3);
   Node* phi = new PhiNode(region, TypeInt::INT);
 
-  Node* result = new StrIndexOfCharNode(control(), memory(TypeAryPtr::BYTES), src_start, src_count, tgt, ae);
+  Node* result = new StrIndexOfCharNode(control(), memory(TypeAryPtr::BYTES), src_start, src_count, int_ch, ae);
   C->set_has_split_ifs(true); // Has chance for split-if optimization
   _gvn.transform(result);
 
diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIndexOfCharIntrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIndexOfCharIntrinsics.java
new file mode 100644
index 00000000000..a02b4918140
--- /dev/null
+++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIndexOfCharIntrinsics.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8301491
+ * @summary Check for correct return value when calling indexOfChar intrinsics with negative value.
+ * @library /test/lib
+ *
+ * @run main/othervm -XX:CompileCommand=quiet
+ *                   -XX:-TieredCompilation
+ *                   -XX:CompileCommand=compileonly,compiler.intrinsics.string.TestStringIndexOfCharIntrinsics::testIndexOfChar*
+ *                   -XX:CompileCommand=inline,java.lang.String*::indexOf*
+ *                   -XX:PerBytecodeTrapLimit=20000
+ *                   -XX:PerMethodTrapLimit=20000
+ *                   compiler.intrinsics.string.TestStringIndexOfCharIntrinsics
+ */
+
+package compiler.intrinsics.string;
+
+import jdk.test.lib.Asserts;
+
+public class TestStringIndexOfCharIntrinsics {
+
+    static byte byArr[] = new byte[500];
+
+    public static void main(String[] args) {
+        for (int j = 0; j < byArr.length; j++) {
+            byArr[j] = (byte)j;
+        }
+        // Test value for aarch64
+        byArr[24] = 0x7;
+        byArr[23] = -0x80;
+        // Warmup
+        for (int i = 0; i < 10000; i++) {
+            testIndexOfCharArg(i);
+            testIndexOfCharConst();
+        }
+        Asserts.assertEquals(testIndexOfCharConst() , -1, "must be -1 (character not found)");
+        Asserts.assertEquals(testIndexOfCharArg(-2147483641) , -1, "must be -1 (character not found)");
+    }
+
+    static int testIndexOfCharConst() {
+        String s = new String(byArr);
+        return s.indexOf(-2147483641);
+    }
+
+    static int testIndexOfCharArg(int ch) {
+        String s = new String(byArr);
+        return s.indexOf(ch);
+    }
+}
-- 
GitLab