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
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 @@ -1562,7 +1562,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 @@ -1835,18 +1835,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,23 +27,33 @@
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.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 @@ -58,8 +68,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
99 changes: 50 additions & 49 deletions core/src/main/java/org/jruby/java/proxies/ConcreteJavaProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,8 @@
import java.util.Map;

import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyClass;
import org.jruby.RubyModule;
import org.jruby.exceptions.RaiseException;
import org.jruby.internal.runtime.AbstractIRMethod;
import org.jruby.internal.runtime.SplitSuperState;
import org.jruby.internal.runtime.methods.DynamicMethod;
Expand All @@ -45,20 +43,17 @@
import org.jruby.javasupport.Java;
import org.jruby.javasupport.Java.JCreateMethod;
import org.jruby.javasupport.Java.JCtorCache;
import org.jruby.javasupport.JavaConstructor;
import org.jruby.javasupport.JavaObject;
import org.jruby.javasupport.proxy.JavaProxyClass;
import org.jruby.javasupport.proxy.JavaProxyConstructor;
import org.jruby.javasupport.proxy.ReifiedJavaProxy;
import org.jruby.runtime.Block;
import org.jruby.runtime.CallSite;
import org.jruby.runtime.JavaInternalBlockBody;
import org.jruby.runtime.MethodIndex;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.Signature;
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 @@ -209,12 +204,12 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
*/
public static class StaticJCreateMethod extends JavaMethodNBlock {

private Constructor<? extends ReifiedJavaProxy> withBlock;
private DynamicMethod oldInit;
private final Constructor<? extends ReifiedJavaProxy> withBlock;
final DynamicMethod oldInit;

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

Expand All @@ -236,10 +231,6 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz
return self;
}

public DynamicMethod getOriginal() {
return oldInit;
}

public static void tryInstall(Ruby runtime, RubyClass clazz, JavaProxyClass proxyClass,
Class<? extends ReifiedJavaProxy> reified, boolean overwriteInitialize) {
try {
Expand Down Expand Up @@ -335,77 +326,87 @@ public static final class SplitCtorData {
* Picks and converts arguments for the super call
* Leaves ctorIndex and arguments ready for the super call
*/
public SplitCtorData(IRubyObject[] args, JCtorCache cache, Ruby rt) {
public SplitCtorData(IRubyObject[] args, JCtorCache cache, Ruby runtime) {
rbarguments = args;
if (cache == null) { // (ruby < ruby < java) super call from one IRO to another IRO ctor
ctorIndex = -1;
arguments = null;
} else {
ctorIndex = JCreateMethod.forTypes(args, cache, rt);
ctorIndex = JCreateMethod.forTypes(args, cache, runtime);
arguments = RubyToJavaInvoker.convertArguments(cache.constructors[ctorIndex], args);
}
}

public SplitCtorData(IRubyObject[] args, JCtorCache cache, Ruby rt, AbstractIRMethod air2, SplitSuperState<?> state2,
Block blk2) {
this(args, cache, rt);
air = air2;
state =state2;
blk = blk2;
public SplitCtorData(IRubyObject[] args, JCtorCache cache, Ruby runtime, AbstractIRMethod method, SplitSuperState<?> state,
Block block) {
this(args, cache, runtime);
this.method = method;
this.state =state;
blk = block;
}

public SplitCtorData(IRubyObject[] args, JCtorCache cache, Ruby rt, AbstractIRMethod air2, String name2, Block blk2) {
this(args, cache, rt);
air = air2;
name = name2;
blk = blk2;
public SplitCtorData(IRubyObject[] args, JCtorCache cache, Ruby runtime, AbstractIRMethod method, String name, Block block) {
this(args, cache, runtime);
this.method = method;
this.name = name;
blk = block;
}

// fields below are only used in ConcreteJavaProxy finishInitialize
private AbstractIRMethod air = null;
private String name = null;
private SplitSuperState<?> state = null;
AbstractIRMethod method;
String name;
SplitSuperState<?> state;
}

/**
* 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 != null && (dm instanceof StaticJCreateMethod)) dm = ((StaticJCreateMethod) dm).getOriginal();
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(args, jcc, getRuntime(), air, name, blk);
} else {
return new SplitCtorData(state.callArrayArgs.toJavaArrayMaybeUnsafe(), jcc, getRuntime(), air, state, blk);
return new SplitCtorData(args, jcc, runtime, air, name, block);
}
} else {
return new SplitCtorData(args, jcc, getRuntime());
return new SplitCtorData(state.callArrayArgs.toJavaArrayMaybeUnsafe(), jcc, runtime, air, state, block);
}
return new SplitCtorData(args, jcc, runtime);
}

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;
}

/**
* Used by reified classes, this method is tightly coupled with RealClassGenerator, splitInitialize
* Do not refactor without looking at RCG
*/
public void finishInitialize(SplitCtorData returned) {
if (returned.air != null) {
if (returned.method != null) {
ThreadContext context = getRuntime().getCurrentContext();
if (returned.state != null) {
returned.air.finishSplitCall(returned.state);
returned.method.finishSplitCall(returned.state);
} else { // no super, direct call
returned.air.call(getRuntime().getCurrentContext(), this, getMetaClass(),
returned.name, returned.rbarguments, returned.blk);
returned.method.call(context, this, getMetaClass(), returned.name, returned.rbarguments, returned.blk);
}
}
// Ignore other cases
Expand Down