#summary How GWT handles exceptions in web mode.
Object derived from `java.lang.Throwable` are implemented in the same way as any other type derived from `java.lang.Object`. The normal Java try/catch semantics are implemented, including type-based dispatch in catch blocks. Furthermore, the runtime libraries will attempt to provide some degree of stack trace data via `Throwable.getStackTrace()`.
= Control flow =
The Java statement
{{{
try {
throw new FooException();
} catch (BarException t) {
// Do something
}
}}}
is implemented in the JavaScript as a typical try/catch block, except that a sequence of type checks are made in the catch block to simulate the normal JVM behavior. If the exception would be uncaught in the Java code, the exception object is simply re-thrown.
Exceptions thrown by the JS runtime or by external libraries are modeled with a specific `com.google.gwt.core.client.JavaScriptException` type, which serves as a type-wrapper around the original thrown value (which may be of any JavaScript type).
An example of the compiled code is below:
{{{
try {
// Object instantiation and JS throw statement
throw FooException$(new FooException());
}
catch ($e0) {
// If $e0 is not a Java-derived object, wrap it in a a JavaScriptException
$e0 = caught_0($e0);
// Type-check the wrapped object to simulate JVM dispatch
if (instanceOf($e0, 5)) {
// Do something
}
else // Rethrow uncaught exceptions (e.g. RuntimeException)
throw $e0;
}
}}}
= Stack traces =
The instance initializer of `java.lang.Throwable` calls `fillInStackTrace()` which in turn invokes `com.google.gwt.core.client.impl.StackTraceCreator`. The `StackTraceCreator` type has an inner class `Collector` that is sensitive to deferred-binding decisions. The Collector type implements two main functions: `collect()` which creates a stack trace based on the current state of execution and `infer(JavaScriptObject e)` which attempts to infer a stack trace from a previously-thrown object and is used by JavaScriptException.
Because the call to `fillinStackTrace()` will be inlined into each `Throwable` constructor function, the type of exception can always be inferred from the stack trace. This is especially useful when `Class` metadata has been removed from the compilation.
As presently implement, only `StackTraceElement.getMethodName()` returns useful data. The other methods in `StackTraceElement` return placeholder values.
== Strategies ==
`StrackTraceCreator.Collector` is sensitive to deferred-biding and various implementations provide the following strategies for gathering the list of methods.
=== Safari, IE ===
* `collect()` is implemented by crawling `arguments.callee.caller`. Because the `caller` property returns function objects and not activation records, data returned by this implementation is necessarily incomplete in the case of reentrant functions.
* `inferFrom()` is not implemented and returns a zero-length array.
=== Mozilla, Opera ===
* `collect()` raises an exception and passes it to `infer()`.
* `infer()` is implemented and uses the browser's `e.stack` or `e.message` property to read activation records to produce a reasonably complete stack trace.
= Emulated Stack Data =
The GWT compiler can optionally emit JavaScript code to maintain a meta-stack that emulates standard JS dispatch semantics. This meta-stack can be used to provide stack trace data on browsers that do not provide stack data for all exception types. This is implemented as an additional compiler pass that is conditionalized on the value of the `compiler.emulatedStack` deferred-binding property being set to `true`. Full documentation on the transforms performed is located in the javadoc for [http://code.google.com/p/google-web-toolkit/source/browse/trunk/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java JsStackEmulator], but the basic transformation is as follows:
* The execution stack is modeled as an array that contains references to the JavaScript functions being executed. There is a global variable that maintains the current stack depth and an optional co-array that provides current file and line number data.
* A stack frame is pushed on every function entrance. This involves incrementing the stack depth counter and assigning the current function into the meta-stack array. The stack depth for the function's invocation is saved in a local variable.
* Before every last statement in normal flow control, the stack is popped simply by decrementing the stack depth variable. The last statement is any return statement not in a try/finally block, conditionally the last statement in a finally block whose associated try contains a return statement, and the last statement in the function.
* A return statement inside of a try block with an associated finally block simply sets a function-local variable indicating that the stack should be popped at the end of the finally block.
* When any exception is thrown (Java-derived or a native browser exception), the stack depth is reset after the call to `Exceptions.caught` to the function's local stack index variable.
* In order to ensure that a native exception's stack data is recorded properly and any subsequent finally block is executed with the correct global stack depth, any try/finally statement without a catch block has a trivial catch block added to ensure the currently-propagating exception has been correctly wrapped, to reset the global stack depth to the local stack index, and then to re-throw the exception.
== Controls ==
Control properties are defined in [http://code.google.com/p/google-web-toolkit/source/browse/trunk/user/src/com/google/gwt/core/EmulateJsStack.gwt.xml EmulateJsStack.gwt.xml] which is inherited via `Core.gwt.xml`.
* `compiler.emulatedStack` is a binding property with values `true` or `false`.
* `compiler.emulatedStack.recordLineNumbers` is a boolean configuration property that causes line-number data to be encoded in the emitted JS.
* `compiler.emulatedStack.recordFileNames` is a boolean configuration property that also includes source filename information in the emitted JS. `recordFileNames` implies `recordLineNumbers`. If you are using a resymbolization technique, the symbol map files already have the file names.
= Resymbolization =
Method names in deployed code will have been obfuscated and will not be particularly useful as encoded in the module permutations. To that end, a means for resymbolizing a stack trace has been implemented.
* The Linker artifact `CompilationResult` provides a method `getSymbolMap()` which returns a string mapping of JSNI identifiers for types, methods, and fields to their obfuscated identifiers.
* A `symbolMaps` linker is added in `Core.gwt.xml` that emits the symbol map data as a series of files `_symbolMap.properties`.
* The data emitted by this linker is very raw; one method may exist in several methods due to compiler optimizations. Consider `ArrayList.add(Object)`:
{{{
java.util.ArrayList = ArrayList
java.util.ArrayList::$add(Ljava/util/ArrayList;Ljava/lang/Object;) = $add
java.util.ArrayList::add(Ljava/lang/Object;) = add_3
}}}
* The first entry `$add` is a static-dispatch variant used when the compiler is able to determine that a variable must be an `ArrayList`. The second variant `add_3` is used for polymorphic dispatch when the variable would have been accessed through the `List` interface.
* The method `GWT.getPermutationStrongName()` and the associated `$strongName` variable have been added to allow permutations to identify themselves at runtime.
* A utility class `HttpThrowableReporter` has been provided to send JSON-formatted representations via HTTP requests.