Skip to content

Commit

Permalink
Showing 5 changed files with 77 additions and 49 deletions.
12 changes: 9 additions & 3 deletions core/src/main/java/org/jruby/ir/instructions/EQQInstr.java
Original file line number Diff line number Diff line change
@@ -9,16 +9,22 @@
import org.jruby.ir.runtime.IRRuntimeHelpers;
import org.jruby.ir.transformations.inlining.CloneInfo;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.CallSite;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.FunctionalCachingCallSite;

// If v2 is an array, compare v1 with every element of v2 and stop on first match!
public class EQQInstr extends TwoOperandResultBaseInstr implements FixedArityInstr {
private final CallSite callSite;

public EQQInstr(Variable result, Operand v1, Operand v2) {
super(Operation.EQQ, result, v1, v2);

assert result != null: "EQQInstr result is null";

this.callSite = new FunctionalCachingCallSite("===");
}

public Operand getArg1() {
@@ -47,9 +53,9 @@ public static EQQInstr decode(IRReaderDecoder d) {

@Override
public Object interpret(ThreadContext context, StaticScope currScope, DynamicScope currDynScope, IRubyObject self, Object[] temp) {
return IRRuntimeHelpers.isEQQ(context,
(IRubyObject) getArg1().retrieve(context, self, currScope, currDynScope, temp),
(IRubyObject) getArg2().retrieve(context, self, currScope, currDynScope, temp));
IRubyObject recv = (IRubyObject) getArg1().retrieve(context, self, currScope, currDynScope, temp);
IRubyObject value = (IRubyObject) getArg2().retrieve(context, self, currScope, currDynScope, temp);
return IRRuntimeHelpers.isEQQ(context, recv, value, callSite);
}

@Override
6 changes: 3 additions & 3 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -424,18 +424,18 @@ public static IRubyObject isExceptionHandled(ThreadContext context, IRubyObject
return context.runtime.newBoolean(ret);
}

public static IRubyObject isEQQ(ThreadContext context, IRubyObject receiver, IRubyObject value) {
public static IRubyObject isEQQ(ThreadContext context, IRubyObject receiver, IRubyObject value, CallSite callSite) {
boolean isUndefValue = value == UndefinedValue.UNDEFINED;
if (receiver instanceof RubyArray) {
RubyArray testVals = (RubyArray)receiver;
for (int i = 0, n = testVals.getLength(); i < n; i++) {
IRubyObject v = testVals.eltInternal(i);
IRubyObject eqqVal = isUndefValue ? v : v.callMethod(context, "===", value);
IRubyObject eqqVal = isUndefValue ? v : callSite.call(context, v, v, value);
if (eqqVal.isTrue()) return eqqVal;
}
return context.runtime.newBoolean(false);
} else {
return isUndefValue ? receiver : receiver.callMethod(context, "===", value);
return isUndefValue ? receiver : callSite.call(context, receiver, receiver, value);
}
}

60 changes: 60 additions & 0 deletions core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter.java
Original file line number Diff line number Diff line change
@@ -17,7 +17,13 @@
import org.jruby.runtime.Helpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.CachingCallSite;
import org.jruby.runtime.callsite.FunctionalCachingCallSite;
import org.jruby.runtime.callsite.NormalCachingCallSite;
import org.jruby.runtime.callsite.RefinedCachingCallSite;
import org.jruby.runtime.callsite.VariableCachingCallSite;
import org.jruby.util.ByteList;
import org.jruby.util.JavaNameMangler;
import org.jruby.util.RegexpOptions;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
@@ -44,6 +50,60 @@ public IRBytecodeAdapter(SkinnyMethodAdapter adapter, Signature signature, Class
this.classData = classData;
}

/**
* Utility to lazily construct and cache a call site object.
*
* @param method the SkinnyMethodAdapter to that's generating the containing method body
* @param className the name of the class in which the field will reside
* @param siteName the unique name of the site, used for the field
* @param rubyName the Ruby method name being invoked
* @param callType the type of call
* @param isPotentiallyRefined whether the call might be refined
*/
public static void cacheCallSite(SkinnyMethodAdapter method, String className, String siteName, String rubyName, CallType callType, boolean isPotentiallyRefined) {
// call site object field
method.getClassVisitor().visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, siteName, ci(CachingCallSite.class), null, null).visitEnd();

// lazily construct it
method.getstatic(className, siteName, ci(CachingCallSite.class));
method.dup();
Label doCall = new Label();
method.ifnonnull(doCall);
method.pop();
method.ldc(rubyName);
Class<? extends CachingCallSite> siteClass;
String signature;
if (isPotentiallyRefined) {
siteClass = RefinedCachingCallSite.class;
signature = sig(siteClass, String.class, String.class);
method.ldc(callType.name());
} else {
switch (callType) {
case NORMAL:
siteClass = NormalCachingCallSite.class;
break;
case FUNCTIONAL:
siteClass = FunctionalCachingCallSite.class;
break;
case VARIABLE:
siteClass = VariableCachingCallSite.class;
break;
default:
throw new RuntimeException("BUG: Unexpected call type " + callType + " in JVM6 invoke logic");
}
signature = sig(siteClass, String.class);
}
method.invokestatic(p(IRRuntimeHelpers.class), "new" + siteClass.getSimpleName(), signature);
method.dup();
method.putstatic(className, siteName, ci(CachingCallSite.class));

method.label(doCall);
}

public String getUniqueSiteName(String name) {
return "invokeOther" + getClassData().callSiteCount.getAndIncrement() + ":" + JavaNameMangler.mangleMethodName(name);
}

public ClassData getClassData() {
return classData;
}
44 changes: 2 additions & 42 deletions core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter6.java
Original file line number Diff line number Diff line change
@@ -12,7 +12,6 @@
import org.jcodings.Encoding;
import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyBasicObject;
import org.jruby.RubyBignum;
import org.jruby.RubyBoolean;
import org.jruby.RubyClass;
@@ -36,10 +35,6 @@
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.CachingCallSite;
import org.jruby.runtime.callsite.FunctionalCachingCallSite;
import org.jruby.runtime.callsite.NormalCachingCallSite;
import org.jruby.runtime.callsite.RefinedCachingCallSite;
import org.jruby.runtime.callsite.VariableCachingCallSite;
import org.jruby.runtime.ivars.VariableAccessor;
import org.jruby.util.ByteList;
import org.jruby.util.JavaNameMangler;
@@ -331,7 +326,7 @@ public void invoke(String name, int arity, boolean hasClosure, CallType callType
}
}

String methodName = "invokeOther" + getClassData().callSiteCount.getAndIncrement() + ":" + JavaNameMangler.mangleMethodName(name);
String methodName = getUniqueSiteName(name);

adapter2 = new SkinnyMethodAdapter(
adapter.getClassVisitor(),
@@ -341,44 +336,9 @@ public void invoke(String name, int arity, boolean hasClosure, CallType callType
null,
null);

// call site object field
adapter.getClassVisitor().visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, methodName, ci(CachingCallSite.class), null, null).visitEnd();

// lazily construct it
adapter2.getstatic(getClassData().clsName, methodName, ci(CachingCallSite.class));
adapter2.dup();
Label doCall = new Label();
adapter2.ifnonnull(doCall);
adapter2.pop();
adapter2.ldc(name);
Class<? extends CachingCallSite> siteClass;
String signature;
if (isPotentiallyRefined) {
siteClass = RefinedCachingCallSite.class;
signature = sig(siteClass, String.class, String.class);
adapter2.ldc(callType.name());
} else {
switch (callType) {
case NORMAL:
siteClass = NormalCachingCallSite.class;
break;
case FUNCTIONAL:
siteClass = FunctionalCachingCallSite.class;
break;
case VARIABLE:
siteClass = VariableCachingCallSite.class;
break;
default:
throw new RuntimeException("BUG: Unexpected call type " + callType + " in JVM6 invoke logic");
}
signature = sig(siteClass, String.class);
}
adapter2.invokestatic(p(IRRuntimeHelpers.class), "new" + siteClass.getSimpleName(), signature);
adapter2.dup();
adapter2.putstatic(getClassData().clsName, methodName, ci(CachingCallSite.class));
cacheCallSite(adapter2, getClassData().clsName, methodName, name, callType, isPotentiallyRefined);

// use call site to invoke
adapter2.label(doCall);
adapter2.aload(0); // context
adapter2.aload(1); // caller
adapter2.aload(2); // self
4 changes: 3 additions & 1 deletion core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
@@ -1065,7 +1065,9 @@ public void EQQInstr(EQQInstr eqqinstr) {
jvmMethod().loadContext();
visit(eqqinstr.getArg1());
visit(eqqinstr.getArg2());
jvmMethod().invokeIRHelper("isEQQ", sig(IRubyObject.class, ThreadContext.class, IRubyObject.class, IRubyObject.class));
String siteName = jvmMethod().getUniqueSiteName("===");
IRBytecodeAdapter.cacheCallSite(jvmAdapter(), jvmMethod().getClassData().clsName, siteName, "===", CallType.FUNCTIONAL, false);
jvmMethod().invokeIRHelper("isEQQ", sig(IRubyObject.class, ThreadContext.class, IRubyObject.class, IRubyObject.class, CallSite.class));
jvmStoreLocal(eqqinstr.getResult());
}

0 comments on commit 978e1e2

Please sign in to comment.