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

Commits on Jan 21, 2016

  1. Copy the full SHA
    d71eecf View commit details
  2. Copy the full SHA
    3a8ed98 View commit details
  3. Copy the full SHA
    d6b97fb View commit details
  4. Copy the full SHA
    dafc460 View commit details
2 changes: 1 addition & 1 deletion spec/ruby/core/method/owner_spec.rb
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
"abc".method(:upcase).owner.should == String
end

it "returns the name even when aliased" do
it "returns the same owner when aliased in the same classes" do
obj = MethodSpecs::Methods.new
obj.method(:foo).owner.should == MethodSpecs::Methods
obj.method(:bar).owner.should == MethodSpecs::Methods
19 changes: 19 additions & 0 deletions spec/ruby/core/module/define_method_spec.rb
Original file line number Diff line number Diff line change
@@ -71,6 +71,25 @@ def test_method
end
end

describe "Module#define_method when name is not a special private name" do
describe "given an UnboundMethod" do
it "sets the visibility of the method to the current visibility" do
m = Module.new do
def foo
end
private :foo
end
klass = Class.new do
define_method(:bar, m.instance_method(:foo))
private
define_method(:baz, m.instance_method(:foo))
end
klass.should have_public_instance_method(:bar)
klass.should have_private_instance_method(:baz)
end
end
end

describe "Module#define_method when name is :initialize" do
describe "passed a block" do
it "sets visibility to private when method name is :initialize" do
27 changes: 11 additions & 16 deletions spec/ruby/core/unboundmethod/owner_spec.rb
Original file line number Diff line number Diff line change
@@ -3,29 +3,24 @@

describe "UnboundMethod#owner" do
it "returns the owner of the method" do
"abc".method(:upcase).owner.should == String
String.instance_method(:upcase).owner.should == String
end

it "returns the name even when aliased" do
obj = UnboundMethodSpecs::Methods.new
obj.method(:foo).owner.should == UnboundMethodSpecs::Methods
obj.method(:bar).owner.should == UnboundMethodSpecs::Methods
it "returns the same owner when aliased in the same classes" do
UnboundMethodSpecs::Methods.instance_method(:foo).owner.should == UnboundMethodSpecs::Methods
UnboundMethodSpecs::Methods.instance_method(:bar).owner.should == UnboundMethodSpecs::Methods
end

it "returns the class/module it was defined in" do
UnboundMethodSpecs::C.new.method(:baz).owner.should == UnboundMethodSpecs::A
UnboundMethodSpecs::Methods.new.method(:from_mod).owner.should == UnboundMethodSpecs::Mod
UnboundMethodSpecs::C.instance_method(:baz).owner.should == UnboundMethodSpecs::A
UnboundMethodSpecs::Methods.instance_method(:from_mod).owner.should == UnboundMethodSpecs::Mod
end
end

describe "UnboundMethod#owner" do
before :each do
@parent_singleton_class = class << UnboundMethodSpecs::Parent; self; end
@child_singleton_class = class << UnboundMethodSpecs::Child3; self; end
end
it "returns the new owner for aliased methods on singleton classes" do
parent_singleton_class = UnboundMethodSpecs::Parent.singleton_class
child_singleton_class = UnboundMethodSpecs::Child3.singleton_class

it "returns the new owner for aliased methods" do
@child_singleton_class.instance_method(:class_method).owner.should == @parent_singleton_class
@child_singleton_class.instance_method(:another_class_method).owner.should == @child_singleton_class
child_singleton_class.instance_method(:class_method).owner.should == parent_singleton_class
child_singleton_class.instance_method(:another_class_method).owner.should == child_singleton_class
end
end
1 change: 1 addition & 0 deletions spec/truffle/tags/core/unboundmethod/owner_tags.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fails:UnboundMethod#owner returns the new owner for aliased methods on singleton classes
30 changes: 14 additions & 16 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/ModuleNodes.java
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@
import com.oracle.truffle.api.utilities.ValueProfile;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;

import org.jcodings.Encoding;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.runtime.Visibility;
@@ -48,9 +49,12 @@
import org.jruby.truffle.nodes.core.ModuleNodesFactory.SetVisibilityNodeGen;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.nodes.methods.AddMethodNode;
import org.jruby.truffle.nodes.methods.AddMethodNodeGen;
import org.jruby.truffle.nodes.methods.CanBindMethodToModuleNode;
import org.jruby.truffle.nodes.methods.CanBindMethodToModuleNodeGen;
import org.jruby.truffle.nodes.methods.DeclarationContext;
import org.jruby.truffle.nodes.methods.GetCurrentVisibilityNode;
import org.jruby.truffle.nodes.objects.*;
import org.jruby.truffle.nodes.yield.YieldDispatchHeadNode;
import org.jruby.truffle.runtime.*;
@@ -1036,8 +1040,11 @@ public Object setConstant(DynamicObject module, String name, Object value) {
})
public abstract static class DefineMethodNode extends CoreMethodNode {

@Child AddMethodNode addMethodNode;

public DefineMethodNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
addMethodNode = AddMethodNodeGen.create(context, sourceSection, false, false, null, null, null);
}

@CreateCast("name")
@@ -1134,15 +1141,13 @@ public Object execute(VirtualFrame frame) {

}

@TruffleBoundary
private DynamicObject addMethod(DynamicObject module, String name, InternalMethod method) {
method = method.withName(name);

if (ModuleOperations.isMethodPrivateFromName(name)) {
method = method.withVisibility(Visibility.PRIVATE);
}

Layouts.MODULE.getFields(module).addMethod(getContext(), this, method);
return getSymbol(name);
final Frame frame = RubyCallStack.getCallerFrame(getContext()).getFrame(FrameAccess.READ_ONLY, true);
final Visibility visibility = GetCurrentVisibilityNode.getVisibilityFromNameAndFrame(name, frame);
return addMethodNode.executeAddMethod(module, method, visibility);
}

protected CanBindMethodToModuleNode createCanBindMethodToModuleNode() {
@@ -1965,14 +1970,14 @@ public abstract static class SetMethodVisibilityNode extends RubyNode {

private final Visibility visibility;

@Child SingletonClassNode singletonClassNode;
@Child NameToJavaStringNode nameToJavaStringNode;
@Child AddMethodNode addMethodNode;

public SetMethodVisibilityNode(RubyContext context, SourceSection sourceSection, Visibility visibility) {
super(context, sourceSection);
this.visibility = visibility;
this.nameToJavaStringNode = NameToJavaStringNodeGen.create(context, sourceSection, null);
this.singletonClassNode = SingletonClassNodeGen.create(context, sourceSection, null);
this.addMethodNode = AddMethodNodeGen.create(context, sourceSection, true, false, null, null, null);
}

public abstract DynamicObject executeSetMethodVisibility(VirtualFrame frame, DynamicObject module, Object name);
@@ -1994,14 +1999,7 @@ public DynamicObject setMethodVisibility(VirtualFrame frame, DynamicObject modul
* want to add a copy of the method with a different visibility
* to this module.
*/
if (visibility == Visibility.MODULE_FUNCTION) {
Layouts.MODULE.getFields(module).addMethod(getContext(), this, method.withVisibility(Visibility.PRIVATE));
Layouts.MODULE.getFields(singletonClassNode.executeSingletonClass(module)).addMethod(getContext(), this, method.withVisibility(Visibility.PUBLIC));
} else {
Layouts.MODULE.getFields(module).addMethod(getContext(), this, method.withVisibility(visibility));
}

return module;
return addMethodNode.executeAddMethod(module, method, visibility);
}

}
Original file line number Diff line number Diff line change
@@ -54,7 +54,7 @@
@CoreClass(name = "Truffle::Primitive")
public abstract class TrufflePrimitiveNodes {

@CoreMethod(names = "binding_of_caller", onSingleton = true)
@CoreMethod(names = "binding_of_caller", isModuleFunction = true)
public abstract static class BindingOfCallerNode extends CoreMethodArrayArgumentsNode {

public BindingOfCallerNode(RubyContext context, SourceSection sourceSection) {
@@ -94,7 +94,7 @@ public MaterializedFrame visitFrame(FrameInstance frameInstance) {

}

@CoreMethod(names = "source_of_caller", onSingleton = true)
@CoreMethod(names = "source_of_caller", isModuleFunction = true)
public abstract static class SourceOfCallerNode extends CoreMethodArrayArgumentsNode {

public SourceOfCallerNode(RubyContext context, SourceSection sourceSection) {
Original file line number Diff line number Diff line change
@@ -9,13 +9,7 @@
*/
package org.jruby.truffle.nodes.methods;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.objects.SingletonClassNode;
import org.jruby.truffle.nodes.objects.SingletonClassNodeGen;
@@ -24,53 +18,60 @@
import org.jruby.truffle.runtime.layouts.Layouts;
import org.jruby.truffle.runtime.methods.InternalMethod;

public class AddMethodNode extends RubyNode {
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
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.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;

@NodeChildren({
@NodeChild("moduleNode"),
@NodeChild("methodNode"),
@NodeChild("visibilityNode")
})
public abstract class AddMethodNode extends RubyNode {

private final boolean isDefs; // def expr.meth()
private final boolean ignoreNameVisibility; // def expr.meth()
private final boolean isLiteralDef;

@Child private RubyNode receiver;
@Child private MethodDefinitionNode methodNode;
@Child private SingletonClassNode singletonClassNode;

public AddMethodNode(RubyContext context, SourceSection section, RubyNode receiver, MethodDefinitionNode method, boolean isDefs) {
super(context, section);
this.isDefs = isDefs;
this.receiver = receiver;
this.methodNode = method;
this.singletonClassNode = SingletonClassNodeGen.create(context, section, null);
public AddMethodNode(RubyContext context, SourceSection sourceSection, boolean ignoreNameVisibility, boolean isLiteralDef) {
super(context, sourceSection);
this.ignoreNameVisibility = ignoreNameVisibility;
this.isLiteralDef = isLiteralDef;
this.singletonClassNode = SingletonClassNodeGen.create(context, sourceSection, null);
}

@Override
public DynamicObject execute(VirtualFrame frame) {
CompilerDirectives.transferToInterpreter();

final Object receiverObject = receiver.execute(frame);
public abstract DynamicObject executeAddMethod(DynamicObject module, InternalMethod method, Visibility visibility);

final InternalMethod methodObject = (InternalMethod) methodNode.execute(frame);
@TruffleBoundary
@Specialization(guards = "isRubyModule(module)")
public DynamicObject addMethod(DynamicObject module, InternalMethod method, Visibility visibility) {
if (!ignoreNameVisibility && ModuleOperations.isMethodPrivateFromName(method.getName())) {
visibility = Visibility.PRIVATE;
}

final DynamicObject module = (DynamicObject) receiverObject;
assert RubyGuards.isRubyModule(module);
method = method.withVisibility(visibility);

final Visibility visibility = getVisibility(frame, methodObject.getName());
final InternalMethod method = methodObject.withDeclaringModule(module).withVisibility(visibility);
if (isLiteralDef) {
method = method.withDeclaringModule(module);
}

if (method.getVisibility() == Visibility.MODULE_FUNCTION) {
Layouts.MODULE.getFields(module).addMethod(getContext(), this, method.withVisibility(Visibility.PRIVATE));
Layouts.MODULE.getFields(singletonClassNode.executeSingletonClass(module)).addMethod(getContext(), this, method.withVisibility(Visibility.PUBLIC));
if (visibility == Visibility.MODULE_FUNCTION) {
addMethodToModule(module, method.withVisibility(Visibility.PRIVATE));
final DynamicObject singletonClass = singletonClassNode.executeSingletonClass(module);
addMethodToModule(singletonClass, method.withDeclaringModule(singletonClass).withVisibility(Visibility.PUBLIC));
} else {
Layouts.MODULE.getFields(module).addMethod(getContext(), this, method);
addMethodToModule(module, method);
}

return getSymbol(method.getName());
}

private Visibility getVisibility(Frame frame, String name) {
if (isDefs) {
return Visibility.PUBLIC;
} else if (ModuleOperations.isMethodPrivateFromName(name)) {
return Visibility.PRIVATE;
} else {
return DeclarationContext.findVisibility(frame);
}
public void addMethodToModule(final DynamicObject module, InternalMethod method) {
Layouts.MODULE.getFields(module).addMethod(getContext(), this, method);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2013, 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.runtime.Visibility;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyContext;

import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
import com.oracle.truffle.api.source.SourceSection;

public class GetCurrentVisibilityNode extends RubyNode {

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

@Override
public Visibility execute(VirtualFrame frame) {
return DeclarationContext.findVisibility(frame);
}

@TruffleBoundary
public static Visibility getVisibilityFromNameAndFrame(String name, Frame frame) {
if (ModuleOperations.isMethodPrivateFromName(name)) {
return Visibility.PRIVATE;
} else {
return DeclarationContext.findVisibility(frame);
}
}

}
Original file line number Diff line number Diff line change
@@ -323,7 +323,8 @@ public Object removeClassVariable(RubyContext context, Node currentNode, String

@CompilerDirectives.TruffleBoundary
public void addMethod(RubyContext context, Node currentNode, InternalMethod method) {
assert method != null;
assert ModuleOperations.canBindMethodTo(method.getDeclaringModule(), rubyModuleObject) ||
ModuleOperations.assignableTo(context.getCoreLibrary().getObjectClass(), method.getDeclaringModule());

if (context.getCoreLibrary().isLoadingRubyCore()) {
final InternalMethod currentMethod = methods.get(method.getName());
@@ -334,7 +335,7 @@ public void addMethod(RubyContext context, Node currentNode, InternalMethod meth
}

checkFrozen(context, currentNode);
methods.put(method.getName(), method.withDeclaringModule(rubyModuleObject));
methods.put(method.getName(), method);
newVersion();

if (context.getCoreLibrary().isLoaded() && !method.isUndefined()) {
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;

import org.jcodings.specific.UTF8Encoding;
import org.joni.NameEntry;
import org.joni.Regex;
@@ -25,6 +26,7 @@
import org.jruby.parser.ParserSupport;
import org.jruby.runtime.ArgumentDescriptor;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyRootNode;
import org.jruby.truffle.nodes.ThreadLocalObjectNode;
@@ -1205,9 +1207,16 @@ protected RubyNode translateMethodDefinition(SourceSection sourceSection, RubyNo

final MethodTranslator methodCompiler = new MethodTranslator(currentNode, context, this, newEnvironment, false, source, argsNode);

final MethodDefinitionNode functionExprNode = methodCompiler.compileMethodNode(sourceSection, methodName, bodyNode, sharedMethodInfo);
final MethodDefinitionNode methodDefinitionNode = methodCompiler.compileMethodNode(sourceSection, methodName, bodyNode, sharedMethodInfo);

final RubyNode visibilityNode;
if (isDefs) {
visibilityNode = new LiteralNode(context, sourceSection, Visibility.PUBLIC);
} else {
visibilityNode = new GetCurrentVisibilityNode(context, sourceSection);
}

return new AddMethodNode(context, sourceSection, classNode, functionExprNode, isDefs);
return AddMethodNodeGen.create(context, sourceSection, isDefs, true, classNode, methodDefinitionNode, visibilityNode);
}

@Override
Loading