Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,34 @@ jobs:
- name: rake ${{ matrix.target }}
run: bin/jruby -S rake ${{ matrix.target }}

repeat-specs:
runs-on: ubuntu-latest

strategy:
fail-fast: false

name: run specs repeatedly to test optimizations

steps:
- name: checkout
uses: actions/checkout@v3
- name: remove default java except 21
run: sudo apt remove temurin-8-jdk temurin-11-jdk temurin-17-jdk
- name: set up java 21
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 21
cache: 'maven'
- name: bootstrap
run: mvn -ntp -Pbootstrap clean package
- name: bundle install
run: bin/jruby --dev -S bundle install
- name: run specs
env:
JAVA_OPTS: '-XX:TieredStopAtLevel=1'
run: bin/jruby spec/mspec/bin/mspec ci -R 4 -T-Xjit.threshold=0 :language

jruby-tests-dev:
runs-on: ubuntu-latest

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/RubyKernel.java
Original file line number Diff line number Diff line change
Expand Up @@ -1278,7 +1278,7 @@ private static IRubyObject evalCommon(ThreadContext context, IRubyObject recv, I
binding.setLine(0);
}
} else { // no explicit file/line argument given
binding.setFile("(eval at " + context.getFileAndLine() + ")");
binding.setFile("(eval at " + context.getSingleBacktrace().getFileAndLine() + ")");
binding.setLine(0);
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/RubyObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ public IRubyObject specificEval(ThreadContext context, RubyModule mod, IRubyObje
file = args[1].convertToString().asJavaString();
line = args.length > 2 ? toInt(context, args[2]) - 1 : 0;
} else {
file = "(eval at " + context.getFileAndLine() + ")";
file = "(eval at " + context.getSingleBacktrace().getFileAndLine() + ")";
line = 0;
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/IRVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ private void error(Object object) {
public void BuildCompoundArrayInstr(BuildCompoundArrayInstr instr) { error(instr); }
public void BuildCompoundStringInstr(BuildCompoundStringInstr instr) { error(instr); }
public void BuildDynRegExpInstr(BuildDynRegExpInstr instr) { error(instr); }
public void BuildNthRefInstr(BuildNthRefInstr instr) { error(instr); }
public void BuildRangeInstr(BuildRangeInstr instr) { error(instr); }
public void BuildSplatInstr(BuildSplatInstr instr) { error(instr); }
public void CallInstr(CallInstr callinstr) { error(callinstr); }
Expand Down Expand Up @@ -189,7 +190,6 @@ private void error(Object object) {
public void Label(Label label) { error(label); }
public void LocalVariable(LocalVariable localvariable) { error(localvariable); }
public void Nil(Nil nil) { error(nil); }
public void NthRef(NthRef nthref) { error(nthref); }
public void NullBlock(NullBlock nullblock) { error(nullblock); }
public void Range(Range range) { error(range); }
public void Rational(Rational rational) { error(rational); }
Expand Down
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/ir/Operation.java
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ public enum Operation {
BINDING_LOAD(OpFlags.f_is_load),
BINDING_STORE(OpFlags.f_is_store | OpFlags.f_has_side_effect),
BUILD_BACKREF(OpFlags.f_can_raise_exception),
BUILD_NTHREF(OpFlags.f_can_raise_exception),
BUILD_COMPOUND_ARRAY(OpFlags.f_can_raise_exception),
BUILD_COMPOUND_STRING(OpFlags.f_can_raise_exception),
BUILD_DREGEXP(OpFlags.f_can_raise_exception),
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/builder/IRBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -1807,7 +1807,7 @@ protected Operand buildNext(final Operand rv, int line) {
}

protected Operand buildNthRef(int matchNumber) {
return copy(new NthRef(scope, matchNumber));
return addResultInstr(new BuildNthRefInstr(temp(), matchNumber));
}

// FIXME: The logic for lazy and non-lazy building is pretty icky...clean up
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.jruby.RubyRegexp;
import org.jruby.ir.persistence.IRReaderDecoder;
import org.jruby.ir.persistence.IRWriterEncoder;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.DynamicScope;
Expand Down Expand Up @@ -54,6 +55,8 @@ public Object interpret(ThreadContext context, StaticScope currScope, DynamicSco
case '`' : return RubyRegexp.match_pre(context, backref);
case '\'': return RubyRegexp.match_post(context, backref);
case '+' : return RubyRegexp.match_last(context, backref);
case 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 :
return IRRuntimeHelpers.nthMatch(context, type);
default:
assert false: "backref with invalid type";
return null;
Expand Down
65 changes: 65 additions & 0 deletions core/src/main/java/org/jruby/ir/instructions/BuildNthRefInstr.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.jruby.ir.instructions;

import org.jruby.RubyRegexp;
import org.jruby.ir.IRFlags;
import org.jruby.ir.IRScope;
import org.jruby.ir.IRVisitor;
import org.jruby.ir.Operation;
import org.jruby.ir.operands.Variable;
import org.jruby.ir.persistence.IRReaderDecoder;
import org.jruby.ir.persistence.IRWriterEncoder;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

import java.util.EnumSet;

// Represents a backref node in Ruby code
public class BuildNthRefInstr extends NoOperandResultBaseInstr {
final public int group;

public BuildNthRefInstr(Variable result, int group) {
super(Operation.BUILD_NTHREF, result);
this.group = group;
}

@Override
public void encode(IRWriterEncoder e) {
super.encode(e);
e.encode(group);
}

public static BuildNthRefInstr decode(IRReaderDecoder d) {
return new BuildNthRefInstr(d.decodeVariable(), d.decodeInt());
}

@Override
public Instr clone(CloneInfo ii) {
return new BuildNthRefInstr(ii.getRenamedVariable(result), group);
}

@Override
public String[] toStringNonOperandArgs() {
return new String[] {"$" + "'" + group + "'"};
}

@Override
public Object interpret(ThreadContext context, StaticScope currScope, DynamicScope currDynScope, IRubyObject self, Object[] temp) {
return IRRuntimeHelpers.nthMatch(context, group);
}

@Override
public void visit(IRVisitor visitor) {
visitor.BuildNthRefInstr(this);
}

@Override
public boolean computeScopeFlags(IRScope scope, EnumSet<IRFlags> flags) {
flags.add(IRFlags.REQUIRES_BACKREF);

return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import java.util.EnumSet;

import static org.jruby.ir.IRFlags.REQUIRES_BACKREF;
import static org.jruby.ir.IRFlags.REQUIRES_CLASS;

public class RuntimeHelperCall extends NOperandResultBaseInstr {
Expand Down Expand Up @@ -71,6 +72,9 @@ public boolean computeScopeFlags(IRScope scope, EnumSet<IRFlags> flags) {
if (helperMethod == Methods.IS_DEFINED_SUPER) {
modifiedScope = true;
flags.add(REQUIRES_CLASS);
} else if (helperMethod == Methods.IS_DEFINED_BACKREF || helperMethod == Methods.IS_DEFINED_NTH_REF) {
modifiedScope = true;
flags.add(REQUIRES_BACKREF);
}

return modifiedScope;
Expand Down
50 changes: 0 additions & 50 deletions core/src/main/java/org/jruby/ir/operands/NthRef.java

This file was deleted.

2 changes: 0 additions & 2 deletions core/src/main/java/org/jruby/ir/persistence/IRDumper.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import org.jruby.ir.operands.LocalVariable;
import org.jruby.ir.operands.MutableString;
import org.jruby.ir.operands.Nil;
import org.jruby.ir.operands.NthRef;
import org.jruby.ir.operands.NullBlock;
import org.jruby.ir.operands.Operand;
import org.jruby.ir.operands.Range;
Expand Down Expand Up @@ -338,7 +337,6 @@ public void Hash(Hash hash) {
public void Label(Label label) { print(label.toString()); }
public void LocalVariable(LocalVariable localvariable) { print(localvariable.getName()); }
public void Nil(Nil nil) { }
public void NthRef(NthRef nthref) { print(nthref.getId()); }
public void NullBlock(NullBlock nullblock) { }
public void Rational(Rational rational) { print(rational.getNumerator() + "/" + rational.getDenominator()); }
public void Range(Range range) { print(range.getBegin() + (range.isExclusive() ? "..." : "..") + range.getEnd()); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ public Instr decodeInstr() {
case BUILD_COMPOUND_ARRAY: return BuildCompoundArrayInstr.decode(this);
case BUILD_COMPOUND_STRING: return BuildCompoundStringInstr.decode(this);
case BUILD_DREGEXP: return BuildDynRegExpInstr.decode(this);
case BUILD_NTHREF: return BuildNthRefInstr.decode(this);
case BUILD_RANGE: return BuildRangeInstr.decode(this);
case BUILD_SPLAT: return BuildSplatInstr.decode(this);
case CALL_1F:
Expand Down Expand Up @@ -532,7 +533,6 @@ public Operand decode(OperandType type) {
case LABEL: return Label.decode(this);
case LOCAL_VARIABLE: return LocalVariable.decode(this);
case NIL: return manager.getNil();
case NTH_REF: return NthRef.decode(this);
case NULL_BLOCK: return NullBlock.decode(this);
case RANGE: return Range.decode(this);
case RATIONAL: return Rational.decode(this);
Expand Down
16 changes: 9 additions & 7 deletions core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -1163,7 +1163,7 @@ public void BuildBackrefInstr(BuildBackrefInstr instr) {
jvmAdapter().invokevirtual(p(ThreadContext.class), "match_last", sig(IRubyObject.class));
break;
default:
assert false: "backref with invalid type";
throw new NotCompilableException("backref with invalid type");
}
jvmStoreLocal(instr.getResult());
}
Expand Down Expand Up @@ -1233,6 +1233,14 @@ public void BuildDynRegExpInstr(BuildDynRegExpInstr instr) {
jvmStoreLocal(instr.getResult());
}

@Override
public void BuildNthRefInstr(BuildNthRefInstr instr) {
jvmMethod().loadContext();
jvmAdapter().pushInt(instr.group);
jvmMethod().invokeIRHelper("nthMatch", sig(IRubyObject.class, ThreadContext.class, int.class));
jvmStoreLocal(instr.getResult());
}

@Override
public void BuildRangeInstr(BuildRangeInstr instr) {
jvmMethod().loadContext();
Expand Down Expand Up @@ -2868,12 +2876,6 @@ public void Nil(Nil nil) {
jvmMethod().getValueCompiler().pushNil();
}

@Override
public void NthRef(NthRef nthref) {
jvmMethod().loadContext();
jvmAdapter().pushInt(nthref.matchNumber);
jvmMethod().invokeIRHelper("nthMatch", sig(IRubyObject.class, ThreadContext.class, int.class));
}

@Override
public void NullBlock(NullBlock nullblock) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,20 +71,20 @@ public BuildDynamicStringSite(MethodType type, Object[] stringArgs) {
Binder binder = Binder.from(type);

int dynamicArgs = type.parameterCount() - 1;
int[] permute = new int[3 * dynamicArgs + 1]; // context followed by context, arg, arg triplets
int to_sArgCount = 2;
int[] permute = new int[to_sArgCount * dynamicArgs + 1]; // context followed by context, arg, arg triplets
permute[0] = 0;
for (int i = 0; i < dynamicArgs; i++) {
int base = i * 3 + 1;
int base = i * to_sArgCount + 1;
permute[base] = 0;
permute[base + 1] = i + 1;
permute[base + 2] = i + 1;
}
binder = binder.permute(permute);

// now collect them by binding to AsStringSite
for (int i = 0; i < dynamicArgs; i++) {
// separate filter for each dynamic argument, so they can type profile independently
binder = binder.collect(i + 1, 3, IRubyObject.class, constructGuardedToStringFilter());
binder = binder.collect(i + 1, to_sArgCount, IRubyObject.class, constructGuardedToStringFilter());
}

boolean specialize = elementCount <= MAX_ELEMENTS_FOR_SPECIALIZE1;
Expand Down Expand Up @@ -126,17 +126,17 @@ public BuildDynamicStringSite(MethodType type, Object[] stringArgs) {

private static MethodHandle constructGuardedToStringFilter() {
// create an invoke site for the to_s call
MethodType toSType = MethodType.methodType(IRubyObject.class, ThreadContext.class, IRubyObject.class, IRubyObject.class);
CallSite toS = NormalInvokeSite.bootstrap(MethodHandles.lookup(), "invokeOther:to_s", toSType, 0, 0, "", -1);
MethodType toSType = MethodType.methodType(IRubyObject.class, ThreadContext.class, IRubyObject.class);
CallSite toS = SelfInvokeSite.bootstrap(MethodHandles.lookup(), "invokeFunctional:to_s", toSType, 0, 0, "", -1);
MethodHandle toS_handle = toS.dynamicInvoker();

// guarded with "Appendable" interface for trivially-appendable types
MethodHandle checkcast = Binder.from(toSType.changeReturnType(boolean.class))
.permute(2)
.permute(1)
.cast(boolean.class, Object.class)
.prepend(Appendable.class)
.invokeVirtualQuiet("isInstance");
MethodHandle guardedToS = MethodHandles.guardWithTest(checkcast, Binder.from(toSType).permute(2).identity(), toS_handle);
MethodHandle guardedToS = MethodHandles.guardWithTest(checkcast, Binder.from(toSType).permute(1).identity(), toS_handle);

return guardedToS;
}
Expand Down
4 changes: 1 addition & 3 deletions core/src/main/java/org/jruby/ir/targets/indy/InvokeSite.java
Original file line number Diff line number Diff line change
Expand Up @@ -1244,9 +1244,7 @@ MethodHandle buildNewInstanceHandle(CacheEntry entry, IRubyObject self) {
MethodHandle mh = null;
DynamicMethod method = entry.method;

if (method == self.getRuntime().getBaseNewMethod()) {
RubyClass recvClass = (RubyClass) self;

if (method == self.getRuntime().getBaseNewMethod() && self instanceof RubyClass recvClass && recvClass.getAllocator() != null) {
// Bind a second site as a dynamic invoker to guard against changes in new object's type
MethodType type = type();
if (!functional) type = type.dropParameterTypes(1, 2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ public final int getLineNumber() {
return lineNumber;
}

public String getFileAndLine() {
return "" + fileName + ":" + lineNumber;
}

public final String getMethodName() {
return methodName;
}
Expand Down
Loading