Skip to content
Draft
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
22 changes: 22 additions & 0 deletions core/src/main/java/org/jruby/Ruby.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
import org.jruby.util.WeakIdentityHashMap;
import org.jruby.util.collections.ConcurrentWeakHashMap;
import org.jruby.util.collections.IntHashMap;
import org.jruby.util.collections.WeakValuedMap;
import org.jruby.util.io.EncodingUtils;
import org.objectweb.asm.util.TraceClassVisitor;

Expand Down Expand Up @@ -176,6 +177,7 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.VarHandle;
import java.lang.ref.WeakReference;
import java.math.BigInteger;
import java.net.BindException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
Expand Down Expand Up @@ -205,6 +207,7 @@
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -4756,6 +4759,22 @@ public RuntimeCache getRuntimeCache() {
return runtimeCache;
}

public IRubyObject cacheFixnum(Long value) {
return cacheImmutableLiteral(value, (v) -> newFixnum(v));
}

public IRubyObject cacheFloat(Double value) {
return cacheImmutableLiteral(value, (v) -> newFloat(v));
}

public IRubyObject cacheBignum(BigInteger value) {
return cacheImmutableLiteral(value, (v) -> RubyBignum.newBignum(this, v));
}

public <T> IRubyObject cacheImmutableLiteral(T key, Function<T, IRubyObject> constructor) {
return literalCache.computeIfAbsent(key, (k) -> constructor.apply((T) k));
}

public List<StrptimeToken> getCachedStrptimePattern(String pattern) {
List<StrptimeToken> tokens = strptimeFormatCache.get(pattern);

Expand Down Expand Up @@ -5524,6 +5543,9 @@ public interface RecursiveFunctionEx<T> extends ThreadContext.RecursiveFunctionE
// A global cache for Java-to-Ruby calls
private final RuntimeCache runtimeCache;

// A global cache for literal values represented as objects
private final Map<Object, IRubyObject> literalCache = Collections.synchronizedMap(new WeakValuedMap<>());

// Message for Errno exceptions that will not generate a backtrace
public static final String ERRNO_BACKTRACE_MESSAGE = "errno backtraces disabled; run with -Xerrno.backtrace=true to enable";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.jruby.ir.targets.indy;

import org.jruby.RubyBignum;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.objectweb.asm.Handle;
Expand Down Expand Up @@ -38,6 +37,6 @@ public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, Metho
}

public IRubyObject construct(ThreadContext context) {
return RubyBignum.newBignum(context.runtime, value);
return context.runtime.cacheBignum(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
* Created by headius on 10/23/14.
*/
public class FixnumObjectSite extends LazyObjectSite {
private final long value;
// Long to avoid constructing new wrappers for cache call below
private final Long value;

public FixnumObjectSite(MethodType type, long value) {
super(type);
Expand All @@ -36,6 +37,6 @@ public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, Metho
}

public IRubyObject construct(ThreadContext context) {
return asFixnum(context, value);
return context.runtime.cacheFixnum(value);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.jruby.ir.targets.indy;

import org.jruby.RubyFloat;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.objectweb.asm.Handle;
Expand All @@ -17,7 +16,8 @@
* Created by headius on 10/23/14.
*/
public class FloatObjectSite extends LazyObjectSite {
private final double value;
// Double to avoid constructing new wrappers for cache call below
private final Double value;

public FloatObjectSite(MethodType type, double value) {
super(type);
Expand All @@ -37,6 +37,6 @@ public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, Metho
}

public IRubyObject construct(ThreadContext context) {
return RubyFloat.newFloat(context.runtime, value);
return context.runtime.cacheFloat(value);
}
}
48 changes: 21 additions & 27 deletions core/src/main/java/org/jruby/ir/targets/indy/RangeObjectSite.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public RangeObjectSite(MethodType type, boolean exclusive) {
false);

public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type, int exclusive) {
return new RangeObjectSite(type, exclusive == 1 ? true : false).bootstrap(lookup);
return new RangeObjectSite(type, exclusive == 1).bootstrap(lookup);
}

public IRubyObject construct(ThreadContext context, IRubyObject begin, IRubyObject end) throws Throwable {
Expand Down Expand Up @@ -64,28 +64,26 @@ public static CallSite bootstrapFixnums(MethodHandles.Lookup lookup, String name
}

public static class FixnumRangeObjectSite extends RangeObjectSite {
protected final long beginOrOnly;
protected final long end;
protected final boolean beginless;
protected final boolean endless;
protected final FixnumRange range;

public FixnumRangeObjectSite(MethodType type, long beginOrOnly, long end, boolean beginless, boolean endless, boolean exclusive) {
super(type, exclusive);

this.beginOrOnly = beginOrOnly;
this.end = end;
this.beginless = beginless;
this.endless = endless;
this.range = new FixnumRange(beginOrOnly, end, beginless, endless, exclusive);
}

public IRubyObject construct(ThreadContext context) throws Throwable {
if (beginless) {
return RubyRange.newBeginlessRange(context, beginOrOnly, exclusive);
} else if (endless) {
return RubyRange.newEndlessRange(context, beginOrOnly, exclusive);
}
return RubyRange.newRange(context, beginOrOnly, end, exclusive);
return context.runtime.cacheImmutableLiteral(range, (r) -> {
if (r.beginless) {
return RubyRange.newBeginlessRange(context, r.beginOrOnly, r.exclusive);
} else if (r.endless) {
return RubyRange.newEndlessRange(context, r.beginOrOnly, r.exclusive);
}
return RubyRange.newRange(context, r.beginOrOnly, r.end, r.exclusive);
});
}

record FixnumRange(long beginOrOnly, long end, boolean beginless, boolean endless, boolean exclusive) {}
}

public static final Handle BOOTSTRAP_STRING_STRING = new Handle(
Expand All @@ -100,26 +98,22 @@ public static CallSite bootstrapStrings(MethodHandles.Lookup lookup, String name
}

public static class StringRangeObjectSite extends RangeObjectSite {
protected final ByteList begin;
protected final int beginCR;
protected final ByteList end;
protected final int endCR;
protected final StringRange range;

public StringRangeObjectSite(MethodType type, ByteList begin, int beginCR, ByteList end, int endCR, boolean exclusive) {
super(type, exclusive);

this.begin = begin;
this.beginCR = beginCR;
this.end = end;
this.endCR = endCR;
this.range = new StringRange(begin, beginCR, end, endCR, exclusive);
}

public IRubyObject construct(ThreadContext context) throws Throwable {
return RubyRange.newRange(
return context.runtime.cacheImmutableLiteral(range, (r) -> RubyRange.newRange(
context,
IRRuntimeHelpers.newFrozenString(context, begin, beginCR),
IRRuntimeHelpers.newFrozenString(context, end, endCR),
exclusive);
IRRuntimeHelpers.newFrozenString(context, r.begin, r.beginCR),
IRRuntimeHelpers.newFrozenString(context, r.end, r.endCR),
r.exclusive));
}

record StringRange(ByteList begin, int beginCR, ByteList end, int endCR, boolean exclusive) {}
}
}
18 changes: 8 additions & 10 deletions core/src/main/java/org/jruby/ir/targets/indy/RegexpObjectSite.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.jruby.ir.targets.indy;

import org.jruby.RubyRegexp;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
Expand All @@ -20,14 +19,12 @@
* Created by headius on 10/23/14.
*/
public class RegexpObjectSite extends LazyObjectSite {
protected final ByteList pattern;
protected final RegexpOptions options;
protected final Regexp regexp;

public RegexpObjectSite(MethodType type, ByteList pattern, int embeddedOptions) {
public RegexpObjectSite(MethodType type, ByteList pattern, RegexpOptions options) {
super(type);

this.pattern = pattern;
this.options = RegexpOptions.fromEmbeddedOptions(embeddedOptions);
this.regexp = new Regexp(pattern, options);
}

public static final Handle BOOTSTRAP = new Handle(
Expand All @@ -38,13 +35,14 @@ public RegexpObjectSite(MethodType type, ByteList pattern, int embeddedOptions)
false);

public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type, String value, String encodingName, int options) {
return new RegexpObjectSite(type, StringBootstrap.bytelist(value, encodingName), options).bootstrap(lookup);
return new RegexpObjectSite(type, StringBootstrap.bytelist(value, encodingName), RegexpOptions.fromEmbeddedOptions(options)).bootstrap(lookup);
}

// normal regexp
public IRubyObject construct(ThreadContext context) {
RubyRegexp regexp = IRRuntimeHelpers.newLiteralRegexp(context, pattern, options);

return regexp;
return context.runtime.cacheImmutableLiteral(regexp,
(r) -> IRRuntimeHelpers.newLiteralRegexp(context, r.pattern, r.options));
}

record Regexp(ByteList pattern, RegexpOptions options) {}
}
18 changes: 8 additions & 10 deletions core/src/main/java/org/jruby/ir/targets/indy/SymbolObjectSite.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.jruby.ir.targets.indy;

import org.jruby.RubyEncoding;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;
Expand All @@ -20,14 +18,12 @@
* Created by headius on 10/23/14.
*/
public class SymbolObjectSite extends LazyObjectSite {
private final String value;
private final String encoding;
protected final Symbol symbol;

public SymbolObjectSite(MethodType type, String value, String encoding) {
public SymbolObjectSite(MethodType type, ByteList bytes) {
super(type);

this.value = value;
this.encoding = encoding;
this.symbol = new Symbol(bytes);
}

public static final Handle BOOTSTRAP = new Handle(
Expand All @@ -38,11 +34,13 @@ public SymbolObjectSite(MethodType type, String value, String encoding) {
false);

public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type, String value, String encoding) {
return new SymbolObjectSite(type, value, encoding).bootstrap(lookup);
return new SymbolObjectSite(type, StringBootstrap.bytelist(value, encoding)).bootstrap(lookup);
}

public IRubyObject construct(ThreadContext context) {
return asSymbol(context,
new ByteList(RubyEncoding.encodeISO(value), IRRuntimeHelpers.retrieveJCodingsEncoding(context, encoding), false));
return context.runtime.cacheImmutableLiteral(symbol,
(s) -> asSymbol(context, s.bytes));
}

protected record Symbol(ByteList bytes) {}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.jruby.ir.targets.indy;

import org.jruby.RubyEncoding;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
Expand All @@ -16,15 +15,13 @@
import static org.jruby.util.CodegenUtils.p;
import static org.jruby.util.CodegenUtils.sig;

public class SymbolProcObjectSite extends LazyObjectSite {
private final String value;
private final String encoding;
public class SymbolProcObjectSite extends SymbolObjectSite {
private final SymbolProc symbolProc;

public SymbolProcObjectSite(MethodType type, String value, String encoding) {
super(type);
public SymbolProcObjectSite(MethodType type, ByteList bytes) {
super(type, bytes);

this.value = value;
this.encoding = encoding;
symbolProc = new SymbolProc(symbol);
}

public static final Handle BOOTSTRAP = new Handle(
Expand All @@ -35,13 +32,13 @@ public SymbolProcObjectSite(MethodType type, String value, String encoding) {
false);

public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type, String value, String encoding) {
return new SymbolProcObjectSite(type, value, encoding).bootstrap(lookup);
return new SymbolProcObjectSite(type, StringBootstrap.bytelist(value, encoding)).bootstrap(lookup);
}

public IRubyObject construct(ThreadContext context) {
var symbol = asSymbol(context, new ByteList(RubyEncoding.encodeISO(value),
IRRuntimeHelpers.retrieveJCodingsEncoding(context, encoding), false));

return IRRuntimeHelpers.newSymbolProc(context, symbol);
return context.runtime.cacheImmutableLiteral(symbolProc,
(sp) -> IRRuntimeHelpers.newSymbolProc(context, asSymbol(context, sp.symbol.bytes())));
}

record SymbolProc(Symbol symbol) {}
}
Loading