Revision: 6849
Author: [email protected]
Date: Wed Nov 11 15:07:51 2009
Log: Update CompilationUnit wiki doc for GWT 2.0.
http://code.google.com/p/google-web-toolkit/source/detail?r=6849

Added:
  /wiki/CompilationUnit_1_5.wiki
Modified:
  /wiki/CompilationUnit.wiki

=======================================
--- /dev/null
+++ /wiki/CompilationUnit_1_5.wiki      Wed Nov 11 15:07:51 2009
@@ -0,0 +1,113 @@
+#summary The new design for compilation units as of GWT 1.5
+#labels Phase-Design
+_NOTE: This design document is out of date.  For the new design as of GWT  
2.0, please see CompilationUnit._
+
+= How Compilation Units are Managed in the GWT Infrastructure =
+== Overview ==
+In GWT, both running hosted mode and compiling for web mode share  
infrastructure for building {{{TypeOracle}}} and managing Generators.  Up  
to now we have not had a good name or well-defined boundaries for this  
viscera, but hopefully this design doc will shed some light on things  
related to the {{{CompilationUnit}}}.  All doc is circa GWT 1.5 RC1, when a  
big refactoring effort over all this infrastructure occurred, code  
named "Flaming Sword of Death".
+
+Update: _*GRAVEYARD* is now implemented in Gwt trunk (r5048)._
+
+== Goals ==
+  * Read Java source files off the classpath based on module source  
inclusions
+  * Compile included Java source using JDT
+  * Perform custom error checking for GWT-specific constructs
+  * Log any compilation errors
+  * Build and maintain a {{{TypeOracle}}}, which reflects the full body of  
compilation units
+  * Assimilate new compilation units from Generators
+  * Produce Java class files for use in hosted mode
+  * Efficiently refresh from disk (important for hosted mode refreshes)
+  * Provide compiled class files for hosted mode execution without  
additional compilation
+
+== Glossary of Moving Parts ==
+==={{{CompilationState}}}===
+  Represents the total set of {{{CompilationUnits}}} for a module; a  
member of a GWT module.  The {{{CompilationState}}} is reponsible for  
managing the set of {{{CompilationUnits}}} and ensuring orderly state  
transitions.  The {{{CompilationState}}} also manages the module's  
{{{TypeOracle}}}.
+
+==={{{CompilationUnit}}}===
+  The central piece of the whole puzzle.  A {{{CompilationUnit}}}  
represents a single Java source file, but includes all accumulated state  
and output as compilation and validation proceeds.  Subparts include:
+    * the parsed JDT AST for the {{{CompilationUnit}}}
+    * a set of {{{CompiledClasses}}}, which contain class-specific  
artifacts
+
+==={{{CompilationUnit.State}}}===
+  Any given {{{CompilationUnit}}} can be in exactly one of several  
discreet states.  Here are the possible states and associated invariants:
+  * *FRESH*: All internal state is cleared; the unit's source has not yet  
been compiled by JDT.
+  * *COMPILED*: In this intermediate state, the unit's source has been  
compiled by JDT.  The unit will contain a set of {{{CompiledClasses}}}.
+  * *ERROR*: In this final state, the unit was compiled, but contained one  
or more errors.  Those errors are cached inside the unit, but all other  
internal state is cleared.
+  * *CHECKED*: In this final state, the unit has been compiled and is  
error free.  Additionally, all other units this unit depends on  
(transitively) are also error free.  The unit contains a set of checked  
{{{CompiledClasses}}}.  The unit and each contained {{{CompiledClass}}}  
releases all references to the JDT AST.  Each class contains a reference to  
a valid JRealClassType, which has been added to the module's  
{{{TypeOracle}}}, as well as byte code, JSNI methods, and all other final  
state.
+  * *GRAVEYARD*: A *CHECKED* generated unit enters this state at the start  
of a refresh.  If a generator generates the same unit with identical  
source, the unit bypasses costly compilation, validation, and  
{{{TypeOracle}}} building. Note that a *GRAVEYARD* unit is invalidated in  
any of the following cases:
+   * if its source changes
+   * if the state of any units that it depends on has become *FRESH* or  
*ERROR*
+   * if a source unit with the same main type is found
+
+==={{{CompiledClass}}}===
+  Represents a single compiled Java class; a member of a  
{{{CompilationUnit}}}.  Subparts include:
+  * the parsed JDT AST for the class
+  * a reference to a JRealClassType in the module's {{{TypeOracle}}}
+  * the actual byte code of the class file
+  * a set of JSNI methods associated with the class
+
+==={{{TypeOracleMediator}}}===
+  Helper class to handle the details of reflecting the JDT AST nodes  
provided by the {{{CompilationState}}} as a {{{TypeOracle}}}.
+
+==={{{JdtCompiler}}}===
+  Helper class to handle the details of transforming Java source files  
into both JDT AST nodes and compiled Java byte code.
+
+==={{{JavaSourceOracle}}}===
+  An abstraction that provides a single unified view of all source files  
available to the current module.  Implemented on top of a  
{{{ResourceOracle}}}.
+
+==={{{ResourceOracle}}}===
+  A classpath abstraction that provides a unified view of all resources  
available on the Java classpath given a set of included packages and  
optional filters.  This is used for both source files and public files, and  
the set of included packages is determined by the module's source and  
public declarations.
+
+== Class Connection Diagram ==
+
+http://google-web-toolkit.googlecode.com/svn/wiki/TypeOracleCompilationDesign.png
+
+== Algorithm Overview for Various Use Cases ==
+===#1: {{{ModuleDef}}}.getTypeOracle() called the first time===
+  # {{{CompilationState}}} compiles
+  # {{{JdtCompiler}}} compiles all *FRESH* and *ERROR* units; those units  
become *COMPILED*
+  # All valid type names for classes with corresponding source code are  
recorded for validation
+  # Any units with JDT errors transition to *ERROR* state; all errors are  
logged
+  # Custom validation is performed over *COMPILED* units, recording new  
errors
+    # JSO restrictions checked using JDT AST
+    # Primitive long access from JSNI methods checked using JDT AST
+    # References to binary types checked using set of valid source types  
and JDT AST
+    # Any units with custom errors transition to *ERROR* state; all errors  
are logged
+  # Any units (transitively) depending on *ERROR* units are invalidated  
and become *FRESH*
+    # Each *COMPILED* unit lazily computes its direct references to other  
units
+    # All units depending on *FRESH* or *ERROR* units are transitively  
invalidated and become *FRESH*
+    # Each unit that is invalidated generates an error log message
+  # JSNI methods are collected from each unit that remains *COMPILED*
+  # {{{TypeOracleMediator}}} builds a JRealClassType for each class that  
belongs to a *COMPILED* unit, and places that JRealClassType into  
{{{TypeOracle}}}
+  # All *COMPILED* units become *CHECKED*
+    # Unneeded internal state (such as references to JDT's AST) are now  
cleared
+
+===#2: {{{ModuleDef}}} wants to refresh===
+  # {{{ResourceOracle}}} for source path refreshes against file system
+  # {{{JavaSourceOracle}}} refreshes against {{{ResourceOracle}}} if  
{{{ResourceOracle}}} state changed
+  # {{{CompilationState}}} refreshes against {{{JavaSourceOracle}}}
+    # All *GRAVEYARD* units are removed
+    # All generated units become *GRAVEYARD*
+      # Any contained JRealClassTypes are removed from {{{TypeOracle}}}
+    # Any source files whose corresponding file was changed in  
{{{JavaSourceOracle}}} are invalidated and become *FRESH*
+    # The graveyard units are checked against new source units
+    # All units whose corresponding file was removed from  
{{{JavaSourceOracle}}} are removed
+    # Any new source files in {{{JavaSourceOracle}}} have new  
{{{CompilationUnits}}} created
+    # All units depending on *FRESH* units are transitively invalidated  
and become *FRESH*
+  # The sequence of events in use case #1 occurs
+
+===#3: Newly generated units need to be assimilated===
+  # A set of *FRESH* {{{CompilationUnits}}} contained generated source are  
added to the {{{CompilationState}}}
+  # For each new unit, if a *GRAVEYARD* unit with the same type name  
already exists, the source of the new unit is compared to the source of the  
existing unit.
+    # If the new unit's source is identical to the old unit's source, the  
new unit is discarded
+      # All JRealClassTypes in the contained {{{CompiledClasses}}} are  
re-added to {{{TypeOracle}}}
+    # If the new unit's source differs from the old unit's source, the old  
unit is discarded and the new unit is added
+  # If any *FRESH* units remain, the sequence of events in use case #1  
occurs
+
+===#4: A {{{CompilationUnit}}} becomes invalid===
+  # The reference to the JDT cud is removed
+  # The set of cached references to other units is cleared
+  # For each {{{CompiledClass}}}
+    # The contained JRealClassType is removed from {{{TypeOracle}}}
+    # All internal state is cleared
+  # The set of {{{CompiledClasses}}} is cleared
=======================================
--- /wiki/CompilationUnit.wiki  Thu Mar 19 15:24:58 2009
+++ /wiki/CompilationUnit.wiki  Wed Nov 11 15:07:51 2009
@@ -1,112 +1,34 @@
-#summary The new design for compilation units as of GWT 1.5
+#summary The new design for building CompilationState as of GWT 2.0
  #labels Phase-Design
-
-= How Compilation Units are Managed in the GWT Infrastructure =
-== Overview ==
-In GWT, both running hosted mode and compiling for web mode share  
infrastructure for building {{{TypeOracle}}} and managing Generators.  Up  
to now we have not had a good name or well-defined boundaries for this  
viscera, but hopefully this design doc will shed some light on things  
related to the {{{CompilationUnit}}}.  All doc is circa GWT 1.5 RC1, when a  
big refactoring effort over all this infrastructure occurred, code  
named "Flaming Sword of Death".
-
-Update: _*GRAVEYARD* is now implemented in Gwt trunk (r5048)._
-
-== Goals ==
-  * Read Java source files off the classpath based on module source  
inclusions
-  * Compile included Java source using JDT
-  * Perform custom error checking for GWT-specific constructs
-  * Log any compilation errors
-  * Build and maintain a {{{TypeOracle}}}, which reflects the full body of  
compilation units
-  * Assimilate new compilation units from Generators
-  * Produce Java class files for use in hosted mode
-  * Efficiently refresh from disk (important for hosted mode refreshes)
-  * Provide compiled class files for hosted mode execution without  
additional compilation
-
-== Glossary of Moving Parts ==
-==={{{CompilationState}}}===
-  Represents the total set of {{{CompilationUnits}}} for a module; a  
member of a GWT module.  The {{{CompilationState}}} is reponsible for  
managing the set of {{{CompilationUnits}}} and ensuring orderly state  
transitions.  The {{{CompilationState}}} also manages the module's  
{{{TypeOracle}}}.
-
-==={{{CompilationUnit}}}===
-  The central piece of the whole puzzle.  A {{{CompilationUnit}}}  
represents a single Java source file, but includes all accumulated state  
and output as compilation and validation proceeds.  Subparts include:
-    * the parsed JDT AST for the {{{CompilationUnit}}}
-    * a set of {{{CompiledClasses}}}, which contain class-specific  
artifacts
-
-==={{{CompilationUnit.State}}}===
-  Any given {{{CompilationUnit}}} can be in exactly one of several  
discreet states.  Here are the possible states and associated invariants:
-  * *FRESH*: All internal state is cleared; the unit's source has not yet  
been compiled by JDT.
-  * *COMPILED*: In this intermediate state, the unit's source has been  
compiled by JDT.  The unit will contain a set of {{{CompiledClasses}}}.
-  * *ERROR*: In this final state, the unit was compiled, but contained one  
or more errors.  Those errors are cached inside the unit, but all other  
internal state is cleared.
-  * *CHECKED*: In this final state, the unit has been compiled and is  
error free.  Additionally, all other units this unit depends on  
(transitively) are also error free.  The unit contains a set of checked  
{{{CompiledClasses}}}.  The unit and each contained {{{CompiledClass}}}  
releases all references to the JDT AST.  Each class contains a reference to  
a valid JRealClassType, which has been added to the module's  
{{{TypeOracle}}}, as well as byte code, JSNI methods, and all other final  
state.
-  * *GRAVEYARD*: A *CHECKED* generated unit enters this state at the start  
of a refresh.  If a generator generates the same unit with identical  
source, the unit bypasses costly compilation, validation, and  
{{{TypeOracle}}} building. Note that a *GRAVEYARD* unit is invalidated in  
any of the following cases:
-   * if its source changes
-   * if the state of any units that it depends on has become *FRESH* or  
*ERROR*
-   * if a source unit with the same main type is found
-
-==={{{CompiledClass}}}===
-  Represents a single compiled Java class; a member of a  
{{{CompilationUnit}}}.  Subparts include:
-  * the parsed JDT AST for the class
-  * a reference to a JRealClassType in the module's {{{TypeOracle}}}
-  * the actual byte code of the class file
-  * a set of JSNI methods associated with the class
-
-==={{{TypeOracleMediator}}}===
-  Helper class to handle the details of reflecting the JDT AST nodes  
provided by the {{{CompilationState}}} as a {{{TypeOracle}}}.
-
-==={{{JdtCompiler}}}===
-  Helper class to handle the details of transforming Java source files  
into both JDT AST nodes and compiled Java byte code.
-
-==={{{JavaSourceOracle}}}===
-  An abstraction that provides a single unified view of all source files  
available to the current module.  Implemented on top of a  
{{{ResourceOracle}}}.
-
-==={{{ResourceOracle}}}===
-  A classpath abstraction that provides a unified view of all resources  
available on the Java classpath given a set of included packages and  
optional filters.  This is used for both source files and public files, and  
the set of included packages is determined by the module's source and  
public declarations.
-
-== Class Connection Diagram ==
-
-http://google-web-toolkit.googlecode.com/svn/wiki/TypeOracleCompilationDesign.png
-
-== Algorithm Overview for Various Use Cases ==
-===#1: {{{ModuleDef}}}.getTypeOracle() called the first time===
-  # {{{CompilationState}}} compiles
-  # {{{JdtCompiler}}} compiles all *FRESH* and *ERROR* units; those units  
become *COMPILED*
-  # All valid type names for classes with corresponding source code are  
recorded for validation
-  # Any units with JDT errors transition to *ERROR* state; all errors are  
logged
-  # Custom validation is performed over *COMPILED* units, recording new  
errors
-    # JSO restrictions checked using JDT AST
-    # Primitive long access from JSNI methods checked using JDT AST
-    # References to binary types checked using set of valid source types  
and JDT AST
-    # Any units with custom errors transition to *ERROR* state; all errors  
are logged
-  # Any units (transitively) depending on *ERROR* units are invalidated  
and become *FRESH*
-    # Each *COMPILED* unit lazily computes its direct references to other  
units
-    # All units depending on *FRESH* or *ERROR* units are transitively  
invalidated and become *FRESH*
-    # Each unit that is invalidated generates an error log message
-  # JSNI methods are collected from each unit that remains *COMPILED*
-  # {{{TypeOracleMediator}}} builds a JRealClassType for each class that  
belongs to a *COMPILED* unit, and places that JRealClassType into  
{{{TypeOracle}}}
-  # All *COMPILED* units become *CHECKED*
-    # Unneeded internal state (such as references to JDT's AST) are now  
cleared
-
-===#2: {{{ModuleDef}}} wants to refresh===
-  # {{{ResourceOracle}}} for source path refreshes against file system
-  # {{{JavaSourceOracle}}} refreshes against {{{ResourceOracle}}} if  
{{{ResourceOracle}}} state changed
-  # {{{CompilationState}}} refreshes against {{{JavaSourceOracle}}}
-    # All *GRAVEYARD* units are removed
-    # All generated units become *GRAVEYARD*
-      # Any contained JRealClassTypes are removed from {{{TypeOracle}}}
-    # Any source files whose corresponding file was changed in  
{{{JavaSourceOracle}}} are invalidated and become *FRESH*
-    # The graveyard units are checked against new source units
-    # All units whose corresponding file was removed from  
{{{JavaSourceOracle}}} are removed
-    # Any new source files in {{{JavaSourceOracle}}} have new  
{{{CompilationUnits}}} created
-    # All units depending on *FRESH* units are transitively invalidated  
and become *FRESH*
-  # The sequence of events in use case #1 occurs
-
-===#3: Newly generated units need to be assimilated===
-  # A set of *FRESH* {{{CompilationUnits}}} contained generated source are  
added to the {{{CompilationState}}}
-  # For each new unit, if a *GRAVEYARD* unit with the same type name  
already exists, the source of the new unit is compared to the source of the  
existing unit.
-    # If the new unit's source is identical to the old unit's source, the  
new unit is discarded
-      # All JRealClassTypes in the contained {{{CompiledClasses}}} are  
re-added to {{{TypeOracle}}}
-    # If the new unit's source differs from the old unit's source, the old  
unit is discarded and the new unit is added
-  # If any *FRESH* units remain, the sequence of events in use case #1  
occurs
-
-===#4: A {{{CompilationUnit}}} becomes invalid===
-  # The reference to the JDT cud is removed
-  # The set of cached references to other units is cleared
-  # For each {{{CompiledClass}}}
-    # The contained JRealClassType is removed from {{{TypeOracle}}}
-    # All internal state is cleared
-  # The set of {{{CompiledClasses}}} is cleared
+_NOTE: For the older, GWT 1.5 design please see CompilationUnit_1_5._
+
+= Building {{{CompilationState}}} and {{{TypeOracle}}} =
+== Problem and Background ==
+Before GWT 2.0, {{{CompilationState}}}, and {{{TypeOracle}}} were  
per-module singletons. Unfortunately, they were also currently quite  
stateful. In hosted mode in particular, types were added to  
{{{TypeOracle}}} and {{{CompilationState}}} over time as Generators ran,  
then those types were removed on refresh. This was not a problem as long as  
a user only has one "session" at a time open. However, in 2.0 out of  
process development mode encourages patterns where users might concurrently  
access the same module in multiple tabs, or multiple browsers. In this  
case, unpredictable behavior was likely to occur. This problem also  
manifested trying to do a JUnit test using multiple concurrent dev mode  
browsers.
+
+For more pre-2.0 background, please see CompilationUnit_1_5.
+
+== Basic Solution ==
+We create multiple instances of {{{CompilationState}}}, one per active dev  
mode sesions, or per concurrent compile. Each {{{CompilationState}}} state  
has its own {{{TypeOracle}}}, and neither of these can be reset  
or "refreshed". They operate in a forward-only fashion.. new types can be  
added via generators, but existing types cannot be removed or changed.
+
+== Problem - Building {{{CompilationState}}} is too expensive ==
+However, {{{CompilationState}}} is extremely expensive to build from  
scratch. One possible solution to the problem could have been to simply  
recycle old {{{CompilationState}}}s when a page is refreshed, using the old  
{{{CompilationState}}} refresh logic; if a user opened multiple tabs we'd  
simply have to spend tons of CPU creating multiple instances of  
{{{CompilationState}}}. However, this solution is not workable because  
generally speaking, we don't know when a page is being refreshed. In the  
current dev mode architecture, old sessions may hang around for several  
seconds after a new session is up and running, thwarting a recycling  
strategy. Something more sophisticated is needed.
+
+== Refinement #1 ==
+In GWT 2.0, multiple independent {{{CompilationState}}} intances are all  
built from a shared singleton subsystem, {{{CompilationState}}}Builder. It  
makes sense for it to be a singleton, because ultimately all Java source  
files (henceforth, compilation units) that can possibly be managed, exist  
on the singleton system class path. {{{CompilationState}}}Builder is  
responsible for building new {{{CompilationState}}} instances using  
compiled compilation units that reflect the current contents of some subset  
of Java source files on the system class path. It also efficiently caches  
already-compiled units, and correctly and smartly recompiles stale units  
(and any units which depend on stale units). Ensuring cache correctness is  
a two-fold problem. First, {{{CompilationState}}}Builder must ensure that  
any time an underlying source file changes, the associated  
{{{CompilationUnit}}} is seen as stale. Secondly,  
{{{CompilationState}}}Builder must accurately track dependencies between  
units, such that one stale unit causes a cascading series of recompiles of  
units that transitively depend on the stale unit.
+
+{{{CompilationState}}}Builder solves the first problem by mapping compiled  
units by {{{ContentId}}}. A {{{ContentId}}} consists of the main type name  
of a {{{CompilationUnit}}}, and a strong hash of the source file contents.  
This combination ensures that changes to source files can be identified in  
a lightweight manner. In addition, the {{{ContentId}}} instances themselves  
are cached by absolute resource location and last modified timestamp. As  
long as a resource's timstamp has not changed, the associated  
{{{ContentId}}} is assumed to be fresh.
+
+{{{CompilationState}}}Builder solves the second problem using the existing  
dependency tracking mechanisms that have been in place since GWT 1.5 and  
earlier, and in addition it now also tracks JSNI references between units.  
These dependencies are recorded as {{{ContentId}}} instances, so that one  
{{{CompilationUnit}}}'s dependencies can be uniquely resolved to one  
particular revision of another {{{CompilationUnit}}}.
+
+== Problem - {{{TypeOracle}}} is built from JDT data structures ==
+Priior to GWT 2.0, JDT data structures were directly used to build  
{{{TypeOracle}}}. The JDT structures were transient and only existed until  
{{{TypeOracle}}} finished builder. If {{{TypeOracle}}} was later refreshed,  
old {{{TypeOracle}}} components would simply be reused. However, in the new  
design, multiple instances of a {{{TypeOracle}}} need to coexist, and new  
{{{TypeOracle}}} instances may be built from cache at a later time. Keeping  
the JDT structures cached in order to later build new {{{TypeOracle}}} data  
structures would consume an unacceptable amount of memory, and those JDT  
structures cannot natively be serialized to disk.  One possible solution  
could have been to modify {{{TypeOracle}}} so that individual components  
can be serialized, and a new {{{TypeOracle}}} could be built from  
deserialized pieces. However, the design of {{{TypeOracle}}} was not  
amenable to this approach.
+
+== Refinement #2 ==
+Fortunately, John Tamplin already did the work necessary to build  
{{{TypeOracle}}} instances directly from bytecode as part of the Instant  
Hosted Mode effort. We took this one piece of IHM and thereby eliminated  
the need to cache JDT structures, instead we only cache bytecode.
+
+== Problem - Generated Compilation Units ==
+Prior to GWT 2.0, we cached the {{{CompilationUnit}}} for generated source  
files. If the same source file was regenerated with the exact same  
contents, the old {{{CompilationUnit}}} could be reused without  
recompiling. (This process was referred to as the GRAVEYARD in the existing  
wiki doc). We need to translate this idea to allow  
{{{CompilationState}}}Builder to also reuse generated units with the same  
source.
+
+== Refinement #3 ==
+Generated units are simply cached by {{{ContentId}}} without regard to  
modification time. When a new source file is generated, a {{{ContentId}}}  
is created and an existing unit can simply be looked up in the cache.

--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---

Reply via email to