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

Commits on Aug 20, 2015

  1. [Truffle] Share logic between Proc.new and Kernel#proc.

    * No need for Proc#allocate and #initialize anymore.
    eregon committed Aug 20, 2015
    Copy the full SHA
    ddd1a5e View commit details
  2. Copy the full SHA
    feca81e View commit details
  3. Copy the full SHA
    9fc5d0b View commit details
  4. Copy the full SHA
    44f06d9 View commit details
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/proc/block_pass_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/proc/clone_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/proc/dup_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/proc/hash_tags.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
fails:Proc#hash is stable
fails:Proc#hash does not depend on whether self is a proc or lambda
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/proc/lambda_tags.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
fails:Proc#lambda? is preserved when passing a Proc with & to the lambda keyword
fails:Proc#lambda? is preserved when passing a Proc with & to the proc keyword
fails:Proc#lambda? is preserved when passing a Proc with & to Proc.new
fails:Proc#lambda? is preserved when a Proc is curried
fails:Proc#lambda? is preserved when a curried Proc is called without enough arguments
15 changes: 0 additions & 15 deletions spec/truffle/tags/core/proc/new_tags.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1 @@
fails:Proc.new with an associated block raises a LocalJumpError when context of the block no longer exists
fails:Proc.new with an associated block returns from within enclosing method when 'return' is used in the block
fails:Proc.new with an associated block returns a subclass of Proc
fails:Proc.new with an associated block returns a new Proc instance from the block passed to the containing method
fails:Proc.new with an associated block called on a subclass of Proc returns an instance of the subclass
fails:Proc.new with an associated block called on a subclass of Proc using a reified block parameter returns an instance of the subclass
fails:Proc.new with an associated block called on a subclass of Proc that does not 'super' in 'initialize' still constructs a functional proc
fails:Proc.new with a block argument returns the passed proc created from a block
fails:Proc.new with a block argument returns the passed proc created from a method
fails:Proc.new with a block argument returns the passed proc created from a symbol
fails:Proc.new with a block argument called indirectly from a subclass returns the passed proc created from a block
fails:Proc.new with a block argument called indirectly from a subclass returns the passed proc created from a method
fails:Proc.new with a block argument called indirectly from a subclass returns the passed proc created from a symbol
fails:Proc.new without a block raises an ArgumentError
fails:Proc.new without a block raises an ArgumentError if invoked from within a method with no block
fails:Proc.new without a block raises an ArgumentError if invoked on a subclass from within a method with no block
6 changes: 0 additions & 6 deletions spec/truffle/tags/core/proc/source_location_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/proc/to_proc_tags.txt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ConditionProfile;

import org.jcodings.Encoding;
import org.jcodings.specific.USASCIIEncoding;
import org.jcodings.specific.UTF8Encoding;
@@ -43,6 +44,8 @@
import org.jruby.truffle.nodes.core.KernelNodesFactory.CopyNodeFactory;
import org.jruby.truffle.nodes.core.KernelNodesFactory.SameOrEqualNodeFactory;
import org.jruby.truffle.nodes.core.KernelNodesFactory.SingletonMethodsNodeFactory;
import org.jruby.truffle.nodes.core.ProcNodes.ProcNewNode;
import org.jruby.truffle.nodes.core.ProcNodesFactory.ProcNewNodeFactory;
import org.jruby.truffle.nodes.core.array.ArrayNodes;
import org.jruby.truffle.nodes.core.hash.HashNodes;
import org.jruby.truffle.nodes.dispatch.*;
@@ -56,6 +59,7 @@
import org.jruby.truffle.pack.runtime.PackResult;
import org.jruby.truffle.pack.runtime.exceptions.*;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.array.ArrayUtils;
import org.jruby.truffle.runtime.backtrace.Activation;
import org.jruby.truffle.runtime.backtrace.Backtrace;
import org.jruby.truffle.runtime.control.RaiseException;
@@ -1348,50 +1352,16 @@ public DynamicObject privateMethods(VirtualFrame frame, Object self, boolean inc
@CoreMethod(names = "proc", isModuleFunction = true, needsBlock = true)
public abstract static class ProcNode extends CoreMethodArrayArgumentsNode {

@Child ProcNewNode procNewNode;

public ProcNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
procNewNode = ProcNewNodeFactory.create(context, sourceSection, null);
}

@TruffleBoundary
@Specialization
public DynamicObject proc(NotProvided block) {
final Frame parentFrame = RubyCallStack.getCallerFrame(getContext()).getFrame(FrameAccess.READ_ONLY, true);
final DynamicObject parentBlock = RubyArguments.getBlock(parentFrame.getArguments());

if (parentBlock == null) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().argumentError("tried to create Proc object without a block", this));
}

if (isANormalProc(parentBlock)) {
return procNormal(parentBlock);
} else {
return procSpecial(parentBlock);
}
}

@Specialization(guards = { "isRubyProc(block)", "isANormalProc(block)" })
public DynamicObject procNormal(DynamicObject block) {
return block;
}

@Specialization(guards = { "isRubyProc(block)", "!isANormalProc(block)" })
public DynamicObject procSpecial(DynamicObject block) {
// Just make it a normal Proc without a singleton class
return ProcNodes.createRubyProc(
getContext().getCoreLibrary().getProcClass(),
Layouts.PROC.getType(block),
Layouts.PROC.getSharedMethodInfo(block),
Layouts.PROC.getCallTargetForType(block),
Layouts.PROC.getCallTargetForLambdas(block),
Layouts.PROC.getDeclarationFrame(block),
Layouts.PROC.getMethod(block),
Layouts.PROC.getSelf(block),
Layouts.PROC.getBlock(block));
}

protected boolean isANormalProc(DynamicObject block) {
return Layouts.BASIC_OBJECT.getMetaClass(block) == getContext().getCoreLibrary().getProcClass();
public DynamicObject proc(VirtualFrame frame, Object block) {
return procNewNode.executeProcNew(frame, getContext().getCoreLibrary().getProcClass(), ArrayUtils.EMPTY_ARRAY, block);
}

}
204 changes: 102 additions & 102 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/ProcNodes.java
Original file line number Diff line number Diff line change
@@ -9,33 +9,39 @@
*/
package org.jruby.truffle.nodes.core;

import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.FrameInstance;
import com.oracle.truffle.api.frame.FrameInstanceVisitor;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.DynamicObjectFactory;
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.truffle.nodes.RubyGuards;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.array.ArrayNodes;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.nodes.yield.YieldDispatchHeadNode;
import org.jruby.truffle.runtime.NotProvided;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyCallStack;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.layouts.Layouts;
import org.jruby.truffle.runtime.methods.InternalMethod;
import org.jruby.truffle.runtime.methods.SharedMethodInfo;
import org.jruby.util.Memo;

import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives;
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.frame.Frame;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
import com.oracle.truffle.api.nodes.Node.Child;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.DynamicObjectFactory;
import com.oracle.truffle.api.source.NullSourceSection;
import com.oracle.truffle.api.source.SourceSection;

@CoreClass(name = "Proc")
public abstract class ProcNodes {
@@ -51,46 +57,104 @@ public static Object rootCall(DynamicObject proc, Object... args) {
args));
}

public static void initialize(DynamicObject proc, SharedMethodInfo sharedMethodInfo, CallTarget callTargetForProcs, CallTarget callTargetForLambdas,
MaterializedFrame declarationFrame, InternalMethod method, Object self,
DynamicObject block) {
assert RubyGuards.isRubyProc(proc);

Layouts.PROC.setSharedMethodInfo(proc, sharedMethodInfo);
Layouts.PROC.setCallTargetForType(proc, Layouts.PROC.getType(proc) == Type.PROC ? callTargetForProcs : callTargetForLambdas);
Layouts.PROC.setCallTargetForLambdas(proc, callTargetForLambdas);
Layouts.PROC.setDeclarationFrame(proc, declarationFrame);
Layouts.PROC.setMethod(proc, method);
Layouts.PROC.setSelf(proc, self);
assert block == null || RubyGuards.isRubyProc(block);
Layouts.PROC.setBlock(proc, block);
}

public static DynamicObject createRubyProc(DynamicObject procClass, Type type) {
return createRubyProc(procClass, type, null, null, null, null, null, null, null);
}

public static DynamicObject createRubyProc(DynamicObject procClass, Type type, SharedMethodInfo sharedMethodInfo, CallTarget callTargetForProcs,
CallTarget callTargetForLambdas, MaterializedFrame declarationFrame, InternalMethod method,
Object self, DynamicObject block) {
return createRubyProc(Layouts.CLASS.getInstanceFactory(procClass), type, sharedMethodInfo, callTargetForProcs,
return createRubyProc(Layouts.CLASS.getInstanceFactory(procClass),
type, sharedMethodInfo, callTargetForProcs,
callTargetForLambdas, declarationFrame, method,
self, block);
}

public static DynamicObject createRubyProc(DynamicObjectFactory instanceFactory, Type type, SharedMethodInfo sharedMethodInfo, CallTarget callTargetForProcs,
CallTarget callTargetForLambdas, MaterializedFrame declarationFrame, InternalMethod method,
Object self, DynamicObject block) {
final DynamicObject proc = Layouts.PROC.createProc(instanceFactory, type, null, null, null, null, null, null, null);
ProcNodes.initialize(proc, sharedMethodInfo, callTargetForProcs, callTargetForLambdas, declarationFrame, method,
self, block);
return proc;
assert block == null || RubyGuards.isRubyProc(block);
final CallTarget callTargetForType = (type == Type.PROC) ? callTargetForProcs : callTargetForLambdas;
return Layouts.PROC.createProc(instanceFactory, type, sharedMethodInfo, callTargetForType, callTargetForLambdas, declarationFrame, method, self, block);
}

public enum Type {
PROC, LAMBDA
}

@CoreMethod(names = "new", constructor = true, needsBlock = true, rest = true)
public abstract static class ProcNewNode extends CoreMethodArrayArgumentsNode {

@Child private CallDispatchHeadNode initializeNode;

public ProcNewNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
initializeNode = DispatchHeadNodeFactory.createMethodCallOnSelf(context);
}

public abstract DynamicObject executeProcNew(VirtualFrame frame, DynamicObject procClass, Object[] args, Object block);

@Specialization
public DynamicObject proc(VirtualFrame frame, DynamicObject procClass, Object[] args, NotProvided block) {
final Frame parentFrame = RubyCallStack.getCallerFrame(getContext()).getFrame(FrameAccess.READ_ONLY, true);
final DynamicObject parentBlock = RubyArguments.getBlock(parentFrame.getArguments());

if (parentBlock == null) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().argumentError("tried to create Proc object without a block", this));
}

return executeProcNew(frame, procClass, args, parentBlock);
}

@Specialization(guards = "procClass == metaClass(block)")
public DynamicObject procNormal(DynamicObject procClass, Object[] args, DynamicObject block) {
return block;
}

@Specialization(guards = "procClass != metaClass(block)")
public DynamicObject procSpecial(VirtualFrame frame, DynamicObject procClass, Object[] args, DynamicObject block) {
// Instantiate a new instance of procClass as classes do not correspond
DynamicObject proc = ProcNodes.createRubyProc(
procClass,
Layouts.PROC.getType(block),
Layouts.PROC.getSharedMethodInfo(block),
Layouts.PROC.getCallTargetForType(block),
Layouts.PROC.getCallTargetForLambdas(block),
Layouts.PROC.getDeclarationFrame(block),
Layouts.PROC.getMethod(block),
Layouts.PROC.getSelf(block),
Layouts.PROC.getBlock(block));
initializeNode.call(frame, proc, "initialize", block, args);
return proc;
}

protected DynamicObject metaClass(DynamicObject object) {
return Layouts.BASIC_OBJECT.getMetaClass(object);
}

}

@CoreMethod(names = { "dup", "clone" })
public abstract static class DupNode extends UnaryCoreMethodNode {

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

@Specialization
public DynamicObject dup(DynamicObject proc) {
DynamicObject copy = ProcNodes.createRubyProc(
Layouts.BASIC_OBJECT.getLogicalClass(proc),
Layouts.PROC.getType(proc),
Layouts.PROC.getSharedMethodInfo(proc),
Layouts.PROC.getCallTargetForType(proc),
Layouts.PROC.getCallTargetForLambdas(proc),
Layouts.PROC.getDeclarationFrame(proc),
Layouts.PROC.getMethod(proc),
Layouts.PROC.getSelf(proc),
Layouts.PROC.getBlock(proc));
return copy;
}

}

@CoreMethod(names = "arity")
public abstract static class ArityNode extends CoreMethodArrayArgumentsNode {

@@ -145,57 +209,6 @@ public Object call(VirtualFrame frame, DynamicObject proc, Object[] args, Dynami

}

@CoreMethod(names = "initialize", needsBlock = true)
public abstract static class InitializeNode extends CoreMethodArrayArgumentsNode {

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

@Specialization(guards = "isRubyProc(block)")
public DynamicObject initialize(DynamicObject proc, DynamicObject block) {
ProcNodes.initialize(proc, Layouts.PROC.getSharedMethodInfo(block), Layouts.PROC.getCallTargetForType(block),
Layouts.PROC.getCallTargetForLambdas(block), Layouts.PROC.getDeclarationFrame(block), Layouts.PROC.getMethod(block),
Layouts.PROC.getSelf(block), Layouts.PROC.getBlock(block));

return nil();
}

@TruffleBoundary
@Specialization
public DynamicObject initialize(DynamicObject proc, NotProvided block) {
final Memo<Integer> frameCount = new Memo<>(0);

// The parent will be the Proc.new call. We need to go an extra level up in order to get the parent
// of the Proc.new call, since that is where the block should be inherited from.
final MaterializedFrame grandparentFrame = Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor<MaterializedFrame>() {

@Override
public MaterializedFrame visitFrame(FrameInstance frameInstance) {
if (frameCount.get() == 1) {
return frameInstance.getFrame(FrameInstance.FrameAccess.READ_WRITE, false).materialize();
} else {
frameCount.set(frameCount.get() + 1);
return null;
}
}

});

final DynamicObject grandparentBlock = RubyArguments.getBlock(grandparentFrame.getArguments());

if (grandparentBlock == null) {
CompilerDirectives.transferToInterpreter();

// TODO (nirvdrum 19-Feb-15) MRI reports this error on the #new method, not #initialize.
throw new RaiseException(getContext().getCoreLibrary().argumentError("tried to create Proc object without a block", this));
}

return initialize(proc, grandparentBlock);
}

}

@CoreMethod(names = "lambda?")
public abstract static class LambdaNode extends CoreMethodArrayArgumentsNode {

@@ -253,17 +266,4 @@ public Object sourceLocation(DynamicObject proc) {

}

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {

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

@Specialization
public DynamicObject allocate(DynamicObject rubyClass) {
return createRubyProc(rubyClass, Type.PROC);
}

}
}
Original file line number Diff line number Diff line change
@@ -151,7 +151,7 @@ protected DynamicObject createProc(DynamicObject symbol) {
ProcNodes.Type.PROC,
sharedMethodInfo,
callTarget, callTarget, null,
null, Layouts.MODULE.getFields(Layouts.BASIC_OBJECT.getLogicalClass(symbol)).getContext().getCoreLibrary().getNilObject(),
null, getContext().getCoreLibrary().getNilObject(),
null);
}

Loading