![JAR search and dependency download from the Maven repository](/logo.png)
org.jruby.ir.operands.MethodHandle Maven / Gradle / Ivy
package org.jruby.ir.operands;
import org.jruby.RubyClass;
import org.jruby.RubyString;
import org.jruby.RubySymbol;
import org.jruby.internal.runtime.methods.DynamicMethod;
import org.jruby.ir.IRVisitor;
import org.jruby.ir.transformations.inlining.InlinerInfo;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.CacheEntry;
import java.util.List;
import java.util.Map;
// This represents a method handle bound to a receiver -- it is used during
// compilation / interpretation to represent a method handle returned by a
// method lookup instruction. It may not necessarily have been fully resolved.
// During interpretation / compilation, we may get a fully resolved method handle
// which might be stored in an inline cache.
public class MethodHandle extends Operand {
final protected Operand methodName;
final protected Operand receiver;
// Used during interpretation
private String resolvedMethodName;
private CacheEntry cachedMethod;
private IRubyObject receiverObj;
public MethodHandle(Operand methodName, Operand receiver) {
this.methodName = methodName;
this.receiver = receiver;
}
public Operand getMethodNameOperand() {
return methodName;
}
public DynamicMethod getResolvedMethod() {
return cachedMethod.method;
}
public String getResolvedMethodName() {
return resolvedMethodName;
}
public IRubyObject getReceiverObj() {
return receiverObj;
}
@Override
public void addUsedVariables(List l) {
methodName.addUsedVariables(l);
receiver.addUsedVariables(l);
}
@Override
public boolean canCopyPropagate() {
return true;
}
@Override
public Operand getSimplifiedOperand(Map valueMap, boolean force) {
Operand newMethodName = methodName.getSimplifiedOperand(valueMap, force);
Operand newReceiver = receiver.getSimplifiedOperand(valueMap, force);
return (newMethodName == methodName && newReceiver == receiver) ? this : new MethodHandle(newMethodName, newReceiver);
}
@Override
public String toString() {
return "<" + receiver + "." + methodName + ">";
}
@Override
public Operand cloneForInlining(InlinerInfo ii) {
return new MethodHandle(methodName.cloneForInlining(ii), receiver.cloneForInlining(ii));
}
@Override
public Object retrieve(ThreadContext context, IRubyObject self, DynamicScope currDynScope, Object[] temp) {
receiverObj = (IRubyObject)receiver.retrieve(context, self, currDynScope, temp);
if (methodName instanceof MethAddr) {
resolvedMethodName = ((MethAddr)methodName).getName();
} else {
IRubyObject mnameObj = (IRubyObject)methodName.retrieve(context, self, currDynScope, temp);
// SSS FIXME: If this is not a ruby string or a symbol, then this is an error in the source code!
// Raise an exception and throw an error. This should not be an assert.
assert (mnameObj instanceof RubyString || mnameObj instanceof RubySymbol);
// Clear cached method if the method name has changed!
if (!mnameObj.toString().equals(resolvedMethodName)) {
cachedMethod = null;
resolvedMethodName = mnameObj.toString();
}
}
RubyClass receiverClass = receiverObj.getMetaClass();
if (cachedMethod == null || !cachedMethod.typeOk(receiverClass)) {
// lookup -- 'm' can be an undefined method. It is the caller's responsibility to deal with that
cachedMethod = receiverClass.searchWithCache(resolvedMethodName);
}
return this;
}
@Override
public void visit(IRVisitor visitor) {
visitor.MethodHandle(this);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy