Skip to content

Commit

Permalink
[Truffle] Array#[]= beyond the end of the array.
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisseaton committed Feb 4, 2015
1 parent 9da6ed4 commit dcc29bf
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 48 deletions.
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/array/element_set_tags.txt
@@ -1,4 +1,3 @@
fails:Array#[]= sets the value of the element at index
fails:Array#[]= sets the section defined by [start,length] to other
fails:Array#[]= replaces the section defined by [start,length] with the given values
fails:Array#[]= just sets the section defined by [start,length] to other even if other is nil
Expand All @@ -22,8 +21,6 @@ fails:Array#[]= raises an IndexError when passed indexes out of bounds
fails:Array#[]= calls to_ary on its rhs argument for multi-element sets
fails:Array#[]= does not call to_ary on rhs array subclasses for multi-element sets
fails:Array#[]= raises a RuntimeError on a frozen array
fails:Array#[]= with [index] returns value assigned if idx far beyond right array boundary
fails:Array#[]= with [index] sets the value of the element at index
fails:Array#[]= with [index, count] returns non-array value if non-array value assigned
fails:Array#[]= with [index, count] returns array if array assigned
fails:Array#[]= with [index, count] just sets the section defined by [start,length] to nil even if the rhs is nil
Expand Down
163 changes: 118 additions & 45 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/ArrayNodes.java
Expand Up @@ -871,37 +871,70 @@ public IndexSetNode(IndexSetNode prev) {
// Set a simple index in an empty array

@Specialization(guards = "isNull")
public Object setNullIntegerFixnum(RubyArray array, int index, int value, UndefinedPlaceholder unused) {
public Object setNull(RubyArray array, int index, int value, UndefinedPlaceholder unused) {
if (index == 0) {
array.setStore(new int[]{value}, 1);
} else {
CompilerDirectives.transferToInterpreter();
throw new UnsupportedOperationException();
beyondBranch.enter();
final Object[] newStore = new Object[index + 1];
for (int n = 0; n < index; n++) {
newStore[n] = getContext().getCoreLibrary().getNilObject();
}
newStore[index] = value;
array.setStore(newStore, newStore.length);
}

return value;
}

@Specialization(guards = "isNull")
public Object setNullLongFixnum(RubyArray array, int index, long value, UndefinedPlaceholder unused) {
public Object setNull(RubyArray array, int index, long value, UndefinedPlaceholder unused) {
if (index == 0) {
array.setStore(new long[]{value}, 1);
} else {
CompilerDirectives.transferToInterpreter();
throw new UnsupportedOperationException();
beyondBranch.enter();
final Object[] newStore = new Object[index + 1];
for (int n = 0; n < index; n++) {
newStore[n] = getContext().getCoreLibrary().getNilObject();
}
newStore[index] = value;
array.setStore(newStore, newStore.length);
}

return value;
}

@Specialization(guards = "isNull")
public Object setNull(RubyArray array, int index, double value, UndefinedPlaceholder unused) {
if (index == 0) {
array.setStore(new double[]{value}, 1);
} else {
beyondBranch.enter();
final Object[] newStore = new Object[index + 1];
for (int n = 0; n < index; n++) {
newStore[n] = getContext().getCoreLibrary().getNilObject();
}
newStore[index] = value;
array.setStore(newStore, newStore.length);
}

return value;
}

@Specialization(guards = "isNull")
public Object setNullObject(RubyArray array, int index, Object value, UndefinedPlaceholder unused) {
public Object setNull(RubyArray array, int index, Object value, UndefinedPlaceholder unused) {
notDesignedForCompilation();

if (index == 0) {
array.slowPush(value);
} else {
throw new UnsupportedOperationException();
beyondBranch.enter();
final Object[] newStore = new Object[index + 1];
for (int n = 0; n < index; n++) {
newStore[n] = getContext().getCoreLibrary().getNilObject();
}
newStore[index] = value;
array.setStore(newStore, newStore.length);
}

return value;
Expand Down Expand Up @@ -933,7 +966,15 @@ public int setIntegerFixnum(RubyArray array, int index, int value, UndefinedPlac
array.setSize(array.getSize() + 1);
} else if (normalisedIndex > array.getSize()) {
beyondBranch.enter();
throw new UnsupportedOperationException();
final Object[] newStore = new Object[index + 1];
for (int n = 0; n < array.getSize(); n++) {
newStore[n] = store[n];
}
for (int n = array.getSize(); n < index; n++) {
newStore[n] = getContext().getCoreLibrary().getNilObject();
}
newStore[index] = value;
array.setStore(newStore, newStore.length);
}
} else {
store[normalisedIndex] = value;
Expand Down Expand Up @@ -972,7 +1013,15 @@ public long setLongInIntegerFixnum(RubyArray array, int index, long value, Undef
array.setSize(array.getSize() + 1);
} else if (normalisedIndex > array.getSize()) {
beyondBranch.enter();
throw new UnsupportedOperationException();
final Object[] newStore = new Object[index + 1];
for (int n = 0; n < array.getSize(); n++) {
newStore[n] = store[n];
}
for (int n = array.getSize(); n < index; n++) {
newStore[n] = getContext().getCoreLibrary().getNilObject();
}
newStore[index] = value;
array.setStore(newStore, newStore.length);
}
} else {
store[normalisedIndex] = value;
Expand All @@ -981,38 +1030,6 @@ public long setLongInIntegerFixnum(RubyArray array, int index, long value, Undef
return value;
}

@Specialization(guards = "isIntegerFixnum")
public RubyArray setIntegerFixnum(RubyArray array, int start, int length, RubyArray value) {
notDesignedForCompilation();

if (length < 0) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexNegativeLength(length, this));
}

if (value.getSize() == 0) {
final int begin = array.normaliseIndex(start);
final int exclusiveEnd = begin + length;
int[] store = (int[]) array.getStore();

if (begin < 0) {
tooSmallBranch.enter();
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexTooSmallError("array", start, array.getSize(), this));
} else if (exclusiveEnd > array.getSize()) {
throw new UnsupportedOperationException();
}

// TODO: This is a moving overlapping memory, should we use sth else instead?
System.arraycopy(store, exclusiveEnd, store, begin, array.getSize() - exclusiveEnd);
array.setSize(array.getSize() - length);

return value;
} else {
throw new UnsupportedOperationException();
}
}

@Specialization(guards = "isLongFixnum")
public int setLongFixnum(RubyArray array, int index, int value, UndefinedPlaceholder unused) {
setLongFixnum(array, index, (long) value, unused);
Expand Down Expand Up @@ -1043,7 +1060,15 @@ public long setLongFixnum(RubyArray array, int index, long value, UndefinedPlace
array.setSize(array.getSize() + 1);
} else if (normalisedIndex > array.getSize()) {
beyondBranch.enter();
throw new UnsupportedOperationException();
final Object[] newStore = new Object[index + 1];
for (int n = 0; n < array.getSize(); n++) {
newStore[n] = store[n];
}
for (int n = array.getSize(); n < index; n++) {
newStore[n] = getContext().getCoreLibrary().getNilObject();
}
newStore[index] = value;
array.setStore(newStore, newStore.length);
}
} else {
store[normalisedIndex] = value;
Expand Down Expand Up @@ -1076,7 +1101,15 @@ public double setFloat(RubyArray array, int index, double value, UndefinedPlaceh
array.setSize(array.getSize() + 1);
} else if (normalisedIndex > array.getSize()) {
beyondBranch.enter();
throw new UnsupportedOperationException();
final Object[] newStore = new Object[index + 1];
for (int n = 0; n < array.getSize(); n++) {
newStore[n] = store[n];
}
for (int n = array.getSize(); n < index; n++) {
newStore[n] = getContext().getCoreLibrary().getNilObject();
}
newStore[index] = value;
array.setStore(newStore, newStore.length);
}
} else {
store[normalisedIndex] = value;
Expand Down Expand Up @@ -1109,7 +1142,15 @@ public Object setObject(RubyArray array, int index, Object value, UndefinedPlace
array.setSize(array.getSize() + 1);
} else if (normalisedIndex > array.getSize()) {
beyondBranch.enter();
throw new UnsupportedOperationException();
final Object[] newStore = new Object[index + 1];
for (int n = 0; n < array.getSize(); n++) {
newStore[n] = store[n];
}
for (int n = array.getSize(); n < index; n++) {
newStore[n] = getContext().getCoreLibrary().getNilObject();
}
newStore[index] = value;
array.setStore(newStore, newStore.length);
}
} else {
store[normalisedIndex] = value;
Expand Down Expand Up @@ -1141,6 +1182,38 @@ public Object setObject(RubyArray array, int start, int length, Object value) {

// Set a slice of the array to another array

@Specialization(guards = "isIntegerFixnum")
public RubyArray setIntegerFixnum(RubyArray array, int start, int length, RubyArray value) {
notDesignedForCompilation();

if (length < 0) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexNegativeLength(length, this));
}

if (value.getSize() == 0) {
final int begin = array.normaliseIndex(start);
final int exclusiveEnd = begin + length;
int[] store = (int[]) array.getStore();

if (begin < 0) {
tooSmallBranch.enter();
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexTooSmallError("array", start, array.getSize(), this));
} else if (exclusiveEnd > array.getSize()) {
throw new UnsupportedOperationException();
}

// TODO: This is a moving overlapping memory, should we use sth else instead?
System.arraycopy(store, exclusiveEnd, store, begin, array.getSize() - exclusiveEnd);
array.setSize(array.getSize() - length);

return value;
} else {
throw new UnsupportedOperationException();
}
}

@Specialization(guards = "isIntegerFixnum")
public RubyArray setIntegerFixnumRange(RubyArray array, RubyRange.IntegerFixnumRange range, RubyArray other, UndefinedPlaceholder unused) {
if (range.doesExcludeEnd()) {
Expand Down

0 comments on commit dcc29bf

Please sign in to comment.