1/*
2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23package org.graalvm.compiler.debug;
24
25import java.util.ArrayList;
26import java.util.Locale;
27
28/**
29 * Indicates a condition that should never occur during normal operation.
30 */
31public class GraalError extends Error {
32
33    private static final long serialVersionUID = 531632331813456233L;
34    private final ArrayList<String> context = new ArrayList<>();
35
36    public static RuntimeException unimplemented() {
37        throw new GraalError("unimplemented");
38    }
39
40    public static RuntimeException unimplemented(String msg) {
41        throw new GraalError("unimplemented: %s", msg);
42    }
43
44    public static RuntimeException shouldNotReachHere() {
45        throw new GraalError("should not reach here");
46    }
47
48    public static RuntimeException shouldNotReachHere(String msg) {
49        throw new GraalError("should not reach here: %s", msg);
50    }
51
52    public static RuntimeException shouldNotReachHere(Throwable cause) {
53        throw new GraalError(cause);
54    }
55
56    /**
57     * Checks a given condition and throws a {@link GraalError} if it is false. Guarantees are
58     * stronger than assertions in that they are always checked. Error messages for guarantee
59     * violations should clearly indicate the nature of the problem as well as a suggested solution
60     * if possible.
61     *
62     * @param condition the condition to check
63     * @param msg the message that will be associated with the error
64     */
65    public static void guarantee(boolean condition, String msg) {
66        if (!condition) {
67            throw new GraalError("failed guarantee: " + msg);
68        }
69    }
70
71    /**
72     * Checks a given condition and throws a {@link GraalError} if it is false. Guarantees are
73     * stronger than assertions in that they are always checked. Error messages for guarantee
74     * violations should clearly indicate the nature of the problem as well as a suggested solution
75     * if possible.
76     *
77     * @param condition the condition to check
78     * @param msg the message that will be associated with the error, in
79     *            {@link String#format(String, Object...)} syntax
80     * @param arg argument to the format string in {@code msg}
81     */
82    public static void guarantee(boolean condition, String msg, Object arg) {
83        if (!condition) {
84            throw new GraalError("failed guarantee: " + msg, arg);
85        }
86    }
87
88    /**
89     * Checks a given condition and throws a {@link GraalError} if it is false. Guarantees are
90     * stronger than assertions in that they are always checked. Error messages for guarantee
91     * violations should clearly indicate the nature of the problem as well as a suggested solution
92     * if possible.
93     *
94     * @param condition the condition to check
95     * @param msg the message that will be associated with the error, in
96     *            {@link String#format(String, Object...)} syntax
97     * @param arg1 argument to the format string in {@code msg}
98     * @param arg2 argument to the format string in {@code msg}
99     */
100    public static void guarantee(boolean condition, String msg, Object arg1, Object arg2) {
101        if (!condition) {
102            throw new GraalError("failed guarantee: " + msg, arg1, arg2);
103        }
104    }
105
106    /**
107     * Checks a given condition and throws a {@link GraalError} if it is false. Guarantees are
108     * stronger than assertions in that they are always checked. Error messages for guarantee
109     * violations should clearly indicate the nature of the problem as well as a suggested solution
110     * if possible.
111     *
112     * @param condition the condition to check
113     * @param msg the message that will be associated with the error, in
114     *            {@link String#format(String, Object...)} syntax
115     * @param arg1 argument to the format string in {@code msg}
116     * @param arg2 argument to the format string in {@code msg}
117     * @param arg3 argument to the format string in {@code msg}
118     */
119    public static void guarantee(boolean condition, String msg, Object arg1, Object arg2, Object arg3) {
120        if (!condition) {
121            throw new GraalError("failed guarantee: " + msg, arg1, arg2, arg3);
122        }
123    }
124
125    /**
126     * This override exists to catch cases when {@link #guarantee(boolean, String, Object)} is
127     * called with one argument bound to a varargs method parameter. It will bind to this method
128     * instead of the single arg variant and produce a deprecation warning instead of silently
129     * wrapping the Object[] inside of another Object[].
130     */
131    @Deprecated
132    public static void guarantee(boolean condition, String msg, Object... args) {
133        if (!condition) {
134            throw new GraalError("failed guarantee: " + msg, args);
135        }
136    }
137
138    /**
139     * This constructor creates a {@link GraalError} with a given message.
140     *
141     * @param msg the message that will be associated with the error
142     */
143    public GraalError(String msg) {
144        super(msg);
145    }
146
147    /**
148     * This constructor creates a {@link GraalError} with a message assembled via
149     * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to
150     * always generate the same output.
151     *
152     * @param msg the message that will be associated with the error, in String.format syntax
153     * @param args parameters to String.format - parameters that implement {@link Iterable} will be
154     *            expanded into a [x, x, ...] representation.
155     */
156    public GraalError(String msg, Object... args) {
157        super(format(msg, args));
158    }
159
160    /**
161     * This constructor creates a {@link GraalError} for a given causing Throwable instance.
162     *
163     * @param cause the original exception that contains additional information on this error
164     */
165    public GraalError(Throwable cause) {
166        super(cause);
167    }
168
169    /**
170     * This constructor creates a {@link GraalError} and adds all the
171     * {@linkplain #addContext(String) context} of another {@link GraalError}.
172     *
173     * @param e the original {@link GraalError}
174     */
175    public GraalError(GraalError e) {
176        super(e);
177        context.addAll(e.context);
178    }
179
180    @Override
181    public String toString() {
182        StringBuilder str = new StringBuilder();
183        str.append(super.toString());
184        for (String s : context) {
185            str.append("\n\tat ").append(s);
186        }
187        return str.toString();
188    }
189
190    private static String format(String msg, Object... args) {
191        if (args != null) {
192            // expand Iterable parameters into a list representation
193            for (int i = 0; i < args.length; i++) {
194                if (args[i] instanceof Iterable<?>) {
195                    ArrayList<Object> list = new ArrayList<>();
196                    for (Object o : (Iterable<?>) args[i]) {
197                        list.add(o);
198                    }
199                    args[i] = list.toString();
200                }
201            }
202        }
203        return String.format(Locale.ENGLISH, msg, args);
204    }
205
206    public GraalError addContext(String newContext) {
207        this.context.add(newContext);
208        return this;
209    }
210
211    public GraalError addContext(String name, Object obj) {
212        return addContext(format("%s: %s", name, obj));
213    }
214}
215