view graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java @ 8952:ef450d176a20

fixed bug in transformation of a type check profile into type check hints
author Doug Simon <doug.simon@oracle.com>
date Tue, 09 Apr 2013 17:38:33 +0200
parents 06e08471949e
children 38d7b55f87b0
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.graal.api.code;

import static com.oracle.graal.api.meta.MetaUtil.*;
import static java.lang.reflect.Modifier.*;

import java.util.*;

import com.oracle.graal.api.meta.*;
import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;

/**
 * Utility for deriving hint types for a type check instruction (e.g. checkcast or instanceof) based
 * on the target type of the check and any profiling information available for the instruction.
 */
public class TypeCheckHints {

    /**
     * A receiver type profiled in a type check instruction.
     */
    public static class Hint {

        /**
         * A type seen while profiling a type check instruction.
         */
        public final ResolvedJavaType type;

        /**
         * Specifies if {@link #type} was a sub-type of the checked type.
         */
        public final boolean positive;

        Hint(ResolvedJavaType type, boolean positive) {
            this.type = type;
            this.positive = positive;
        }
    }

    private static final Hint[] NO_HINTS = {};

    /**
     * If true, then {@link #hints} contains the only possible type that could pass the type check
     * because the target of the type check is a final class or has been speculated to be a final
     * class.
     */
    public final boolean exact;

    /**
     * The most likely types that the type check instruction will see.
     */
    public final Hint[] hints;

    /**
     * Derives hint information for use when generating the code for a type check instruction.
     * 
     * @param targetType the target type of the type check
     * @param profile the profiling information available for the instruction (if any)
     * @param assumptions the object in which speculations are recorded. This is null if
     *            speculations are not supported.
     * @param minHintHitProbability if the probability that the type check will hit one of the
     *            profiled types (up to {@code maxHints}) is below this value, then {@link #hints}
     *            will be null
     * @param maxHints the maximum length of {@link #hints}
     */
    public TypeCheckHints(ResolvedJavaType targetType, JavaTypeProfile profile, Assumptions assumptions, double minHintHitProbability, int maxHints) {
        if (targetType != null && !canHaveSubtype(targetType)) {
            hints = new Hint[]{new Hint(targetType, true)};
            exact = true;
        } else {
            ResolvedJavaType uniqueSubtype = targetType == null ? null : targetType.findUniqueConcreteSubtype();
            if (uniqueSubtype != null) {
                hints = new Hint[]{new Hint(uniqueSubtype, true)};
                if (assumptions.useOptimisticAssumptions()) {
                    assumptions.recordConcreteSubtype(targetType, uniqueSubtype);
                    exact = true;
                } else {
                    exact = false;
                }
            } else {
                exact = false;
                Hint[] hintsBuf = NO_HINTS;
                JavaTypeProfile typeProfile = profile;
                if (typeProfile != null) {
                    double notRecordedTypes = typeProfile.getNotRecordedProbability();
                    ProfiledType[] ptypes = typeProfile.getTypes();
                    if (notRecordedTypes < (1D - minHintHitProbability) && ptypes != null && ptypes.length > 0) {
                        hintsBuf = new Hint[ptypes.length];
                        int hintCount = 0;
                        double totalHintProbability = 0.0d;
                        for (ProfiledType ptype : ptypes) {
                            if (targetType != null) {
                                ResolvedJavaType hintType = ptype.getType();
                                hintsBuf[hintCount++] = new Hint(hintType, targetType.isAssignableFrom(hintType));
                                totalHintProbability += ptype.getProbability();
                            }
                        }
                        if (totalHintProbability >= minHintHitProbability) {
                            if (hintsBuf.length != hintCount || hintCount > maxHints) {
                                hintsBuf = Arrays.copyOf(hintsBuf, Math.min(maxHints, hintCount));
                            }
                        } else {
                            hintsBuf = NO_HINTS;
                        }

                    }
                }
                this.hints = hintsBuf;
            }
        }
    }

    /**
     * Determines if a given type can have subtypes other than itself. This analysis is purely
     * static; no assumptions are made.
     * 
     * @return true if {@code type} can have subtypes
     */
    public static boolean canHaveSubtype(ResolvedJavaType type) {
        return !isFinal(getElementalType(type).getModifiers());
    }
}