Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 256e753aaa07
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: e03c4f16581a
Choose a head ref
  • 3 commits
  • 7 files changed
  • 1 contributor

Commits on Mar 16, 2016

  1. Preallocate blocking task for strscan.

    For #3735, though it has only a minor impact on a scan bench.
    headius committed Mar 16, 2016
    Copy the full SHA
    a1dbe82 View commit details
  2. Copy the full SHA
    b8b7b48 View commit details
  3. Always use invokeynamic to lookup and cache constants.

    * This adds a hard requirement on Java 7+. However, we crossed
      that line some time ago.
    * Indy can take long to warm up. However, this case is a very
      simple chain of handles.
    * This improves the performance of constant lookup, since JVM6 did
      not do any caching.
    headius committed Mar 16, 2016
    Copy the full SHA
    e03c4f1 View commit details
64 changes: 42 additions & 22 deletions core/src/main/java/org/jruby/ext/strscan/RubyStringScanner.java
Original file line number Diff line number Diff line change
@@ -41,6 +41,7 @@
import org.jruby.RubyObject;
import org.jruby.RubyRegexp;
import org.jruby.RubyString;
import org.jruby.RubyThread;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.common.IRubyWarnings.ID;
@@ -237,7 +238,21 @@ private IRubyObject extractBegLen(Ruby runtime, int beg, int len) {
return str.makeSharedString19(runtime, beg, len);
}

private IRubyObject scan(IRubyObject regex, boolean succptr, boolean getstr, boolean headonly) {
ThreadLocal<Matcher> currentMatcher = new ThreadLocal<>();
RubyThread.Task<RubyStringScanner, Integer> task = new RubyThread.Task<RubyStringScanner, Integer>() {
@Override
public Integer run(ThreadContext context, RubyStringScanner rubyStringScanner) throws InterruptedException {
ByteList value = str.getByteList();
return currentMatcher.get().matchInterruptible(value.begin() + pos, value.begin() + value.realSize(), Option.NONE);
}

@Override
public void wakeup(RubyThread thread, RubyStringScanner rubyStringScanner) {
thread.getNativeThread().interrupt();
}
};

private IRubyObject scan(ThreadContext context, IRubyObject regex, boolean succptr, boolean getstr, boolean headonly) {
final Ruby runtime = getRuntime();
if (!(regex instanceof RubyRegexp)) throw runtime.newTypeError("wrong argument type " + regex.getMetaClass() + " (expected Regexp)");
check();
@@ -250,10 +265,15 @@ private IRubyObject scan(IRubyObject regex, boolean succptr, boolean getstr, boo

ByteList value = str.getByteList();
Matcher matcher = pattern.matcher(value.getUnsafeBytes(), value.getBegin() + pos, value.getBegin() + value.getRealSize());
currentMatcher.set(matcher);

final int ret;
if (headonly) {
ret = RubyRegexp.matcherMatch(runtime, matcher, value.getBegin() + pos, value.getBegin() + value.getRealSize(), Option.NONE);
try {
ret = runtime.getCurrentContext().getThread().executeTask(context, this, task);
} catch (InterruptedException ie) {
throw runtime.newInterruptedRegexpError("Regexp Interrupted");
}
} else {
ret = RubyRegexp.matcherSearch(runtime, matcher, value.getBegin() + pos, value.getBegin() + value.getRealSize(), Option.NONE);
}
@@ -276,53 +296,53 @@ private IRubyObject scan(IRubyObject regex, boolean succptr, boolean getstr, boo
}

@JRubyMethod(name = "scan", required = 1)
public IRubyObject scan(IRubyObject regex) {
return scan(regex, true, true, true);
public IRubyObject scan(ThreadContext context, IRubyObject regex) {
return scan(context, regex, true, true, true);
}

@JRubyMethod(name = "match?", required = 1)
public IRubyObject match_p(IRubyObject regex) {
return scan(regex, false, false, true);
public IRubyObject match_p(ThreadContext context, IRubyObject regex) {
return scan(context, regex, false, false, true);
}

@JRubyMethod(name = "skip", required = 1)
public IRubyObject skip(IRubyObject regex) {
return scan(regex, true, false, true);
public IRubyObject skip(ThreadContext context, IRubyObject regex) {
return scan(context, regex, true, false, true);
}

@JRubyMethod(name = "check", required = 1)
public IRubyObject check(IRubyObject regex) {
return scan(regex, false, true, true);
public IRubyObject check(ThreadContext context, IRubyObject regex) {
return scan(context, regex, false, true, true);
}

@JRubyMethod(name = "scan_full", required = 3)
public IRubyObject scan_full(IRubyObject regex, IRubyObject s, IRubyObject f) {
return scan(regex, s.isTrue(), f.isTrue(), true);
public IRubyObject scan_full(ThreadContext context, IRubyObject regex, IRubyObject s, IRubyObject f) {
return scan(context, regex, s.isTrue(), f.isTrue(), true);
}

@JRubyMethod(name = "scan_until", required = 1)
public IRubyObject scan_until(IRubyObject regex) {
return scan(regex, true, true, false);
public IRubyObject scan_until(ThreadContext context, IRubyObject regex) {
return scan(context, regex, true, true, false);
}

@JRubyMethod(name = "exist?", required = 1)
public IRubyObject exist_p(IRubyObject regex) {
return scan(regex, false, false, false);
public IRubyObject exist_p(ThreadContext context, IRubyObject regex) {
return scan(context, regex, false, false, false);
}

@JRubyMethod(name = "skip_until", required = 1)
public IRubyObject skip_until(IRubyObject regex) {
return scan(regex, true, false, false);
public IRubyObject skip_until(ThreadContext context, IRubyObject regex) {
return scan(context, regex, true, false, false);
}

@JRubyMethod(name = "check_until", required = 1)
public IRubyObject check_until(IRubyObject regex) {
return scan(regex, false, true, false);
public IRubyObject check_until(ThreadContext context, IRubyObject regex) {
return scan(context, regex, false, true, false);
}

@JRubyMethod(name = "search_full", required = 3)
public IRubyObject search_full(IRubyObject regex, IRubyObject s, IRubyObject f) {
return scan(regex, s.isTrue(), f.isTrue(), false);
public IRubyObject search_full(ThreadContext context, IRubyObject regex, IRubyObject s, IRubyObject f) {
return scan(context, regex, s.isTrue(), f.isTrue(), false);
}

private void adjustRegisters() {
20 changes: 0 additions & 20 deletions core/src/main/java/org/jruby/ir/targets/Bootstrap.java
Original file line number Diff line number Diff line change
@@ -796,26 +796,6 @@ public static boolean testType(RubyClass original, IRubyObject self) {
return ((RubyBasicObject)self).getMetaClass() == original;
}

///////////////////////////////////////////////////////////////////////////
// constant lookup

public static Handle searchConst() {
return new Handle(Opcodes.H_INVOKESTATIC, p(Bootstrap.class), "searchConst", sig(CallSite.class, Lookup.class, String.class, MethodType.class, String.class, int.class));
}

public static CallSite searchConst(Lookup lookup, String searchType, MethodType type, String constName, int publicOnly) {
ConstantLookupSite site = new ConstantLookupSite(type, constName, publicOnly == 0 ? false : true);

MethodHandle handle = Binder
.from(lookup, type)
.insert(0, site)
.invokeVirtualQuiet(LOOKUP, searchType);

site.setTarget(handle);

return site;
}

///////////////////////////////////////////////////////////////////////////
// Fixnum binding

26 changes: 25 additions & 1 deletion core/src/main/java/org/jruby/ir/targets/ConstantLookupSite.java
Original file line number Diff line number Diff line change
@@ -7,16 +7,23 @@
import org.jruby.parser.StaticScope;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.CodegenUtils;
import org.jruby.util.cli.Options;
import org.jruby.util.log.Logger;
import org.jruby.util.log.LoggerFactory;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;

import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
import java.lang.invoke.SwitchPoint;

import static java.lang.invoke.MethodHandles.guardWithTest;
import static org.jruby.util.CodegenUtils.p;
import static org.jruby.util.CodegenUtils.sig;

/**
* Created by headius on 1/31/16.
@@ -25,12 +32,29 @@ public class ConstantLookupSite extends MutableCallSite {
private static final Logger LOG = LoggerFactory.getLogger("ConstantLookupSite");
private final String name;
private final boolean publicOnly;
private final MethodHandles.Lookup lookup;

public ConstantLookupSite(MethodType type, String name, boolean publicOnly) {
public static final Handle BOOTSTRAP = new Handle(Opcodes.H_INVOKESTATIC, p(ConstantLookupSite.class), "constLookup", sig(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, String.class, int.class));

public ConstantLookupSite(MethodHandles.Lookup lookup, MethodType type, String name, boolean publicOnly) {
super(type);

this.name = name;
this.publicOnly = publicOnly;
this.lookup = lookup;
}

public static CallSite constLookup(MethodHandles.Lookup lookup, String searchType, MethodType type, String constName, int publicOnly) {
ConstantLookupSite site = new ConstantLookupSite(lookup, type, constName, publicOnly == 0 ? false : true);

MethodHandle handle = Binder
.from(lookup, type)
.insert(0, site)
.invokeVirtualQuiet(lookup, searchType);

site.setTarget(handle);

return site;
}

public IRubyObject searchConst(ThreadContext context, StaticScope staticScope) {
12 changes: 4 additions & 8 deletions core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter6.java
Original file line number Diff line number Diff line change
@@ -712,20 +712,16 @@ private static boolean anyTrue(boolean[] booleans) {
}

public void searchConst(String name, boolean noPrivateConsts) {
adapter.ldc(name);
adapter.ldc(noPrivateConsts);
invokeIRHelper("searchConst", sig(IRubyObject.class, ThreadContext.class, StaticScope.class, String.class, boolean.class));
adapter.invokedynamic("searchConst", sig(JVM.OBJECT, params(ThreadContext.class, StaticScope.class)), ConstantLookupSite.BOOTSTRAP, name, noPrivateConsts ? 1 : 0);
}

public void inheritanceSearchConst(String name, boolean noPrivateConsts) {
adapter.ldc(name);
adapter.ldc(noPrivateConsts);
invokeIRHelper("inheritedSearchConst", sig(IRubyObject.class, ThreadContext.class, IRubyObject.class, String.class, boolean.class));
adapter.invokedynamic("inheritanceSearchConst", sig(JVM.OBJECT, params(ThreadContext.class, IRubyObject.class)), ConstantLookupSite.BOOTSTRAP, name, noPrivateConsts ? 1 : 0);
}

public void lexicalSearchConst(String name) {
adapter.ldc(name);
invokeIRHelper("lexicalSearchConst", sig(IRubyObject.class, ThreadContext.class, StaticScope.class, String.class));}
adapter.invokedynamic("lexicalSearchConst", sig(JVM.OBJECT, params(ThreadContext.class, StaticScope.class)), ConstantLookupSite.BOOTSTRAP, name, 0);
}

public void pushNil() {
loadContext();
15 changes: 0 additions & 15 deletions core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter7.java
Original file line number Diff line number Diff line change
@@ -19,9 +19,7 @@
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.Block;
import org.jruby.runtime.BlockBody;
import org.jruby.runtime.CallType;
import org.jruby.runtime.CompiledIRBlockBody;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
@@ -35,7 +33,6 @@
import java.math.BigInteger;

import static org.jruby.util.CodegenUtils.ci;
import static org.jruby.util.CodegenUtils.p;
import static org.jruby.util.CodegenUtils.params;
import static org.jruby.util.CodegenUtils.sig;

@@ -245,18 +242,6 @@ public void invokeZSuper(String name, int arity, boolean hasClosure, boolean[] s
}
}

public void searchConst(String name, boolean noPrivateConsts) {
adapter.invokedynamic("searchConst", sig(JVM.OBJECT, params(ThreadContext.class, StaticScope.class)), Bootstrap.searchConst(), name, noPrivateConsts?1:0);
}

public void inheritanceSearchConst(String name, boolean noPrivateConsts) {
adapter.invokedynamic("inheritanceSearchConst", sig(JVM.OBJECT, params(ThreadContext.class, IRubyObject.class)), Bootstrap.searchConst(), name, noPrivateConsts?1:0);
}

public void lexicalSearchConst(String name) {
adapter.invokedynamic("lexicalSearchConst", sig(JVM.OBJECT, params(ThreadContext.class, StaticScope.class)), Bootstrap.searchConst(), name, 0);
}

public void pushNil() {
loadContext();
adapter.invokedynamic("nil", sig(IRubyObject.class, ThreadContext.class), Bootstrap.contextValue());
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/runtime/ThreadContext.java
Original file line number Diff line number Diff line change
@@ -143,6 +143,7 @@ public static ThreadContext newContext(Ruby runtime) {

private static boolean trySHA1PRNG = true;

@SuppressWarnings("deprecated")
public SecureRandom getSecureRandom() {
SecureRandom secureRandom = this.secureRandom;
if (secureRandom == null) {
12 changes: 1 addition & 11 deletions core/src/main/java/org/jruby/runtime/opto/OptoFactory.java
Original file line number Diff line number Diff line change
@@ -49,17 +49,7 @@ public static final Object newConstantWrapper(Class type, Object object) {
}

public static Invalidator newConstantInvalidator() {
if (indyEnabled() && indyConstants()) {
try {
return new SwitchPointInvalidator();
} catch (Error e) {
disableIndy();
throw e;
} catch (Throwable t) {
disableIndy();
}
}
return new ObjectIdentityInvalidator();
return new SwitchPointInvalidator();
}

private static Boolean indyEnabled() {