001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.opt;
014
015import java.io.PrintWriter;
016import java.io.StringWriter;
017
018import org.jikesrvm.VM;
019import org.jikesrvm.classloader.TypeReference;
020
021/**
022 * Use this exception if we encounter a runtime error in the dynamic
023 * optimizing compiler.  The caller can recover by calling the
024 * non-optimizing compiler instead (or by reverting to the previous
025 * version of compiled code).
026 */
027public class OptimizingCompilerException extends RuntimeException {
028  /** Support for exception serialization */
029  static final long serialVersionUID = -868535710873341956L;
030
031  /**
032   * Capture illegal upcasts from magic types to java.lang.Object
033   */
034  public static final class IllegalUpcast extends RuntimeException {
035    /** Support for exception serialization */
036    static final long serialVersionUID = -847866659938089530L;
037    /** Unboxed type that was attempted to convert to an Object */
038    final transient TypeReference magicType;
039
040    public IllegalUpcast(TypeReference type) {
041      super("Illegal upcast from " + type + " to java.lang.Object");
042      magicType = type;
043    }
044  }
045
046  /**
047   * When running in the RVM, typically optimizing compiler
048   * exceptions are caught, optionally a message is printed, and we
049   * fallback to using the baseline compiler.  However, this
050   * may not be desirable when running regression testing because
051   * an optimizing compiler exception may be a symptom of a serious failure.
052   * Thus, the code throwing the exception can use an optional boolean value
053   * to indicate if the exception is "normal" or if it should be treated
054   * as a fatal failure for the purpose of regression testing.
055   */
056  public boolean isFatal = true;
057
058  public OptimizingCompilerException() { }
059
060  /**
061   * @param   b is the exception fatal?
062   */
063  public OptimizingCompilerException(boolean b) {
064    isFatal = b;
065  }
066
067  /**
068   * @param  err message describing reason for exception
069   */
070  public OptimizingCompilerException(String err) {
071    super(err);
072  }
073
074  /**
075   * @param   err message describing reason for exception
076   * @param   b is the exception fatal?
077   */
078  public OptimizingCompilerException(String err, boolean b) {
079    super(err);
080    isFatal = b;
081  }
082
083  /**
084   * @param   module opt compiler module in which exception was raised
085   * @param   err message describing reason for exception
086   */
087  public OptimizingCompilerException(String module, String err) {
088    super("ERROR produced in module:" + module + "\n    " + err + "\n");
089  }
090
091  /**
092   * @param   module opt compiler module in which exception was raised
093   * @param   err1 message describing reason for exception
094   * @param   err2 message describing reason for exception
095   */
096  public OptimizingCompilerException(String module, String err1, String err2) {
097    super("ERROR produced in module:" + module + "\n    " + err1 + " " + err2 + "\n");
098  }
099
100  /**
101   * @param   module opt compiler module in which exception was raised
102   * @param   err1 message describing reason for exception
103   * @param   obj  object to print describing reason for exception
104   */
105  public OptimizingCompilerException(String module, String err1, Object obj) {
106    this(module, err1, obj.toString());
107  }
108
109  /**
110   * @param   module opt compiler module in which exception was raised
111   * @param   err1 message describing reason for exception
112   * @param   val  integer to print describing reason for exception
113   */
114  public OptimizingCompilerException(String module, String err1, int val) {
115    this(module, err1, Integer.toString(val));
116  }
117
118  /**
119   * @param   module opt compiler module in which exception was raised
120   * @param   err1 message describing reason for exception
121   * @param   err2 message describing reason for exception
122   * @param   err3 message describing reason for exception
123   */
124  public OptimizingCompilerException(String module, String err1, String err2, String err3) {
125    super("ERROR produced in module:" + module + "\n    " + err1 + " " + err2 + "\n" + err3 + "\n");
126  }
127
128  /**
129   * @param   module opt compiler module in which exception was raised
130   * @param   err1 message describing reason for exception
131   * @param   err2 message describing reason for exception
132   * @param   obj  object to print describing reason for exception
133   */
134  public OptimizingCompilerException(String module, String err1, String err2, Object obj) {
135    this(module, err1, err2, obj.toString());
136  }
137
138  /**
139   * @param   module opt compiler module in which exception was raised
140   * @param   err1 message describing reason for exception
141   * @param   err2 message describing reason for exception
142   * @param   val  integer to print describing reason for exception
143   */
144  OptimizingCompilerException(String module, String err1, String err2, int val) {
145    this(module, err1, err2, Integer.toString(val));
146  }
147
148  /**
149   * Use the UNREACHABLE methods to mark code that should never execute
150   * e.g., unexpected cases of switch statements and nested if/then/else
151   * @throws OptimizingCompilerException because the code is supposed
152   *  to be unreachable
153   */
154  public static void UNREACHABLE() throws OptimizingCompilerException {
155    throw new OptimizingCompilerException("Executed UNREACHABLE code");
156  }
157
158  /**
159   * Use the UNREACHABLE methods to mark code that should never execute
160   * e.g., unexpected cases of switch statements and nested if/then/else
161   * @param module module in which exception occurred
162   * @throws OptimizingCompilerException because the code is supposed
163   *  to be unreachable
164   */
165  public static void UNREACHABLE(String module) throws OptimizingCompilerException {
166    throw new OptimizingCompilerException(module, "Executed UNREACHABLE code");
167  }
168
169  /**
170   * Use the UNREACHABLE methods to mark code that should never execute
171   * e.g., unexpected cases of switch statements and nested if/then/else
172   * @param   module opt compiler module in which exception was raised
173   * @param   err1 message describing reason for exception
174   * @throws OptimizingCompilerException because the code is supposed
175   *  to be unreachable
176   */
177  public static void UNREACHABLE(String module, String err1) throws OptimizingCompilerException {
178    throw new OptimizingCompilerException(module, "Executed UNREACHABLE code", err1);
179  }
180
181  /**
182   * Use the UNREACHABLE methods to mark code that should never execute
183   * e.g., unexpected cases of switch statements and nested if/then/else
184   * @param   module opt compiler module in which exception was raised
185   * @param   err1 message describing reason for exception
186   * @param   err2 message describing reason for exception
187   * @throws OptimizingCompilerException because the code is supposed
188   *  to be unreachable
189   */
190  public static void UNREACHABLE(String module, String err1, String err2) throws OptimizingCompilerException {
191    throw new OptimizingCompilerException(module, "Executed UNREACHABLE code", err1, err2);
192  }
193
194  /**
195   * Incomplete function in IA32 port.
196   * @throws OptimizingCompilerException because the required functionality
197   *  is NYI
198   */
199  public static void TODO() throws OptimizingCompilerException {
200    throw new OptimizingCompilerException("Unsupported function in IA32 port");
201  }
202
203  /**
204   * Incomplete function in IA32 port.
205   * @param   module opt compiler module in which exception was raised
206   * @throws OptimizingCompilerException because the required functionality
207   *  is NYI
208   */
209  public static void TODO(String module) throws OptimizingCompilerException {
210    throw new OptimizingCompilerException(module, "Unsupported function in IA32 port");
211  }
212
213  /**
214   * Checks that the condition holds. Fails by throwing an {@link OptimizingCompilerException}
215   * if the condition doesn't hold and assertions are enabled.
216   * <p>
217   * Use this in preference to normal assertions if it's possible to recover from the
218   * error by switching to the baseline compiler
219   *
220   * @param b condition to check
221   */
222  public static void opt_assert(boolean b) {
223    if (!VM.VerifyAssertions) {
224      throw new Error("Assertion should have been guarded by VM.VerifyAssertions");
225    }
226    if (!b) {
227      throw new OptimizingCompilerException("Assertion failure");
228    }
229  }
230
231  /**
232   * Checks that the condition holds. Fails by throwing an {@link OptimizingCompilerException}
233   * if the condition doesn't hold and assertions are enabled.
234   * <p>
235   * Use this in preference to normal assertions if it's possible to recover from the
236   * error by switching to the baseline compiler
237   *
238   * @param b condition to check
239   * @param message the message to print
240   */
241  public static void opt_assert(boolean b, String message) {
242    if (!VM.VerifyAssertions) {
243      throw new Error("Assertion should have been guarded by VM.VerifyAssertions");
244    }
245    if (!b) {
246      throw new OptimizingCompilerException("Assertion failure - " + message);
247    }
248  }
249
250  /**
251   * Return a string that is the printout of level stackframes in the stacktrace.
252   * @param level the number of levels to print
253   * @return n-level dump of stacktrace
254   */
255  public String trace(int level) {
256    StringWriter sw = new StringWriter();
257    PrintWriter pw = new PrintWriter(sw);
258    printStackTrace(pw);
259    int count = 0, i = 0;
260    StringBuffer sb = sw.getBuffer();
261    for (; i < sb.length() && count < level + 1; i++) {
262      if (sb.charAt(i) == '\n') {
263        count++;
264      }
265    }
266    sb.setLength(i);
267    return sb.toString();
268  }
269}