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: c5fa69253e83
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 7cd4f1c093ac
Choose a head ref
  • 3 commits
  • 6 files changed
  • 1 contributor

Commits on Feb 10, 2015

  1. [Truffle] Remove duplication.

    eregon committed Feb 10, 2015
    1
    Copy the full SHA
    f5a7f2e View commit details
  2. Copy the full SHA
    bccceb7 View commit details
  3. Copy the full SHA
    7cd4f1c View commit details
3 changes: 0 additions & 3 deletions spec/truffle/tags/language/super_tags.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
fails:The super keyword calls the correct method when the method visibility is modified
fails:The super keyword supers up appropriate name even if used for multiple method names
fails:The super keyword passes along modified rest args when they weren't originally empty
fails:The super keyword passes along modified rest args when they were originally empty
fails:The super keyword raises a RuntimeError when called with implicit arguments from a method defined with define_method
fails:The super keyword invokes methods from a chain of anonymous modules
fails:The super keyword calls method_missing when a superclass method is not found
fails:The super keyword sees the included version of a module a method is alias from
Original file line number Diff line number Diff line change
@@ -86,21 +86,11 @@ public CallNode(CallNode prev) {

@Specialization
public Object call(VirtualFrame frame, RubyMethod method, Object[] arguments, @SuppressWarnings("unused") UndefinedPlaceholder block) {
// TODO(CS 11-Jan-15) should use a cache and DirectCallNode here so that we can inline - but it's
// incompatible with our current dispatch chain.

final InternalMethod internalMethod = method.getMethod();

return callNode.call(frame, method.getMethod().getCallTarget(), RubyArguments.pack(
internalMethod,
internalMethod.getDeclarationFrame(),
method.getReceiver(),
null,
arguments));
return doCall(frame, method, arguments, null);
}

@Specialization
public Object call(VirtualFrame frame, RubyMethod method, Object[] arguments, RubyProc block) {
public Object doCall(VirtualFrame frame, RubyMethod method, Object[] arguments, RubyProc block) {
// TODO(CS 11-Jan-15) should use a cache and DirectCallNode here so that we can inline - but it's
// incompatible with our current dispatch chain.

Original file line number Diff line number Diff line change
@@ -13,7 +13,6 @@
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.FrameInstance;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.source.SourceSection;
@@ -25,59 +24,55 @@
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyClass;
import org.jruby.truffle.runtime.core.RubyModule;
import org.jruby.truffle.runtime.core.RubyProc;
import org.jruby.truffle.runtime.methods.MethodLike;
import org.jruby.truffle.runtime.methods.InternalMethod;

public abstract class AbstractGeneralSuperCallNode extends RubyNode {

@Child protected DirectCallNode callNode;

@CompilerDirectives.CompilationFinal protected InternalMethod currentMethod;
@CompilerDirectives.CompilationFinal protected Assumption unmodifiedAssumption;
@CompilerDirectives.CompilationFinal protected InternalMethod method;
@CompilerDirectives.CompilationFinal protected InternalMethod superMethod;

public AbstractGeneralSuperCallNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

protected boolean guard() {
// TODO(CS): not sure this is enough... lots of 'unspecified' behaviour in the ISO spec here
return method != null && unmodifiedAssumption != null && unmodifiedAssumption.isValid();
InternalMethod method = RubyCallStack.getCurrentMethod();

return method == currentMethod && unmodifiedAssumption.isValid();
}

protected void lookup(VirtualFrame frame) {
CompilerAsserts.neverPartOfCompilation();

final FrameInstance currentFrame = Truffle.getRuntime().getCurrentFrame();
MethodLike methodLike = RubyCallStack.getMethod(currentFrame);

while (!(methodLike instanceof InternalMethod)) {
methodLike = ((RubyProc) methodLike).getMethod();
}

final String name = ((InternalMethod) methodLike).getName();
currentMethod = RubyCallStack.getCurrentMethod();

String name = currentMethod.getName();
// TODO: this is wrong, we need the lexically enclosing method (or define_method)'s module
final RubyModule declaringModule = RubyCallStack.getCurrentDeclaringModule();
RubyModule declaringModule = currentMethod.getDeclaringModule();

final RubyClass selfMetaClass = getContext().getCoreLibrary().getMetaClass(RubyArguments.getSelf(frame.getArguments()));

method = ModuleOperations.lookupSuperMethod(declaringModule, name, selfMetaClass);
superMethod = ModuleOperations.lookupSuperMethod(declaringModule, name, selfMetaClass);

if (method == null || method.isUndefined()) {
method = null;
if (superMethod == null || superMethod.isUndefined()) {
superMethod = null;
// TODO: should add " for #{receiver.inspect}" in error message
throw new RaiseException(getContext().getCoreLibrary().noMethodError(String.format("super: no superclass method `%s'", name), this));
}

final DirectCallNode newCallNode = Truffle.getRuntime().createDirectCallNode(method.getCallTarget());
unmodifiedAssumption = declaringModule.getUnmodifiedAssumption();

final DirectCallNode newCallNode = Truffle.getRuntime().createDirectCallNode(superMethod.getCallTarget());

if (callNode == null) {
callNode = insert(newCallNode);
} else {
callNode.replace(newCallNode);
}

unmodifiedAssumption = declaringModule.getUnmodifiedAssumption();
}

@Override
@@ -93,7 +88,7 @@ public Object isDefined(VirtualFrame frame) {
lookup(frame);
}

if (method == null || method.isUndefined() || !method.isVisibleTo(this, context.getCoreLibrary().getMetaClass(self))) {
if (superMethod == null || superMethod.isUndefined() || !superMethod.isVisibleTo(this, context.getCoreLibrary().getMetaClass(self))) {
return getContext().getCoreLibrary().getNilObject();
} else {
return context.makeString("super");
Original file line number Diff line number Diff line change
@@ -79,19 +79,15 @@ public final Object execute(VirtualFrame frame) {
lookup(frame);
}

if (method == null || callNode == null) {
throw new IllegalStateException("No call node installed");
}

// Call the method

if (isSplatted) {
// TODO(CS): need something better to splat the arguments array
notDesignedForCompilation();
final RubyArray argumentsArray = (RubyArray) argumentsObjects[0];
return callNode.call(frame, RubyArguments.pack(method, method.getDeclarationFrame(), self, blockObject,argumentsArray.slowToArray()));
return callNode.call(frame, RubyArguments.pack(superMethod, superMethod.getDeclarationFrame(), self, blockObject,argumentsArray.slowToArray()));
} else {
return callNode.call(frame, RubyArguments.pack(method, method.getDeclarationFrame(), self, blockObject, argumentsObjects));
return callNode.call(frame, RubyArguments.pack(superMethod, superMethod.getDeclarationFrame(), self, blockObject, argumentsObjects));
}
}

Original file line number Diff line number Diff line change
@@ -9,9 +9,12 @@
*/
package org.jruby.truffle.nodes.supercall;

import java.util.Arrays;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyContext;

@@ -31,18 +34,18 @@ public final Object execute(VirtualFrame frame) {
lookup(frame);
}

if (method == null || callNode == null) {
throw new IllegalStateException("No call node installed");
}

final Object[] superArguments;
final Object[] originalArguments;

if (inBlock) {
superArguments = RubyArguments.getDeclarationFrame(frame.getArguments()).getArguments();
originalArguments = RubyArguments.getDeclarationFrame(frame.getArguments()).getArguments();
} else {
superArguments = frame.getArguments();
originalArguments = frame.getArguments();
}

final Object[] superArguments = Arrays.copyOf(originalArguments, originalArguments.length);

superArguments[RubyArguments.METHOD_INDEX] = superMethod;

return callNode.call(frame, superArguments);
}

11 changes: 11 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/runtime/RubyCallStack.java
Original file line number Diff line number Diff line change
@@ -14,10 +14,12 @@
import com.oracle.truffle.api.frame.FrameInstance;
import com.oracle.truffle.api.frame.FrameInstanceVisitor;
import com.oracle.truffle.api.nodes.Node;

import org.jruby.truffle.nodes.CoreSourceSection;
import org.jruby.truffle.runtime.backtrace.Activation;
import org.jruby.truffle.runtime.backtrace.Backtrace;
import org.jruby.truffle.runtime.core.RubyModule;
import org.jruby.truffle.runtime.core.RubyProc;
import org.jruby.truffle.runtime.methods.InternalMethod;
import org.jruby.truffle.runtime.methods.MethodLike;
import org.jruby.util.Memo;
@@ -34,6 +36,15 @@ public static RubyModule getCurrentDeclaringModule() {
return method.getDeclaringModule();
}

public static InternalMethod getCurrentMethod() {
final FrameInstance currentFrame = Truffle.getRuntime().getCurrentFrame();
MethodLike methodLike = getMethod(currentFrame);
while (!(methodLike instanceof InternalMethod)) {
methodLike = ((RubyProc) methodLike).getMethod();
}
return (InternalMethod) methodLike;
}

public static InternalMethod getCallingMethod() {
CompilerAsserts.neverPartOfCompilation();