All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.truffle.object.DynamicObjectImpl Maven / Gradle / Ivy

Go to download

Truffle is a multi-language framework for executing dynamic languages that achieves high performance when combined with Graal.

There is a newer version: 24.1.1
Show newest version
/*
 * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * The Universal Permissive License (UPL), Version 1.0
 *
 * Subject to the condition set forth below, permission is hereby granted to any
 * person obtaining a copy of this software, associated documentation and/or
 * data (collectively the "Software"), free of charge and under any and all
 * copyright rights in the Software, and any and all patent rights owned or
 * freely licensable by each licensor hereunder covering either (i) the
 * unmodified Software as contributed to or provided by such licensor, or (ii)
 * the Larger Works (as defined below), to deal in both
 *
 * (a) the Software, and
 *
 * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
 * one is included with the Software each a "Larger Work" to which the Software
 * is contributed by such licensors),
 *
 * without restriction, including without limitation the rights to copy, create
 * derivative works of, display, perform, and distribute the Software and make,
 * use, sell, offer for sale, import, export, have made, and have sold the
 * Software and the Larger Work(s), and to sublicense the foregoing rights on
 * either these or other terms.
 *
 * This license is subject to the following condition:
 *
 * The above copyright notice and either this complete permission notice or at a
 * minimum a reference to the UPL must be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
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;

/** @since 0.17 or earlier */
@SuppressWarnings("deprecation")
@ExportLibrary(DynamicDispatchLibrary.class)
public abstract class DynamicObjectImpl extends DynamicObject implements Cloneable {

    /** @since 0.17 or earlier */
    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);
    }

    /** @since 0.17 or earlier */
    protected abstract void initialize(Shape initialShape);

    /** @since 0.17 or earlier */
    public final void setShapeAndResize(Shape newShape) {
        setShapeAndResize(getShape(), newShape);
    }

    /** @since 0.17 or earlier */
    @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);
        }
    }

    /**
     * Set shape to an immediate child of the current shape, optionally growing the extension array.
     * Typically this would add a single property. Cannot shrink or grow more than one property at a
     * time.
     *
     * @see #setShapeAndResize(Shape, Shape)
     * @since 0.17 or earlier
     */
    @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);
        }
    }

    /**
     * Simpler version of {@link #resizeStore} when the object is only increasing in size.
     */
    private void growStore(Shape oldShape, Shape newShape) {
        growObjectStore(oldShape, newShape);
        if (((ShapeImpl) newShape).hasPrimitiveArray) {
            growPrimitiveStore(oldShape, newShape);
        }
    }

    /** @since 0.17 or earlier */
    protected abstract void growObjectStore(Shape oldShape, Shape newShape);

    /** @since 0.17 or earlier */
    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);
        }
    }

    /** @since 0.17 or earlier */
    protected abstract void resizePrimitiveStore(Shape oldShape, Shape newShape);

    /** @since 0.17 or earlier */
    protected abstract void resizeObjectStore(Shape oldShape, Shape newShape);

    /**
     * Check whether fast transition is valid.
     *
     * @see #setShapeAndGrow
     */
    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;
    }

    /**
     * Check whether the extension arrays are in accordance with the description in the shape.
     *
     * @since 0.17 or earlier
     */
    protected abstract boolean checkExtensionArrayInvariants(Shape newShape);

    /** @since 0.17 or earlier */
    @Override
    protected final DynamicObject clone() {
        return LayoutImpl.ACCESS.objectClone(this);
    }

    /** @since 0.17 or earlier */
    protected abstract DynamicObject cloneWithShape(Shape currentShape);

    /** @since 0.17 or earlier */
    protected abstract void reshape(ShapeImpl newShape);

    /**
     * @param ancestor common ancestor shape between from and to object shapes
     * @since 0.17 or earlier
     */
    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 toMapIt = toShape.getPropertyMap().reverseOrderedValueIterator(); toMapIt.hasNext();) {
            Property toProperty = toMapIt.next();
            Property fromProperty = fromMap.get(toProperty.getKey());

            // copy only if property has a location and it's not the same as the source location
            if (!toProperty.getLocation().isValue() && !toProperty.getLocation().equals(fromProperty.getLocation())) {
                toProperty.setInternal(this, fromProperty.get(fromObject, false));
                assert toShape.isValid();
            }
        }
    }

    /** @since 0.17 or earlier */
    @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;
        }
    }

    /** @since 0.17 or earlier */
    public String debugDump(int level) {
        return debugDump(0, level);
    }

    /** @since 0.17 or earlier */
    public String debugDump(int level, int levelStop) {
        return Debug.dumpObject(this, level, levelStop);
    }

    /** @since 0.17 or earlier */
    @Override
    public String toString() {
        return getShape().getObjectType().toString(this);
    }

    /** @since 0.17 or earlier */
    @Override
    public boolean equals(Object obj) {
        return getShape().getObjectType().equals(this, obj);
    }

    /** @since 0.17 or earlier */
    @Override
    public int hashCode() {
        return getShape().getObjectType().hashCode(this);
    }

    /** @since 0.17 or earlier */
    @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;
        }
    }

    /** @since 0.17 or earlier */
    @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;
        }
    }

    /** @since 0.17 or earlier */
    @Override
    @TruffleBoundary
    public void define(Object key, Object value, int flags) {
        define(key, value, flags, null);
    }

    /** @since 0.17 or earlier */
    @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);
    }

    /** @since 0.17 or earlier */
    @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;
        }
    }

    /** @since 0.17 or earlier */
    @Override
    public final boolean updateShape() {
        return getShapeImpl().getLayout().getStrategy().updateShape(this);
    }

    /** @since 0.17 or earlier */
    @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 typeClass) {
            return true;
        }

        @Specialization(replaces = "doCachedShape")
        static boolean doCachedTypeClass(DynamicObjectImpl receiver,
                        @Shared("cachedTypeClass") @Cached(value = "getObjectType(receiver.getShape()).getClass()", allowUncached = true) Class 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 typeClass) {
            return cachedShape.getObjectType().dispatch();
        }

        @Specialization(replaces = "doCachedShape")
        static Class doCachedTypeClass(DynamicObjectImpl receiver,
                        @Shared("cachedTypeClass") @Cached(value = "getObjectType(receiver.getShape()).getClass()", allowUncached = true) Class typeClass) {
            com.oracle.truffle.api.object.ObjectType objectType = CompilerDirectives.castExact(receiver.getShape().getObjectType(), typeClass);
            return objectType.dispatch();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy