Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: b105728091cb
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 8f25e4eee0c7
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Jun 26, 2015

  1. Copy the full SHA
    3e27965 View commit details
  2. [Truffle] Add cache to Kernel#method.

    * No cache needed directly in MethodNode!
    * Use a generic LookupMethodNode instead.
    eregon committed Jun 26, 2015
    4
    Copy the full SHA
    8f25e4e View commit details
38 changes: 19 additions & 19 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/KernelNodes.java
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@
import org.jruby.truffle.nodes.cast.BooleanCastWithDefaultNodeGen;
import org.jruby.truffle.nodes.cast.NumericToFloatNode;
import org.jruby.truffle.nodes.cast.NumericToFloatNodeGen;
import org.jruby.truffle.nodes.coerce.NameToJavaStringNodeGen;
import org.jruby.truffle.nodes.coerce.ToStrNodeGen;
import org.jruby.truffle.nodes.constants.LookupConstantNode;
import org.jruby.truffle.nodes.core.KernelNodesFactory.CopyNodeFactory;
@@ -1111,36 +1112,35 @@ public RubyBasicObject methodName() {
}

@CoreMethod(names = "method", required = 1)
public abstract static class MethodNode extends CoreMethodArrayArgumentsNode {
@NodeChildren({
@NodeChild(type = RubyNode.class, value = "object"),
@NodeChild(type = RubyNode.class, value = "name")
})
public abstract static class MethodNode extends CoreMethodNode {

@Child LookupMethodNode lookupMethodNode;

public MethodNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
lookupMethodNode = LookupMethodNodeGen.create(context, sourceSection, null, null);
}

@Specialization(guards = "isRubyString(name)")
public RubyBasicObject methodString(Object object, RubyBasicObject name) {
return method(object, name.toString());
@CreateCast("name")
public RubyNode coerceToString(RubyNode name) {
return NameToJavaStringNodeGen.create(getContext(), getSourceSection(), name);
}

@Specialization(guards = "isRubySymbol(name)")
public RubyBasicObject methodSymbol(Object object, RubyBasicObject name) {
return method(object, SymbolNodes.getString(name));
}

private RubyBasicObject method(Object object, String name) {
CompilerDirectives.transferToInterpreter();

// TODO(CS, 11-Jan-15) cache this lookup

final InternalMethod method = ModuleOperations.lookupMethod(getContext().getCoreLibrary().getMetaClass(object), name);
@Specialization
public RubyBasicObject methodCached(VirtualFrame frame, Object self, String name) {
InternalMethod method = lookupMethodNode.executeLookupMethod(frame, self, name);

if (method == null) {
throw new RaiseException(
getContext().getCoreLibrary().nameErrorUndefinedMethod(
name, getContext().getCoreLibrary().getLogicalClass(object), this));
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().nameErrorUndefinedMethod(
name, getContext().getCoreLibrary().getLogicalClass(self), this));
}

return MethodNodes.createMethod(getContext().getCoreLibrary().getMethodClass(), object, method);
return MethodNodes.createMethod(getContext().getCoreLibrary().getMethodClass(), self, method);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.dispatch;

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.objects.MetaClassNode;
import org.jruby.truffle.nodes.objects.MetaClassNodeGen;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyClass;
import org.jruby.truffle.runtime.methods.InternalMethod;

@NodeChildren({
@NodeChild("self"),
@NodeChild("name")
})
public abstract class LookupMethodNode extends RubyNode {

protected static int getCacheLimit() {
return DispatchNode.DISPATCH_POLYMORPHIC_MAX;
}

@Child MetaClassNode metaClassNode;

public LookupMethodNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
metaClassNode = MetaClassNodeGen.create(context, sourceSection, null);
}

public abstract InternalMethod executeLookupMethod(VirtualFrame frame, Object self, String name);

@Specialization(
guards = "metaClass(frame, self) == selfMetaClass",
assumptions = "selfMetaClass.getUnmodifiedAssumption()",
limit = "getCacheLimit()")
protected InternalMethod lookupMethodCached(VirtualFrame frame, Object self, String name,
@Cached("metaClass(frame, self)") RubyClass selfMetaClass,
@Cached("doLookup(selfMetaClass, name)") InternalMethod method) {
return method;
}

@Specialization
protected InternalMethod lookupMethodUncached(VirtualFrame frame, Object self, String name) {
RubyClass selfMetaClass = metaClass(frame, self);
return doLookup(selfMetaClass, name);
}

protected RubyClass metaClass(VirtualFrame frame, Object object) {
return metaClassNode.executeMetaClass(frame, object);
}

protected InternalMethod doLookup(RubyClass selfMetaClass, String name) {
InternalMethod method = ModuleOperations.lookupMethod(selfMetaClass, name);
// TODO (eregon, 26 June 2015): Is this OK for all usages?
if (method != null && method.isUndefined()) {
method = null;
}
return method;
}

}