package com.oracle.truffle.object;
import static com.oracle.truffle.object.LayoutImpl.ACCESS;
import java.lang.reflect.Field;
import java.util.Objects;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.FinalLocationException;
import com.oracle.truffle.api.object.IncompatibleLocationException;
import com.oracle.truffle.api.object.Location;
import com.oracle.truffle.api.object.Property;
import com.oracle.truffle.api.object.Shape;
import sun.misc.Unsafe;
@SuppressWarnings("deprecation")
abstract class CoreLocations {
static final int LONG_FIELD_SLOT_SIZE = 1;
static final int LONG_ARRAY_SLOT_SIZE = 2;
static final int OBJECT_SLOT_SIZE = 1;
static final int MAX_DYNAMIC_FIELDS = 1000;
public interface TypedLocation extends com.oracle.truffle.api.object.TypedLocation {
Class<?> getType();
}
public interface ObjectLocation extends TypedLocation, com.oracle.truffle.api.object.ObjectLocation {
Class<? extends Object> getType();
boolean isNonNull();
}
public interface IntLocation extends TypedLocation, com.oracle.truffle.api.object.IntLocation {
int getInt(DynamicObject store, boolean condition);
void setInt(DynamicObject store, int value, boolean condition);
default Class<Integer> getType() {
return int.class;
}
@Override
default int getInt(DynamicObject store, Shape shape) {
return getInt(store, store.getShape() == shape);
}
@Override
default void setInt(DynamicObject store, int value, Shape shape) throws FinalLocationException {
setInt(store, value, store.getShape() == shape);
}
@Override
default void setInt(DynamicObject store, int value) throws FinalLocationException {
setInt(store, value, false);
}
@Override
default void setInt(DynamicObject store, int value, Shape oldShape, Shape newShape) {
ACCESS.growAndSetShape(store, oldShape, newShape);
setInt(store, value, false);
}
}
public interface LongLocation extends TypedLocation, com.oracle.truffle.api.object.LongLocation {
long getLong(DynamicObject store, boolean condition);
void setLong(DynamicObject store, long value, boolean condition);
default Class<Long> getType() {
return long.class;
}
boolean isImplicitCastIntToLong();
@Override
default long getLong(DynamicObject store, Shape shape) {
return getLong(store, store.getShape() == shape);
}
@Override
default void setLong(DynamicObject store, long value, Shape shape) throws FinalLocationException {
setLong(store, value, store.getShape() == shape);
}
@Override
default void setLong(DynamicObject store, long value) throws FinalLocationException {
setLong(store, value, false);
}
@Override
default void setLong(DynamicObject store, long value, Shape oldShape, Shape newShape) {
ACCESS.growAndSetShape(store, oldShape, newShape);
setLong(store, value, false);
}
}
public interface DoubleLocation extends TypedLocation, com.oracle.truffle.api.object.DoubleLocation {
double getDouble(DynamicObject store, boolean condition);
void setDouble(DynamicObject store, double value, boolean condition);
default Class<Double> getType() {
return double.class;
}
boolean isImplicitCastIntToDouble();
@Override
default double getDouble(DynamicObject store, Shape shape) {
return getDouble(store, store.getShape() == shape);
}
@Override
default void setDouble(DynamicObject store, double value, Shape shape) throws FinalLocationException {
setDouble(store, value, store.getShape() == shape);
}
@Override
default void setDouble(DynamicObject store, double value) throws FinalLocationException {
setDouble(store, value, false);
}
@Override
default void setDouble(DynamicObject store, double value, Shape oldShape, Shape newShape) {
ACCESS.growAndSetShape(store, oldShape, newShape);
setDouble(store, value, false);
}
}
public interface BooleanLocation extends TypedLocation, com.oracle.truffle.api.object.BooleanLocation {
boolean getBoolean(DynamicObject store, boolean condition);
void setBoolean(DynamicObject store, boolean value, boolean condition);
default Class<Boolean> getType() {
return boolean.class;
}
@Override
default boolean getBoolean(DynamicObject store, Shape shape) {
return getBoolean(store, store.getShape() == shape);
}
@Override
default void setBoolean(DynamicObject store, boolean value, Shape shape) throws FinalLocationException {
setBoolean(store, value, store.getShape() == shape);
}
@Override
default void setBoolean(DynamicObject store, boolean value) throws FinalLocationException {
setBoolean(store, value, false);
}
@Override
default void setBoolean(DynamicObject store, boolean value, Shape oldShape, Shape newShape) {
ACCESS.growAndSetShape(store, oldShape, newShape);
setBoolean(store, value, false);
}
}
public abstract static class ValueLocation extends CoreLocation {
private final Object value;
ValueLocation(Object value) {
assert !(value instanceof Location);
this.value = value;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((value == null) ? 0 : 0 );
return result;
}
@Override
public boolean equals(Object obj) {
return super.equals(obj) && Objects.equals(value, ((ValueLocation) obj).value);
}
@Override
public final Object get(DynamicObject store, boolean condition) {
return value;
}
@Override
public boolean canStore(Object val) {
return valueEquals(this.value, val);
}
@Override
public final void set(DynamicObject store, Object value, boolean condition) throws IncompatibleLocationException, FinalLocationException {
if (!canStore(value)) {
throw finalLocation();
}
}
@Override
public final void setInternal(DynamicObject store, Object value, boolean condition) throws IncompatibleLocationException {
if (!canStore(value)) {
CompilerDirectives.transferToInterpreterAndInvalidate();
throw new UnsupportedOperationException();
}
}
@Override
public String toString() {
return "=" + String.valueOf(value);
}
@Override
public final void accept(LocationVisitor locationVisitor) {
}
@Override
public final boolean isValue() {
return true;
}
}
public static final class ConstantLocation extends ValueLocation {
ConstantLocation(Object value) {
super(value);
}
@Override
public boolean isConstant() {
return true;
}
}
public static final class DeclaredLocation extends ValueLocation {
DeclaredLocation(Object value) {
super(value);
}
@Override
public boolean isDeclared() {
return true;
}
}
public abstract static class ArrayLocation extends CoreLocation {
protected final int index;
protected final CoreLocation arrayLocation;
protected ArrayLocation(int index, CoreLocation arrayLocation) {
this.index = index;
this.arrayLocation = arrayLocation;
}
protected final Object getArray(DynamicObject store, boolean condition) {
return arrayLocation.get(store, condition);
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + index;
return result;
}
@Override
public boolean equals(Object obj) {
if (!super.equals(obj)) {
return false;
}
ArrayLocation other = (ArrayLocation) obj;
if (index != other.index) {
return false;
}
return true;
}
public final int getIndex() {
return index;
}
@Override
public String getWhereString() {
return "[" + index + "]";
}
}
public abstract static class FieldLocation extends CoreLocation {
private final int index;
protected FieldLocation(int index) {
this.index = index;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + index;
return result;
}
@Override
public boolean equals(Object obj) {
if (!super.equals(obj)) {
return false;
}
FieldLocation other = (FieldLocation) obj;
if (index != other.index) {
return false;
}
return true;
}
public final int getIndex() {
return index;
}
@Override
public String getWhereString() {
return "@" + index;
}
public abstract Class<? extends DynamicObject> getDeclaringClass();
protected final void receiverCheck(DynamicObject store) {
if (!getDeclaringClass().isInstance(store)) {
CompilerDirectives.transferToInterpreterAndInvalidate();
throw illegalReceiver(store);
}
}
private IllegalArgumentException illegalReceiver(DynamicObject store) {
CompilerAsserts.neverPartOfCompilation();
return new IllegalArgumentException(String.format("Invalid receiver type (expected %s, was %s)", getDeclaringClass(), store == null ? null : store.getClass()));
}
}
static class ObjectArrayLocation extends ArrayLocation implements ObjectLocation {
protected ObjectArrayLocation(int index, CoreLocation arrayLocation) {
super(index, arrayLocation);
}
@Override
public Object get(DynamicObject store, boolean condition) {
return ((Object[]) getArray(store, condition))[index];
}
@Override
public final void setInternal(DynamicObject store, Object value, boolean condition) {
((Object[]) getArray(store, condition))[index] = value;
}
@Override
public boolean canStore(Object value) {
return true;
}
public Class<? extends Object> getType() {
return Object.class;
}
public final boolean isNonNull() {
return false;
}
@Override
public int objectArrayCount() {
return OBJECT_SLOT_SIZE;
}
@Override
public final void accept(LocationVisitor locationVisitor) {
locationVisitor.visitObjectArray(index, OBJECT_SLOT_SIZE);
}
}
public abstract static class SimpleObjectFieldLocation extends FieldLocation implements ObjectLocation {
protected SimpleObjectFieldLocation(int index) {
super(index);
}
@Override
public abstract Object get(DynamicObject store, boolean condition);
@Override
public abstract void setInternal(DynamicObject store, Object value, boolean condition);
@Override
public boolean canStore(Object value) {
return true;
}
public Class<? extends Object> getType() {
return Object.class;
}
public boolean isNonNull() {
return false;
}
@Override
public int objectFieldCount() {
return OBJECT_SLOT_SIZE;
}
@Override
public final void accept(LocationVisitor locationVisitor) {
locationVisitor.visitObjectField(getIndex(), OBJECT_SLOT_SIZE);
}
}
static class LongArrayLocation extends ArrayLocation implements LongLocation {
private static final Unsafe UNSAFE = getUnsafe();
private static final int ALIGN = LONG_ARRAY_SLOT_SIZE - 1;
private static final long ARRAY_INT_BASE_OFFSET = UNSAFE.arrayBaseOffset(int[].class);
private static final long ARRAY_INT_INDEX_SCALE = UNSAFE.arrayIndexScale(int[].class);
protected final boolean allowInt;
protected LongArrayLocation(int index, CoreLocation arrayLocation, boolean allowInt) {
super(index, arrayLocation);
this.allowInt = allowInt;
}
protected LongArrayLocation(int index, CoreLocation arrayLocation) {
this(index, arrayLocation, false);
}
@Override
public final Object get(DynamicObject store, boolean condition) {
return getLong(store, condition);
}
@Override
public final void setInternal(DynamicObject store, Object value, boolean condition) throws IncompatibleLocationException {
if (canStore(value)) {
setLongInternal(store, longValue(value));
} else {
throw incompatibleLocation();
}
}
private long longValue(Object value) {
if (!allowInt || value instanceof Long) {
return ((Long) value).longValue();
} else {
return ((Integer) value).longValue();
}
}
@Override
public long getLong(DynamicObject store, boolean condition) {
int[] array = (int[]) getArray(store, condition);
return UNSAFE.getLong(array, getOffset(array));
}
public final void setLongInternal(DynamicObject store, long value) {
int[] array = (int[]) getArray(store, false);
long offset = getOffset(array);
UNSAFE.putLong(array, offset, value);
}
@Override
public void setLong(DynamicObject store, long value, boolean condition) {
setLongInternal(store, value);
}
@Override
public final boolean canStore(Object value) {
return value instanceof Long || (allowInt && value instanceof Integer);
}
public final Class<Long> getType() {
return long.class;
}
@Override
public int primitiveArrayCount() {
return LONG_ARRAY_SLOT_SIZE;
}
@Override
public final void accept(LocationVisitor locationVisitor) {
locationVisitor.visitPrimitiveArray(getIndex(), LONG_ARRAY_SLOT_SIZE);
}
@Override
public boolean equals(Object obj) {
return super.equals(obj) && this.allowInt == ((LongArrayLocation) obj).allowInt;
}
@Override
public boolean isImplicitCastIntToLong() {
return allowInt;
}
protected final long getOffset(int[] array) {
int idx = index;
if (idx < 0 || idx >= array.length - ALIGN) {
CompilerDirectives.transferToInterpreterAndInvalidate();
throw new ArrayIndexOutOfBoundsException(idx);
}
return ARRAY_INT_BASE_OFFSET + ARRAY_INT_INDEX_SCALE * idx;
}
}
public static LongLocation createLongLocation(LongLocation longLocation, boolean allowInt) {
if ((!allowInt && (longLocation instanceof LongLocationDecorator)) || (longLocation instanceof LongLocationDecorator && ((LongLocationDecorator) longLocation).allowInt == allowInt)) {
return longLocation;
} else {
return new LongLocationDecorator(longLocation, allowInt);
}
}
static class LongLocationDecorator extends PrimitiveLocationDecorator implements LongLocation {
protected final boolean allowInt;
protected LongLocationDecorator(LongLocation longLocation, boolean allowInt) {
super(longLocation);
this.allowInt = allowInt;
}
@Override
public final Object get(DynamicObject store, boolean condition) {
return getLong(store, condition);
}
@Override
public long getLong(DynamicObject store, boolean condition) {
return super.getLongInternal(store, condition);
}
@Override
public final void setInternal(DynamicObject store, Object value, boolean condition) throws IncompatibleLocationException {
if (canStore(value)) {
setLong(store, longValue(value), condition);
} else {
throw incompatibleLocation();
}
}
@Override
public void setLong(DynamicObject store, long value, boolean condition) {
super.setLongInternal(store, value, condition);
}
private long longValue(Object value) {
if (!allowInt || value instanceof Long) {
return ((Long) value).longValue();
} else {
return ((Integer) value).longValue();
}
}
@Override
public final boolean canStore(Object value) {
return value instanceof Long || (allowInt && value instanceof Integer);
}
@Override
public Class<Long> getType() {
return long.class;
}
@Override
public boolean equals(Object obj) {
return super.equals(obj) && this.allowInt == ((LongLocationDecorator) obj).allowInt;
}
@Override
public boolean isImplicitCastIntToLong() {
return allowInt;
}
}
public abstract static class SimpleLongFieldLocation extends FieldLocation implements LongLocation {
protected SimpleLongFieldLocation(int index) {
super(index);
}
@Override
public final Object get(DynamicObject store, boolean condition) {
return getLong(store, condition);
}
@Override
public final void setInternal(DynamicObject store, Object value, boolean condition) throws IncompatibleLocationException {
if (canStore(value)) {
setLong(store, ((Long) value).longValue(), condition);
} else {
throw incompatibleLocation();
}
}
@Override
public final boolean canStore(Object value) {
return value instanceof Long;
}
@Override
public abstract long getLong(DynamicObject store, boolean condition);
@Override
public final long getLong(DynamicObject store, Shape shape) {
return getLong(store, checkShape(store, shape));
}
@Override
public abstract void setLong(DynamicObject store, long value, boolean condition);
@Override
public int primitiveFieldCount() {
return LONG_FIELD_SLOT_SIZE;
}
@Override
public final Class<Long> getType() {
return long.class;
}
@Override
public void accept(LocationVisitor locationVisitor) {
locationVisitor.visitPrimitiveField(getIndex(), LONG_FIELD_SLOT_SIZE);
}
@Override
public boolean isImplicitCastIntToLong() {
return false;
}
}
public abstract static class PrimitiveLocationDecorator extends CoreLocation {
private final LongLocation longLocation;
protected PrimitiveLocationDecorator(LongLocation longLocation) {
this.longLocation = longLocation;
}
public final long getLongInternal(DynamicObject store, boolean condition) {
return longLocation.getLong(store, condition);
}
public final void setLongInternal(DynamicObject store, long value, boolean condition) {
longLocation.setLong(store, value, condition);
}
public final LongLocation getInternalLongLocation() {
return longLocation;
}
@Override
protected final LocationImpl getInternalLocation() {
return (LocationImpl) longLocation;
}
@Override
public final int primitiveFieldCount() {
return ((LocationImpl) longLocation).primitiveFieldCount();
}
@Override
public final int primitiveArrayCount() {
return ((LocationImpl) longLocation).primitiveArrayCount();
}
@Override
public final void accept(LocationVisitor locationVisitor) {
((LocationImpl) longLocation).accept(locationVisitor);
}
@Override
public String getWhereString() {
return ((LocationImpl) longLocation).getWhereString();
}
@Override
public boolean equals(Object obj) {
return super.equals(obj) && this.longLocation.equals(((PrimitiveLocationDecorator) obj).longLocation);
}
@Override
public int hashCode() {
return longLocation.hashCode();
}
}
static class IntLocationDecorator extends PrimitiveLocationDecorator implements IntLocation {
protected IntLocationDecorator(LongLocation longLocation) {
super(longLocation);
}
@Override
public final Object get(DynamicObject store, boolean condition) {
return getInt(store, condition);
}
@Override
public int getInt(DynamicObject store, boolean condition) {
return (int) getLongInternal(store, condition);
}
@Override
public void setInt(DynamicObject store, int value, boolean condition) {
setLongInternal(store, value, condition);
}
@Override
public final void setInternal(DynamicObject store, Object value, boolean condition) throws IncompatibleLocationException {
if (canStore(value)) {
setLongInternal(store, (int) value, condition);
} else {
throw incompatibleLocation();
}
}
@Override
public final int getInt(DynamicObject store, Shape shape) {
return getInt(store, checkShape(store, shape));
}
@Override
public final boolean canStore(Object value) {
return value instanceof Integer;
}
public Class<Integer> getType() {
return int.class;
}
}
static class DoubleLocationDecorator extends PrimitiveLocationDecorator implements DoubleLocation {
private final boolean allowInt;
protected DoubleLocationDecorator(LongLocation longLocation, boolean allowInt) {
super(longLocation);
this.allowInt = allowInt;
}
@Override
public final Object get(DynamicObject store, boolean condition) {
return getDouble(store, condition);
}
@Override
public double getDouble(DynamicObject store, boolean condition) {
return Double.longBitsToDouble(getLongInternal(store, condition));
}
@Override
public void setDouble(DynamicObject store, double value, boolean condition) {
setLongInternal(store, Double.doubleToRawLongBits(value), condition);
}
@Override
public final void setInternal(DynamicObject store, Object value, boolean condition) throws IncompatibleLocationException {
if (canStore(value)) {
setDouble(store, doubleValue(value), condition);
} else {
throw incompatibleLocation();
}
}
private double doubleValue(Object value) {
if (!allowInt || value instanceof Double) {
return ((Double) value).doubleValue();
} else {
return ((Integer) value).doubleValue();
}
}
@Override
public final double getDouble(DynamicObject store, Shape shape) {
return getDouble(store, checkShape(store, shape));
}
@Override
public final boolean canStore(Object value) {
return value instanceof Double || (allowInt && value instanceof Integer);
}
@Override
public Class<Double> getType() {
return double.class;
}
@Override
public boolean equals(Object obj) {
return super.equals(obj) && this.allowInt == ((DoubleLocationDecorator) obj).allowInt;
}
@Override
public boolean isImplicitCastIntToDouble() {
return allowInt;
}
}
static class BooleanLocationDecorator extends PrimitiveLocationDecorator implements BooleanLocation {
protected BooleanLocationDecorator(LongLocation longLocation) {
super(longLocation);
}
@Override
public final Object get(DynamicObject store, boolean condition) {
return getBoolean(store, condition);
}
@Override
public boolean getBoolean(DynamicObject store, boolean condition) {
return getLongInternal(store, condition) != 0;
}
@Override
public void setBoolean(DynamicObject store, boolean value, boolean condition) {
setLongInternal(store, value ? 1 : 0, condition);
}
@Override
public final void setInternal(DynamicObject store, Object value, boolean condition) throws IncompatibleLocationException {
if (canStore(value)) {
setBoolean(store, (boolean) value, condition);
} else {
throw incompatibleLocation();
}
}
@Override
public final boolean getBoolean(DynamicObject store, Shape shape) {
return getBoolean(store, checkShape(store, shape));
}
@Override
public final boolean canStore(Object value) {
return value instanceof Boolean;
}
@Override
public Class<Boolean> getType() {
return boolean.class;
}
}
static final SimpleObjectFieldLocation OBJECT_ARRAY_LOCATION;
static final SimpleObjectFieldLocation PRIMITIVE_ARRAY_LOCATION;
static long decodeLong(int lower, int upper) {
return (lower & 0xffff_ffffL) | ((long) upper << 32);
}
static int lowerInt(long value) {
return (int) value;
}
static int upperInt(long value) {
return (int) (value >>> 32);
}
static final class DynamicObjectFieldLocation extends SimpleObjectFieldLocation {
private final long offset;
private final Class<? extends DynamicObject> tclass;
private static final Unsafe UNSAFE = getUnsafe();
private DynamicObjectFieldLocation(int index, long offset, Class<? extends DynamicObject> declaringClass) {
super(index);
this.offset = offset;
this.tclass = declaringClass;
}
DynamicObjectFieldLocation(int index, Field objectField) {
this(index, UNSAFE.objectFieldOffset(objectField), objectField.getDeclaringClass().asSubclass(DynamicObject.class));
if (objectField.getType() != Object.class) {
throw new IllegalArgumentException();
}
}
@Override
public Object get(DynamicObject store, boolean condition) {
receiverCheck(store);
return UNSAFE.getObject(store, offset);
}
@Override
public void setInternal(DynamicObject store, Object value, boolean condition) {
receiverCheck(store);
UNSAFE.putObject(store, offset, value);
}
@Override
public Class<? extends DynamicObject> getDeclaringClass() {
return tclass;
}
}
static final class DynamicLongFieldLocation extends SimpleLongFieldLocation {
private final long offset;
private final Class<? extends DynamicObject> tclass;
private static final Unsafe UNSAFE = getUnsafe();
DynamicLongFieldLocation(int index, long offset, Class<? extends DynamicObject> declaringClass) {
super(index);
this.offset = offset;
this.tclass = declaringClass;
assert offset % Long.BYTES == 0;
}
@Override
public long getLong(DynamicObject store, boolean condition) {
receiverCheck(store);
return UNSAFE.getLong(store, offset);
}
@Override
public void setLong(DynamicObject store, long value, boolean condition) {
receiverCheck(store);
UNSAFE.putLong(store, offset, value);
}
@Override
public Class<? extends DynamicObject> getDeclaringClass() {
return tclass;
}
}
static int getLocationOrdinal(CoreLocation loc) {
LocationImpl internal = loc.getInternalLocation();
boolean isPrimitive = internal instanceof CoreLocations.LongLocation;
if (internal instanceof CoreLocations.FieldLocation) {
return (isPrimitive ? Integer.MIN_VALUE : 0) + ((CoreLocations.FieldLocation) internal).getIndex();
} else if (internal instanceof CoreLocations.ArrayLocation) {
return (isPrimitive ? Integer.MIN_VALUE : 0) + MAX_DYNAMIC_FIELDS + ((CoreLocations.ArrayLocation) internal).getIndex();
} else {
throw new IllegalArgumentException(internal.getClass().getName());
}
}
static Unsafe getUnsafe() {
try {
return Unsafe.getUnsafe();
} catch (SecurityException e) {
}
try {
Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeInstance.setAccessible(true);
return (Unsafe) theUnsafeInstance.get(Unsafe.class);
} catch (Exception e) {
throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
}
}
static {
int index = 0;
OBJECT_ARRAY_LOCATION = new SimpleObjectFieldLocation(index++) {
@Override
public Object[] get(DynamicObject store, boolean condition) {
return LayoutImpl.ACCESS.getObjectArray(store);
}
@Override
public void setInternal(DynamicObject store, Object value, boolean condition) {
LayoutImpl.ACCESS.setObjectArray(store, (Object[]) value);
}
@Override
public Class<? extends DynamicObject> getDeclaringClass() {
return DynamicObject.class;
}
};
PRIMITIVE_ARRAY_LOCATION = new SimpleObjectFieldLocation(index++) {
@Override
public int[] get(DynamicObject store, boolean condition) {
return LayoutImpl.ACCESS.getPrimitiveArray(store);
}
@Override
public void setInternal(DynamicObject store, Object value, boolean condition) {
LayoutImpl.ACCESS.setPrimitiveArray(store, (int[]) value);
}
@Override
public Class<? extends DynamicObject> getDeclaringClass() {
return DynamicObject.class;
}
};
}
}