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

Commits on Jan 13, 2015

  1. Revert "[Truffle] Removed Array#find since it should be defined in En…

    …umerable."
    
    This reverts commit 7899944.
    nirvdrum committed Jan 13, 2015
    Copy the full SHA
    4ffdea3 View commit details
  2. Revert "[Truffle] Removed Array#each_with_index since it should be de…

    …fined in Enumerable."
    
    This reverts commit 249ee7b.
    nirvdrum committed Jan 13, 2015
    Copy the full SHA
    bd6c262 View commit details
  3. Revert "[Truffle] Removed Array#min since it should be defined in Enu…

    …merable."
    
    This reverts commit 28e743e.
    nirvdrum committed Jan 13, 2015
    Copy the full SHA
    a436dcd View commit details
  4. Revert "[Truffle] Removed Array#max since it should be defined in Enu…

    …merable."
    
    This reverts commit cd998aa.
    nirvdrum committed Jan 13, 2015
    Copy the full SHA
    5f6aa00 View commit details
Showing with 414 additions and 0 deletions.
  1. +400 −0 core/src/main/java/org/jruby/truffle/nodes/core/ArrayNodes.java
  2. +14 −0 core/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java
400 changes: 400 additions & 0 deletions core/src/main/java/org/jruby/truffle/nodes/core/ArrayNodes.java
Original file line number Diff line number Diff line change
@@ -1539,6 +1539,66 @@ public Object eachObject(VirtualFrame frame, RubyArray array, RubyProc block) {

}

@CoreMethod(names = "each_with_index", needsBlock = true)
@ImportGuards(ArrayGuards.class)
public abstract static class EachWithIndexNode extends YieldingCoreMethodNode {

private final BranchProfile breakProfile = BranchProfile.create();
private final BranchProfile nextProfile = BranchProfile.create();
private final BranchProfile redoProfile = BranchProfile.create();

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

public EachWithIndexNode(EachWithIndexNode prev) {
super(prev);
}

@Specialization(guards = "isNull")
public RubyArray eachWithEmpty(VirtualFrame frame, RubyArray array, RubyProc block) {
return array;
}

@Specialization(guards = "isObject")
public Object eachWithIndexObject(VirtualFrame frame, RubyArray array, RubyProc block) {
final Object[] store = (Object[]) array.getStore();

int count = 0;

try {
outer:
for (int n = 0; n < array.getSize(); n++) {
while (true) {
if (CompilerDirectives.inInterpreter()) {
count++;
}

try {
yield(frame, block, store[n], n);
continue outer;
} catch (BreakException e) {
breakProfile.enter();
return e.getResult();
} catch (NextException e) {
nextProfile.enter();
continue outer;
} catch (RedoException e) {
redoProfile.enter();
}
}
}
} finally {
if (CompilerDirectives.inInterpreter()) {
((RubyRootNode) getRootNode()).reportLoopCount(count);
}
}

return array;
}

}

@CoreMethod(names = "empty?")
public abstract static class EmptyNode extends ArrayCoreMethodNode {

@@ -1557,6 +1617,108 @@ public boolean isEmpty(RubyArray array) {

}

@CoreMethod(names = "find", needsBlock = true)
@ImportGuards(ArrayGuards.class)
public abstract static class FindNode extends YieldingCoreMethodNode {

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

public FindNode(FindNode prev) {
super(prev);
}

@Specialization(guards = "isNull")
public Object findNull(VirtualFrame frame, RubyArray array, RubyProc block) {
return getContext().getCoreLibrary().getNilObject();
}

@Specialization(guards = "isIntegerFixnum")
public Object findIntegerFixnum(VirtualFrame frame, RubyArray array, RubyProc block) {
notDesignedForCompilation();

final int[] store = (int[]) array.getStore();

for (int n = 0; n < array.getSize(); n++) {
try {
final Object value = store[n];

if (yieldIsTruthy(frame, block, value)) {
return value;
}
} catch (BreakException e) {
break;
}
}

return getContext().getCoreLibrary().getNilObject();
}

@Specialization(guards = "isLongFixnum")
public Object findLongFixnum(VirtualFrame frame, RubyArray array, RubyProc block) {
notDesignedForCompilation();

final long[] store = (long[]) array.getStore();

for (int n = 0; n < array.getSize(); n++) {
try {
final Object value = store[n];

if (yieldIsTruthy(frame, block, value)) {
return value;
}
} catch (BreakException e) {
break;
}
}

return getContext().getCoreLibrary().getNilObject();
}

@Specialization(guards = "isFloat")
public Object findFloat(VirtualFrame frame, RubyArray array, RubyProc block) {
notDesignedForCompilation();

final double[] store = (double[]) array.getStore();

for (int n = 0; n < array.getSize(); n++) {
try {
final Object value = store[n];

if (yieldIsTruthy(frame, block, value)) {
return value;
}
} catch (BreakException e) {
break;
}
}

return getContext().getCoreLibrary().getNilObject();
}

@Specialization(guards = "isObject")
public Object findObject(VirtualFrame frame, RubyArray array, RubyProc block) {
notDesignedForCompilation();

final Object[] store = (Object[]) array.getStore();

for (int n = 0; n < array.getSize(); n++) {
try {
final Object value = store[n];

if (yieldIsTruthy(frame, block, value)) {
return value;
}
} catch (BreakException e) {
break;
}
}

return getContext().getCoreLibrary().getNilObject();
}
}

@CoreMethod(names = "first")
public abstract static class FirstNode extends ArrayCoreMethodNode {

@@ -2305,6 +2467,244 @@ public RubyArray mapInPlaceObject(VirtualFrame frame, RubyArray array, RubyProc

// TODO: move into Enumerable?

@CoreMethod(names = "max")
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();
}

public MaxNode(MaxNode prev) {
super(prev);
eachNode = prev.eachNode;
maxBlock = prev.maxBlock;
}

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

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

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

final RubyProc block = new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.PROC,
maxBlock.getSharedMethodInfo(), maxBlock.getCallTarget(), maxBlock.getCallTarget(),
maxBlock.getCallTarget(), maximumClosureFrame.materialize(), null, null, array, null);

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

if (maximum.get() == null) {
return getContext().getCoreLibrary().getNilObject();
} else {
return maximum.get();
}
}

}

public abstract static class MaxBlockNode extends CoreMethodNode {

@Child private CallDispatchHeadNode compareNode;

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

public MaxBlockNode(MaxBlockNode prev) {
super(prev);
compareNode = prev.compareNode;
}

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

// TODO(CS): cast

final Object current = maximum.get();

if (current == null || (int) compareNode.call(frame, value, "<=>", null, current) < 0) {
maximum.set(value);
}

return getContext().getCoreLibrary().getNilObject();
}

}

public static class MaxBlock implements MethodLike {

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

public MaxBlock(RubyContext context) {
final SourceSection sourceSection = new CoreSourceSection("Array", "max");

frameDescriptor = new FrameDescriptor();
frameSlot = frameDescriptor.addFrameSlot("maximum_memo");

sharedMethodInfo = new SharedMethodInfo(sourceSection, null, "max", false, null, false);

callTarget = Truffle.getRuntime().createCallTarget(new RubyRootNode(
context, sourceSection, null, sharedMethodInfo,
ArrayNodesFactory.MaxBlockNodeFactory.create(context, sourceSection, new RubyNode[]{
ReadLevelVariableNodeFactory.create(context, sourceSection, frameSlot, 1),
new ReadPreArgumentNode(context, sourceSection, 0, MissingArgumentBehaviour.RUNTIME_ERROR)
})));
}

public FrameDescriptor getFrameDescriptor() {
return frameDescriptor;
}

public FrameSlot getFrameSlot() {
return frameSlot;
}

@Override
public SharedMethodInfo getSharedMethodInfo() {
return sharedMethodInfo;
}

@Override
public RubyModule getDeclaringModule() {
throw new UnsupportedOperationException();
}

public CallTarget getCallTarget() {
return callTarget;
}
}

@CoreMethod(names = "min")
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();
}

public MinNode(MinNode prev) {
super(prev);
eachNode = prev.eachNode;
minBlock = prev.minBlock;
}

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

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

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

final RubyProc block = new RubyProc(getContext().getCoreLibrary().getProcClass(), RubyProc.Type.PROC,
minBlock.getSharedMethodInfo(), minBlock.getCallTarget(), minBlock.getCallTarget(),
minBlock.getCallTarget(), minimumClosureFrame.materialize(), null, null, array, null);

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

if (minimum.get() == null) {
return getContext().getCoreLibrary().getNilObject();
} else {
return minimum.get();
}
}

}

public abstract static class MinBlockNode extends CoreMethodNode {

@Child private CallDispatchHeadNode compareNode;

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

public MinBlockNode(MinBlockNode prev) {
super(prev);
compareNode = prev.compareNode;
}

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

// TODO(CS): cast

final Object current = minimum.get();

if (current == null || (int) compareNode.call(frame, value, "<=>", null, current) < 0) {
minimum.set(value);
}

return getContext().getCoreLibrary().getNilObject();
}

}

public static class MinBlock implements MethodLike {

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

public MinBlock(RubyContext context) {
final SourceSection sourceSection = new CoreSourceSection("Array", "min");

frameDescriptor = new FrameDescriptor();
frameSlot = frameDescriptor.addFrameSlot("minimum_memo");

sharedMethodInfo = new SharedMethodInfo(sourceSection, null, "min", false, null, false);

callTarget = Truffle.getRuntime().createCallTarget(new RubyRootNode(
context, sourceSection, null, sharedMethodInfo,
ArrayNodesFactory.MinBlockNodeFactory.create(context, sourceSection, new RubyNode[]{
ReadLevelVariableNodeFactory.create(context, sourceSection, frameSlot, 1),
new ReadPreArgumentNode(context, sourceSection, 0, MissingArgumentBehaviour.RUNTIME_ERROR)
})));
}

public FrameDescriptor getFrameDescriptor() {
return frameDescriptor;
}

public FrameSlot getFrameSlot() {
return frameSlot;
}

@Override
public SharedMethodInfo getSharedMethodInfo() {
return sharedMethodInfo;
}

@Override
public RubyModule getDeclaringModule() {
throw new UnsupportedOperationException();
}

public CallTarget getCallTarget() {
return callTarget;
}
}

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

14 changes: 14 additions & 0 deletions core/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java
Original file line number Diff line number Diff line change
@@ -121,6 +121,9 @@ public class CoreLibrary {
@CompilerDirectives.CompilationFinal private RubyNilClass nilObject;
@CompilerDirectives.CompilationFinal private RubyHash envHash;

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

public CoreLibrary(RubyContext context) {
this.context = context;
}
@@ -345,6 +348,9 @@ public void initialize() {

initializeEncodingConstants();

arrayMinBlock = new ArrayNodes.MinBlock(context);
arrayMaxBlock = new ArrayNodes.MaxBlock(context);

argv = new RubyArray(arrayClass);
objectClass.setConstant(null, "ARGV", argv);

@@ -901,6 +907,14 @@ private RubyHash getSystemEnv() {
return HashOperations.verySlowFromEntries(context, entries);
}

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

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

public RubyClass getNumericClass() {
return numericClass;
}