From 5e869070177ba8bcc54057abc809eb58eda4a596 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 10 Oct 2023 14:03:07 -0500 Subject: [PATCH 01/10] Arity-split values_at All methods now have specific-arity paths up to 3 arguments. --- .../jruby/ext/strscan/RubyStringScanner.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java index 60385905ae..f580624ece 100644 --- a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java +++ b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java @@ -921,6 +921,34 @@ public IRubyObject values_at(ThreadContext context, IRubyObject[] args) { return newAry; } + @JRubyMethod(name = "values_at") + public IRubyObject values_at(ThreadContext context) { + if (!isMatched()) return context.nil; + + return RubyArray.newEmptyArray(context.runtime); + } + + @JRubyMethod(name = "values_at") + public IRubyObject values_at(ThreadContext context, IRubyObject index) { + if (!isMatched()) return context.nil; + + return RubyArray.newArray(context.runtime, op_aref(context, index)); + } + + @JRubyMethod(name = "values_at") + public IRubyObject values_at(ThreadContext context, IRubyObject index1, IRubyObject index2) { + if (!isMatched()) return context.nil; + + return RubyArray.newArray(context.runtime, op_aref(context, index1), op_aref(context, index2)); + } + + @JRubyMethod(name = "values_at") + public IRubyObject values_at(ThreadContext context, IRubyObject index1, IRubyObject index2, IRubyObject index3) { + if (!isMatched()) return context.nil; + + return RubyArray.newArray(context.runtime, op_aref(context, index1), op_aref(context, index2), op_aref(context, index3)); + } + @Deprecated public IRubyObject initialize(IRubyObject[] args, Block unusedBlock) { str = args[0].convertToString(); From c332c4763b7b4cbd7752cf863e0ccfd2659a64a0 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 10 Oct 2023 14:05:58 -0500 Subject: [PATCH 02/10] Remove long-deprecated forms --- .../jruby/ext/strscan/RubyStringScanner.java | 63 +------------------ 1 file changed, 1 insertion(+), 62 deletions(-) diff --git a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java index f580624ece..367baf582d 100644 --- a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java +++ b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java @@ -716,7 +716,7 @@ public IRubyObject matchedsize(ThreadContext context) { if (runtime.isVerbose()) { runtime.getWarnings().warning(ID.DEPRECATED_METHOD, "StringScanner#matchedsize is obsolete; use #matched_size instead"); } - return matched_size(); + return matched_size(context); } @JRubyMethod(name = "[]") @@ -949,67 +949,6 @@ public IRubyObject values_at(ThreadContext context, IRubyObject index1, IRubyObj return RubyArray.newArray(context.runtime, op_aref(context, index1), op_aref(context, index2), op_aref(context, index3)); } - @Deprecated - public IRubyObject initialize(IRubyObject[] args, Block unusedBlock) { - str = args[0].convertToString(); - return this; - } - - @Deprecated - public IRubyObject initialize_copy(IRubyObject other) { - return initialize_copy(getRuntime().getCurrentContext(), other); - } - - @Deprecated - public IRubyObject concat(IRubyObject obj) { - return concat(getRuntime().getCurrentContext(), obj); - } - - @Deprecated - public RubyFixnum pos() { - return pos(getRuntime().getCurrentContext()); - } - - @Deprecated - public IRubyObject set_pos(IRubyObject pos) { - return set_pos(getRuntime().getCurrentContext(), pos); - } - - @Deprecated - public IRubyObject getch19(ThreadContext context) { - return getch(context); - } - - @Deprecated - public IRubyObject reset() { - return reset(getRuntime().getCurrentContext()); - } - - @Deprecated - public IRubyObject unscan() { - return unscan(getRuntime().getCurrentContext()); - } - - @Deprecated - public IRubyObject matched_size() { - return matched_size(getRuntime().getCurrentContext()); - } - - @Deprecated - public IRubyObject bol_p() { - return bol_p(getRuntime().getCurrentContext()); - } - - @Deprecated - public RubyFixnum rest_size() { - return rest_size(getRuntime().getCurrentContext()); - } - - @Deprecated - public IRubyObject getchCommon(ThreadContext context, boolean is1_9) { - return getchCommon(context); - } - /** * @deprecated Only defined for backward compatibility in CRuby. */ From 672891ead43df61dc6280fd5def94245826e3390 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 10 Oct 2023 14:07:17 -0500 Subject: [PATCH 03/10] Clean up imports --- ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java index 367baf582d..e6e97ae8dc 100644 --- a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java +++ b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java @@ -51,7 +51,6 @@ import org.jruby.ast.util.ArgsUtil; import org.jruby.common.IRubyWarnings.ID; import org.jruby.exceptions.RaiseException; -import org.jruby.runtime.Block; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.ByteList; From 3b581e435409a9229efa56c41ab0433a38517b42 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 10 Oct 2023 14:09:36 -0500 Subject: [PATCH 04/10] Clean up doco --- ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java index e6e97ae8dc..3c37310eef 100644 --- a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java +++ b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java @@ -61,7 +61,9 @@ import static org.jruby.runtime.Visibility.PRIVATE; /** - * @author kscott + * JRuby implementation of the strscan library from Ruby. + * + * Original implementation by Kelly Nawrocke. Currently a loose port of the C implementation from CRuby. */ @JRubyClass(name = "StringScanner") public class RubyStringScanner extends RubyObject { From 00633474d294df23089946a1dd0328152fa3e04c Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 10 Oct 2023 14:14:58 -0500 Subject: [PATCH 05/10] Just use a boolean for the sole flag we support --- ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java index 3c37310eef..af67f2ab57 100644 --- a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java +++ b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java @@ -74,7 +74,7 @@ public class RubyStringScanner extends RubyObject { private Region regs; private Regex pattern; - private int scannerFlags; + private boolean matched; private boolean fixedAnchor; private static final int MATCHED_STR_SCN_F = 1 << 11; @@ -196,15 +196,15 @@ public int getNumRegs(Region region) { } private void clearMatched() { - scannerFlags &= ~MATCHED_STR_SCN_F; + matched = false; } private void setMatched() { - scannerFlags |= MATCHED_STR_SCN_F; + matched = true; } private boolean isMatched() { - return (scannerFlags & MATCHED_STR_SCN_F) != 0; + return matched; } private void check(ThreadContext context) { @@ -245,7 +245,7 @@ public IRubyObject initialize_copy(ThreadContext context, IRubyObject other) { str = otherScanner.str; curr = otherScanner.curr; prev = otherScanner.prev; - scannerFlags = otherScanner.scannerFlags; + matched = otherScanner.matched; regs = otherScanner.regs.clone(); pattern = otherScanner.pattern; From 17d2572fead7d7388ca8a2d574bf0b3f2fb873f9 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 10 Oct 2023 14:15:11 -0500 Subject: [PATCH 06/10] Dead code --- .../org/jruby/ext/strscan/RubyStringScanner.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java index af67f2ab57..5b252766de 100644 --- a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java +++ b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java @@ -351,20 +351,6 @@ private IRubyObject extractBegLen(Ruby runtime, int beg, int len) { return str.makeSharedString(runtime, beg, len); } - final ThreadLocal currentMatcher = new ThreadLocal<>(); - final RubyThread.Task task = new RubyThread.Task() { - @Override - public Integer run(ThreadContext context, RubyStringScanner rubyStringScanner) throws InterruptedException { - ByteList value = str.getByteList(); - return currentMatcher.get().matchInterruptible(value.begin() + curr, value.begin() + value.realSize(), Option.NONE); - } - - @Override - public void wakeup(RubyThread thread, RubyStringScanner rubyStringScanner) { - thread.getNativeThread().interrupt(); - } - }; - // MRI: strscan_do_scan private IRubyObject scan(ThreadContext context, IRubyObject regex, boolean succptr, boolean getstr, boolean headonly) { final Ruby runtime = context.runtime; From 261e81a0c6b7876610d57512448d586b935e5d53 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 10 Oct 2023 14:28:08 -0500 Subject: [PATCH 07/10] Avoid retrieving values repeatedly --- .../jruby/ext/strscan/RubyStringScanner.java | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java index 5b252766de..36409ef653 100644 --- a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java +++ b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java @@ -612,8 +612,9 @@ public IRubyObject peek(ThreadContext context, IRubyObject length) { } ByteList value = str.getByteList(); - if (curr >= value.getRealSize()) return RubyString.newEmptyString(context.runtime); - if (curr + len > value.getRealSize()) len = value.getRealSize() - curr; + int realSize = value.getRealSize(); + if (curr >= realSize) return RubyString.newEmptyString(context.runtime); + if (curr + len > realSize) len = realSize - curr; return extractBegLen(context.runtime, curr, len); } @@ -766,12 +767,13 @@ public IRubyObject rest(ThreadContext context) { Ruby runtime = context.runtime; ByteList value = str.getByteList(); + int realSize = value.getRealSize(); - if (curr >= value.getRealSize()) { + if (curr >= realSize) { return RubyString.newEmptyString(runtime); } - return extractRange(runtime, curr, value.getRealSize()); + return extractRange(runtime, curr, realSize); } @JRubyMethod(name = "rest_size") @@ -780,10 +782,11 @@ public RubyFixnum rest_size(ThreadContext context) { Ruby runtime = context.runtime; ByteList value = str.getByteList(); + int realSize = value.getRealSize(); - if (curr >= value.getRealSize()) return RubyFixnum.zero(runtime); + if (curr >= realSize) return RubyFixnum.zero(runtime); - return RubyFixnum.newFixnum(runtime, value.getRealSize() - curr); + return RubyFixnum.newFixnum(runtime, realSize - curr); } @JRubyMethod(name = "restsize") @@ -799,9 +802,15 @@ public RubyFixnum restsize(ThreadContext context) { @Override public IRubyObject inspect() { if (str == null) return inspect("(uninitialized)"); - if (curr >= str.getByteList().getRealSize()) return inspect("fin"); - if (curr == 0) return inspect(curr + "/" + str.getByteList().getRealSize() + " @ " + inspect2()); - return inspect(curr + "/" + str.getByteList().getRealSize() + " " + inspect1() + " @ " + inspect2()); + + ByteList byteList = str.getByteList(); + int realSize = byteList.getRealSize(); + + if (curr >= realSize) return inspect("fin"); + + if (curr == 0) return inspect(curr + "/" + realSize + " @ " + inspect2()); + + return inspect(curr + "/" + realSize + " " + inspect1() + " @ " + inspect2()); } @JRubyMethod(name = "fixed_anchor?") @@ -855,8 +864,14 @@ private IRubyObject inspect1() { private IRubyObject inspect2() { final Ruby runtime = getRuntime(); - if (curr >= str.getByteList().getRealSize()) return RubyString.newEmptyString(runtime); - int len = str.getByteList().getRealSize() - curr; + + ByteList byteList = str.getByteList(); + int realSize = byteList.getRealSize(); + + if (curr >= realSize) return RubyString.newEmptyString(runtime); + + int len = realSize - curr; + if (len > INSPECT_LENGTH) { return ((RubyString) str.substr(runtime, curr, INSPECT_LENGTH)).cat(DOT_BYTES).inspect(); } From d6826faad5b42ac7bdee98f75a117f2e83d27a34 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 10 Oct 2023 14:29:01 -0500 Subject: [PATCH 08/10] Use getClassFromPath to do it all at once --- ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java index 36409ef653..7bee3f4bf4 100644 --- a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java +++ b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java @@ -635,7 +635,7 @@ public IRubyObject unscan(ThreadContext context) { if (!isMatched()) { Ruby runtime = context.runtime; - RubyClass errorClass = runtime.getClass("StringScanner").getClass("Error"); + RubyClass errorClass = (RubyClass) runtime.getClassFromPath("StringScanner::Error"); throw RaiseException.from(runtime, errorClass, "unscan failed: previous match had failed"); } From 1804c958de621df11ea5ccbea037b405c2c34859 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 10 Oct 2023 14:29:13 -0500 Subject: [PATCH 09/10] Whitespace --- ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java index 7bee3f4bf4..0b4d6338ff 100644 --- a/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java +++ b/ext/jruby/org/jruby/ext/strscan/RubyStringScanner.java @@ -855,10 +855,13 @@ private IRubyObject inspect(String msg) { private IRubyObject inspect1() { final Ruby runtime = getRuntime(); + if (curr == 0) return RubyString.newEmptyString(runtime); + if (curr > INSPECT_LENGTH) { return RubyString.newStringNoCopy(runtime, DOT_BYTES).append(str.substr(runtime, curr - INSPECT_LENGTH, INSPECT_LENGTH)).inspect(); } + return str.substr(runtime, 0, curr).inspect(); } @@ -875,6 +878,7 @@ private IRubyObject inspect2() { if (len > INSPECT_LENGTH) { return ((RubyString) str.substr(runtime, curr, INSPECT_LENGTH)).cat(DOT_BYTES).inspect(); } + return str.substr(runtime, curr, len).inspect(); } From 5aae8bf9c6a2e57e580cadbaafbbc504cdc2a84c Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 10 Oct 2023 14:35:35 -0500 Subject: [PATCH 10/10] Use JRuby 9.4.1.0 for CI due to region changes The Region changes in JRuby's regex engine require that we support both the old and new API for a while. Unfortunately the only version of JRuby that contains both APIs is 9.4.1.0 so we have to at least build against that version. Testing can occur against any version, but for now this is the simplest way to get CI green. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa30a4bc51..e95e3f352d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: - '3.1' - '3.2' - debug - - jruby-head + - jruby-9.4.1.0 - truffleruby - truffleruby-head include: