view graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java @ 4441:4e3aaf14cbc6

fixed graal to hotspot
author Christian Haeubl <christian.haeubl@oracle.com>
date Mon, 23 Jan 2012 13:22:43 -0800
parents 271220b49abc
children 7d9469b37f1f
line wrap: on
line source

/*
 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.oracle.max.graal.hotspot.ri;

import sun.misc.*;

import com.oracle.max.cri.ri.*;
import com.oracle.max.graal.hotspot.*;
import com.oracle.max.graal.hotspot.Compiler;


public final class HotSpotMethodData extends CompilerObject {

    /**
     *
     */
    private static final long serialVersionUID = -8873133496591225071L;
    // TODO (ch) use same logic as in NodeClass?
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final HotSpotMethodDataAccessor NO_DATA_ACCESSOR = new NoDataAccessor();
    private static final HotSpotMethodDataAccessor[] PROFILE_DATA_ACCESSORS = {
        null, new BitData(), new CounterData(), new JumpData(),
        new TypeCheckData(), new VirtualCallData(), new RetData(),
        new BranchData(), new MultiBranchData(), new ArgInfoData()
    };

    private Object javaMirror;
    private int normalDataSize;
    private int extraDataSize;

    // TODO (ch) how are we going to handle methodData->is_mature()

    private HotSpotMethodData(Compiler compiler) {
        super(compiler);
        throw new IllegalStateException("this constructor is never actually called, because the objects are allocated from within the VM");
    }

    public boolean hasNormalData() {
        return normalDataSize > 0;
    }

    public boolean hasExtraData() {
        return extraDataSize > 0;
    }

    public boolean isWithinData(int position) {
        return position >= 0 && position < normalDataSize + extraDataSize;
    }

    public HotSpotMethodDataAccessor getNormalData(int position) {
        if (position >= normalDataSize) {
            return null;
        }

        HotSpotMethodDataAccessor result = getData(position, 0);
        assert result != null : "NO_DATA tag is not allowed";
        return result;
    }

    public HotSpotMethodDataAccessor getExtraData(int position) {
        if (position >= extraDataSize) {
            return null;
        }
        return getData(position, normalDataSize);
    }

    public static HotSpotMethodDataAccessor getNoDataAccessor() {
        return NO_DATA_ACCESSOR;
    }

    private HotSpotMethodDataAccessor getData(int position, int displacement) {
        assert position >= 0 : "out of bounds";
        int tag = AbstractMethodDataAccessor.readTag(this, displacement + position);
        assert tag >= 0 && tag < PROFILE_DATA_ACCESSORS.length : "illegal tag";
        return PROFILE_DATA_ACCESSORS[tag];
    }

    private int readUnsignedByte(int position, int offsetInCells) {
        long offsetInBytes = computeOffsetInBytes(position, offsetInCells);
        return unsafe.getByte(javaMirror, offsetInBytes) & 0xFF;
    }

    private int readUnsignedShort(int position, int offsetInCells) {
        long offsetInBytes = computeOffsetInBytes(position, offsetInCells);
        return unsafe.getShort(javaMirror, offsetInBytes) & 0xFFFF;
    }

    private long readUnsignedInt(int position, int offsetInCells) {
        long offsetInBytes = computeOffsetInBytes(position, offsetInCells);
        return unsafe.getInt(javaMirror, offsetInBytes) & 0xFFFFFFFFL;
    }

    private int readUnsignedIntAsSignedInt(int position, int offsetInCells) {
        long value = readUnsignedInt(position, offsetInCells);
        return truncateLongToInt(value);
    }

    private int readInt(int position, int offsetInCells) {
        long offsetInBytes = computeOffsetInBytes(position, offsetInCells);
        return unsafe.getInt(javaMirror, offsetInBytes);
    }

    private Object readObject(int position, int offsetInCells) {
        long offsetInBytes = computeOffsetInBytes(position, offsetInCells);
        return unsafe.getObject(javaMirror, offsetInBytes);
    }

    private static int truncateLongToInt(long value) {
        return value > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) value;
    }

    private static int computeOffsetInBytes(int position, int offsetInCells) {
        HotSpotVMConfig config = getHotSpotVMConfig();
        return config.methodDataOopDataOffset + position + offsetInCells * config.dataLayoutCellSize;
    }

    private static HotSpotVMConfig getHotSpotVMConfig() {
        return CompilerImpl.getInstance().getConfig();
    }

    private abstract static class AbstractMethodDataAccessor implements HotSpotMethodDataAccessor {
        private static final int IMPLICIT_EXCEPTIONS_MASK = 0x0E;

        private final int tag;
        private final int staticCellCount;

        protected AbstractMethodDataAccessor(int tag, int staticCellCount) {
            this.tag = tag;
            this.staticCellCount = staticCellCount;
        }

        @Override
        public int getTag() {
            return tag;
        }

        public static int readTag(HotSpotMethodData data, int position) {
            HotSpotVMConfig config = getHotSpotVMConfig();
            return data.readUnsignedByte(position, config.dataLayoutTagOffset);
        }

        @Override
        public int getBCI(HotSpotMethodData data, int position) {
            HotSpotVMConfig config = getHotSpotVMConfig();
            return data.readUnsignedShort(position, config.dataLayoutBCIOffset);
        }

        @Override
        public int getSize(HotSpotMethodData data, int position) {
            HotSpotVMConfig config = getHotSpotVMConfig();
            return config.dataLayoutHeaderSize + (staticCellCount + getDynamicCellCount(data, position)) * config.dataLayoutCellSize;
        }

        @Override
        public boolean getImplicitExceptionSeen(HotSpotMethodData data, int position) {
            // TODO (ch) might return true too often because flags are also used for deoptimization reasons
            return (getFlags(data, position) & IMPLICIT_EXCEPTIONS_MASK) != 0;
        }

        @Override
        public RiTypeProfile getTypeProfile(HotSpotMethodData data, int position) {
            return null;
        }

        @Override
        public double getBranchTakenProbability(HotSpotMethodData data, int position) {
            return -1;
        }

        @Override
        public double[] getSwitchProbabilities(HotSpotMethodData data, int position) {
            return null;
        }

        @Override
        public int getExecutionCount(HotSpotMethodData data, int position) {
            return -1;
        }

        protected int getFlags(HotSpotMethodData data, int position) {
            HotSpotVMConfig config = getHotSpotVMConfig();
            return data.readUnsignedByte(position, config.dataLayoutFlagsOffset);
        }

        protected int getDynamicCellCount(@SuppressWarnings("unused") HotSpotMethodData data, @SuppressWarnings("unused") int position) {
            return 0;
        }
    }

    private static class NoDataAccessor extends AbstractMethodDataAccessor {
        private static final int NO_DATA_TAG = 0;
        private static final int NO_DATA_SIZE = 0;

        protected NoDataAccessor() {
            super(NO_DATA_TAG, NO_DATA_SIZE);
        }

        @Override
        public int getBCI(HotSpotMethodData data, int position) {
            return -1;
        }


        @Override
        public boolean getImplicitExceptionSeen(HotSpotMethodData data, int position) {
            return false;
        }
    }

    private static class BitData extends AbstractMethodDataAccessor {
        private static final int BIT_DATA_TAG = 1;
        private static final int BIT_DATA_CELLS = 0;
        private static final int BIT_DATA_NULL_SEEN_FLAG = 0x01;

        private BitData() {
            super(BIT_DATA_TAG, BIT_DATA_CELLS);
        }

        protected BitData(int tag, int staticCellCount) {
            super(tag, staticCellCount);
        }

        public boolean getNullSeen(HotSpotMethodData data, int position) {
            return (getFlags(data, position) & BIT_DATA_NULL_SEEN_FLAG) != 0;
        }
    }

    private static class CounterData extends BitData {
        private static final int COUNTER_DATA_TAG = 2;
        private static final int COUNTER_DATA_CELLS = 1;
        private static final int COUNTER_DATA_COUNT_OFFSET = 0;

        public CounterData() {
            super(COUNTER_DATA_TAG, COUNTER_DATA_CELLS);
        }

        protected CounterData(int tag, int staticCellCount) {
            super(tag, staticCellCount);
        }

        @Override
        public int getExecutionCount(HotSpotMethodData data, int position) {
            return getCounterValue(data, position);
        }

        protected int getCounterValue(HotSpotMethodData data, int position) {
            return data.readUnsignedIntAsSignedInt(position, COUNTER_DATA_COUNT_OFFSET);
        }
    }

    private static class JumpData extends AbstractMethodDataAccessor {
        private static final int JUMP_DATA_TAG = 3;
        private static final int JUMP_DATA_CELLS = 2;
        protected static final int TAKEN_COUNT_OFFSET = 0;
        protected static final int TAKEN_DISPLACEMENT_OFFSET = 1;

        public JumpData() {
            super(JUMP_DATA_TAG, JUMP_DATA_CELLS);
        }

        protected JumpData(int tag, int staticCellCount) {
            super(tag, staticCellCount);
        }

        @Override
        public double getBranchTakenProbability(HotSpotMethodData data, int position) {
            return 1;
        }

        @Override
        public int getExecutionCount(HotSpotMethodData data, int position) {
            return data.readUnsignedIntAsSignedInt(position, TAKEN_COUNT_OFFSET);
        }

        public int getDisplacement(HotSpotMethodData data, int position) {
            return data.readInt(position, TAKEN_DISPLACEMENT_OFFSET);
        }
    }

    private static class AbstractTypeData extends CounterData {
        private static final int RECEIVER_TYPE_DATA_ROW_CELL_COUNT = 2;
        private static final int RECEIVER_TYPE_DATA_FIRST_RECEIVER_OFFSET = 1;
        private static final int RECEIVER_TYPE_DATA_FIRST_COUNT_OFFSET = 2;

        protected AbstractTypeData(int tag, int staticCellCount) {
            super(tag, staticCellCount);
        }

        @Override
        public RiTypeProfile getTypeProfile(HotSpotMethodData data, int position) {
            HotSpotVMConfig config = getHotSpotVMConfig();
            int typeProfileWidth = config.typeProfileWidth;

            RiResolvedType[] sparseTypes = new RiResolvedType[typeProfileWidth];
            double[] counts = new double[typeProfileWidth];
            long totalCount = 0;
            int entries = 0;

            for (int i = 0; i < typeProfileWidth; i++) {
                Object receiverKlassOop = data.readObject(position, getReceiverOffset(i));
                if (receiverKlassOop != null) {
                    Object graalMirror = unsafe.getObject(receiverKlassOop, (long) config.klassOopGraalMirrorOffset);
                    if (graalMirror == null) {
                        Class<?> javaClass = (Class<?>) unsafe.getObject(receiverKlassOop, (long) config.classMirrorOffset);
                        graalMirror = CompilerImpl.getInstance().getVMEntries().getType(javaClass);
                        assert graalMirror != null : "must not return null";
                    }

                    long count = data.readUnsignedInt(position, getCountOffset(i));
                    if (count > 0) {
                        totalCount += count;
                        counts[entries] = count;
                        entries++;
                    }

                    sparseTypes[i] = (RiResolvedType) graalMirror;
                }
            }

            RiResolvedType[] types;
            double[] probabilities;

            if (entries <= 0) {
                return null;
            } else if (entries < typeProfileWidth) {
                RiResolvedType[] compactedTypes = new RiResolvedType[entries];
                System.arraycopy(sparseTypes, 0, compactedTypes, 0, entries);
                types = compactedTypes;
                probabilities = new double[entries];
            } else {
                types = sparseTypes;
                probabilities = counts;
            }

            for (int i = 0; i < typeProfileWidth; i++) {
                probabilities[i] = counts[i] / totalCount;
            }
            return new RiTypeProfile(types, probabilities);
        }

        @Override
        protected int getDynamicCellCount(HotSpotMethodData data, int position) {
            HotSpotVMConfig config = getHotSpotVMConfig();
            return config.typeProfileWidth * RECEIVER_TYPE_DATA_ROW_CELL_COUNT;
        }

        private static int getReceiverOffset(int row) {
            return RECEIVER_TYPE_DATA_FIRST_RECEIVER_OFFSET + row * RECEIVER_TYPE_DATA_ROW_CELL_COUNT;
        }

        protected static int getCountOffset(int row) {
            return RECEIVER_TYPE_DATA_FIRST_COUNT_OFFSET + row * RECEIVER_TYPE_DATA_ROW_CELL_COUNT;
        }
    }

    private static class TypeCheckData extends AbstractTypeData {
        private static final int RECEIVER_TYPE_DATA_TAG = 4;
        private static final int RECEIVER_TYPE_DATA_CELLS = 1;

        public TypeCheckData() {
            super(RECEIVER_TYPE_DATA_TAG, RECEIVER_TYPE_DATA_CELLS);
        }

        @Override
        public int getExecutionCount(HotSpotMethodData data, int position) {
            return -1;
        }
    }

    private static class VirtualCallData extends AbstractTypeData {
        private static final int VIRTUAL_CALL_DATA_TAG = 5;
        private static final int VIRTUAL_CALL_DATA_CELLS = 1;

        public VirtualCallData() {
            super(VIRTUAL_CALL_DATA_TAG, VIRTUAL_CALL_DATA_CELLS);
        }

        @Override
        public int getExecutionCount(HotSpotMethodData data, int position) {
            HotSpotVMConfig config = getHotSpotVMConfig();
            int typeProfileWidth = config.typeProfileWidth;

            long total = 0;
            for (int i = 0; i < typeProfileWidth; i++) {
                total += data.readUnsignedInt(position, getCountOffset(i));
            }

            total += getCounterValue(data, position);
            return truncateLongToInt(total);
        }
    }

    private static class RetData extends CounterData {
        private static final int RET_DATA_TAG = 6;
        private static final int RET_DATA_CELLS = 1;
        private static final int RET_DATA_ROW_CELL_COUNT = 3;

        public RetData() {
            super(RET_DATA_TAG, RET_DATA_CELLS);
        }

        @Override
        protected int getDynamicCellCount(HotSpotMethodData data, int position) {
            HotSpotVMConfig config = getHotSpotVMConfig();
            return config.bciProfileWidth * RET_DATA_ROW_CELL_COUNT;
        }
    }

    private static class BranchData extends JumpData {
        private static final int BRANCH_DATA_TAG = 7;
        private static final int BRANCH_DATA_CELLS = 3;
        private static final int NOT_TAKEN_COUNT_OFFSET = 2;

        public BranchData() {
            super(BRANCH_DATA_TAG, BRANCH_DATA_CELLS);
        }

        @Override
        public double getBranchTakenProbability(HotSpotMethodData data, int position) {
            long takenCount = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET);
            long notTakenCount = data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET);
            long total = takenCount + notTakenCount;

            if (total < 40) {
                return -1;
            } else {
                return takenCount / (double) total;
            }
        }
    }

    private static class ArrayData extends AbstractMethodDataAccessor {
        private static final int ARRAY_DATA_LENGTH_OFFSET = 0;
        private static final int ARRAY_DATA_START_OFFSET = 1;

        public ArrayData(int tag, int staticCellCount) {
            super(tag, staticCellCount);
        }

        @Override
        protected int getDynamicCellCount(HotSpotMethodData data, int position) {
            return getLength(data, position);
        }

        protected static int getLength(HotSpotMethodData data, int position) {
            return data.readInt(position, ARRAY_DATA_LENGTH_OFFSET);
        }

        protected static int getElementOffset(int index) {
            return ARRAY_DATA_START_OFFSET + index;
        }
    }

    private static class MultiBranchData extends ArrayData {
        private static final int MULTI_BRANCH_DATA_TAG = 8;
        private static final int MULTI_BRANCH_DATA_CELLS = 1;
        private static final int MULTI_BRANCH_DATA_COUNT_OFFSET = 0;
        private static final int MULTI_BRANCH_DATA_DISPLACEMENT_OFFSET = 1;

        public MultiBranchData() {
            super(MULTI_BRANCH_DATA_TAG, MULTI_BRANCH_DATA_CELLS);
        }

        @Override
        public double[] getSwitchProbabilities(HotSpotMethodData data, int position) {
            int length = getLength(data, position);
            assert length > 0 : "switch must have at least the default case";

            long total = 0;
            double[] result = new double[length];

            for (int i = 0; i < length; i++) {
                int offset = getCountOffset(i);
                long count = data.readUnsignedInt(position, offset);
                total += count;
                result[i] = count;
            }

            if (total < 10 * (length + 2)) {
                return null;
            } else {
                for (int i = 0; i < length; i++) {
                    result[i] = result[i] / total;
                }

                // default case is expected as last entry
                if (length >= 2) {
                    double defaultCase = result[0];
                    result[0] = result[length - 1];
                    result[length - 1] = defaultCase;
                }
                return result;
            }
        }

        @Override
        public int getExecutionCount(HotSpotMethodData data, int position) {
            int length = getLength(data, position);
            long total = 0;

            for (int i = 0; i < length; i++) {
                int offset = getCountOffset(i);
                total += data.readUnsignedInt(position, offset);
            }

            return truncateLongToInt(total);
        }

        private static int getCountOffset(int index) {
            return getElementOffset(index + MULTI_BRANCH_DATA_COUNT_OFFSET);
        }
    }

    private static class ArgInfoData extends ArrayData {
        private static final int ARG_INFO_DATA_TAG = 9;
        private static final int ARG_INFO_DATA_CELLS = 1;

        public ArgInfoData() {
            super(ARG_INFO_DATA_TAG, ARG_INFO_DATA_CELLS);
        }
    }
}