#summary Design document for "Instant Hosted Mode" #labels Phase-Design,Phase-Requirements *_Work in progress_* = Introduction = Hosted mode currently takes too long to start up. A significant portion of this startup time is in compiling from source. Instant Hosted Mode proposes to make use of existing class files where possible, which will help reduce startup time. Note that we would implement this in stages -- the first step would be the minimum to usefully use bytecode rather than source in the general case, and we would just fall back to using source. Later efforts would extend the set of cases where we can use bytecode and integrate better with IDEs and other tools. = Considerations = * JSNI is not preserved in class files, so we will still need to read from source. We can however, save the JSNI to a file (or in the class file itself) and reuse it if the source file has not changed. * Due to type erasure, generics are not preserved in bytecode. Since STOB and UIBinder heavily use this data, we need to retain it some way for this to have much gain. It may be possible to write an annotation processor that collects this data, though configuring that may be problematic in some environments. * It isn't clear how super-source fits in - we may need to always load them from source, but their number is small. * Do we need to do anything special for the bridge classes (!ShellJavaScriptHost and GWTBridge, plus Emma)? * External bytecode rewriting tools, such as Emma, need to be considered - specifically, will they do anything to the bytecode that might remove or invalidate data we need. * The current generator API makes some aspects of this more complicated, so it might be useful to alter the API (and might be combined with other ideas for allowing generators to run outside a GWT compile or specifying their dependencies to avoid redundant executions) * Method parameter names are not generally available (though it might be possible to use debug information to get them), and some generators require them. * This may lead to a mix of code generated by different compilers. This is particularly an issue regarding class names for anonymous inner classes, though that should be largely solved with the existing Emma integration. * IDE and/or build system integration = Contact Points = This section describe the major components which interact with the proposed changes. * *!CompilingClassLoader* !CompilingClassLoader gets called when the bytecode for a given class needs to be loaded by the JVM. Besides compiling from source, it is responsible for rewriting the bytecode for JSO interfaces and interacting with other bytecode rewriting tools like Emma. * *!TypeOracle* Generators need !TypeOracle to get information about the various known classes. = Implementation Plan = * It looks like it would be straightforward to create a !CompilationUnit subclass which handles pre-compiled classes. By reading the top-level class, it can find any enclosed classes and load them as other !CompiledClass instances. This would save the compile but not the bytecode rewrite, though that is fast and eliminating it would involve integration with other compilers via APT or similar. * Data needed by the !TypeOracle API would be gathered via ASM reads of the bytecode. Generic information would be added into the bytecode by an annotation processor. Some of the data may require more work to generate, but for the initial pass we will not undertake any !TypeOracle API changes. We may revisit this when doing other generator work that may benefit from API changes. * If information is required that is not available from the bytecode, such as JSNI method source or parameter names where the class was not compiled in debug mode, we can either drop the bytecode entirely and proceed as before, or we can use JDT to just parse the source to get the missing data (getting all such missing data in one pass). == Questions == * Are we guaranteed to load Foo before Foo$Bar? * Does not appear this is guaranteed * If we load Foo$Bar, can we definitely know its enclosing class or do we have to make heuristic guesses? If the latter, how safe will those be across different compilers? * ASM appears to visit INNERCLASS and OUTERCLASS for each class, so when loading Foo$Bar, we will see OUTERCLASS Foo while processing the class. So, when we first get a request for a previously unseen class, if it has an OUTERCLASS, we walk up the tree until we get to a top-level class, then load all the classes under it (which we get from INNERCLASS visits on the top-level type and the subtypes that leads us to). We have to do this since our heuristic for matching up anonymous inner classes between different compilers requires knowing all the synthetic names up front. Also, this fits well with !CompilationUnit. * Can we get all the generic information we need from an annotation processor? If we require APT, does this limit deployment scnenarios?