package com.oracle.truffle.js.runtime.array.dyn;
import static com.oracle.truffle.api.CompilerDirectives.FASTPATH_PROBABILITY;
import static com.oracle.truffle.api.CompilerDirectives.injectBranchProbability;
import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetArray;
import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arraySetArray;
import java.util.Objects;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.js.runtime.JSConfig;
import com.oracle.truffle.js.runtime.array.ScriptArray;
import com.oracle.truffle.js.runtime.objects.JSDynamicObject;
public abstract class AbstractJSObjectArray extends AbstractWritableArray {
protected AbstractJSObjectArray(int integrityLevel, DynamicArrayCache cache) {
super(integrityLevel, cache);
}
@Override
AbstractWritableArray sameTypeHolesArray(DynamicObject object, int length, Object array, long indexOffset, int arrayOffset, int usedLength, int holeCount) {
return HolesJSObjectArray.makeHolesJSObjectArray(object, length, (JSDynamicObject[]) array, indexOffset, arrayOffset, usedLength, holeCount, integrityLevel);
}
public abstract void setInBoundsFast(DynamicObject object, int index, JSDynamicObject value);
@Override
public final ScriptArray setElementImpl(DynamicObject object, long index, Object value, boolean strict) {
assert index >= 0;
if (injectBranchProbability(FASTPATH_PROBABILITY, JSDynamicObject.isJSDynamicObject(value) && isSupported(object, index))) {
setSupported(object, (int) index, (JSDynamicObject) value, ProfileHolder.empty());
return this;
} else {
return rewrite(object, index, value).setElementImpl(object, index, value, strict);
}
}
private ScriptArray rewrite(DynamicObject object, long index, Object value) {
if (isSupportedContiguous(object, index)) {
return toContiguous(object, index, value);
} else if (isSupportedHoles(object, index)) {
return toHoles(object, index, value);
} else {
return toObject(object, index, value);
}
}
@Override
public Object getInBoundsFast(DynamicObject object, int index) {
return getInBoundsFastJSObject(object, index);
}
@Override
int getArrayLength(Object array) {
return ((JSDynamicObject[]) array).length;
}
protected static JSDynamicObject[] getArray(DynamicObject object) {
Object array = arrayGetArray(object);
if (array.getClass() == JSDynamicObject[].class) {
return CompilerDirectives.castExact(array, JSDynamicObject[].class);
} else {
throw CompilerDirectives.shouldNotReachHere();
}
}
public abstract DynamicObject getInBoundsFastJSObject(DynamicObject object, int index);
public final void setInBounds(DynamicObject object, int index, JSDynamicObject value, ProfileHolder profile) {
getArray(object)[prepareInBounds(object, index, profile)] = checkNonNull(value);
if (JSConfig.TraceArrayWrites) {
traceWriteValue("InBounds", index, value);
}
}
public final void setSupported(DynamicObject object, int index, JSDynamicObject value, ProfileHolder profile) {
int preparedIndex = prepareSupported(object, index, profile);
getArray(object)[preparedIndex] = checkNonNull(value);
if (JSConfig.TraceArrayWrites) {
traceWriteValue("Supported", index, value);
}
}
@Override
void fillWithHoles(Object array, int fromIndex, int toIndex) {
JSDynamicObject[] objectArray = (JSDynamicObject[]) array;
for (int i = fromIndex; i < toIndex; i++) {
objectArray[i] = null;
}
}
@Override
protected final void setHoleValue(DynamicObject object, int preparedIndex) {
getArray(object)[preparedIndex] = null;
}
@Override
protected final void fillHoles(DynamicObject object, int internalIndex, int grown, ProfileHolder profile) {
if (grown != 0) {
incrementHolesCount(object, Math.abs(grown) - 1);
}
}
@Override
protected final boolean isHolePrepared(DynamicObject object, int preparedIndex) {
return HolesObjectArray.isHoleValue(getArray(object)[preparedIndex]);
}
@Override
protected final int getArrayCapacity(DynamicObject object) {
return getArray(object).length;
}
@Override
protected final void resizeArray(DynamicObject object, int newCapacity, int oldCapacity, int offset) {
JSDynamicObject[] newArray = new JSDynamicObject[newCapacity];
System.arraycopy(getArray(object), 0, newArray, offset, oldCapacity);
arraySetArray(object, newArray);
}
@Override
public abstract AbstractJSObjectArray toHoles(DynamicObject object, long index, Object value);
@Override
public abstract AbstractWritableArray toObject(DynamicObject object, long index, Object value);
@Override
public final AbstractWritableArray toDouble(DynamicObject object, long index, double value) {
return this;
}
@Override
public ScriptArray deleteElementImpl(DynamicObject object, long index, boolean strict) {
return toHoles(object, index, null).deleteElementImpl(object, index, strict);
}
@Override
protected final void moveRangePrepared(DynamicObject object, int src, int dst, int len) {
JSDynamicObject[] array = getArray(object);
System.arraycopy(array, src, array, dst, len);
}
@Override
public final Object allocateArray(int length) {
return new JSDynamicObject[length];
}
@Override
public Object cloneArray(DynamicObject object) {
return getArray(object).clone();
}
@Override
protected abstract AbstractJSObjectArray withIntegrityLevel(int newIntegrityLevel);
protected static JSDynamicObject checkNonNull(JSDynamicObject value) {
assert value != null;
return value;
}
protected DynamicObject castNonNull(DynamicObject value) {
if (JSConfig.MarkElementsNonNull) {
return Objects.requireNonNull(value);
} else {
return value;
}
}
}