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

Commits on Feb 10, 2015

  1. [Truffle] super: we also need to check if the ancestors are compatible.

    * Unfortunately it seems no spec tests that.
    * Additionally test if we found a method.
    eregon committed Feb 10, 2015
    Copy the full SHA
    049480d View commit details
  2. Copy the full SHA
    12c8ade View commit details
  3. [Truffle] No need to check visibility for super since there is never …

    …an explicit receiver.
    eregon committed Feb 10, 2015
    Copy the full SHA
    59122d2 View commit details
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyArguments;
@@ -30,22 +31,35 @@ public abstract class AbstractGeneralSuperCallNode extends RubyNode {

@Child protected DirectCallNode callNode;

@CompilerDirectives.CompilationFinal protected InternalMethod currentMethod;
@CompilerDirectives.CompilationFinal protected Assumption unmodifiedAssumption;
@CompilerDirectives.CompilationFinal private InternalMethod currentMethod;
@CompilerDirectives.CompilationFinal private RubyClass selfMetaClass;
@CompilerDirectives.CompilationFinal private Assumption unmodifiedAssumption;
@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
protected boolean guard(Object self) {
InternalMethod method = RubyCallStack.getCurrentMethod();

return method == currentMethod && unmodifiedAssumption.isValid();
// This is overly restrictive, but seems the be the only reasonable check in term of performance.
// The ideal condition would be to check if both ancestor lists starting at
// the current method's module are identical, which is non-trivial
// if the current method's module is an (included) module and not a class.
boolean compatibleAncestors = getContext().getCoreLibrary().getMetaClass(self) == selfMetaClass;

return superMethod != null &&
method == currentMethod &&
compatibleAncestors &&
unmodifiedAssumption.isValid();
}

protected void lookup(VirtualFrame frame) {
lookup(frame, false);
}

private void lookup(VirtualFrame frame, boolean checkIfDefined) {
CompilerAsserts.neverPartOfCompilation();

currentMethod = RubyCallStack.getCurrentMethod();
@@ -54,12 +68,15 @@ protected void lookup(VirtualFrame frame) {
// TODO: this is wrong, we need the lexically enclosing method (or define_method)'s module
RubyModule declaringModule = currentMethod.getDeclaringModule();

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

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

if (superMethod == null || superMethod.isUndefined()) {
superMethod = null;
if (checkIfDefined) {
return;
}
// TODO: should add " for #{receiver.inspect}" in error message
throw new RaiseException(getContext().getCoreLibrary().noMethodError(String.format("super: no superclass method `%s'", name), this));
}
@@ -79,22 +96,16 @@ protected void lookup(VirtualFrame frame) {
public Object isDefined(VirtualFrame frame) {
notDesignedForCompilation();

final RubyContext context = getContext();
final Object self = RubyArguments.getSelf(frame.getArguments());

try {
final Object self = RubyArguments.getSelf(frame.getArguments());

if (!guard()) {
lookup(frame);
}
if (!guard(self)) {
lookup(frame, true);
}

if (superMethod == null || superMethod.isUndefined() || !superMethod.isVisibleTo(this, context.getCoreLibrary().getMetaClass(self))) {
return getContext().getCoreLibrary().getNilObject();
} else {
return context.makeString("super");
}
} catch (Throwable t) {
if (superMethod == null) {
return getContext().getCoreLibrary().getNilObject();
} else {
return getContext().makeString("super");
}
}

Original file line number Diff line number Diff line change
@@ -45,7 +45,7 @@ public GeneralSuperCallNode(RubyContext context, SourceSection sourceSection, Ru
@ExplodeLoop
@Override
public final Object execute(VirtualFrame frame) {
final RubyBasicObject self = (RubyBasicObject) RubyArguments.getSelf(frame.getArguments());
final Object self = RubyArguments.getSelf(frame.getArguments());

// Execute the arguments

@@ -74,7 +74,7 @@ public final Object execute(VirtualFrame frame) {

// Check we have a method and the module is unmodified

if (!guard()) {
if (!guard(self)) {
CompilerDirectives.transferToInterpreterAndInvalidate();
lookup(frame);
}
Original file line number Diff line number Diff line change
@@ -29,7 +29,9 @@ public GeneralSuperReCallNode(RubyContext context, SourceSection sourceSection,

@Override
public final Object execute(VirtualFrame frame) {
if (!guard()) {
final Object self = RubyArguments.getSelf(frame.getArguments());

if (!guard(self)) {
CompilerDirectives.transferToInterpreterAndInvalidate();
lookup(frame);
}