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

Commits on Jun 26, 2015

  1. Copy the full SHA
    dea5d82 View commit details
  2. Copy the full SHA
    bd75f63 View commit details
  3. [Truffle] Add PE tests for Method#call.

    * And possibly future tests for Kernel#method, Method#unbind and UnboundMethod#bind.
    eregon committed Jun 26, 2015
    2
    Copy the full SHA
    717610c View commit details
15 changes: 15 additions & 0 deletions test/truffle/pe/core/method_pe.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright (c) 2014, 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

example "1.method(:abs).call"
example "1.method(:abs).unbind.bind(-2).call"

# These 3 are not constant currently since they produce new objects
# example "1.method(:abs)"
# example "1.method(:abs).unbind"
# example "1.method(:abs).unbind.bind(-2)"
1 change: 1 addition & 0 deletions test/truffle/pe/pe.rb
Original file line number Diff line number Diff line change
@@ -50,6 +50,7 @@ def tagged_example(code)
require_relative 'core/fixnum_pe.rb'
require_relative 'core/float_pe.rb'
require_relative 'core/symbol_pe.rb'
require_relative 'core/method_pe.rb'
require_relative 'core/array_pe.rb'
require_relative 'core/hash_pe.rb'
require_relative 'macro/pushing_pixels_pe.rb'
Original file line number Diff line number Diff line change
@@ -275,8 +275,6 @@ public UnbindNode(RubyContext context, SourceSection sourceSection) {

@Specialization
public RubyBasicObject unbind(VirtualFrame frame, RubyBasicObject method) {
CompilerDirectives.transferToInterpreter();

RubyClass receiverClass = classNode.executeGetClass(frame, getReceiver(method));
return UnboundMethodNodes.createUnboundMethod(getContext().getCoreLibrary().getUnboundMethodClass(), receiverClass, getMethod(method));
}
Original file line number Diff line number Diff line change
@@ -11,16 +11,20 @@

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.*;
import com.oracle.truffle.api.source.NullSourceSection;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.ast.ArgsNode;
import org.jruby.runtime.ArgumentDescriptor;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.core.array.ArrayNodes;
import org.jruby.truffle.nodes.methods.CanBindMethodToModuleNode;
import org.jruby.truffle.nodes.methods.CanBindMethodToModuleNodeGen;
import org.jruby.truffle.nodes.objects.MetaClassNode;
import org.jruby.truffle.nodes.objects.MetaClassNodeGen;
import org.jruby.truffle.runtime.ModuleOperations;
@@ -116,37 +120,37 @@ public int arity(RubyBasicObject method) {
public abstract static class BindNode extends CoreMethodArrayArgumentsNode {

@Child private MetaClassNode metaClassNode;
@Child private CanBindMethodToModuleNode canBindMethodToModuleNode;

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

private RubyClass metaClass(VirtualFrame frame, Object object) {
if (metaClassNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
metaClassNode = insert(MetaClassNodeGen.create(getContext(), getSourceSection(), null));
}
return metaClassNode.executeMetaClass(frame, object);
metaClassNode = MetaClassNodeGen.create(context, sourceSection, null);
canBindMethodToModuleNode = CanBindMethodToModuleNodeGen.create(context, sourceSection, null, null);
}

@Specialization
public RubyBasicObject bind(VirtualFrame frame, RubyBasicObject unboundMethod, Object object) {
CompilerDirectives.transferToInterpreter();
final RubyClass objectMetaClass = metaClass(frame, object);

RubyModule module = getMethod(unboundMethod).getDeclaringModule();
// the (redundant) instanceof is to satisfy FindBugs with the following cast
if (module instanceof RubyClass && !ModuleOperations.canBindMethodTo(module, metaClass(frame, object))) {
if (!canBindMethodToModuleNode.executeCanBindMethodToModule(frame, getMethod(unboundMethod), objectMetaClass)) {
CompilerDirectives.transferToInterpreter();
if (((RubyClass) module).isSingleton()) {
throw new RaiseException(getContext().getCoreLibrary().typeError("singleton method called for a different object", this));
final RubyModule declaringModule = getMethod(unboundMethod).getDeclaringModule();
if (declaringModule instanceof RubyClass && ((RubyClass) declaringModule).isSingleton()) {
throw new RaiseException(getContext().getCoreLibrary().typeError(
"singleton method called for a different object", this));
} else {
throw new RaiseException(getContext().getCoreLibrary().typeError("bind argument must be an instance of " + module.getName(), this));
throw new RaiseException(getContext().getCoreLibrary().typeError(
"bind argument must be an instance of " + declaringModule.getName(), this));
}
}

return MethodNodes.createMethod(getContext().getCoreLibrary().getMethodClass(), object, getMethod(unboundMethod));
}

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

}

@CoreMethod(names = "name")
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* 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.methods;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.dispatch.DispatchNode;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyModule;
import org.jruby.truffle.runtime.methods.InternalMethod;

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;

@NodeChildren({
@NodeChild("method"),
@NodeChild("module")
})
public abstract class CanBindMethodToModuleNode extends RubyNode {

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

public abstract boolean executeCanBindMethodToModule(VirtualFrame frame, InternalMethod method, RubyModule module);

@Specialization(
guards = { "method.getDeclaringModule() == declaringModule", "module == cachedModule" },
limit = "getCacheLimit()")
protected boolean canBindMethodToCached(VirtualFrame frame, InternalMethod method, RubyModule module,
@Cached("method.getDeclaringModule()") RubyModule declaringModule,
@Cached("module") RubyModule cachedModule,
@Cached("canBindMethodTo(declaringModule, cachedModule)") boolean canBindMethodTo) {
return canBindMethodTo;
}

@Specialization
protected boolean canBindMethodToUncached(VirtualFrame frame, InternalMethod method, RubyModule module) {
final RubyModule declaringModule = method.getDeclaringModule();
return canBindMethodTo(declaringModule, module);
}

protected boolean canBindMethodTo(RubyModule declaringModule, RubyModule module) {
return ModuleOperations.canBindMethodTo(declaringModule, module);
}

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

}