Skip to content

Commit

Permalink
[Truffle] Array#compact and #compact!
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisseaton committed Feb 9, 2015
1 parent b40c330 commit 0a36252
Show file tree
Hide file tree
Showing 12 changed files with 141 additions and 53 deletions.
10 changes: 0 additions & 10 deletions spec/truffle/tags/core/array/compact_tags.txt

This file was deleted.

90 changes: 78 additions & 12 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/ArrayNodes.java
Expand Up @@ -498,6 +498,7 @@ public RubyArray clear(RubyArray array) {
}

@CoreMethod(names = "compact")
@ImportGuards(ArrayGuards.class)
public abstract static class CompactNode extends ArrayCoreMethodNode {

public CompactNode(RubyContext context, SourceSection sourceSection) {
Expand All @@ -508,28 +509,93 @@ public CompactNode(CompactNode prev) {
super(prev);
}

@Specialization(guards = "isIntArray")
public RubyArray compactInt(RubyArray array) {
return new RubyArray(getContext().getCoreLibrary().getArrayClass(),
Arrays.copyOf((int[]) array.getStore(), array.getSize()), array.getSize());
}

@Specialization(guards = "isLongArray")
public RubyArray compactLong(RubyArray array) {
return new RubyArray(getContext().getCoreLibrary().getArrayClass(),
Arrays.copyOf((long[]) array.getStore(), array.getSize()), array.getSize());
}

@Specialization(guards = "isDoubleArray")
public RubyArray compactDouble(RubyArray array) {
return new RubyArray(getContext().getCoreLibrary().getArrayClass(),
Arrays.copyOf((double[]) array.getStore(), array.getSize()), array.getSize());
}

@Specialization(guards = "isObjectArray")
public Object compactObjects(RubyArray array) {
// TODO CS 9-Feb-15 by removing nil we could make this array suitable for a primitive array storage class

final Object[] store = (Object[]) array.getStore();
final Object[] newStore = new Object[store.length];
final int size = array.getSize();

int m = 0;

for (int n = 0; n < size; n++) {
if (store[n] != getContext().getCoreLibrary().getNilObject()) {
newStore[m] = store[n];
m++;
}
}

return new RubyArray(getContext().getCoreLibrary().getArrayClass(), newStore, m);
}

}

@CoreMethod(names = "compact!")
public abstract static class CompactBangNode extends ArrayCoreMethodNode {

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

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

@Specialization(guards = "!isObject")
public RubyArray compatNotObjects(RubyArray array) {
return array;
public RubyNilClass compactNotObjects(RubyArray array) {
if (array.isFrozen()) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().frozenError("String", this));
}

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

@Specialization(guards = "isObject")
public RubyArray compatObjects(RubyArray array) {
notDesignedForCompilation();
public Object compactObjects(RubyArray array) {
if (array.isFrozen()) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().frozenError("String", this));
}

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

final Object[] compacted = new Object[array.getSize()];
int compactedSize = 0;
int m = 0;

for (Object object : array.slowToArray()) {
if (object != getContext().getCoreLibrary().getNilObject()) {
compacted[compactedSize] = object;
compactedSize++;
for (int n = 0; n < size; n++) {
if (store[n] != getContext().getCoreLibrary().getNilObject()) {
store[m] = store[n];
m++;
}
}

array.setStore(compacted, compactedSize);
array.setStore(store, m);

return array;
if (m == size) {
return getContext().getCoreLibrary().getNilObject();
} else {
return array;
}
}

}
Expand Down
Expand Up @@ -2111,7 +2111,7 @@ public boolean tainted(RubyBasicObject object) {
try {
return readTaintNode.isSet(object) && readTaintNode.executeBoolean(object);
} catch (UnexpectedResultException e) {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException(readTaintNode.execute(object).toString());
}
}

Expand Down
Expand Up @@ -20,12 +20,10 @@
@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class ReadBooleanObjectFieldNode extends ReadObjectFieldChainNode {

private final Shape objectLayout;
private final BooleanLocation storageLocation;

public ReadBooleanObjectFieldNode(Shape objectLayout, BooleanLocation storageLocation, ReadObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
super(objectLayout, next);
this.storageLocation = storageLocation;
}

Expand Down
Expand Up @@ -20,12 +20,10 @@
@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class ReadDoubleObjectFieldNode extends ReadObjectFieldChainNode {

private final Shape objectLayout;
private final DoubleLocation storageLocation;

public ReadDoubleObjectFieldNode(Shape objectLayout, DoubleLocation storageLocation, ReadObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
super(objectLayout, next);
this.storageLocation = storageLocation;
}

Expand Down
Expand Up @@ -20,12 +20,10 @@
@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class ReadIntegerObjectFieldNode extends ReadObjectFieldChainNode {

private final Shape objectLayout;
private final IntLocation storageLocation;

public ReadIntegerObjectFieldNode(Shape objectLayout, IntLocation storageLocation, ReadObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
super(objectLayout, next);
this.storageLocation = storageLocation;
}

Expand Down
Expand Up @@ -20,12 +20,10 @@
@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class ReadLongObjectFieldNode extends ReadObjectFieldChainNode {

private final Shape objectLayout;
private final LongLocation storageLocation;

public ReadLongObjectFieldNode(Shape objectLayout, LongLocation storageLocation, ReadObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
super(objectLayout, next);
this.storageLocation = storageLocation;
}

Expand Down
Expand Up @@ -18,11 +18,8 @@
@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class ReadMissingObjectFieldNode extends ReadObjectFieldChainNode {

private final Shape objectLayout;

public ReadMissingObjectFieldNode(Shape objectLayout, ReadObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
super(objectLayout, next);
}

@Override
Expand All @@ -41,4 +38,22 @@ public Object execute(RubyBasicObject object) {
}
}

@Override
public boolean isSet(RubyBasicObject object) {
try {
objectLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
return next.isSet(object);
}

final boolean condition = object.getObjectLayout() == objectLayout;

if (condition) {
return false;
} else {
return next.isSet(object);
}
}

}
Expand Up @@ -9,12 +9,37 @@
*/
package org.jruby.truffle.nodes.objectstorage;

import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.object.Shape;
import org.jruby.truffle.runtime.core.RubyBasicObject;

public abstract class ReadObjectFieldChainNode extends ReadObjectFieldNode {

protected final Shape objectLayout;

@Child protected ReadObjectFieldNode next;

public ReadObjectFieldChainNode(ReadObjectFieldNode next) {
public ReadObjectFieldChainNode(Shape objectLayout, ReadObjectFieldNode next) {
this.objectLayout = objectLayout;
this.next = next;
}

@Override
public boolean isSet(RubyBasicObject object) {
try {
objectLayout.getValidAssumption().check();
} catch (InvalidAssumptionException e) {
replace(next);
return next.isSet(object);
}

final boolean condition = object.getObjectLayout() == objectLayout;

if (condition) {
return true;
} else {
return next.isSet(object);
}
}

}
Expand Up @@ -57,8 +57,6 @@ public double executeDouble(RubyBasicObject object) throws UnexpectedResultExcep
}
}

public boolean isSet(RubyBasicObject object) {
return true;
}
public abstract boolean isSet(RubyBasicObject object);

}
Expand Up @@ -19,12 +19,10 @@
@NodeInfo(cost = NodeCost.POLYMORPHIC)
public class ReadObjectObjectFieldNode extends ReadObjectFieldChainNode {

private final Shape objectLayout;
private final Location storageLocation;

public ReadObjectObjectFieldNode(Shape objectLayout, Location storageLocation, ReadObjectFieldNode next) {
super(next);
this.objectLayout = objectLayout;
super(objectLayout, next);
this.storageLocation = storageLocation;
}

Expand Down
Expand Up @@ -26,13 +26,22 @@ public UninitializedReadObjectFieldNode(Object name) {

@Override
public Object execute(RubyBasicObject object) {
return rewrite(object).execute(object);
}

@Override
public boolean isSet(RubyBasicObject object) {
return rewrite(object).isSet(object);
}

private ReadObjectFieldNode rewrite(RubyBasicObject object) {
CompilerDirectives.transferToInterpreterAndInvalidate();

if (object.getDynamicObject().updateShape()) {
ReadObjectFieldNode topNode = getTopNode();
if (topNode != this) {
// retry existing cache nodes
return topNode.execute(object);
return topNode;
}
}

Expand Down Expand Up @@ -62,12 +71,7 @@ public Object execute(RubyBasicObject object) {
}

replace(newNode, "adding new read object field node to chain");
return newNode.execute(object);
}

@Override
public boolean isSet(RubyBasicObject object) {
return object.getObjectLayout().getProperty(name) != null;
return newNode;
}

private ReadObjectFieldNode getTopNode() {
Expand Down

0 comments on commit 0a36252

Please sign in to comment.