My favorites | Sign in
Google
                
Search
for
Updated Aug 20, 2009 by bobv@google.com
WebModeExceptions  
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

Mozilla, Opera

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 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 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.



Sign in to add a comment