001/*
002 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package jdk.internal.jvmci.common;
024
025import java.util.*;
026
027/**
028 * Indicates a condition in JVMCI related code that should never occur during normal operation.
029 */
030public class JVMCIError extends Error {
031
032    private static final long serialVersionUID = 531632331813456233L;
033    private final ArrayList<String> context = new ArrayList<>();
034
035    public static RuntimeException unimplemented() {
036        throw new JVMCIError("unimplemented");
037    }
038
039    public static RuntimeException unimplemented(String msg) {
040        throw new JVMCIError("unimplemented: %s", msg);
041    }
042
043    public static RuntimeException shouldNotReachHere() {
044        throw new JVMCIError("should not reach here");
045    }
046
047    public static RuntimeException shouldNotReachHere(String msg) {
048        throw new JVMCIError("should not reach here: %s", msg);
049    }
050
051    public static RuntimeException shouldNotReachHere(Throwable cause) {
052        throw new JVMCIError(cause);
053    }
054
055    /**
056     * Checks a given condition and throws a {@link JVMCIError} if it is false. Guarantees are
057     * stronger than assertions in that they are always checked. Error messages for guarantee
058     * violations should clearly indicate the nature of the problem as well as a suggested solution
059     * if possible.
060     *
061     * @param condition the condition to check
062     * @param msg the message that will be associated with the error, in
063     *            {@link String#format(String, Object...)} syntax
064     * @param args arguments to the format string
065     */
066    public static void guarantee(boolean condition, String msg, Object... args) {
067        if (!condition) {
068            throw new JVMCIError("failed guarantee: " + msg, args);
069        }
070    }
071
072    /**
073     * This constructor creates a {@link JVMCIError} with a message assembled via
074     * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to
075     * always generate the same output.
076     *
077     * @param msg the message that will be associated with the error, in String.format syntax
078     * @param args parameters to String.format - parameters that implement {@link Iterable} will be
079     *            expanded into a [x, x, ...] representation.
080     */
081    public JVMCIError(String msg, Object... args) {
082        super(format(msg, args));
083    }
084
085    /**
086     * This constructor creates a {@link JVMCIError} for a given causing Throwable instance.
087     *
088     * @param cause the original exception that contains additional information on this error
089     */
090    public JVMCIError(Throwable cause) {
091        super(cause);
092    }
093
094    /**
095     * This constructor creates a {@link JVMCIError} and adds all the
096     * {@linkplain #addContext(String) context} of another {@link JVMCIError}.
097     *
098     * @param e the original {@link JVMCIError}
099     */
100    public JVMCIError(JVMCIError e) {
101        super(e);
102        context.addAll(e.context);
103    }
104
105    @Override
106    public String toString() {
107        StringBuilder str = new StringBuilder();
108        str.append(super.toString());
109        for (String s : context) {
110            str.append("\n\tat ").append(s);
111        }
112        return str.toString();
113    }
114
115    private static String format(String msg, Object... args) {
116        if (args != null) {
117            // expand Iterable parameters into a list representation
118            for (int i = 0; i < args.length; i++) {
119                if (args[i] instanceof Iterable<?>) {
120                    ArrayList<Object> list = new ArrayList<>();
121                    for (Object o : (Iterable<?>) args[i]) {
122                        list.add(o);
123                    }
124                    args[i] = list.toString();
125                }
126            }
127        }
128        return String.format(Locale.ENGLISH, msg, args);
129    }
130
131    public JVMCIError addContext(String newContext) {
132        this.context.add(newContext);
133        return this;
134    }
135
136    public JVMCIError addContext(String name, Object obj) {
137        return addContext(format("%s: %s", name, obj));
138    }
139}