package com.oracle.truffle.object;
import java.util.Iterator;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Cached.Shared;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.library.DynamicDispatchLibrary;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.LocationFactory;
import com.oracle.truffle.api.object.Property;
import com.oracle.truffle.api.object.Shape;
@SuppressWarnings("deprecation")
@ExportLibrary(DynamicDispatchLibrary.class)
public abstract class DynamicObjectImpl extends DynamicObject implements Cloneable {
protected DynamicObjectImpl(Shape shape) {
super(shape.getRoot(), LayoutImpl.ACCESS);
initialize(shape);
setShapeImpl(shape);
if (ObjectStorageOptions.Profile) {
Debug.trackObject(this);
}
}
final ShapeImpl getShapeImpl() {
return (ShapeImpl) getShape();
}
private void setShapeImpl(Shape shape) {
assert shape instanceof ShapeImpl;
LayoutImpl.ACCESS.setShape(this, shape);
}
protected abstract void initialize(Shape initialShape);
public final void setShapeAndResize(Shape newShape) {
setShapeAndResize(getShape(), newShape);
}
@Override
public final void setShapeAndResize(Shape oldShape, Shape newShape) {
assert getShape() == oldShape : "wrong old shape";
assert !oldShape.isShared();
if (oldShape != newShape) {
resizeStore(oldShape, newShape);
setShapeImpl(newShape);
assert checkExtensionArrayInvariants(newShape);
}
}
@Override
public final void setShapeAndGrow(Shape oldShape, Shape newShape) {
assert getShape() == oldShape : "wrong old shape";
if (oldShape != newShape) {
assert checkSetShape(oldShape, newShape);
growStore(oldShape, newShape);
setShapeImpl(newShape);
assert checkExtensionArrayInvariants(newShape);
}
}
private void growStore(Shape oldShape, Shape newShape) {
growObjectStore(oldShape, newShape);
if (((ShapeImpl) newShape).hasPrimitiveArray) {
growPrimitiveStore(oldShape, newShape);
}
}
protected abstract void growObjectStore(Shape oldShape, Shape newShape);
protected abstract void growPrimitiveStore(Shape oldShape, Shape newShape);
protected void resizeStore(Shape oldShape, Shape newShape) {
resizeObjectStore(oldShape, newShape);
if (((ShapeImpl) newShape).hasPrimitiveArray) {
resizePrimitiveStore(oldShape, newShape);
}
}
protected abstract void resizePrimitiveStore(Shape oldShape, Shape newShape);
protected abstract void resizeObjectStore(Shape oldShape, Shape newShape);
private boolean checkSetShape(Shape oldShape, Shape newShape) {
Shape currentShape = getShape();
assert oldShape != newShape : "Wrong old shape assumption?";
assert newShape != currentShape : "Redundant shape change? shape=" + currentShape;
return true;
}
protected abstract boolean checkExtensionArrayInvariants(Shape newShape);
@Override
protected final DynamicObject clone() {
return LayoutImpl.ACCESS.objectClone(this);
}
protected abstract DynamicObject cloneWithShape(Shape currentShape);
protected abstract void reshape(ShapeImpl newShape);
public final void copyProperties(DynamicObject fromObject, Shape ancestor) {
copyProperties(fromObject);
}
private void copyProperties(DynamicObject fromObject) {
ShapeImpl fromShape = (ShapeImpl) fromObject.getShape();
ShapeImpl toShape = getShapeImpl();
assert toShape.isRelated(fromShape);
assert toShape.isValid();
assert !fromShape.isShared();
PropertyMap fromMap = fromShape.getPropertyMap();
for (Iterator<Property> toMapIt = toShape.getPropertyMap().reverseOrderedValueIterator(); toMapIt.hasNext();) {
Property toProperty = toMapIt.next();
Property fromProperty = fromMap.get(toProperty.getKey());
if (!toProperty.getLocation().isValue() && !toProperty.getLocation().equals(fromProperty.getLocation())) {
toProperty.setInternal(this, fromProperty.get(fromObject, false));
assert toShape.isValid();
}
}
}
@TruffleBoundary
public boolean changeFlags(Object key, int newFlags) {
Shape oldShape = getShape();
Property existing = oldShape.getProperty(key);
if (existing != null) {
if (existing.getFlags() != newFlags) {
Property newProperty = existing.copyWithFlags(newFlags);
Shape newShape = oldShape.replaceProperty(existing, newProperty);
setShapeImpl(newShape);
}
return true;
} else {
return false;
}
}
public String debugDump(int level) {
return debugDump(0, level);
}
public String debugDump(int level, int levelStop) {
return Debug.dumpObject(this, level, levelStop);
}
@Override
public String toString() {
return getShape().getObjectType().toString(this);
}
@Override
public boolean equals(Object obj) {
return getShape().getObjectType().equals(this, obj);
}
@Override
public int hashCode() {
return getShape().getObjectType().hashCode(this);
}
@Override
@TruffleBoundary
public Object get(Object key, Object defaultValue) {
Property existing = getShape().getProperty(key);
if (existing != null) {
return existing.get(this, false);
} else {
return defaultValue;
}
}
@Override
@TruffleBoundary
public boolean set(Object key, Object value) {
Property existing = getShape().getProperty(key);
if (existing != null) {
existing.setGeneric(this, value, null);
return true;
} else {
return false;
}
}
@Override
@TruffleBoundary
public void define(Object key, Object value, int flags) {
define(key, value, flags, getShapeImpl().getLayout().getStrategy().getDefaultLocationFactory());
}
@Override
@TruffleBoundary
public void define(Object key, Object value, int flags, LocationFactory locationFactory) {
ShapeImpl oldShape = getShapeImpl();
oldShape.getLayout().getStrategy().objectDefineProperty(this, key, value, flags, locationFactory, oldShape);
}
@Override
@TruffleBoundary
public boolean delete(Object key) {
ShapeImpl oldShape = getShapeImpl();
Property existing = oldShape.getProperty(key);
if (existing != null) {
oldShape.getLayout().getStrategy().objectRemoveProperty(this, existing, oldShape);
return true;
} else {
return false;
}
}
@Override
public final boolean updateShape() {
return getShapeImpl().getLayout().getStrategy().updateShape(this);
}
@Override
public final DynamicObject copy(Shape currentShape) {
return cloneWithShape(currentShape);
}
static com.oracle.truffle.api.object.ObjectType getObjectType(Shape shape) {
return shape.getObjectType();
}
@ExportMessage
static class Accepts {
@Specialization(limit = "1", guards = "cachedShape == receiver.getShape()")
@SuppressWarnings("unused")
static boolean doCachedShape(DynamicObjectImpl receiver,
@Shared("cachedShape") @Cached("receiver.getShape()") Shape cachedShape,
@Shared("cachedTypeClass") @Cached(value = "getObjectType(receiver.getShape()).getClass()", allowUncached = true) Class<? extends com.oracle.truffle.api.object.ObjectType> typeClass) {
return true;
}
@Specialization(replaces = "doCachedShape")
static boolean doCachedTypeClass(DynamicObjectImpl receiver,
@Shared("cachedTypeClass") @Cached(value = "getObjectType(receiver.getShape()).getClass()", allowUncached = true) Class<? extends com.oracle.truffle.api.object.ObjectType> typeClass) {
return typeClass == receiver.getShape().getObjectType().getClass();
}
}
@ExportMessage
static class Dispatch {
@Specialization(limit = "1", guards = "cachedShape == receiver.getShape()")
@SuppressWarnings("unused")
static Class<?> doCachedShape(DynamicObjectImpl receiver,
@Shared("cachedShape") @Cached("receiver.getShape()") Shape cachedShape,
@Shared("cachedTypeClass") @Cached(value = "getObjectType(receiver.getShape()).getClass()", allowUncached = true) Class<? extends com.oracle.truffle.api.object.ObjectType> typeClass) {
return cachedShape.getObjectType().dispatch();
}
@Specialization(replaces = "doCachedShape")
static Class<?> doCachedTypeClass(DynamicObjectImpl receiver,
@Shared("cachedTypeClass") @Cached(value = "getObjectType(receiver.getShape()).getClass()", allowUncached = true) Class<? extends com.oracle.truffle.api.object.ObjectType> typeClass) {
com.oracle.truffle.api.object.ObjectType objectType = CompilerDirectives.castExact(receiver.getShape().getObjectType(), typeClass);
return objectType.dispatch();
}
}
}