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

Commits on Sep 11, 2016

  1. Copy the full SHA
    56ef6b9 View commit details
  2. Revert "[Truffle] Use Array#{max,min} from rubinius"

    This reverts commit 67c90da.
    chrisseaton committed Sep 11, 2016
    Copy the full SHA
    553b5c1 View commit details
Showing with 266 additions and 2 deletions.
  1. +4 −2 ci.hocon
  2. +14 −0 truffle/src/main/java/org/jruby/truffle/core/CoreLibrary.java
  3. +248 −0 truffle/src/main/java/org/jruby/truffle/core/array/ArrayNodes.java
6 changes: 4 additions & 2 deletions ci.hocon
Original file line number Diff line number Diff line change
@@ -130,8 +130,10 @@ sulong: ${labsjdk} {
graal-vm: {
downloads: {
GRAALVM_DIR: {
name: graalvm-snapshot,
version: latest,
// name: graalvm-snapshot,
// version: latest,
name: graalvm-release,
version: "0.16",
platformspecific: true
}
}
14 changes: 14 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/core/CoreLibrary.java
Original file line number Diff line number Diff line change
@@ -274,6 +274,9 @@ public class CoreLibrary {
@CompilationFinal private DynamicObject eagainWaitReadable;
@CompilationFinal private DynamicObject eagainWaitWritable;

@CompilationFinal private ArrayNodes.MinBlock arrayMinBlock;
@CompilationFinal private ArrayNodes.MaxBlock arrayMaxBlock;

private final Map<Errno, DynamicObject> errnoClasses = new HashMap<>();

@CompilationFinal private InternalMethod basicObjectSendMethod;
@@ -677,6 +680,9 @@ public void initialize() {
}

public void addCoreMethods(PrimitiveManager primitiveManager) {
arrayMinBlock = new ArrayNodes.MinBlock(context);
arrayMaxBlock = new ArrayNodes.MaxBlock(context);

final CoreMethodNodeManager coreMethodNodeManager =
new CoreMethodNodeManager(context, node.getSingletonClassNode(), primitiveManager);

@@ -1333,6 +1339,14 @@ public DynamicObject getENV() {
return (DynamicObject) Layouts.MODULE.getFields(objectClass).getConstant("ENV").getValue();
}

public ArrayNodes.MinBlock getArrayMinBlock() {
return arrayMinBlock;
}

public ArrayNodes.MaxBlock getArrayMaxBlock() {
return arrayMaxBlock;
}

public DynamicObject getNumericClass() {
return numericClass;
}
248 changes: 248 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/core/array/ArrayNodes.java
Original file line number Diff line number Diff line change
@@ -39,6 +39,8 @@
import org.jruby.truffle.builtins.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.builtins.CoreMethodNode;
import org.jruby.truffle.builtins.YieldingCoreMethodNode;
import org.jruby.truffle.core.array.ArrayNodesFactory.MaxBlockNodeFactory;
import org.jruby.truffle.core.array.ArrayNodesFactory.MinBlockNodeFactory;
import org.jruby.truffle.core.array.ArrayNodesFactory.RejectInPlaceNodeFactory;
import org.jruby.truffle.core.array.ArrayNodesFactory.ReplaceNodeFactory;
import org.jruby.truffle.core.cast.ToAryNodeGen;
@@ -1354,6 +1356,252 @@ protected ArrayWriteNormalizedNode createWriteNode() {

}

// TODO: move into Enumerable?

@CoreMethod(names = "max", needsBlock = true)
public abstract static class MaxNode extends ArrayCoreMethodNode {

@Child private CallDispatchHeadNode eachNode;
private final MaxBlock maxBlock;

public MaxNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
eachNode = DispatchHeadNodeFactory.createMethodCall(context);
maxBlock = context.getCoreLibrary().getArrayMaxBlock();
}

@Specialization
public Object max(VirtualFrame frame, DynamicObject array, NotProvided blockNotProvided) {
// TODO: can we just write to the frame instead of having this indirect object?

final Memo<Object> maximum = new Memo<>();

final InternalMethod method = RubyArguments.getMethod(frame);
final VirtualFrame maximumClosureFrame = Truffle.getRuntime().createVirtualFrame(
RubyArguments.pack(null, null, method, DeclarationContext.BLOCK, null, array, null, new Object[]{}), maxBlock.getFrameDescriptor());
maximumClosureFrame.setObject(maxBlock.getFrameSlot(), maximum);

final DynamicObject block = ProcOperations.createRubyProc(coreLibrary().getProcFactory(), ProcType.PROC,
maxBlock.getSharedMethodInfo(), maxBlock.getCallTarget(), maxBlock.getCallTarget(),
maximumClosureFrame.materialize(), method, array, null);

eachNode.callWithBlock(frame, array, "each", block);

if (maximum.get() == null) {
return nil();
} else {
return maximum.get();
}
}

@Specialization
public Object max(
VirtualFrame frame,
DynamicObject array,
DynamicObject block,
@Cached("createMethodCall()") CallDispatchHeadNode callNode) {
return callNode.callWithBlock(frame, array, "max_internal", block);
}

}

public abstract static class MaxBlockNode extends CoreMethodArrayArgumentsNode {

@Child private CallDispatchHeadNode compareNode;

private final BranchProfile errorProfile = BranchProfile.create();

public MaxBlockNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
compareNode = DispatchHeadNodeFactory.createMethodCall(context);
}

@Specialization
public DynamicObject max(VirtualFrame frame, Object maximumObject, Object value) {
@SuppressWarnings("unchecked")
final Memo<Object> maximum = (Memo<Object>) maximumObject;

final Object current = maximum.get();

if (current == null) {
maximum.set(value);
} else {
final Object compared = compareNode.call(frame, value, "<=>", current);

if (compared instanceof Integer) {
if ((int) compared > 0) {
maximum.set(value);
}
} else {
errorProfile.enter();
// Should be the actual type and object in this string - but this method should go away soon
throw new RaiseException(coreExceptions().argumentError("comparison of X with Y failed", this));
}
}

return nil();
}

}

public static class MaxBlock {

private final FrameDescriptor frameDescriptor;
private final FrameSlot frameSlot;
private final SharedMethodInfo sharedMethodInfo;
private final CallTarget callTarget;

public MaxBlock(RubyContext context) {
frameDescriptor = new FrameDescriptor(context.getCoreLibrary().getNilObject());
frameSlot = frameDescriptor.addFrameSlot("maximum_memo");

sharedMethodInfo = new SharedMethodInfo(SourceSection.createUnavailable(null, "Array#max block"), null, Arity.NO_ARGUMENTS, "max", false, null, false, false, false);

callTarget = Truffle.getRuntime().createCallTarget(new RubyRootNode(context, sharedMethodInfo.getSourceSection(), null, sharedMethodInfo, MaxBlockNodeFactory.create(context, null, new RubyNode[]{
new ReadDeclarationVariableNode(context, null, LocalVariableType.FRAME_LOCAL, 1, frameSlot),
new ProfileArgumentNode(new ReadPreArgumentNode(0, MissingArgumentBehavior.RUNTIME_ERROR))
}), false));
}

public FrameDescriptor getFrameDescriptor() {
return frameDescriptor;
}

public FrameSlot getFrameSlot() {
return frameSlot;
}

public SharedMethodInfo getSharedMethodInfo() {
return sharedMethodInfo;
}

public CallTarget getCallTarget() {
return callTarget;
}
}

@CoreMethod(names = "min", needsBlock = true)
public abstract static class MinNode extends ArrayCoreMethodNode {

@Child private CallDispatchHeadNode eachNode;
private final MinBlock minBlock;

public MinNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
eachNode = DispatchHeadNodeFactory.createMethodCall(context);
minBlock = context.getCoreLibrary().getArrayMinBlock();
}

@Specialization
public Object min(VirtualFrame frame, DynamicObject array, NotProvided blockNotProvided) {
// TODO: can we just write to the frame instead of having this indirect object?

final Memo<Object> minimum = new Memo<>();

final InternalMethod method = RubyArguments.getMethod(frame);
final VirtualFrame minimumClosureFrame = Truffle.getRuntime().createVirtualFrame(
RubyArguments.pack(null, null, method, DeclarationContext.BLOCK, null, array, null, new Object[]{}), minBlock.getFrameDescriptor());
minimumClosureFrame.setObject(minBlock.getFrameSlot(), minimum);

final DynamicObject block = ProcOperations.createRubyProc(coreLibrary().getProcFactory(), ProcType.PROC,
minBlock.getSharedMethodInfo(), minBlock.getCallTarget(), minBlock.getCallTarget(),
minimumClosureFrame.materialize(), method, array, null);

eachNode.callWithBlock(frame, array, "each", block);

if (minimum.get() == null) {
return nil();
} else {
return minimum.get();
}
}

@Specialization
public Object min(
VirtualFrame frame,
DynamicObject array,
DynamicObject block,
@Cached("new()") SnippetNode snippetNode) {
return snippetNode.execute(frame, "array.min_internal(&block)", "array", array, "block", block);
}

}

public abstract static class MinBlockNode extends CoreMethodArrayArgumentsNode {

@Child private CallDispatchHeadNode compareNode;

private final BranchProfile errorProfile = BranchProfile.create();

public MinBlockNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
compareNode = DispatchHeadNodeFactory.createMethodCall(context);
}

@Specialization
public DynamicObject min(VirtualFrame frame, Object minimumObject, Object value) {
@SuppressWarnings("unchecked")
final Memo<Object> minimum = (Memo<Object>) minimumObject;

final Object current = minimum.get();

if (current == null) {
minimum.set(value);
} else {
final Object compared = compareNode.call(frame, value, "<=>", current);

if (compared instanceof Integer) {
if ((int) compared < 0) {
minimum.set(value);
}
} else {
errorProfile.enter();
// Should be the actual type and object in this string - but this method should go away soon
throw new RaiseException(coreExceptions().argumentError("comparison of X with Y failed", this));
}
}

return nil();
}

}

public static class MinBlock {

private final FrameDescriptor frameDescriptor;
private final FrameSlot frameSlot;
private final SharedMethodInfo sharedMethodInfo;
private final CallTarget callTarget;

public MinBlock(RubyContext context) {
frameDescriptor = new FrameDescriptor(context.getCoreLibrary().getNilObject());
frameSlot = frameDescriptor.addFrameSlot("minimum_memo");

sharedMethodInfo = new SharedMethodInfo(SourceSection.createUnavailable(null, "Array#min block"), null, Arity.NO_ARGUMENTS, "min", false, null, false, false, false);

callTarget = Truffle.getRuntime().createCallTarget(new RubyRootNode(context, sharedMethodInfo.getSourceSection(), null, sharedMethodInfo, MinBlockNodeFactory.create(context, null, new RubyNode[]{
new ReadDeclarationVariableNode(context, null, LocalVariableType.FRAME_LOCAL, 1, frameSlot),
new ProfileArgumentNode(new ReadPreArgumentNode(0, MissingArgumentBehavior.RUNTIME_ERROR))
}), false));
}

public FrameDescriptor getFrameDescriptor() {
return frameDescriptor;
}

public FrameSlot getFrameSlot() {
return frameSlot;
}

public SharedMethodInfo getSharedMethodInfo() {
return sharedMethodInfo;
}

public CallTarget getCallTarget() {
return callTarget;
}
}

@CoreMethod(names = "pack", required = 1, taintFrom = 1)
@ImportStatic(StringCachingGuards.class)
public abstract static class PackNode extends ArrayCoreMethodNode {