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

com.oracle.truffle.api.impl.FrameWithoutBoxing 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, 2022, 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.api.impl;

import java.lang.reflect.Field;
import java.util.Arrays;

import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameSlotKind;
import com.oracle.truffle.api.frame.FrameSlotTypeException;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;

import sun.misc.Unsafe;

/**
 * More efficient implementation of the Truffle frame that has no safety checks for frame accesses
 * and therefore is much faster. Should not be used during debugging as potential misuses of the
 * frame object would show up very late and would be hard to identify.
 */
public final class FrameWithoutBoxing implements VirtualFrame, MaterializedFrame {
    private static final String UNEXPECTED_STATIC_WRITE = "Unexpected static write of non-static frame slot";
    private static final String UNEXPECTED_NON_STATIC_READ = "Unexpected non-static read of static frame slot";
    private static final String UNEXPECTED_NON_STATIC_WRITE = "Unexpected non-static write of static frame slot";

    private static final boolean ASSERTIONS_ENABLED;

    private final FrameDescriptor descriptor;
    private final Object[] arguments;

    private final Object[] indexedLocals;
    private final long[] indexedPrimitiveLocals;
    private final byte[] indexedTags;

    private Object[] auxiliarySlots;

    private static final Object OBJECT_LOCATION = new Object();
    private static final Object PRIMITIVE_LOCATION = new Object();

    private static final long INT_MASK = 0xFFFFFFFFL;

    /*
     * Changing these constants implies changes in NewFrameNode.java as well:
     */
    public static final byte OBJECT_TAG = 0;
    public static final byte LONG_TAG = 1;
    public static final byte INT_TAG = 2;
    public static final byte DOUBLE_TAG = 3;
    public static final byte FLOAT_TAG = 4;
    public static final byte BOOLEAN_TAG = 5;
    public static final byte BYTE_TAG = 6;
    public static final byte ILLEGAL_TAG = 7;
    public static final byte STATIC_TAG = 8;

    private static final byte STATIC_OBJECT_TAG = STATIC_TAG | OBJECT_TAG;
    private static final byte STATIC_LONG_TAG = STATIC_TAG | LONG_TAG;
    private static final byte STATIC_INT_TAG = STATIC_TAG | INT_TAG;
    private static final byte STATIC_DOUBLE_TAG = STATIC_TAG | DOUBLE_TAG;
    private static final byte STATIC_FLOAT_TAG = STATIC_TAG | FLOAT_TAG;
    private static final byte STATIC_BOOLEAN_TAG = STATIC_TAG | BOOLEAN_TAG;
    private static final byte STATIC_BYTE_TAG = STATIC_TAG | BYTE_TAG;
    private static final byte STATIC_ILLEGAL_TAG = STATIC_TAG | ILLEGAL_TAG;

    private static final Object[] EMPTY_OBJECT_ARRAY = {};
    private static final long[] EMPTY_LONG_ARRAY = {};
    private static final byte[] EMPTY_BYTE_ARRAY = {};

    private static final Unsafe UNSAFE = initUnsafe();

    static {
        assert OBJECT_TAG == FrameSlotKind.Object.tag;
        assert ILLEGAL_TAG == FrameSlotKind.Illegal.tag;
        assert LONG_TAG == FrameSlotKind.Long.tag;
        assert INT_TAG == FrameSlotKind.Int.tag;
        assert DOUBLE_TAG == FrameSlotKind.Double.tag;
        assert FLOAT_TAG == FrameSlotKind.Float.tag;
        assert BOOLEAN_TAG == FrameSlotKind.Boolean.tag;
        assert BYTE_TAG == FrameSlotKind.Byte.tag;
        assert STATIC_TAG == FrameSlotKind.Static.tag;

        // Check if assertions are enabled
        boolean enabled = false;
        assert enabled = true;
        ASSERTIONS_ENABLED = enabled;
    }

    private static Unsafe initUnsafe() {
        try {
            // Fast path when we are trusted.
            return Unsafe.getUnsafe();
        } catch (SecurityException se) {
            // Slow path when we are not trusted.
            try {
                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
                theUnsafe.setAccessible(true);
                return (Unsafe) theUnsafe.get(Unsafe.class);
            } catch (Exception e) {
                throw new RuntimeException("exception while trying to get Unsafe", e);
            }
        }
    }

    public FrameWithoutBoxing(FrameDescriptor descriptor, Object[] arguments) {
        final int indexedSize = descriptor.getNumberOfSlots();
        final int auxiliarySize = descriptor.getNumberOfAuxiliarySlots();
        Object defaultValue = descriptor.getDefaultValue();
        final Accessor.FrameSupport frameSupport = DefaultRuntimeAccessor.FRAME;
        final Object[] indexedLocalsArray;
        final long[] indexedPrimitiveLocalsArray;
        final byte[] indexedTagsArray;
        final Object[] auxiliarySlotsArray;
        if (indexedSize == 0) {
            indexedLocalsArray = EMPTY_OBJECT_ARRAY;
            indexedPrimitiveLocalsArray = EMPTY_LONG_ARRAY;
            indexedTagsArray = EMPTY_BYTE_ARRAY;
        } else {
            indexedLocalsArray = new Object[indexedSize];
            if (defaultValue != null) {
                Arrays.fill(indexedLocalsArray, defaultValue);
            }
            indexedPrimitiveLocalsArray = new long[indexedSize];
            indexedTagsArray = new byte[indexedSize];
            if (frameSupport.usesAllStaticMode(descriptor)) {
                Arrays.fill(indexedTagsArray, STATIC_TAG);
            } else if (frameSupport.usesMixedStaticMode(descriptor)) {
                for (int slot = 0; slot < indexedTagsArray.length; slot++) {
                    if (descriptor.getSlotKind(slot) == FrameSlotKind.Static) {
                        indexedTagsArray[slot] = STATIC_TAG;
                    }
                }
            }
        }
        if (auxiliarySize == 0) {
            auxiliarySlotsArray = EMPTY_OBJECT_ARRAY;
        } else {
            auxiliarySlotsArray = new Object[auxiliarySize];
        }
        this.descriptor = descriptor;
        this.arguments = arguments;
        this.indexedLocals = indexedLocalsArray;
        this.indexedPrimitiveLocals = indexedPrimitiveLocalsArray;
        this.indexedTags = indexedTagsArray;
        this.auxiliarySlots = auxiliarySlotsArray;
    }

    @Override
    public Object[] getArguments() {
        return unsafeCast(arguments, Object[].class, true, true, true);
    }

    @Override
    public MaterializedFrame materialize() {
        ImplAccessor.frameSupportAccessor().markMaterializeCalled(descriptor);
        return this;
    }

    private static long extend(int value) {
        return value & INT_MASK;
    }

    @Override
    public FrameDescriptor getFrameDescriptor() {
        return unsafeCast(descriptor, FrameDescriptor.class, true, true, false);
    }

    private static FrameSlotTypeException frameSlotTypeException() throws FrameSlotTypeException {
        CompilerAsserts.neverPartOfCompilation();
        throw new FrameSlotTypeException();
    }

    private static long getPrimitiveOffset(int slotIndex) {
        return Unsafe.ARRAY_LONG_BASE_OFFSET + slotIndex * (long) Unsafe.ARRAY_LONG_INDEX_SCALE;
    }

    @Override
    public byte getTag(int slotIndex) {
        try {
            final byte tag = getIndexedTags()[slotIndex];
            return tag < STATIC_TAG ? tag : STATIC_TAG;
        } catch (ArrayIndexOutOfBoundsException e) {
            throw CompilerDirectives.shouldNotReachHere("invalid indexed slot", e);
        }
    }

    @SuppressWarnings({"unchecked", "unused"})
    private static  T unsafeCast(Object value, Class type, boolean condition, boolean nonNull, boolean exact) {
        return (T) value;
    }

    @SuppressWarnings("unused")
    private static long unsafeGetLong(Object receiver, long offset, boolean condition, Object locationIdentity) {
        return UNSAFE.getLong(receiver, offset);
    }

    @SuppressWarnings("unused")
    private static Object unsafeGetObject(Object receiver, long offset, boolean condition, Object locationIdentity) {
        return UNSAFE.getObject(receiver, offset);
    }

    @SuppressWarnings("unused")
    private static void unsafePutLong(Object receiver, long offset, long value, Object locationIdentity) {
        UNSAFE.putLong(receiver, offset, value);
    }

    @SuppressWarnings("unused")
    private static void unsafePutObject(Object receiver, long offset, Object value, Object locationIdentity) {
        UNSAFE.putObject(receiver, offset, value);
    }

    @Override
    public Object getValue(int slot) {
        byte tag = getTag(slot);
        assert (indexedTags[slot] & STATIC_TAG) == 0 : UNEXPECTED_NON_STATIC_READ;
        switch (tag) {
            case BOOLEAN_TAG:
                return getBoolean(slot);
            case BYTE_TAG:
                return getByte(slot);
            case INT_TAG:
                return getInt(slot);
            case DOUBLE_TAG:
                return getDouble(slot);
            case LONG_TAG:
                return getLong(slot);
            case FLOAT_TAG:
                return getFloat(slot);
            case OBJECT_TAG:
                return getObject(slot);
            default:
                throw CompilerDirectives.shouldNotReachHere();
        }
    }

    private Object[] getIndexedLocals() {
        return unsafeCast(indexedLocals, Object[].class, true, true, true);
    }

    private long[] getIndexedPrimitiveLocals() {
        return unsafeCast(this.indexedPrimitiveLocals, long[].class, true, true, true);
    }

    private byte[] getIndexedTags() {
        return unsafeCast(indexedTags, byte[].class, true, true, true);
    }

    @Override
    public Object getObject(int slot) throws FrameSlotTypeException {
        boolean condition = verifyIndexedGet(slot, OBJECT_TAG);
        return unsafeGetObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + slot * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, condition, OBJECT_LOCATION);
    }

    @Override
    public void setObject(int slot, Object value) {
        verifyIndexedSet(slot, OBJECT_TAG);
        unsafePutObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + slot * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, value, OBJECT_LOCATION);
    }

    @Override
    public byte getByte(int slot) throws FrameSlotTypeException {
        boolean condition = verifyIndexedGet(slot, BYTE_TAG);
        return (byte) (int) unsafeGetLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(slot), condition, PRIMITIVE_LOCATION);
    }

    @Override
    public void setByte(int slot, byte value) {
        verifyIndexedSet(slot, BYTE_TAG);
        unsafePutLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(slot), extend(value), PRIMITIVE_LOCATION);
    }

    @Override
    public boolean getBoolean(int slot) throws FrameSlotTypeException {
        boolean condition = verifyIndexedGet(slot, BOOLEAN_TAG);
        return (int) unsafeGetLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(slot), condition, PRIMITIVE_LOCATION) != 0;
    }

    @Override
    public void setBoolean(int slot, boolean value) {
        verifyIndexedSet(slot, BOOLEAN_TAG);
        unsafePutLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(slot), value ? 1L : 0L, PRIMITIVE_LOCATION);
    }

    @Override
    public float getFloat(int slot) throws FrameSlotTypeException {
        boolean condition = verifyIndexedGet(slot, FLOAT_TAG);
        return Float.intBitsToFloat((int) unsafeGetLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(slot), condition, PRIMITIVE_LOCATION));
    }

    @Override
    public void setFloat(int slot, float value) {
        verifyIndexedSet(slot, FLOAT_TAG);
        unsafePutLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(slot), extend(Float.floatToRawIntBits(value)), PRIMITIVE_LOCATION);
    }

    @Override
    public long getLong(int slot) throws FrameSlotTypeException {
        boolean condition = verifyIndexedGet(slot, LONG_TAG);
        return unsafeGetLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(slot), condition, PRIMITIVE_LOCATION);
    }

    @Override
    public void setLong(int slot, long value) {
        verifyIndexedSet(slot, LONG_TAG);
        unsafePutLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(slot), value, PRIMITIVE_LOCATION);
    }

    @Override
    public int getInt(int slot) throws FrameSlotTypeException {
        boolean condition = verifyIndexedGet(slot, INT_TAG);
        return (int) unsafeGetLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(slot), condition, PRIMITIVE_LOCATION);
    }

    @Override
    public void setInt(int slot, int value) {
        verifyIndexedSet(slot, INT_TAG);
        unsafePutLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(slot), extend(value), PRIMITIVE_LOCATION);
    }

    @Override
    public double getDouble(int slot) throws FrameSlotTypeException {
        boolean condition = verifyIndexedGet(slot, DOUBLE_TAG);
        return Double.longBitsToDouble(unsafeGetLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(slot), condition, PRIMITIVE_LOCATION));
    }

    @Override
    public void setDouble(int slot, double value) {
        verifyIndexedSet(slot, DOUBLE_TAG);
        unsafePutLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(slot), Double.doubleToRawLongBits(value), PRIMITIVE_LOCATION);
    }

    @Override
    public void copy(int srcSlot, int destSlot) {
        byte tag = getIndexedTagChecked(srcSlot);
        Object value = unsafeGetObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + srcSlot * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, true, OBJECT_LOCATION);
        verifyIndexedSet(destSlot, tag);
        unsafePutObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + destSlot * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, value, OBJECT_LOCATION);
        long primitiveValue = unsafeGetLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(srcSlot), true, PRIMITIVE_LOCATION);
        unsafePutLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(destSlot), primitiveValue, PRIMITIVE_LOCATION);
    }

    @Override
    public void swap(int first, int second) {
        byte firstTag = getIndexedTagChecked(first);
        Object firstValue = unsafeGetObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + first * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, true, OBJECT_LOCATION);
        long firstPrimitiveValue = unsafeGetLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(first), true, PRIMITIVE_LOCATION);
        byte secondTag = getIndexedTagChecked(second);
        Object secondValue = unsafeGetObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + second * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, true, OBJECT_LOCATION);
        long secondPrimitiveValue = unsafeGetLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(second), true, PRIMITIVE_LOCATION);

        verifyIndexedSet(first, secondTag);
        verifyIndexedSet(second, firstTag);
        unsafePutObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + first * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, secondValue, OBJECT_LOCATION);
        unsafePutLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(first), secondPrimitiveValue, PRIMITIVE_LOCATION);
        unsafePutObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + second * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, firstValue, OBJECT_LOCATION);
        unsafePutLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(second), firstPrimitiveValue, PRIMITIVE_LOCATION);
    }

    private void verifyIndexedSet(int slot, byte tag) {
        assert (indexedTags[slot] & STATIC_TAG) == 0 : UNEXPECTED_NON_STATIC_WRITE;
        // this may raise an AIOOBE
        getIndexedTags()[slot] = tag;
    }

    private boolean verifyIndexedGet(int slot, byte expectedTag) throws FrameSlotTypeException {
        byte actualTag = getIndexedTagChecked(slot);
        boolean condition = actualTag == expectedTag;
        if (!condition) {
            CompilerDirectives.transferToInterpreterAndInvalidate();
            throw frameSlotTypeException();
        }
        return condition;
    }

    private byte getIndexedTagChecked(int slot) {
        // this may raise an AIOOBE
        byte tag = getIndexedTags()[slot];
        assert (tag & STATIC_TAG) == 0 : UNEXPECTED_NON_STATIC_READ;
        return tag;
    }

    @Override
    public boolean isObject(int slot) {
        return getTag(slot) == OBJECT_TAG;
    }

    @Override
    public boolean isByte(int slot) {
        return getTag(slot) == BYTE_TAG;
    }

    @Override
    public boolean isBoolean(int slot) {
        return getTag(slot) == BOOLEAN_TAG;
    }

    @Override
    public boolean isInt(int slot) {
        return getTag(slot) == INT_TAG;
    }

    @Override
    public boolean isLong(int slot) {
        return getTag(slot) == LONG_TAG;
    }

    @Override
    public boolean isFloat(int slot) {
        return getTag(slot) == FLOAT_TAG;
    }

    @Override
    public boolean isDouble(int slot) {
        return getTag(slot) == DOUBLE_TAG;
    }

    @Override
    public boolean isStatic(int slot) {
        return getTag(slot) == STATIC_TAG;
    }

    @Override
    public void clear(int slot) {
        verifyIndexedSet(slot, ILLEGAL_TAG);
        unsafePutObject(getIndexedLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + slot * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, null, OBJECT_LOCATION);
        if (CompilerDirectives.inCompiledCode()) {
            unsafePutLong(getIndexedPrimitiveLocals(), getPrimitiveOffset(slot), 0L, PRIMITIVE_LOCATION);
        }
    }

    @Override
    public void setAuxiliarySlot(int slot, Object value) {
        if (auxiliarySlots.length <= slot) {
            CompilerDirectives.transferToInterpreterAndInvalidate();
            auxiliarySlots = Arrays.copyOf(auxiliarySlots, descriptor.getNumberOfAuxiliarySlots());
        }
        auxiliarySlots[slot] = value;
    }

    @Override
    public Object getAuxiliarySlot(int slot) {
        return slot < auxiliarySlots.length ? auxiliarySlots[slot] : null;
    }

    @Override
    public Object getObjectStatic(int slot) {
        assert indexedTags[slot] == STATIC_OBJECT_TAG : "Unexpected read of static object value";

        return indexedLocals[slot];
    }

    @Override
    public void setObjectStatic(int slot, Object value) {
        assert (indexedTags[slot] & STATIC_TAG) != 0 : UNEXPECTED_STATIC_WRITE;
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            indexedTags[slot] = STATIC_OBJECT_TAG;
        }

        indexedLocals[slot] = value;
    }

    @Override
    public byte getByteStatic(int slot) {
        assert indexedTags[slot] == STATIC_BYTE_TAG : "Unexpected read of static byte value";

        return (byte) (int) indexedPrimitiveLocals[slot];
    }

    @Override
    public void setByteStatic(int slot, byte value) {
        assert (indexedTags[slot] & STATIC_TAG) != 0 : UNEXPECTED_STATIC_WRITE;
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            indexedTags[slot] = STATIC_BYTE_TAG;
        }

        indexedPrimitiveLocals[slot] = extend(value);
    }

    @Override
    public boolean getBooleanStatic(int slot) {
        assert indexedTags[slot] == STATIC_BOOLEAN_TAG : "Unexpected read of static boolean value";

        return (int) indexedPrimitiveLocals[slot] != 0;
    }

    @Override
    public void setBooleanStatic(int slot, boolean value) {
        assert (indexedTags[slot] & STATIC_TAG) != 0 : UNEXPECTED_STATIC_WRITE;
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            indexedTags[slot] = STATIC_BOOLEAN_TAG;
        }

        indexedPrimitiveLocals[slot] = value ? 1L : 0L;
    }

    @Override
    public int getIntStatic(int slot) {
        assert indexedTags[slot] == STATIC_INT_TAG : "Unexpected read of static int value";

        return (int) indexedPrimitiveLocals[slot];
    }

    @Override
    public void setIntStatic(int slot, int value) {
        assert (indexedTags[slot] & STATIC_TAG) != 0 : UNEXPECTED_STATIC_WRITE;
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            indexedTags[slot] = STATIC_INT_TAG;
        }

        indexedPrimitiveLocals[slot] = extend(value);
    }

    @Override
    public long getLongStatic(int slot) {
        assert indexedTags[slot] == STATIC_LONG_TAG : "Unexpected read of static long value";

        return indexedPrimitiveLocals[slot];
    }

    @Override
    public void setLongStatic(int slot, long value) {
        assert (indexedTags[slot] & STATIC_TAG) != 0 : UNEXPECTED_STATIC_WRITE;
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            indexedTags[slot] = STATIC_LONG_TAG;
        }

        indexedPrimitiveLocals[slot] = value;
    }

    @Override
    public float getFloatStatic(int slot) {
        assert indexedTags[slot] == STATIC_FLOAT_TAG : "Unexpected read of static float value";

        return Float.intBitsToFloat((int) indexedPrimitiveLocals[slot]);
    }

    @Override
    public void setFloatStatic(int slot, float value) {
        assert (indexedTags[slot] & STATIC_TAG) != 0 : UNEXPECTED_STATIC_WRITE;
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            indexedTags[slot] = STATIC_FLOAT_TAG;
        }

        indexedPrimitiveLocals[slot] = extend(Float.floatToRawIntBits(value));
    }

    @Override
    public double getDoubleStatic(int slot) {
        assert indexedTags[slot] == STATIC_DOUBLE_TAG : "Unexpected read of static double value";

        return Double.longBitsToDouble(indexedPrimitiveLocals[slot]);
    }

    @Override
    public void setDoubleStatic(int slot, double value) {
        assert (indexedTags[slot] & STATIC_TAG) != 0 : UNEXPECTED_STATIC_WRITE;
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            indexedTags[slot] = STATIC_DOUBLE_TAG;
        }

        indexedPrimitiveLocals[slot] = Double.doubleToRawLongBits(value);
    }

    @Override
    public void copyPrimitiveStatic(int srcSlot, int destSlot) {
        assert indexedTags[srcSlot] > STATIC_TAG && (indexedTags[destSlot] & STATIC_TAG) != 0 : "Unexpected copy of static primitive value ";
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            indexedTags[destSlot] = indexedTags[srcSlot];
        }

        indexedPrimitiveLocals[destSlot] = indexedPrimitiveLocals[srcSlot];
    }

    @Override
    public void copyObjectStatic(int srcSlot, int destSlot) {
        assert (indexedTags[srcSlot] == STATIC_OBJECT_TAG || indexedTags[srcSlot] == STATIC_ILLEGAL_TAG) && (indexedTags[destSlot] & STATIC_TAG) != 0 : "Unexpected copy of static object value";
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            indexedTags[destSlot] = indexedTags[srcSlot];
        }

        indexedLocals[destSlot] = indexedLocals[srcSlot];
    }

    @Override
    public void copyStatic(int srcSlot, int destSlot) {
        assert indexedTags[srcSlot] >= STATIC_TAG && indexedTags[destSlot] >= STATIC_TAG : "Unexpected copy of static value";
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            indexedTags[destSlot] = indexedTags[srcSlot];
        }

        indexedLocals[destSlot] = indexedLocals[srcSlot];
        indexedPrimitiveLocals[destSlot] = indexedPrimitiveLocals[srcSlot];
    }

    @Override
    public void swapPrimitiveStatic(int first, int second) {
        assert indexedTags[first] > STATIC_TAG && indexedTags[second] > STATIC_TAG : "Unexpected swap of static primitive value";
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            final byte swapTag = indexedTags[first];
            indexedTags[first] = indexedTags[second];
            indexedTags[second] = swapTag;
        }

        final long firstValue = indexedPrimitiveLocals[first];
        final long secondValue = indexedPrimitiveLocals[second];

        indexedPrimitiveLocals[first] = secondValue;
        indexedPrimitiveLocals[second] = firstValue;
    }

    @Override
    public void swapObjectStatic(int first, int second) {
        assert (indexedTags[first] == STATIC_OBJECT_TAG || indexedTags[first] == STATIC_ILLEGAL_TAG) &&
                        (indexedTags[second] == STATIC_OBJECT_TAG || indexedTags[second] == STATIC_ILLEGAL_TAG) : "Unexpected swap of static object value";
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            final byte swapTag = indexedTags[first];
            indexedTags[first] = indexedTags[second];
            indexedTags[second] = swapTag;
        }

        final Object firstValue = indexedLocals[first];
        final Object secondValue = indexedLocals[second];

        indexedLocals[first] = secondValue;
        indexedLocals[second] = firstValue;
    }

    @Override
    public void swapStatic(int first, int second) {
        assert indexedTags[first] >= STATIC_TAG && indexedTags[second] >= STATIC_TAG : "Unexpected swap of static value";
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            final byte swapTag = indexedTags[first];
            indexedTags[first] = indexedTags[second];
            indexedTags[second] = swapTag;
        }

        final Object firstValue = indexedLocals[first];
        final Object secondValue = indexedLocals[second];
        final long firstPrimitiveValue = indexedPrimitiveLocals[first];
        final long secondPrimitiveValue = indexedPrimitiveLocals[second];

        indexedLocals[first] = secondValue;
        indexedLocals[second] = firstValue;
        indexedPrimitiveLocals[first] = secondPrimitiveValue;
        indexedPrimitiveLocals[second] = firstPrimitiveValue;
    }

    @Override
    public void clearPrimitiveStatic(int slot) {
        assert indexedTags[slot] > STATIC_TAG : "Unexpected clear of static primitive value";
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            indexedTags[slot] = STATIC_ILLEGAL_TAG;
        }

        if (CompilerDirectives.inCompiledCode()) {
            // Avoids keeping track of cleared frame slots in FrameStates
            indexedPrimitiveLocals[slot] = 0L;
        }
    }

    @Override
    public void clearObjectStatic(int slot) {
        assert indexedTags[slot] == STATIC_OBJECT_TAG || indexedTags[slot] == STATIC_ILLEGAL_TAG : "Unexpected clear of static object value";
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            indexedTags[slot] = STATIC_ILLEGAL_TAG;
        }

        indexedLocals[slot] = null;
    }

    @Override
    public void clearStatic(int slot) {
        assert indexedTags[slot] >= STATIC_TAG : "Unexpected clear of static value";
        // We use this check instead of the assert keyword to update the tags in PE'd code.
        if (ASSERTIONS_ENABLED) {
            indexedTags[slot] = STATIC_ILLEGAL_TAG;
        }

        if (CompilerDirectives.inCompiledCode()) {
            // Avoid keeping track of cleared frame slots in FrameStates
            indexedPrimitiveLocals[slot] = 0L;
        }
        indexedLocals[slot] = null;
    }

    /**
     * This method is used to transfer a static slot from a source frame to a target frame before or
     * after OSR. This method must exclusively be used inside
     * {@code BytecodeOSRMetadata#transferIndexedFrameSlot}. It is necessary to support static
     * assertions.
     *
     * @param target The target frame (The frame descriptor of this and the target frame must match)
     * @param slot The slot that should be transferred
     */
    void transferOSRStaticSlot(FrameWithoutBoxing target, int slot) {
        if (ASSERTIONS_ENABLED) {
            final byte tag = indexedTags[slot];
            indexedTags[slot] = STATIC_OBJECT_TAG;
            target.setObjectStatic(slot, getObjectStatic(slot));
            indexedTags[slot] = STATIC_LONG_TAG;
            target.setLongStatic(slot, getLongStatic(slot));
            indexedTags[slot] = tag;
            target.setStaticSlotTag(slot, tag);
        } else {
            target.setObjectStatic(slot, getObjectStatic(slot));
            target.setLongStatic(slot, getLongStatic(slot));
        }
    }

    private void setStaticSlotTag(int slot, byte tag) {
        indexedTags[slot] = tag;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy