Skip to content

Commit

Permalink
Showing 7 changed files with 583 additions and 299 deletions.
Original file line number Diff line number Diff line change
@@ -89,7 +89,7 @@ public RubyNilClass readOutOfBounds(RubyArray array, int index) {

// Guards

public static boolean isInBounds(RubyArray array, int index) {
protected static boolean isInBounds(RubyArray array, int index) {
return index >= 0 && index < array.getSize();
}

Original file line number Diff line number Diff line change
@@ -144,15 +144,15 @@ public RubyArray readObjectOutOfBounds(RubyArray array, int index, int length) {

// Guards

public static boolean indexInBounds(RubyArray array, int index, int length) {
protected static boolean indexInBounds(RubyArray array, int index, int length) {
return index >= 0 && index <= array.getSize();
}

public static boolean lengthPositive(RubyArray array, int index, int length) {
protected static boolean lengthPositive(RubyArray array, int index, int length) {
return length >= 0;
}

public static boolean endInBounds(RubyArray array, int index, int length) {
protected static boolean endInBounds(RubyArray array, int index, int length) {
return index + length < array.getSize();
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.array;

import com.oracle.truffle.api.CompilerDirectives;
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.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyArray;

@NodeChildren({
@NodeChild(value="array", type=RubyNode.class),
@NodeChild(value="index", type=RubyNode.class),
@NodeChild(value="value", type=RubyNode.class)
})
public abstract class ArrayWriteDenormalizedNode extends RubyNode {

@Child private ArrayWriteNormalizedNode readNode;

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

public ArrayWriteDenormalizedNode(ArrayWriteDenormalizedNode prev) {
super(prev);
readNode = prev.readNode;
}

public abstract Object executeWrite(VirtualFrame frame, RubyArray array, int index, Object value);

@Specialization
public Object read(VirtualFrame frame, RubyArray array, int index, Object value) {
if (readNode == null) {
CompilerDirectives.transferToInterpreter();
readNode = insert(ArrayWriteNormalizedNodeFactory.create(getContext(), getSourceSection(), null, null, null));
}

final int normalizedIndex = array.normalizeIndex(index);

return readNode.executeWrite(frame, array, normalizedIndex, value);

This comment has been minimized.

Copy link
@eregon

eregon Feb 9, 2015

Member

This reads in a interesting way 😉

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.array;

import com.oracle.truffle.api.dsl.ImportGuards;
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.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.ArrayGuards;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyNilClass;
import org.jruby.truffle.runtime.util.ArrayUtils;

@NodeChildren({
@NodeChild(value="array", type=RubyNode.class),
@NodeChild(value="index", type=RubyNode.class),
@NodeChild(value="value", type=RubyNode.class)
})
@ImportGuards(ArrayGuards.class)
public abstract class ArrayWriteNormalizedNode extends RubyNode {

@Child private EnsureCapacityArrayNode ensureCapacityNode;
@Child private GeneralizeArrayNode generalizeNode;

public ArrayWriteNormalizedNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);

// TODO CS 9-Feb-15 make this lazy later on
ensureCapacityNode = EnsureCapacityArrayNodeFactory.create(context, sourceSection, null, null);
generalizeNode = GeneralizeArrayNodeFactory.create(context, sourceSection, null, null);
}

public ArrayWriteNormalizedNode(ArrayWriteNormalizedNode prev) {
super(prev);
ensureCapacityNode = prev.ensureCapacityNode;
generalizeNode = prev.generalizeNode;
}

public abstract Object executeWrite(VirtualFrame frame, RubyArray array, int index, Object value);

// Writing at index 0 into a null array creates a new array of the most specific type

@Specialization(
guards={"isNullArray", "isIndex0"}
)
public boolean writeNull0(RubyArray array, int index, boolean value) {
array.setStore(new Object[]{value}, 1);
return value;
}

@Specialization(
guards={"isNullArray", "isIndex0"}
)
public int writeNull0(RubyArray array, int index, int value) {
array.setStore(new int[]{value}, 1);
return value;
}

@Specialization(
guards={"isNullArray", "isIndex0"}
)
public long writeNull0(RubyArray array, int index, long value) {
array.setStore(new long[]{value}, 1);
return value;
}

@Specialization(
guards={"isNullArray", "isIndex0"}
)
public double writeNull0(RubyArray array, int index, double value) {
array.setStore(new double[]{value}, 1);
return value;
}

@Specialization(
guards={"isNullArray", "isIndex0"}
)
public RubyBasicObject writeNull0(RubyArray array, int index, RubyBasicObject value) {
array.setStore(new Object[]{value}, 1);
return value;
}

// Writing beyond index 0 in a null array creates an Object[] as we need to fill the rest with nil

@Specialization(
guards={"isNullArray", "!isIndex0"}
)
public Object writeNullBeyond(RubyArray array, int index, Object value) {
final Object[] store = new Object[index + 1];

for (int n = 0; n < index; n++) {
store[n] = getContext().getCoreLibrary().getNilObject();
}

store[index] = value;
array.setStore(store, store.length);
return value;
}

// Writing within an existing array with a compatible type

@Specialization(
guards={"isObjectArray", "isInBounds"}
)
public boolean writeWithin(RubyArray array, int index, boolean value) {
final Object[] store = (Object[]) array.getStore();
store[index] = value;
return value;
}

@Specialization(
guards={"isIntArray", "isInBounds"}
)
public int writeWithin(RubyArray array, int index, int value) {
final int[] store = (int[]) array.getStore();
store[index] = value;
return value;
}

@Specialization(
guards={"isLongArray", "isInBounds"}
)
public int writeWithinIntIntoLong(RubyArray array, int index, int value) {
writeWithin(array, index, (long) value);
return value;
}

@Specialization(
guards={"isLongArray", "isInBounds"}
)
public long writeWithin(RubyArray array, int index, long value) {
final long[] store = (long[]) array.getStore();
store[index] = value;
return value;
}

@Specialization(
guards={"isDoubleArray", "isInBounds"}
)
public double writeWithin(RubyArray array, int index, double value) {
final double[] store = (double[]) array.getStore();
store[index] = value;
return value;
}

@Specialization(
guards={"isObjectArray", "isInBounds"}
)
public Object writeWithin(RubyArray array, int index, Object value) {
final Object[] store = (Object[]) array.getStore();
store[index] = value;
return value;
}

// Writing within an existing array with an incompatible type - need to generalise

@Specialization(
guards={"isIntArray", "isInBounds"}
)
public long writeWithinInt(RubyArray array, int index, long value) {
final int[] intStore = (int[]) array.getStore();
final long[] longStore = new long[array.getSize()];

for (int n = 0; n < array.getSize(); n++) {
longStore[n] = intStore[n];
}

longStore[index] = value;
array.setStore(longStore, array.getSize());
return value;
}

@Specialization(
guards={"isIntArray", "isInBounds", "!isInteger(value)", "!isLong(value)"}
)
public Object writeWithinInt(RubyArray array, int index, Object value) {
final Object[] objectStore = ArrayUtils.box((int[]) array.getStore());
objectStore[index] = value;
array.setStore(objectStore, array.getSize());
return value;
}

@Specialization(
guards={"isLongArray", "isInBounds", "!isInteger(value)", "!isLong(value)"}
)
public Object writeWithinLong(RubyArray array, int index, Object value) {
final Object[] objectStore = ArrayUtils.box((long[]) array.getStore());
objectStore[index] = value;
array.setStore(objectStore, array.getSize());
return value;
}

@Specialization(
guards={"isDoubleArray", "isInBounds", "!isDouble(value)"}
)
public Object writeWithinDouble(RubyArray array, int index, Object value) {
final Object[] objectStore = ArrayUtils.box((double[]) array.getStore());
objectStore[index] = value;
array.setStore(objectStore, array.getSize());
return value;
}

// Extending an array of compatible type by just one

@Specialization(
guards={"isObjectArray", "isExtendingByOne"}
)
public boolean writeExtendByOne(VirtualFrame frame, RubyArray array, int index, boolean value) {
ensureCapacityNode.executeEnsureCapacity(frame, array, index + 1);
((Object[]) array.getStore())[index] = value;
array.setStore(array.getStore(), index + 1);
return value;
}

@Specialization(
guards={"isIntArray", "isExtendingByOne"}
)
public int writeExtendByOne(VirtualFrame frame, RubyArray array, int index, int value) {
ensureCapacityNode.executeEnsureCapacity(frame, array, index + 1);
((int[]) array.getStore())[index] = value;
array.setStore(array.getStore(), index + 1);
return value;
}

@Specialization(
guards={"isLongArray", "isExtendingByOne"}
)
public int writeExtendByOneIntIntoLong(VirtualFrame frame, RubyArray array, int index, int value) {
ensureCapacityNode.executeEnsureCapacity(frame, array, index + 1);
((long[]) array.getStore())[index] = value;
array.setStore(array.getStore(), index + 1);
return value;
}

@Specialization(
guards={"isLongArray", "isExtendingByOne"}
)
public long writeExtendByOne(VirtualFrame frame, RubyArray array, int index, long value) {
ensureCapacityNode.executeEnsureCapacity(frame, array, index + 1);
((long[]) array.getStore())[index] = value;
array.setStore(array.getStore(), index + 1);
return value;
}

@Specialization(
guards={"isDoubleArray", "isExtendingByOne"}
)
public double writeExtendByOne(VirtualFrame frame, RubyArray array, int index, double value) {
ensureCapacityNode.executeEnsureCapacity(frame, array, index + 1);
((double[]) array.getStore())[index] = value;
array.setStore(array.getStore(), index + 1);
return value;
}

@Specialization(
guards={"isObjectArray", "isExtendingByOne"}
)
public RubyBasicObject writeExtendByOne(VirtualFrame frame, RubyArray array, int index, RubyBasicObject value) {
ensureCapacityNode.executeEnsureCapacity(frame, array, index + 1);
((Object[]) array.getStore())[index] = value;
array.setStore(array.getStore(), index + 1);
return value;
}

// Writing beyond the end of an array - may need to generalise to Object[] or otherwise extend

@Specialization(
guards={"!isObjectArray", "!isInBounds", "!isExtendingByOne"}
)
public Object writeBeyondPrimitive(VirtualFrame frame, RubyArray array, int index, Object value) {
generalizeNode.executeGeneralize(frame, array, index + 1);
final Object[] objectStore = ((Object[]) array.getStore());

for (int n = array.getSize(); n < index; n++) {
objectStore[n] = getContext().getCoreLibrary().getNilObject();
}

objectStore[index] = value;
array.setStore(array.getStore(), index + 1);
return value;
}

@Specialization(
guards={"isObjectArray", "!isInBounds", "!isExtendingByOne"}
)
public Object writeBeyondObject(VirtualFrame frame, RubyArray array, int index, Object value) {
ensureCapacityNode.executeEnsureCapacity(frame, array, index + 1);
final Object[] objectStore = ((Object[]) array.getStore());

for (int n = array.getSize(); n < index; n++) {
objectStore[n] = getContext().getCoreLibrary().getNilObject();
}

objectStore[index] = value;
array.setStore(array.getStore(), index + 1);
return value;
}

// Guards

protected static boolean isInBounds(RubyArray array, int index) {
return index >= 0 && index < array.getSize();
}

protected static boolean isExtendingByOne(RubyArray array, int index) {
return index == array.getSize();
}

protected static boolean isIndex0(RubyArray array, int index) {
return index == 0;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.array;

import com.oracle.truffle.api.dsl.ImportGuards;
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.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ConditionProfile;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.ArrayGuards;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.util.ArrayUtils;

import java.util.Arrays;

@NodeChildren({
@NodeChild(value="array", type=RubyNode.class),
@NodeChild(value="requiredCapacity", type=RubyNode.class)
})
@ImportGuards(ArrayGuards.class)
public abstract class EnsureCapacityArrayNode extends RubyNode {

private final ConditionProfile allocateProfile = ConditionProfile.createCountingProfile();

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

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

public abstract Object executeEnsureCapacity(VirtualFrame frame, RubyArray array, int requiredCapacity);

@Specialization(
guards={"isIntArray"}
)
public boolean ensureCapacityInt(RubyArray array, int requiredCapacity) {
final int[] store = (int[]) array.getStore();

if (allocateProfile.profile(store.length < requiredCapacity)) {
array.setStore(Arrays.copyOf(store, ArrayUtils.capacity(store.length, requiredCapacity)), array.getSize());
return true;
} else {
return false;
}
}

@Specialization(
guards={"isLongArray"}
)
public boolean ensureCapacityLong(RubyArray array, int requiredCapacity) {
final long[] store = (long[]) array.getStore();

if (allocateProfile.profile(store.length < requiredCapacity)) {
array.setStore(Arrays.copyOf(store, ArrayUtils.capacity(store.length, requiredCapacity)), array.getSize());
return true;
} else {
return false;
}
}

@Specialization(
guards={"isDoubleArray"}
)
public boolean ensureCapacityDouble(RubyArray array, int requiredCapacity) {
final double[] store = (double[]) array.getStore();

if (allocateProfile.profile(store.length < requiredCapacity)) {
array.setStore(Arrays.copyOf(store, ArrayUtils.capacity(store.length, requiredCapacity)), array.getSize());
return true;
} else {
return false;
}
}

@Specialization(
guards={"isObjectArray"}
)
public boolean ensureCapacityObject(RubyArray array, int requiredCapacity) {
final Object[] store = (Object[]) array.getStore();

if (allocateProfile.profile(store.length < requiredCapacity)) {
array.setStore(Arrays.copyOf(store, ArrayUtils.capacity(store.length, requiredCapacity)), array.getSize());
return true;
} else {
return false;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.array;

import com.oracle.truffle.api.dsl.ImportGuards;
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.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ConditionProfile;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.ArrayGuards;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.util.ArrayUtils;

import java.util.Arrays;

@NodeChildren({
@NodeChild(value="array", type=RubyNode.class),
@NodeChild(value="requiredCapacity", type=RubyNode.class)
})
@ImportGuards(ArrayGuards.class)
public abstract class GeneralizeArrayNode extends RubyNode {

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

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

public abstract Object executeGeneralize(VirtualFrame frame, RubyArray array, int requiredCapacity);

// TODO CS 9-Feb-15 should use ArrayUtils.capacity?

@Specialization(
guards={"isNullArray"}
)
public RubyArray generalizeNull(RubyArray array, int requiredCapacity) {
array.setStore(new Object[requiredCapacity], array.getSize());
return array;
}

@Specialization(
guards={"isIntArray"}
)
public RubyArray generalizeInt(RubyArray array, int requiredCapacity) {
final int[] intStore = (int[]) array.getStore();
array.setStore(ArrayUtils.box(intStore, requiredCapacity - intStore.length), array.getSize());
return array;
}

@Specialization(
guards={"isLongArray"}
)
public RubyArray generalizeLong(RubyArray array, int requiredCapacity) {
final long[] intStore = (long[]) array.getStore();
array.setStore(ArrayUtils.box(intStore, requiredCapacity - intStore.length), array.getSize());
return array;
}

@Specialization(
guards={"isDoubleArray"}
)
public RubyArray generalizeDouble(RubyArray array, int requiredCapacity) {
final double[] intStore = (double[]) array.getStore();
array.setStore(ArrayUtils.box(intStore, requiredCapacity - intStore.length), array.getSize());
return array;
}

}
312 changes: 17 additions & 295 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/ArrayNodes.java
Original file line number Diff line number Diff line change
@@ -349,315 +349,33 @@ public Object fallback(VirtualFrame frame, RubyArray array, RubyArray args) {
@CoreMethod(names = "[]=", required = 2, optional = 1, lowerFixnumParameters = 0)
public abstract static class IndexSetNode extends ArrayCoreMethodNode {

@Child private ArrayWriteDenormalizedNode writeNode;

private final BranchProfile tooSmallBranch = BranchProfile.create();
private final BranchProfile pastEndBranch = BranchProfile.create();
private final BranchProfile appendBranch = BranchProfile.create();
private final BranchProfile beyondBranch = BranchProfile.create();
private final BranchProfile reallocateBranch = BranchProfile.create();

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

public IndexSetNode(IndexSetNode prev) {
super(prev);
writeNode = prev.writeNode;
}

// Set a simple index in an empty array

@Specialization(guards = "isNull")
public Object setNull(RubyArray array, int index, int value, UndefinedPlaceholder unused) {
if (index == 0) {
array.setStore(new int[]{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 setNull(RubyArray array, int index, long value, UndefinedPlaceholder unused) {
if (index == 0) {
array.setStore(new long[]{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 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 setNull(RubyArray array, int index, Object value, UndefinedPlaceholder unused) {
notDesignedForCompilation();

if (index == 0) {
array.slowPush(value);
} 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;
}

// Set a simple index in an existing array

@Specialization(guards = "isIntegerFixnum")
public int setIntegerFixnum(RubyArray array, int index, int value, UndefinedPlaceholder unused) {
final int normalizedIndex = array.normalizeIndex(index);
int[] store = (int[]) array.getStore();

if (normalizedIndex < 0) {
tooSmallBranch.enter();
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexTooSmallError("array", index, array.getSize(), this));
} else if (normalizedIndex >= array.getSize()) {
pastEndBranch.enter();

if (normalizedIndex == array.getSize()) {
appendBranch.enter();

if (normalizedIndex >= store.length) {
reallocateBranch.enter();
array.setStore(store = Arrays.copyOf(store, ArrayUtils.capacity(store.length, normalizedIndex + 1)), array.getSize());
}

store[normalizedIndex] = value;
array.setStore(store, array.getSize() + 1);
} else if (normalizedIndex > array.getSize()) {
beyondBranch.enter();
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[normalizedIndex] = value;
}

return value;
}

@Specialization(guards = "isIntegerFixnum")
public long setLongInIntegerFixnum(RubyArray array, int index, long value, UndefinedPlaceholder unused) {
if (array.getAllocationSite() != null) {
array.getAllocationSite().convertedIntToLong();
}

final int normalizedIndex = array.normalizeIndex(index);

long[] store = ArrayUtils.longCopyOf((int[]) array.getStore());
array.setStore(store, array.getSize());

if (normalizedIndex < 0) {
tooSmallBranch.enter();
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexTooSmallError("array", index, array.getSize(), this));
} else if (normalizedIndex >= array.getSize()) {
pastEndBranch.enter();

if (normalizedIndex == array.getSize()) {
appendBranch.enter();

if (normalizedIndex >= store.length) {
reallocateBranch.enter();
array.setStore(store = Arrays.copyOf(store, ArrayUtils.capacity(store.length, normalizedIndex + 1)), array.getSize());
}

store[normalizedIndex] = value;
array.setStore(store, array.getSize() + 1);
} else if (normalizedIndex > array.getSize()) {
beyondBranch.enter();
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[normalizedIndex] = value;
}

return value;
}

@Specialization(guards = "isLongFixnum")
public int setLongFixnum(RubyArray array, int index, int value, UndefinedPlaceholder unused) {
setLongFixnum(array, index, (long) value, unused);
return value;
}

@Specialization(guards = "isLongFixnum")
public long setLongFixnum(RubyArray array, int index, long value, UndefinedPlaceholder unused) {
final int normalizedIndex = array.normalizeIndex(index);
long[] store = (long[]) array.getStore();

if (normalizedIndex < 0) {
tooSmallBranch.enter();
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexTooSmallError("array", index, array.getSize(), this));
} else if (normalizedIndex >= array.getSize()) {
pastEndBranch.enter();

if (normalizedIndex == array.getSize()) {
appendBranch.enter();

if (normalizedIndex >= store.length) {
reallocateBranch.enter();
array.setStore(store = Arrays.copyOf(store, ArrayUtils.capacity(store.length, normalizedIndex + 1)), array.getSize());
}

store[normalizedIndex] = value;
array.setStore(store, array.getSize() + 1);
} else if (normalizedIndex > array.getSize()) {
beyondBranch.enter();
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[normalizedIndex] = value;
}

return value;
}

@Specialization(guards = "isFloat")
public double setFloat(RubyArray array, int index, double value, UndefinedPlaceholder unused) {
final int normalizedIndex = array.normalizeIndex(index);
double[] store = (double[]) array.getStore();

if (normalizedIndex < 0) {
tooSmallBranch.enter();
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexTooSmallError("array", index, array.getSize(), this));
} else if (normalizedIndex >= array.getSize()) {
pastEndBranch.enter();

if (normalizedIndex == array.getSize()) {
appendBranch.enter();

if (normalizedIndex >= store.length) {
reallocateBranch.enter();
array.setStore(store = Arrays.copyOf(store, ArrayUtils.capacity(store.length, normalizedIndex + 1)), array.getSize());
}

store[normalizedIndex] = value;
array.setStore(store, array.getSize() + 1);
} else if (normalizedIndex > array.getSize()) {
beyondBranch.enter();
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[normalizedIndex] = value;
}

return value;
}

@Specialization(guards = "isObject")
public Object setObject(RubyArray array, int index, Object value, UndefinedPlaceholder unused) {
final int normalizedIndex = array.normalizeIndex(index);
Object[] store = (Object[]) array.getStore();

if (normalizedIndex < 0) {
tooSmallBranch.enter();
@Specialization
public Object set(VirtualFrame frame, RubyArray array, int index, Object value, UndefinedPlaceholder unused) {
if (writeNode == null) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().indexTooSmallError("array", index, array.getSize(), this));
} else if (normalizedIndex >= array.getSize()) {
pastEndBranch.enter();

if (normalizedIndex == array.getSize()) {
appendBranch.enter();

if (normalizedIndex >= store.length) {
reallocateBranch.enter();
array.setStore(store = Arrays.copyOf(store, ArrayUtils.capacity(store.length, normalizedIndex + 1)), array.getSize());
}

store[normalizedIndex] = value;
array.setStore(store, array.getSize() + 1);
} else if (normalizedIndex > array.getSize()) {
beyondBranch.enter();
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[normalizedIndex] = value;
writeNode = insert(ArrayWriteDenormalizedNodeFactory.create(getContext(), getSourceSection(), null, null, null));
}

return value;
return writeNode.executeWrite(frame, array, index, value);
}

// Set a slice of the array to a particular value

@Specialization(guards = { "isObject", "!isRubyArray(arguments[3])", "!isUndefinedPlaceholder(arguments[3])" })
public Object setObject(RubyArray array, int start, int length, Object value) {
public Object setObject(VirtualFrame frame, RubyArray array, int start, int length, Object value) {
notDesignedForCompilation();

if (length < 0) {
@@ -668,8 +386,12 @@ public Object setObject(RubyArray array, int start, int length, Object value) {
final int begin = array.normalizeIndex(start);

if (begin >= array.getSize()) {
// We don't care of length in this case
return setObject(array, start, value, UndefinedPlaceholder.INSTANCE);
if (writeNode == null) {
CompilerDirectives.transferToInterpreter();
writeNode = insert(ArrayWriteDenormalizedNodeFactory.create(getContext(), getSourceSection(), null, null, null));
}

return writeNode.executeWrite(frame, array, start, value);
} else {
throw new UnsupportedOperationException();
}
@@ -678,7 +400,7 @@ 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) {
public Object setIntegerFixnum(VirtualFrame frame, RubyArray array, int start, int length, RubyArray value) {
notDesignedForCompilation();

if (length < 0) {
@@ -710,7 +432,7 @@ public RubyArray setIntegerFixnum(RubyArray array, int start, int length, RubyAr
}

@Specialization(guards = "isIntegerFixnum")
public RubyArray setIntegerFixnumRange(RubyArray array, RubyRange.IntegerFixnumRange range, RubyArray other, UndefinedPlaceholder unused) {
public Object setIntegerFixnumRange(VirtualFrame frame, RubyArray array, RubyRange.IntegerFixnumRange range, RubyArray other, UndefinedPlaceholder unused) {
if (range.doesExcludeEnd()) {
CompilerDirectives.transferToInterpreter();
throw new UnsupportedOperationException();

0 comments on commit a294f73

Please sign in to comment.