Skip to content

Commit

Permalink
Merge branch 'jruby-9.3'
Browse files Browse the repository at this point in the history
* jruby-9.3:
  [deps] update jruby-openssl to 0.14.2 (jruby#7877)
  [refactor] typo in builtICForJavaConstructor method
  Fixes jruby#7848.  Wrong interpretation of multi-expr when clause
  [build] update mvn wrapper to 3.8.8
  [refactor] InterpreterContext fields can be made final
  [refactor] Java super internals - avoid (un-cached) lookup
  [fix] avoid walking constructor instructions on every call

core/src/main/java/org/jruby/ir/interpreter/ExitableInterpreterContext.java
core/src/main/java/org/jruby/java/proxies/ConcreteJavaProxy.java
  • Loading branch information
kares committed Aug 8, 2023
2 parents e54fd1d + 2c2f456 commit f89d071
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 59 deletions.
15 changes: 4 additions & 11 deletions core/src/main/java/org/jruby/RubyModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -1631,7 +1631,7 @@ public final CacheEntry searchWithCache(String id, boolean cacheUndef) {
}

// MRI: method_entry_resolve_refinement
private final CacheEntry searchWithCacheAndRefinements(String id, boolean cacheUndef, StaticScope refinedScope) {
private CacheEntry searchWithCacheAndRefinements(String id, boolean cacheUndef, StaticScope refinedScope) {
CacheEntry entry = searchWithCache(id, cacheUndef);

if (entry.method.isRefined()) {
Expand Down Expand Up @@ -1904,18 +1904,11 @@ public CacheEntry searchMethodEntryInner(String id) {
}

/**
* Searches for a method up until the superclass, but include modules. This is
* for Concrete java ctor initialization
* TODO: add a cache?
* Searches for a method up until the superclass, but include modules.
*/
@Deprecated
public DynamicMethod searchMethodLateral(String id) {
// int token = generation;
// This flattens some of the recursion that would be otherwise be necessary.
// Used to recurse up the class hierarchy which got messy with prepend.
for (RubyModule module = this; module != null && (module == this || (module instanceof IncludedModuleWrapper)); module = module.getSuperClass()) {
// Only recurs if module is an IncludedModuleWrapper.
// This way only the recursion needs to be handled differently on
// IncludedModuleWrapper.
for (RubyModule module = this; (module == this || (module instanceof IncludedModuleWrapper)); module = module.getSuperClass()) {
DynamicMethod method = module.searchMethodCommon(id);
if (method != null) return method.isNull() ? null : method;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,10 +265,10 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
public SplitSuperState<MethodSplitState> startSplitSuperCall(ThreadContext context, IRubyObject self,
RubyModule clazz, String name, IRubyObject[] args, Block block) {
// TODO: check if IR method, or is it guaranteed?
InterpreterContext ic = ((IRMethod) getIRScope()).builtInterperterContextForJavaConstructor();
if (!(ic instanceof ExitableInterpreterContext)) return null; // no super call/can't split this
ExitableInterpreterContext ic = ((IRMethod) getIRScope()).builtInterpreterContextForJavaConstructor();
if (ic == null) return null; // no super call/can't split this

MethodSplitState state = new MethodSplitState(context, (ExitableInterpreterContext) ic, clazz, self, name);
MethodSplitState state = new MethodSplitState(context, ic, clazz, self, name);

// TODO: JIT?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ protected void printMethodIR() {
public SplitSuperState<MethodSplitState> startSplitSuperCall(ThreadContext context, IRubyObject self,
RubyModule clazz, String name, IRubyObject[] args, Block block) {
// TODO: check if IR method, or is it guaranteed?
InterpreterContext ic = ((IRMethod) getIRScope()).builtInterperterContextForJavaConstructor();
if (!(ic instanceof ExitableInterpreterContext)) return null; // no super call/can't split this
ExitableInterpreterContext ic = ((IRMethod) getIRScope()).builtInterpreterContextForJavaConstructor();
if (ic == null) return null; // no super call/can't split this

MethodSplitState state = new MethodSplitState(context, (ExitableInterpreterContext) ic, clazz, self, name);
MethodSplitState state = new MethodSplitState(context, ic, clazz, self, name);

// TODO: JIT?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,12 +292,10 @@ private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext i
public SplitSuperState<MethodSplitState> startSplitSuperCall(ThreadContext context, IRubyObject self,
RubyModule clazz, String name, IRubyObject[] args, Block block) {
// TODO: check if IR method, or is it guaranteed?
InterpreterContext ic = ((IRMethod) getIRScope()).builtInterperterContextForJavaConstructor();
if (!(ic instanceof ExitableInterpreterContext)) return null; // no super call/can't split this
ExitableInterpreterContext ic = ((IRMethod) getIRScope()).builtInterpreterContextForJavaConstructor();
if (ic == null) return null; // no super call/can't split this

MethodSplitState state = new MethodSplitState(context, (ExitableInterpreterContext) ic, clazz, self, name);

if (IRRuntimeHelpers.isDebug()) doDebug(); // TODO?
MethodSplitState state = new MethodSplitState(context, ic, clazz, self, name);

ExitableReturn result = INTERPRET_METHOD(state, args, block);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,12 +287,11 @@ private IRubyObject INTERPRET_METHOD(ThreadContext context, InterpreterContext i
public SplitSuperState<MethodSplitState> startSplitSuperCall(ThreadContext context, IRubyObject self,
RubyModule clazz, String name, IRubyObject[] args, Block block) {
// TODO: check if IR method, or is it guaranteed?
InterpreterContext ic = ((IRMethod) getIRScope()).builtInterperterContextForJavaConstructor();
if (!(ic instanceof ExitableInterpreterContext)) return null; // no super call/can't split this
// 2 -> IRMethod
ExitableInterpreterContext ic = ((IRMethod) getIRScope()).builtInterpreterContextForJavaConstructor();
if (ic == null) return null; // no super call/can't split this

MethodSplitState state = new MethodSplitState(context, (ExitableInterpreterContext) ic, clazz, self, name);

if (IRRuntimeHelpers.isDebug()) doDebug(); // TODO?
MethodSplitState state = new MethodSplitState(context, ic, clazz, self, name);

// TODO: JIT?

Expand Down
35 changes: 30 additions & 5 deletions core/src/main/java/org/jruby/ir/IRMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,33 @@ public InterpreterContext builtInterpreterContext() {
*
* @return appropriate interpretercontext
*/
public synchronized InterpreterContext builtInterperterContextForJavaConstructor() {
InterpreterContext interpreterContext = builtInterpreterContext();
public ExitableInterpreterContext builtInterpreterContextForJavaConstructor() {
ExitableInterpreterContext interpreterContextForJavaConstructor = this.interpreterContextForJavaConstructor;
if (interpreterContextForJavaConstructor == null) {
synchronized (this) {
interpreterContextForJavaConstructor = this.interpreterContextForJavaConstructor;
if (interpreterContextForJavaConstructor == null) {
interpreterContextForJavaConstructor = builtInterpreterContextForJavaConstructorImpl();
this.interpreterContextForJavaConstructor = interpreterContextForJavaConstructor;
}
}
}
return interpreterContextForJavaConstructor == ExitableInterpreterContext.NULL ? null : interpreterContextForJavaConstructor;
}

private volatile ExitableInterpreterContext interpreterContextForJavaConstructor;

if (usesSuper()) { // We know at least one super is in here somewhere
private synchronized ExitableInterpreterContext builtInterpreterContextForJavaConstructorImpl() {
final InterpreterContext interpreterContext = builtInterpreterContext();
if (usesSuper()) {
// We know at least one super is in here somewhere
int ipc = 0;
int superIPC = -1;
CallBase superCall = null;
Map<Label, Integer> labels = new HashMap<>();
List<Label> earlyJumps = new ArrayList<>();

for(Instr instr: interpreterContext.getInstructions()) {
for (Instr instr: interpreterContext.getInstructions()) {
if (instr instanceof CallBase && ((CallBase) instr).getCallType() == CallType.SUPER) {
// We have already found one super call already. No analysis yet to figure out if this is
// still ok or not so we will error.
Expand Down Expand Up @@ -186,7 +202,16 @@ public synchronized InterpreterContext builtInterperterContextForJavaConstructor
}
}

return interpreterContext;
return ExitableInterpreterContext.NULL;
}

/**
* This method was renamed (due a typo).
* @see #builtInterpreterContextForJavaConstructor()
*/
@Deprecated
public ExitableInterpreterContext builtInterperterContextForJavaConstructor() {
return builtInterpreterContextForJavaConstructor();
}

final InterpreterContext lazilyAcquireInterpreterContext() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,34 @@
package org.jruby.ir.interpreter;

import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;

import org.jruby.ir.IRFlags;
import org.jruby.ir.IRScope;
import org.jruby.ir.instructions.CallBase;
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.ir.instructions.Instr;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

public class ExitableInterpreterContext extends InterpreterContext {

public static final ExitableInterpreterContext NULL = new ExitableInterpreterContext(null, null, 0, null, null, 0);

private final static ExitableInterpreterEngine EXITABLE_INTERPRETER = new ExitableInterpreterEngine();

private CallBase superCall;
private int exitIPC;
private final CallBase superCall;
private final int exitIPC;

public ExitableInterpreterContext(InterpreterContext originalIC, CallBase superCall, int exitIPC) {
super(originalIC.getScope(), Arrays.asList(originalIC.getInstructions()),
originalIC.getTemporaryVariableCount(), originalIC.getFlags());
this(originalIC.getScope(), Arrays.asList(originalIC.getInstructions()), originalIC.getTemporaryVariableCount(), originalIC.getFlags(), superCall, exitIPC);
}

private ExitableInterpreterContext(IRScope scope, List<Instr> instructions, int temporaryVariableCount, EnumSet<IRFlags> flags, CallBase superCall, int exitIPC) {
super(scope, instructions, temporaryVariableCount, flags);

this.superCall = superCall;
this.exitIPC = exitIPC;
Expand All @@ -59,8 +69,7 @@ public int getExitIPC() {
}

@Override
public ExitableInterpreterEngine getEngine()
{
public ExitableInterpreterEngine getEngine() {
return EXITABLE_INTERPRETER;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ public class InterpreterContext {
protected boolean hasExplicitCallProtocol; // Only can be true in Full+
protected boolean dynamicScopeEliminated; // Only can be true in Full+
private boolean reuseParentDynScope; // Only can be true in Full+
private boolean metaClassBodyScope;
private final boolean metaClassBodyScope;

private InterpreterEngine engine;
public final Supplier<List<Instr>> instructionsCallback;
private EnumSet<IRFlags> flags;
private final EnumSet<IRFlags> flags;

private final IRScope scope;

Expand Down
48 changes: 29 additions & 19 deletions core/src/main/java/org/jruby/java/proxies/ConcreteJavaProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.CacheEntry;

public class ConcreteJavaProxy extends JavaProxy {

Expand Down Expand Up @@ -207,10 +208,10 @@ public static class StaticJCreateMethod extends JavaMethodNBlock {
private final Constructor<? extends ReifiedJavaProxy> withBlock;
final DynamicMethod oldInit;

StaticJCreateMethod(RubyModule cls, Constructor<? extends ReifiedJavaProxy> withBlock, DynamicMethod oldInit) {
super(cls, PUBLIC, "__jcreate_static!");
this.withBlock = withBlock;
this.oldInit = oldInit;
StaticJCreateMethod(RubyModule implClass, Constructor<? extends ReifiedJavaProxy> javaProxyConstructor, DynamicMethod oldinit) {
super(implClass, PUBLIC, "__jcreate_static!");
this.withBlock = javaProxyConstructor;
this.oldInit = oldinit;
}

@Override
Expand Down Expand Up @@ -361,35 +362,44 @@ private SplitCtorData(Ruby runtime, IRubyObject[] args, JCtorCache cache,
this.state = state;
this.block = block;
}

}

/**
* Used by reified classes, this method is tightly coupled with RealClassGenerator, finishInitialize
* Do not refactor without looking at RCG
* @return An object used by reified code and the finishInitialize method
*/
public SplitCtorData splitInitialized(RubyClass base, IRubyObject[] args, Block blk, JCtorCache jcc) {
String name = base.getClassConfig().javaCtorMethodName;
DynamicMethod dm = base.searchMethod(name);
if (dm instanceof StaticJCreateMethod) dm = ((StaticJCreateMethod) dm).oldInit;
DynamicMethod dm1 = base.searchMethodLateral(name); // only on ourself //TODO: missing default
public SplitCtorData splitInitialized(RubyClass base, IRubyObject[] args, Block block, JCtorCache jcc) {
final Ruby runtime = getRuntime();
final String name = base.getClassConfig().javaCtorMethodName;
final CacheEntry methodEntry = base.searchWithCache(name);
final boolean isLateral = isClassOrIncludedPrependedModule(methodEntry.sourceModule, base);
DynamicMethod method = methodEntry.method;
if (method instanceof StaticJCreateMethod) method = ((StaticJCreateMethod) method).oldInit;

// jcreate is for nested ruby classes from a java class
if ((dm1 != null && !(dm instanceof InitializeMethod) && !(dm instanceof StaticJCreateMethod))) {
if (isLateral && method instanceof AbstractIRMethod) {

AbstractIRMethod air = (AbstractIRMethod) dm; // TODO: getMetaClass() ? or base? (below v)
AbstractIRMethod air = (AbstractIRMethod) method; // TODO: getMetaClass() ? or base? (below v)

SplitSuperState<?> state = air.startSplitSuperCall(getRuntime().getCurrentContext(), this, getMetaClass(),
name, args, blk);
SplitSuperState<?> state = air.startSplitSuperCall(runtime.getCurrentContext(), this, getMetaClass(), name, args, block);
if (state == null) { // no super in method
return new SplitCtorData(getRuntime(), args, jcc, air, name, blk);
} else {
return new SplitCtorData(getRuntime(), state.callArrayArgs.toJavaArrayMaybeUnsafe(), jcc, air, state, blk);
return new SplitCtorData(runtime, args, jcc, air, name, block);
}
} else {
return new SplitCtorData(getRuntime(), args, jcc);
return new SplitCtorData(runtime, state.callArrayArgs.toJavaArrayMaybeUnsafe(), jcc, air, state, block);
}
return new SplitCtorData(runtime, args, jcc);
}

private static boolean isClassOrIncludedPrependedModule(final RubyModule methodSource, final RubyClass klass) {
if (methodSource == klass) return true;

RubyClass candidate = klass.getSuperClass();
while (candidate != null && (candidate.isIncluded() || candidate.isPrepended())) { // up till 'real' superclass
if (candidate == klass) return true;
}

return false;
}

/**
Expand Down

0 comments on commit f89d071

Please sign in to comment.