Applying new lightweight collections to the Java AST.

Review by: spoon

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5167 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardMethodMember.java b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardMethodMember.java
index e617acf..629ad06 100644
--- a/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardMethodMember.java
+++ b/dev/core/src/com/google/gwt/core/ext/soyc/impl/StandardMethodMember.java
@@ -62,7 +62,7 @@
 
     SortedSet<MethodMember> overrides = new TreeSet<MethodMember>(
         Member.SOURCE_NAME_COMPARATOR);
-    for (JMethod override : method.overrides) {
+    for (JMethod override : method.getOverrides()) {
       overrides.add(factory.get(override));
     }
     overridesView = Collections.unmodifiableSortedSet(overrides);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index cd668cb..61c9682 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -34,6 +34,7 @@
 import com.google.gwt.dev.jjs.UnifiedAst.AST;
 import com.google.gwt.dev.jjs.ast.JBinaryOperation;
 import com.google.gwt.dev.jjs.ast.JBinaryOperator;
+import com.google.gwt.dev.jjs.ast.JBlock;
 import com.google.gwt.dev.jjs.ast.JClassType;
 import com.google.gwt.dev.jjs.ast.JExpression;
 import com.google.gwt.dev.jjs.ast.JField;
@@ -669,9 +670,9 @@
     bootStrapMethod.freezeParamTypes();
 
     JMethodBody body = (JMethodBody) bootStrapMethod.getBody();
-    List<JStatement> statements = body.getStatements();
+    JBlock block = body.getBlock();
     for (String mainClassName : mainClassNames) {
-      statements.add(makeStatsCalls(program, mainClassName));
+      block.addStmt(makeStatsCalls(program, mainClassName));
       JReferenceType mainType = program.getFromTypeMap(mainClassName);
 
       if (mainType == null) {
@@ -685,7 +686,7 @@
       if (mainMethod != null && mainMethod.isStatic()) {
         JMethodCall onModuleLoadCall = new JMethodCall(program, null, null,
             mainMethod);
-        statements.add(onModuleLoadCall.makeStatement());
+        block.addStmt(onModuleLoadCall.makeStatement());
         continue;
       }
 
@@ -709,11 +710,11 @@
         entryCalls.add(onModuleLoadCall);
       }
       if (resultTypes.size() == 1) {
-        statements.add(entryCalls.get(0).makeStatement());
+        block.addStmt(entryCalls.get(0).makeStatement());
       } else {
         JReboundEntryPoint reboundEntryPoint = new JReboundEntryPoint(program,
             null, mainType, resultTypes, entryCalls);
-        statements.add(reboundEntryPoint);
+        block.addStmt(reboundEntryPoint);
       }
     }
     program.addEntryMethod(bootStrapMethod);
@@ -723,7 +724,7 @@
     for (int j = 0; j < referenceType.methods.size(); ++j) {
       JMethod method = referenceType.methods.get(j);
       if (method.getName().equals("onModuleLoad")) {
-        if (method.params.size() == 0) {
+        if (method.getParams().size() == 0) {
           return method;
         }
       }
@@ -803,8 +804,7 @@
         isStatsAvailableMethod);
     JMethodCall onModuleStartCall = new JMethodCall(program, sourceInfo, null,
         onModuleStartMethod);
-    onModuleStartCall.getArgs().add(
-        program.getLiteralString(sourceInfo, mainClassName));
+    onModuleStartCall.addArg(program.getLiteralString(sourceInfo, mainClassName));
 
     JBinaryOperation amp = new JBinaryOperation(program, sourceInfo,
         program.getTypePrimitiveBoolean(), JBinaryOperator.AND, availableCall,
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JBlock.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JBlock.java
index 0da127a..42cfbd7 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JBlock.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JBlock.java
@@ -16,8 +16,9 @@
 package com.google.gwt.dev.jjs.ast;
 
 import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.util.collect.Lists;
 
-import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -25,15 +26,61 @@
  */
 public class JBlock extends JStatement {
 
-  public List<JStatement> statements = new ArrayList<JStatement>();
+  private List<JStatement> statements = Collections.emptyList();
 
   public JBlock(JProgram program, SourceInfo info) {
     super(program, info);
   }
 
+  /**
+   * Insert a statement into this block.
+   */
+  public void addStmt(int index, JStatement toAdd) {
+    statements = Lists.add(statements, index, toAdd);
+  }
+
+  /**
+   * Add a statement to the end of this block.
+   */
+  public void addStmt(JStatement toAdd) {
+    statements = Lists.add(statements, toAdd);
+  }
+
+  /**
+   * Insert a statements into this block.
+   */
+  public void addStmts(int index, List<JStatement> toAdd) {
+    statements = Lists.addAll(statements, index, toAdd);
+  }
+
+  /**
+   * Add statements to the end of this block.
+   */
+  public void addStmts(List<JStatement> toAdd) {
+    statements = Lists.addAll(statements, toAdd);
+  }
+
+  public void clear() {
+    statements = Collections.emptyList();
+  }
+
+  /**
+   * Return the statements in this block.
+   */
+  public List<JStatement> getStatements() {
+    return statements;
+  }
+
+  /**
+   * Removes the statement from this block at the specified index.
+   */
+  public void removeStmt(int index) {
+    statements = Lists.remove(statements, index);
+  }
+
   public void traverse(JVisitor visitor, Context ctx) {
     if (visitor.visit(this, ctx)) {
-      visitor.acceptWithInsertRemove(statements);
+      statements = visitor.acceptWithInsertRemoveImmutable(statements);
     }
     visitor.endVisit(this, ctx);
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
index aeada25..afa5724 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassLiteral.java
@@ -53,8 +53,8 @@
     assert method != null;
 
     JMethodCall call = new JMethodCall(program, info, null, method);
-    call.getArgs().add(program.getLiteralString(info, getPackageName(typeName)));
-    call.getArgs().add(program.getLiteralString(info, getClassName(typeName)));
+    call.addArgs(program.getLiteralString(info, getPackageName(typeName)),
+        program.getLiteralString(info, getClassName(typeName)));
 
     if (type instanceof JClassType && !(type instanceof JArrayType)) {
       /*
@@ -73,14 +73,14 @@
         superclassLiteral = program.getLiteralNull();
       }
 
-      call.getArgs().add(superclassLiteral);
+      call.addArg(superclassLiteral);
 
       if (classType instanceof JEnumType) {
         JEnumType enumType = (JEnumType) classType;
         JMethod valuesMethod = null;
         for (JMethod methodIt : enumType.methods) {
           if ("values".equals(methodIt.getName())) {
-            if (methodIt.params.size() != 0) {
+            if (methodIt.getParams().size() != 0) {
               continue;
             }
             valuesMethod = methodIt;
@@ -93,15 +93,15 @@
         }
         JsniMethodRef jsniMethodRef = new JsniMethodRef(program, info, null,
             valuesMethod);
-        call.getArgs().add(jsniMethodRef);
+        call.addArg(jsniMethodRef);
       } else if (isEnumOrSubclass) {
         // A subclass of an enum class
-        call.getArgs().add(program.getLiteralNull());
+        call.addArg(program.getLiteralNull());
       }
     } else if (type instanceof JArrayType) {
       JArrayType arrayType = (JArrayType) type;
       JClassLiteral componentLiteral = program.getLiteralClass(arrayType.getElementType());
-      call.getArgs().add(componentLiteral);
+      call.addArg(componentLiteral);
     } else {
       assert (type instanceof JInterfaceType || type instanceof JPrimitiveType);
     }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JForStatement.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JForStatement.java
index c485166..7437342 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JForStatement.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JForStatement.java
@@ -16,6 +16,7 @@
 package com.google.gwt.dev.jjs.ast;
 
 import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.util.collect.Lists;
 
 import java.util.List;
 
@@ -25,17 +26,17 @@
 public class JForStatement extends JStatement {
 
   private JStatement body;
-  private final List<JExpressionStatement> increments;
-  private final List<JStatement> initializers;
+  private List<JExpressionStatement> increments;
+  private List<JStatement> initializers;
   private JExpression testExpr;
 
   public JForStatement(JProgram program, SourceInfo info,
       List<JStatement> initializers, JExpression testExpr,
       List<JExpressionStatement> increments, JStatement body) {
     super(program, info);
-    this.initializers = initializers;
+    this.initializers = Lists.normalize(initializers);
     this.testExpr = testExpr;
-    this.increments = increments;
+    this.increments = Lists.normalize(increments);
     this.body = body;
   }
 
@@ -57,11 +58,11 @@
 
   public void traverse(JVisitor visitor, Context ctx) {
     if (visitor.visit(this, ctx)) {
-      visitor.acceptWithInsertRemove(initializers);
+      initializers = visitor.acceptWithInsertRemoveImmutable(initializers);
       if (testExpr != null) {
         testExpr = visitor.accept(testExpr);
       }
-      visitor.acceptWithInsertRemove(increments);
+      increments = visitor.acceptWithInsertRemoveImmutable(increments);
       if (body != null) {
         body = visitor.accept(body);
       }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JGwtCreate.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JGwtCreate.java
index 7587c19..52d2124 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JGwtCreate.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JGwtCreate.java
@@ -37,7 +37,7 @@
     for (int i = 0; i < classType.methods.size(); ++i) {
       JMethod ctor = classType.methods.get(i);
       if (ctor.getName().equals(classType.getShortName())) {
-        if (ctor.params.size() == 0) {
+        if (ctor.getParams().size() == 0) {
           noArgCtor = ctor;
         }
       }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
index 3beb6a6..6017254 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
@@ -17,8 +17,10 @@
 
 import com.google.gwt.dev.jjs.InternalCompilerException;
 import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.util.collect.Lists;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -37,15 +39,6 @@
     System.out.println(code);
   }
 
-  /**
-   * References to any methods which this method overrides. This should be an
-   * EXHAUSTIVE list, that is, if C overrides B overrides A, then C's overrides
-   * list will contain both A and B.
-   */
-  public final List<JMethod> overrides = new ArrayList<JMethod>();
-
-  public final ArrayList<JParameter> params = new ArrayList<JParameter>();
-  public final ArrayList<JClassType> thrownExceptions = new ArrayList<JClassType>();
   private JAbstractMethodBody body = null;
   private final JReferenceType enclosingType;
   private final boolean isAbstract;
@@ -54,6 +47,15 @@
   private final boolean isStatic;
   private final String name;
   private List<JType> originalParamTypes;
+
+  /**
+   * References to any methods which this method overrides. This should be an
+   * EXHAUSTIVE list, that is, if C overrides B overrides A, then C's overrides
+   * list will contain both A and B.
+   */
+  private List<JMethod> overrides = Collections.emptyList();
+
+  private List<JParameter> params = Collections.emptyList();
   private JType returnType;
   private boolean trace = false;
   private boolean traceFirst = true;
@@ -74,14 +76,35 @@
     this.isPrivate = isPrivate;
   }
 
+  /**
+   * Add a method that this method overrides.
+   */
+  public void addOverride(JMethod toAdd) {
+    overrides = Lists.add(overrides, toAdd);
+  }
+
+  /**
+   * Add methods that this method overrides.
+   */
+  public void addOverrides(List<JMethod> toAdd) {
+    overrides = Lists.addAll(overrides, toAdd);
+  }
+
+  /**
+   * Adds a parameter to this method.
+   */
+  public void addParam(JParameter x) {
+    params = Lists.add(params, x);
+  }
+
   public void freezeParamTypes() {
-    List<JType> paramTypes =  new ArrayList<JType>();
+    List<JType> paramTypes = new ArrayList<JType>();
     for (JParameter param : params) {
       paramTypes.add(param.getType());
     }
     setOriginalParamTypes(paramTypes);
   }
-  
+
   public JAbstractMethodBody getBody() {
     return body;
   }
@@ -101,6 +124,20 @@
     return originalParamTypes;
   }
 
+  /**
+   * Returns the transitive closure of all the methods this method overrides.
+   */
+  public List<JMethod> getOverrides() {
+    return overrides;
+  }
+
+  /**
+   * Returns the parameters of this method.
+   */
+  public List<JParameter> getParams() {
+    return params;
+  }
+
   public JType getType() {
     return returnType;
   }
@@ -133,6 +170,13 @@
     return trace;
   }
 
+  /**
+   * Removes the parameter at the specified index.
+   */
+  public void removeParam(int index) {
+    params = Lists.remove(params, index);
+  }
+
   public void setBody(JAbstractMethodBody body) {
     if (body != null) {
       body.setMethod(null);
@@ -149,8 +193,7 @@
     if (originalParamTypes != null) {
       throw new InternalCompilerException("Param types already frozen");
     }
-    originalParamTypes = paramTypes;
-    
+    originalParamTypes = Lists.normalize(paramTypes);
 
     // Determine if we should trace this method.
     if (enclosingType != null) {
@@ -189,7 +232,7 @@
       }
     }
     if (visitor.visit(this, ctx)) {
-      visitor.accept(params);
+      params = visitor.acceptImmutable(params);
       if (body != null) {
         body = (JAbstractMethodBody) visitor.accept(body);
       }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodBody.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodBody.java
index 9cfa18d..aa572f8 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodBody.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodBody.java
@@ -16,8 +16,10 @@
 package com.google.gwt.dev.jjs.ast;
 
 import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.util.collect.Lists;
 
-import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
 /**
@@ -25,20 +27,34 @@
  */
 public class JMethodBody extends JAbstractMethodBody {
 
-  public final ArrayList<JLocal> locals = new ArrayList<JLocal>();
   private JBlock block;
+  private List<JLocal> locals = Collections.emptyList();
 
   public JMethodBody(JProgram program, SourceInfo info) {
     super(program, info);
     block = new JBlock(program, info);
   }
 
+  /**
+   * Adds a local to this method body.
+   */
+  public void addLocal(JLocal local) {
+    locals = Lists.add(locals, local);
+  }
+
   public JBlock getBlock() {
     return block;
   }
 
+  /**
+   * Returns this method's local variables.
+   */
+  public List<JLocal> getLocals() {
+    return locals;
+  }
+
   public List<JStatement> getStatements() {
-    return block.statements;
+    return block.getStatements();
   }
 
   @Override
@@ -46,9 +62,23 @@
     return false;
   }
 
+  /**
+   * Removes a local from this method body.
+   */
+  public void removeLocal(int index) {
+    locals = Lists.remove(locals, index);
+  }
+
+  /**
+   * Sorts this method's locals according to the specified sort.
+   */
+  public void sortLocals(Comparator<? super JLocal> sort) {
+    locals = Lists.sort(locals, sort);
+  }
+
   public void traverse(JVisitor visitor, Context ctx) {
     if (visitor.visit(this, ctx)) {
-      visitor.accept(locals);
+      locals = visitor.acceptImmutable(locals);
       block = (JBlock) visitor.accept(block);
     }
     visitor.endVisit(this, ctx);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodCall.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodCall.java
index a02025c..4602018 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodCall.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodCall.java
@@ -16,15 +16,17 @@
 package com.google.gwt.dev.jjs.ast;
 
 import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.util.collect.Lists;
 
-import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Java method call expression.
  */
 public class JMethodCall extends JExpression {
 
-  private ArrayList<JExpression> args = new ArrayList<JExpression>();
+  private List<JExpression> args = Collections.emptyList();
   private boolean cannotBePolymorphic = false;
   private JExpression instance;
   private final JMethod method;
@@ -71,12 +73,43 @@
     this.overrideReturnType = overrideReturnType;
   }
 
+  /**
+   * Inserts an argument at the specified index.
+   */
+  public void addArg(int index, JExpression toAdd) {
+    args = Lists.add(args, index, toAdd);
+  }
+
+  /**
+   * Adds an argument to this method.
+   */
+  public void addArg(JExpression toAdd) {
+    args = Lists.add(args, toAdd);
+  }
+
+  /**
+   * Adds an argument to this method.
+   */
+  public void addArgs(JExpression... toAdd) {
+    args = Lists.addAll(args, toAdd);
+  }
+
+  /**
+   * Adds arguments to this method.
+   */
+  public void addArgs(List<JExpression> toAdd) {
+    args = Lists.addAll(args, toAdd);
+  }
+
   public boolean canBePolymorphic() {
     return !cannotBePolymorphic && !staticDispatchOnly && !method.isFinal()
         && !method.isStatic();
   }
 
-  public ArrayList<JExpression> getArgs() {
+  /**
+   * Returns the call arguments.
+   */
+  public List<JExpression> getArgs() {
     return args;
   }
 
@@ -106,6 +139,20 @@
     return staticDispatchOnly;
   }
 
+  /**
+   * Removes the argument at the specified index.
+   */
+  public void removeArg(int index) {
+    args = Lists.remove(args, index);
+  }
+
+  /**
+   * Sets the argument at the specified index.
+   */
+  public void setArg(int index, JExpression arg) {
+    args = Lists.set(args, index, arg);
+  }
+
   public void setCannotBePolymorphic() {
     this.cannotBePolymorphic = true;
   }
@@ -119,7 +166,7 @@
       if (instance != null) {
         instance = visitor.accept(instance);
       }
-      visitor.accept(args);
+      args = visitor.acceptImmutable(args);
     }
     visitor.endVisit(this, ctx);
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JModVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JModVisitor.java
index 7d592b8..a8e8919 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JModVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JModVisitor.java
@@ -16,6 +16,7 @@
 package com.google.gwt.dev.jjs.ast;
 
 import com.google.gwt.dev.jjs.InternalCompilerException;
+import com.google.gwt.dev.util.collect.Lists;
 
 import java.util.List;
 
@@ -24,13 +25,21 @@
  */
 public class JModVisitor extends JVisitor {
 
-  private static class ListContext implements Context {
-    boolean didChange;
+  /**
+   * Context for traversing a mutable list.
+   */
+  @SuppressWarnings("unchecked")
+  private class ListContext<T extends JNode> implements Context {
+    boolean ctxDidChange;
     int index;
-    List<JNode> list;
+    final List<T> list;
     boolean removed;
     boolean replaced;
 
+    public ListContext(List<T> list) {
+      this.list = list;
+    }
+
     public boolean canInsert() {
       return true;
     }
@@ -41,27 +50,121 @@
 
     public void insertAfter(JNode node) {
       checkRemoved();
-      list.add(index + 1, node);
-      didChange = true;
+      list.add(index + 1, (T) node);
+      ctxDidChange = true;
     }
 
     public void insertBefore(JNode node) {
       checkRemoved();
-      list.add(index++, node);
-      didChange = true;
+      list.add(index++, (T) node);
+      ctxDidChange = true;
     }
 
     public void removeMe() {
       checkState();
       list.remove(index--);
-      didChange = removed = true;
+      ctxDidChange = removed = true;
     }
 
     public void replaceMe(JNode node) {
       checkState();
       checkReplacement(list.get(index), node);
-      list.set(index, node);
-      didChange = replaced = true;
+      list.set(index, (T) node);
+      ctxDidChange = replaced = true;
+    }
+
+    /**
+     * Cause my list to be traversed by this context.
+     */
+    protected List<T> traverse() {
+      try {
+        for (index = 0; index < list.size(); ++index) {
+          removed = replaced = false;
+          list.get(index).traverse(JModVisitor.this, this);
+        }
+        didChange |= ctxDidChange;
+        return list;
+      } catch (Throwable e) {
+        throw translateException(list.get(index), e);
+      }
+    }
+
+    private void checkRemoved() {
+      if (removed) {
+        throw new InternalCompilerException("Node was already removed");
+      }
+    }
+
+    private void checkState() {
+      checkRemoved();
+      if (replaced) {
+        throw new InternalCompilerException("Node was already replaced");
+      }
+    }
+  }
+
+  /**
+   * Context for traversing an immutable list.
+   */
+  @SuppressWarnings("unchecked")
+  private class ListContextImmutable<T extends JNode> implements Context {
+    boolean ctxDidChange;
+    int index;
+    List<T> list;
+    boolean removed;
+    boolean replaced;
+
+    public ListContextImmutable(List<T> list) {
+      this.list = list;
+    }
+
+    public boolean canInsert() {
+      return true;
+    }
+
+    public boolean canRemove() {
+      return true;
+    }
+
+    public void insertAfter(JNode node) {
+      checkRemoved();
+      list = Lists.add(list, index + 1, (T) node);
+      ctxDidChange = true;
+    }
+
+    public void insertBefore(JNode node) {
+      checkRemoved();
+      list = Lists.add(list, index++, (T) node);
+      ctxDidChange = true;
+    }
+
+    public void removeMe() {
+      checkState();
+      list = Lists.remove(list, index--);
+      ctxDidChange = removed = true;
+    }
+
+    public void replaceMe(JNode node) {
+      checkState();
+      checkReplacement(list.get(index), node);
+      list = Lists.set(list, index, (T) node);
+      ctxDidChange = replaced = true;
+    }
+
+    /**
+     * Cause my list to be traversed by this context.
+     */
+    protected List<T> traverse() {
+      try {
+        for (index = 0; index < list.size(); ++index) {
+          removed = replaced = false;
+          list.get(index).traverse(JModVisitor.this, this);
+        }
+        didChange |= ctxDidChange;
+        return list;
+      } catch (Throwable e) {
+        throw translateException(list.get(index), e);
+      }
     }
 
     private void checkRemoved() {
@@ -138,13 +241,13 @@
   }
 
   @SuppressWarnings("unchecked")
-  public void accept(List<? extends JNode> list) {
+  public <T extends JNode> void accept(List<T> list) {
     NodeContext ctx = new NodeContext();
     try {
       for (int i = 0, c = list.size(); i < c; ++i) {
         (ctx.node = list.get(i)).traverse(this, ctx);
         if (ctx.replaced) {
-          ((List) list).set(i, ctx.node);
+          list.set(i, (T) ctx.node);
           ctx.replaced = false;
         }
       }
@@ -155,20 +258,32 @@
   }
 
   @SuppressWarnings("unchecked")
-  public void acceptWithInsertRemove(List<? extends JNode> list) {
-    ListContext ctx = new ListContext();
+  @Override
+  public <T extends JNode> List<T> acceptImmutable(List<T> list) {
+    NodeContext ctx = new NodeContext();
     try {
-      ctx.list = (List) list;
-      for (ctx.index = 0; ctx.index < list.size(); ++ctx.index) {
-        ctx.removed = ctx.replaced = false;
-        list.get(ctx.index).traverse(this, ctx);
+      for (int i = 0, c = list.size(); i < c; ++i) {
+        (ctx.node = list.get(i)).traverse(this, ctx);
+        if (ctx.replaced) {
+          list = Lists.set(list, i, (T) ctx.node);
+          ctx.replaced = false;
+        }
       }
       didChange |= ctx.didChange;
+      return list;
     } catch (Throwable e) {
-      throw translateException(list.get(ctx.index), e);
+      throw translateException(ctx.node, e);
     }
   }
 
+  public <T extends JNode> void acceptWithInsertRemove(List<T> list) {
+    new ListContext<T>(list).traverse();
+  }
+
+  public <T extends JNode> List<T> acceptWithInsertRemoveImmutable(List<T> list) {
+    return new ListContextImmutable<T>(list).traverse();
+  }
+
   public boolean didChange() {
     return didChange;
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
index 01b2667..e3de02b 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -456,7 +456,7 @@
     JLocal x = new JLocal(this, info, String.valueOf(name), type, isFinal,
         enclosingMethodBody);
 
-    enclosingMethodBody.locals.add(x);
+    enclosingMethodBody.addLocal(x);
     return x;
   }
 
@@ -496,7 +496,7 @@
     JParameter x = new JParameter(this, info, String.valueOf(name), type,
         isFinal, isThis, enclosingMethod);
 
-    enclosingMethod.params.add(x);
+    enclosingMethod.addParam(x);
     return x;
   }
 
@@ -661,7 +661,7 @@
           fieldRef, alloc);
       JMethodBody clinitBody = (JMethodBody) typeSpecialClassLiteralHolder.methods.get(
           0).getBody();
-      clinitBody.getStatements().add(decl);
+      clinitBody.getBlock().addStmt(decl);
 
       SourceInfo literalInfo = createSourceInfoSynthetic(JProgram.class,
           "class literal for " + type.getName());
@@ -967,9 +967,9 @@
   }
 
   /**
-   * If <code>method</code> is a static impl method, returns the instance method
-   * that <code>method</code> is the implementation of. Otherwise, returns
-   * <code>null</code>.
+   * If <code>method</code> is a static impl method, returns the instance
+   * method that <code>method</code> is the implementation of. Otherwise,
+   * returns <code>null</code>.
    */
   public JMethod staticImplFor(JMethod method) {
     return staticToInstanceMap.get(method);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
index d15f794..d3d222f 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
@@ -16,13 +16,13 @@
 package com.google.gwt.dev.jjs.ast;
 
 import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
+import com.google.gwt.dev.util.collect.IdentityHashMap;
+import com.google.gwt.dev.util.collect.IdentityHashSet;
+import com.google.gwt.dev.util.collect.IdentitySets;
 
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -46,7 +46,7 @@
    */
   private static final class CheckClinitVisitor extends JVisitor {
 
-    private final Set<JReferenceType> clinitTargets = new HashSet<JReferenceType>();
+    private final Set<JReferenceType> clinitTargets = new IdentityHashSet<JReferenceType>();
 
     /**
      * Tracks whether any live code is run in this clinit. This is only reliable
@@ -68,7 +68,7 @@
 
     @Override
     public boolean visit(JBlock x, Context ctx) {
-      for (JStatement stmt : x.statements) {
+      for (JStatement stmt : x.getStatements()) {
         if (mightBeDeadCode(stmt)) {
           accept(stmt);
         } else {
@@ -178,8 +178,8 @@
    * 
    * @param type any type
    * @param instantiatedTypes a set of types assumed to be instantiated. If
-   *          <code>null</code>, then there are no assumptions about which types
-   *          are instantiated.
+   *          <code>null</code>, then there are no assumptions about which
+   *          types are instantiated.
    * @return whether the type is instantiated
    */
   private static boolean isInstantiatedType(JReferenceType type,
@@ -205,9 +205,9 @@
 
   private final Map<JClassType, Set<JInterfaceType>> couldImplementMap = new IdentityHashMap<JClassType, Set<JInterfaceType>>();
 
-  private final Set<JInterfaceType> dualImpl = new HashSet<JInterfaceType>();
+  private final Set<JInterfaceType> dualImpl = new IdentityHashSet<JInterfaceType>();
 
-  private final Set<JReferenceType> hasClinitSet = new HashSet<JReferenceType>();
+  private final Set<JReferenceType> hasClinitSet = new IdentityHashSet<JReferenceType>();
 
   private final Map<JClassType, Set<JInterfaceType>> implementsMap = new IdentityHashMap<JClassType, Set<JInterfaceType>>();
 
@@ -239,7 +239,7 @@
    * Collect all supertypes and superinterfaces for a type.
    */
   public Set<JReferenceType> allAssignableFrom(JReferenceType type) {
-    Set<JReferenceType> toReturn = new HashSet<JReferenceType>();
+    Set<JReferenceType> toReturn = new IdentityHashSet<JReferenceType>();
     List<JReferenceType> q = new LinkedList<JReferenceType>();
     q.add(type);
 
@@ -299,13 +299,13 @@
       if (qType instanceof JClassType) {
         return isSubClass(cType, (JClassType) qType);
       } else if (qType instanceof JInterfaceType) {
-        return getOrCreate(couldImplementMap, cType).contains(qType);
+        return get(couldImplementMap, cType).contains(qType);
       }
     } else if (type instanceof JInterfaceType) {
 
       JInterfaceType iType = (JInterfaceType) type;
       if (qType instanceof JClassType) {
-        return getOrCreate(couldBeImplementedMap, iType).contains(qType);
+        return get(couldBeImplementedMap, iType).contains(qType);
       }
     } else if (type instanceof JNullType) {
     }
@@ -376,15 +376,15 @@
 
   /**
    * Returns <code>true</code> if a static field access of <code>toType</code>
-   * from within <code>fromType</code> should generate a clinit call. This will
-   * be true in cases where <code>toType</code> has a live clinit method which
-   * we cannot statically know has already run. We can statically know the
+   * from within <code>fromType</code> should generate a clinit call. This
+   * will be true in cases where <code>toType</code> has a live clinit method
+   * which we cannot statically know has already run. We can statically know the
    * clinit method has already run when:
    * <ol>
    * <li><code>fromType == toType</code></li>
-   * <li><code>toType</code> is a superclass of <code>fromType</code> (because
-   * <code>toType</code>'s clinit would have already run <code>fromType</code>'s
-   * clinit; see JLS 12.4)</li>
+   * <li><code>toType</code> is a superclass of <code>fromType</code>
+   * (because <code>toType</code>'s clinit would have already run
+   * <code>fromType</code>'s clinit; see JLS 12.4)</li>
    * </ol>
    */
   public boolean checkClinit(JReferenceType fromType, JReferenceType toType) {
@@ -446,7 +446,7 @@
    * Returns true if qType is a superinterface of type, directly or indirectly.
    */
   public boolean extendsInterface(JInterfaceType type, JInterfaceType qType) {
-    return getOrCreate(superInterfaceMap, type).contains(qType);
+    return get(superInterfaceMap, type).contains(qType);
   }
 
   public JMethod findConcreteImplementation(JMethod method,
@@ -471,7 +471,7 @@
    */
   public Set<JMethod> getAllOverrides(JMethod method,
       Set<JReferenceType> instantiatedTypes) {
-    Set<JMethod> results = new HashSet<JMethod>();
+    Set<JMethod> results = new IdentityHashSet<JMethod>();
     getAllRealOverrides(method, results);
     getAllVirtualOverrides(method, instantiatedTypes, results);
     return results;
@@ -483,7 +483,7 @@
    * overrides list will contain both A and B.
    */
   public Set<JMethod> getAllRealOverrides(JMethod method) {
-    Set<JMethod> results = new HashSet<JMethod>();
+    Set<JMethod> results = new IdentityHashSet<JMethod>();
     getAllRealOverrides(method, results);
     return results;
   }
@@ -495,7 +495,7 @@
    * override methods with identical signatures declared in unrelated classes.
    */
   public Set<JMethod> getAllVirtualOverrides(JMethod method) {
-    Set<JMethod> results = new HashSet<JMethod>();
+    Set<JMethod> results = new IdentityHashSet<JMethod>();
     getAllVirtualOverrides(method, instantiatedTypes, results);
     return results;
   }
@@ -517,7 +517,7 @@
    * indirectly.
    */
   public boolean implementsInterface(JClassType type, JInterfaceType qType) {
-    return getOrCreate(implementsMap, type).contains(qType);
+    return get(implementsMap, type).contains(qType);
   }
 
   public boolean isInstantiatedType(JReferenceType type) {
@@ -528,14 +528,14 @@
    * Returns true if qType is a subclass of type, directly or indirectly.
    */
   public boolean isSubClass(JClassType type, JClassType qType) {
-    return getOrCreate(subClassMap, type).contains(qType);
+    return get(subClassMap, type).contains(qType);
   }
 
   /**
    * Returns true if qType is a superclass of type, directly or indirectly.
    */
   public boolean isSuperClass(JClassType type, JClassType qType) {
-    return getOrCreate(superClassMap, type).contains(qType);
+    return get(superClassMap, type).contains(qType);
   }
 
   /**
@@ -544,7 +544,7 @@
    */
   public void recomputeAfterOptimizations() {
     hasClinitSet.clear();
-    Set<JReferenceType> computed = new HashSet<JReferenceType>();
+    Set<JReferenceType> computed = new IdentityHashSet<JReferenceType>();
     for (int i = 0; i < program.getDeclaredTypes().size(); ++i) {
       JReferenceType type = program.getDeclaredTypes().get(i);
       computeHasClinit(type, computed);
@@ -554,7 +554,7 @@
   }
 
   public void setInstantiatedTypes(Set<JReferenceType> instantiatedTypes) {
-    this.instantiatedTypes = new HashSet<JReferenceType>();
+    this.instantiatedTypes = new IdentityHashSet<JReferenceType>();
     this.instantiatedTypes.addAll(instantiatedTypes);
   }
 
@@ -567,27 +567,31 @@
    * super types or sub types.
    */
   private void computeCouldImplement(JClassType type) {
-    Set<JInterfaceType> couldImplementSet = getOrCreate(couldImplementMap, type);
+    Set<JInterfaceType> couldImplementSet = new IdentityHashSet<JInterfaceType>();
     // all of my direct implements are trivially true
-    couldImplementSet.addAll(getOrCreate(implementsMap, type));
+    couldImplementSet.addAll(get(implementsMap, type));
     List<JClassType> subclasses = new ArrayList<JClassType>();
-    subclasses.addAll(getOrCreate(subClassMap, type));
+    subclasses.addAll(get(subClassMap, type));
     for (JClassType subclass : subclasses) {
       for (JInterfaceType intf : subclass.implments) {
         couldImplementSet.add(intf);
-        for (JInterfaceType isup : getOrCreate(superInterfaceMap, intf)) {
+        for (JInterfaceType isup : get(superInterfaceMap, intf)) {
           couldImplementSet.add(isup);
         }
       }
     }
-    for (JInterfaceType couldImpl : couldImplementSet) {
-      add(couldBeImplementedMap, couldImpl, type);
+    if (!couldImplementSet.isEmpty()) {
+      couldImplementMap.put(type, IdentitySets.normalize(couldImplementSet));
+      for (JInterfaceType couldImpl : couldImplementSet) {
+        add(couldBeImplementedMap, couldImpl, type);
+      }
     }
   }
 
   private void computeHasClinit(JReferenceType type,
       Set<JReferenceType> computed) {
-    if (computeHasClinitRecursive(type, computed, new HashSet<JReferenceType>())) {
+    if (computeHasClinitRecursive(type, computed,
+        new IdentityHashSet<JReferenceType>())) {
       hasClinitSet.add(type);
     }
     computed.add(type);
@@ -631,20 +635,23 @@
    * Compute all of the things I implement directly, through super types.
    */
   private void computeImplements(JClassType type) {
-    Set<JInterfaceType> implementsSet = getOrCreate(implementsMap, type);
+    Set<JInterfaceType> implementsSet = new IdentityHashSet<JInterfaceType>();
     List<JClassType> list = new ArrayList<JClassType>();
     list.add(type);
-    list.addAll(getOrCreate(superClassMap, type));
+    list.addAll(get(superClassMap, type));
     for (JClassType superclass : list) {
       for (JInterfaceType intf : superclass.implments) {
         implementsSet.add(intf);
-        for (JInterfaceType isup : getOrCreate(superInterfaceMap, intf)) {
+        for (JInterfaceType isup : get(superInterfaceMap, intf)) {
           implementsSet.add(isup);
         }
       }
     }
-    for (JInterfaceType impl : implementsSet) {
-      add(isImplementedMap, impl, type);
+    if (!implementsSet.isEmpty()) {
+      implementsMap.put(type, IdentitySets.normalize(implementsSet));
+      for (JInterfaceType impl : implementsSet) {
+        add(isImplementedMap, impl, type);
+      }
     }
   }
 
@@ -728,8 +735,7 @@
      */
     for (JInterfaceType intf : type.implments) {
       computeVirtualUpRefs(type, intf);
-      Set<JInterfaceType> superIntfs = getOrCreate(superInterfaceMap, intf);
-      for (JInterfaceType superIntf : superIntfs) {
+      for (JInterfaceType superIntf : get(superInterfaceMap, intf)) {
         computeVirtualUpRefs(type, superIntf);
       }
     }
@@ -763,8 +769,7 @@
 
             Map<JClassType, Set<JMethod>> classToMethodMap = getOrCreateMap(
                 virtualUpRefMap, superMethod);
-            Set<JMethod> methodSet = getOrCreate(classToMethodMap, type);
-            methodSet.add(intfMethod);
+            add(classToMethodMap, type, intfMethod);
 
             // do not search additional super types
             continue outer;
@@ -774,20 +779,29 @@
     }
   }
 
+  private <K, V> Set<V> get(Map<K, Set<V>> map, K key) {
+    Set<V> set = map.get(key);
+    if (set == null) {
+      return Collections.emptySet();
+    }
+    return set;
+  }
+
   private void getAllRealOverrides(JMethod method, Set<JMethod> results) {
-    for (JMethod possibleOverride : method.overrides) {
+    for (JMethod possibleOverride : method.getOverrides()) {
       results.add(possibleOverride);
     }
   }
 
   private void getAllVirtualOverrides(JMethod method,
       Set<JReferenceType> instantiatedTypes, Set<JMethod> results) {
-    Map<JClassType, Set<JMethod>> overrideMap = getOrCreateMap(virtualUpRefMap,
-        method);
-    for (JClassType classType : overrideMap.keySet()) {
-      if (isInstantiatedType(classType, instantiatedTypes)) {
-        Set<JMethod> set = overrideMap.get(classType);
-        results.addAll(set);
+    Map<JClassType, Set<JMethod>> overrideMap = virtualUpRefMap.get(method);
+    if (overrideMap != null) {
+      for (JClassType classType : overrideMap.keySet()) {
+        if (isInstantiatedType(classType, instantiatedTypes)) {
+          Set<JMethod> set = overrideMap.get(classType);
+          results.addAll(set);
+        }
       }
     }
   }
@@ -795,7 +809,7 @@
   private <K, V> Set<V> getOrCreate(Map<K, Set<V>> map, K key) {
     Set<V> set = map.get(key);
     if (set == null) {
-      set = new HashSet<V>();
+      set = new IdentityHashSet<V>();
       map.put(key, set);
     }
     return set;
@@ -804,7 +818,7 @@
   private <K, K2, V> Map<K2, V> getOrCreateMap(Map<K, Map<K2, V>> map, K key) {
     Map<K2, V> map2 = map.get(key);
     if (map2 == null) {
-      map2 = new HashMap<K2, V>();
+      map2 = new IdentityHashMap<K2, V>();
       map.put(key, map2);
     }
     return map2;
@@ -818,11 +832,14 @@
    * Record the all of my super classes (and myself as a subclass of them).
    */
   private void recordSuperSubInfo(JClassType type) {
-    Set<JClassType> superSet = getOrCreate(superClassMap, type);
+    Set<JClassType> superSet = new IdentityHashSet<JClassType>();
     for (JClassType t = type.extnds; t != null; t = t.extnds) {
       superSet.add(t);
       add(subClassMap, t, type);
     }
+    if (!superSet.isEmpty()) {
+      superClassMap.put(type, IdentitySets.normalize(superSet));
+    }
   }
 
   /**
@@ -830,8 +847,11 @@
    * them).
    */
   private void recordSuperSubInfo(JInterfaceType type) {
-    Set<JInterfaceType> superSet = getOrCreate(superInterfaceMap, type);
-    recordSuperSubInfo(type, superSet, type);
+    if (!type.implments.isEmpty()) {
+      Set<JInterfaceType> superSet = new IdentityHashSet<JInterfaceType>();
+      recordSuperSubInfo(type, superSet, type);
+      superInterfaceMap.put(type, IdentitySets.normalize(superSet));
+    }
   }
 
   /**
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
index 4d9bd7c..b552eb8 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
@@ -94,7 +94,7 @@
     return (JStatement) accept((JNode) node);
   }
 
-  public void accept(List<? extends JNode> list) {
+  public <T extends JNode> void accept(List<T> list) {
     int i = 0;
     try {
       for (int c = list.size(); i < c; ++i) {
@@ -105,8 +105,18 @@
     }
   }
 
-  public void acceptWithInsertRemove(List<? extends JNode> list) {
+  public <T extends JNode> List<T> acceptImmutable(List<T> list) {
     accept(list);
+    return list;
+  }
+
+  public <T extends JNode> void acceptWithInsertRemove(List<T> list) {
+    accept(list);
+  }
+
+  public <T extends JNode> List<T> acceptWithInsertRemoveImmutable(List<T> list) {
+    accept(list);
+    return list;
   }
 
   public boolean didChange() {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodBody.java b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodBody.java
index 7095710..d59de78 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodBody.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/js/JsniMethodBody.java
@@ -25,9 +25,11 @@
 import com.google.gwt.dev.js.ast.JsFunction;
 import com.google.gwt.dev.js.ast.JsStringLiteral;
 import com.google.gwt.dev.js.ast.JsVisitor;
+import com.google.gwt.dev.util.collect.HashSet;
+import com.google.gwt.dev.util.collect.Lists;
+import com.google.gwt.dev.util.collect.Sets;
 
-import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -36,21 +38,49 @@
  */
 public class JsniMethodBody extends JAbstractMethodBody {
 
-  public final List<JsniFieldRef> jsniFieldRefs = new ArrayList<JsniFieldRef>();
-  public final List<JsniMethodRef> jsniMethodRefs = new ArrayList<JsniMethodRef>();
-  private final Set<String> stringLiterals = new HashSet<String>();
-
   private JsFunction jsFunction = null;
+  private List<JsniFieldRef> jsniFieldRefs = Collections.emptyList();
+  private List<JsniMethodRef> jsniMethodRefs = Collections.emptyList();
+
+  private Set<String> stringLiterals = Collections.emptySet();
 
   public JsniMethodBody(JProgram program, SourceInfo info) {
     super(program, info);
   }
 
+  /**
+   * Adds a reference from this method to a Java field.
+   */
+  public void addJsniRef(JsniFieldRef ref) {
+    jsniFieldRefs = Lists.add(jsniFieldRefs, ref);
+  }
+
+  /**
+   * Adds a reference from this method to a Java method.
+   */
+  public void addJsniRef(JsniMethodRef ref) {
+    jsniMethodRefs = Lists.add(jsniMethodRefs, ref);
+  }
+
   public JsFunction getFunc() {
     assert (this.jsFunction != null);
     return jsFunction;
   }
 
+  /**
+   * Return this method's references to Java fields.
+   */
+  public List<JsniFieldRef> getJsniFieldRefs() {
+    return jsniFieldRefs;
+  }
+
+  /**
+   * Return this method's references to Java methods.
+   */
+  public List<JsniMethodRef> getJsniMethodRefs() {
+    return jsniMethodRefs;
+  }
+
   public Set<String> getUsedStrings() {
     return stringLiterals;
   }
@@ -63,19 +93,21 @@
   public void setFunc(JsFunction jsFunction) {
     assert (this.jsFunction == null);
     this.jsFunction = jsFunction;
+    final Set<String> result = new HashSet<String>();
     class RecordStrings extends JsVisitor {
       @Override
       public void endVisit(JsStringLiteral lit, JsContext<JsExpression> ctx) {
-        stringLiterals.add(lit.getValue());
+        result.add(lit.getValue());
       }
     }
     (new RecordStrings()).accept(jsFunction);
+    stringLiterals = Sets.normalize(result);
   }
 
   public void traverse(JVisitor visitor, Context ctx) {
     if (visitor.visit(this, ctx)) {
-      visitor.accept(jsniFieldRefs);
-      visitor.accept(jsniMethodRefs);
+      jsniFieldRefs = visitor.acceptImmutable(jsniFieldRefs);
+      jsniMethodRefs = visitor.acceptImmutable(jsniMethodRefs);
     }
     visitor.endVisit(this, ctx);
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java
index baddacc..009c79d 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ArrayNormalizer.java
@@ -66,9 +66,8 @@
             // replace this assignment with a call to setCheck()
             JMethodCall call = new JMethodCall(program, x.getSourceInfo(),
                 null, setCheckMethod);
-            call.getArgs().add(arrayRef.getInstance());
-            call.getArgs().add(arrayRef.getIndexExpr());
-            call.getArgs().add(x.getRhs());
+            call.addArgs(arrayRef.getInstance(), arrayRef.getIndexExpr(),
+                x.getRhs());
             ctx.replaceMe(call);
           }
         }
@@ -127,19 +126,16 @@
       JLiteral queryIdLit = program.getLiteralInt(tryGetQueryId(arrayType));
       JExpression dim = x.dims.get(0);
       JType elementType = arrayType.getElementType();
-      call.getArgs().add(classLit);
-      call.getArgs().add(typeIdLit);
-      call.getArgs().add(queryIdLit);
-      call.getArgs().add(dim);
-      call.getArgs().add(getSeedTypeLiteralFor(elementType));
+      call.addArgs(classLit, typeIdLit, queryIdLit, dim,
+          getSeedTypeLiteralFor(elementType));
       ctx.replaceMe(call);
     }
 
     private void processDims(JNewArray x, Context ctx, JArrayType arrayType,
         int dims) {
       // override the type of the called method with the array's type
-      SourceInfo sourceInfo = x.getSourceInfo().makeChild(
-          ArrayVisitor.class, "Creating dimensions");
+      SourceInfo sourceInfo = x.getSourceInfo().makeChild(ArrayVisitor.class,
+          "Creating dimensions");
       JMethodCall call = new JMethodCall(program, sourceInfo, null, initDims,
           arrayType);
       JsonArray classLitList = new JsonArray(program, sourceInfo);
@@ -163,20 +159,16 @@
         dimList.exprs.add(x.dims.get(i));
         cur = curArrayType.getElementType();
       }
-      call.getArgs().add(classLitList);
-      call.getArgs().add(typeIdList);
-      call.getArgs().add(queryIdList);
-      call.getArgs().add(dimList);
-      call.getArgs().add(program.getLiteralInt(dims));
-      call.getArgs().add(getSeedTypeLiteralFor(cur));
+      call.addArgs(classLitList, typeIdList, queryIdList, dimList,
+          program.getLiteralInt(dims), getSeedTypeLiteralFor(cur));
       ctx.replaceMe(call);
     }
 
     private void processInitializers(JNewArray x, Context ctx,
         JArrayType arrayType) {
       // override the type of the called method with the array's type
-      SourceInfo sourceInfo = x.getSourceInfo().makeChild(
-          ArrayVisitor.class, "Array initializer");
+      SourceInfo sourceInfo = x.getSourceInfo().makeChild(ArrayVisitor.class,
+          "Array initializer");
       JMethodCall call = new JMethodCall(program, sourceInfo, null, initValues,
           arrayType);
       JLiteral classLit = x.getClassLiteral();
@@ -186,10 +178,7 @@
       for (int i = 0; i < x.initializers.size(); ++i) {
         initList.exprs.add(x.initializers.get(i));
       }
-      call.getArgs().add(classLit);
-      call.getArgs().add(typeIdLit);
-      call.getArgs().add(queryIdLit);
-      call.getArgs().add(initList);
+      call.addArgs(classLit, typeIdLit, queryIdLit, initList);
       ctx.replaceMe(call);
     }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/AssertionNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/AssertionNormalizer.java
index 0120829..d190e77 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/AssertionNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/AssertionNormalizer.java
@@ -46,7 +46,7 @@
       JMethodCall rhs = new JMethodCall(program, x.getSourceInfo(), null,
           method);
       if (x.getArg() != null) {
-        rhs.getArgs().add(x.getArg());
+        rhs.addArg(x.getArg());
       }
       JBinaryOperation binOp = new JBinaryOperation(program, x.getSourceInfo(),
           program.getTypePrimitiveBoolean(), JBinaryOperator.OR, lhs, rhs);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/AutoboxUtils.java b/dev/core/src/com/google/gwt/dev/jjs/impl/AutoboxUtils.java
index 185dbad..94c70d4 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/AutoboxUtils.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/AutoboxUtils.java
@@ -112,8 +112,8 @@
     JMethod valueOfMethod = null;
     for (JMethod method : wrapperType.methods) {
       if ("valueOf".equals(method.getName())) {
-        if (method.params.size() == 1) {
-          JParameter param = method.params.get(0);
+        if (method.getParams().size() == 1) {
+          JParameter param = method.getParams().get(0);
           if (param.getType() == primitiveType) {
             // Found it.
             valueOfMethod = method;
@@ -135,7 +135,7 @@
     // Create the boxing call.
     JMethodCall call = new JMethodCall(program, toBox.getSourceInfo(), null,
         valueOfMethod);
-    call.getArgs().add(toBox);
+    call.addArg(toBox);
     return call;
   }
 
@@ -170,7 +170,7 @@
     for (JReferenceType boxType : boxTypes) {
       if (boxType != null) {
         for (JMethod method : boxType.methods) {
-          if (!method.isStatic() && method.params.isEmpty()
+          if (!method.isStatic() && method.getParams().isEmpty()
               && method.getName().endsWith("Value")
               && (method.getType() instanceof JPrimitiveType)) {
             unboxMethods.add(method);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
index b451d7b..16daf63 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
@@ -21,7 +21,6 @@
 import com.google.gwt.dev.jjs.SourceInfo;
 import com.google.gwt.dev.jjs.ast.JClassType;
 import com.google.gwt.dev.jjs.ast.JEnumType;
-import com.google.gwt.dev.jjs.ast.JExpression;
 import com.google.gwt.dev.jjs.ast.JField;
 import com.google.gwt.dev.jjs.ast.JInterfaceType;
 import com.google.gwt.dev.jjs.ast.JLocal;
@@ -35,7 +34,6 @@
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JReferenceType;
 import com.google.gwt.dev.jjs.ast.JReturnStatement;
-import com.google.gwt.dev.jjs.ast.JStatement;
 import com.google.gwt.dev.jjs.ast.JType;
 import com.google.gwt.dev.jjs.ast.JField.Disposition;
 import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
@@ -178,7 +176,6 @@
         JMethod newMethod = program.createMethod(info, name.toCharArray(),
             enclosingType, enclosingType, false, false, true, b.isPrivate(),
             false);
-        mapThrownExceptions(newMethod, b);
 
         // Enums have hidden arguments for name and value
         if (enclosingType.isEnumOrSubclass() != null) {
@@ -420,8 +417,6 @@
       JMethodCall call = new JMethodCall(program,
           type.getSourceInfo().makeChild(BuildDeclMapVisitor.class,
               "constructor invocation"), newInstance, constructor);
-      List<JExpression> args = call.getArgs();
-
       /*
        * If the type isn't static, make the first parameter a reference to the
        * instance of the enclosing class. It's the first instance to allow the
@@ -439,14 +434,14 @@
        * In one pass, add the parameters to the synthetic constructor and
        * arguments to the method call.
        */
-      for (Iterator<JParameter> i = constructor.params.iterator(); i.hasNext();) {
+      for (Iterator<JParameter> i = constructor.getParams().iterator(); i.hasNext();) {
         JParameter param = i.next();
         /*
          * This supports x.new Inner() by passing the enclosing instance
          * implicitly as the last argument to the constructor.
          */
         if (enclosingInstance != null && !i.hasNext()) {
-          args.add(new JParameterRef(program,
+          call.addArg(new JParameterRef(program,
               synthetic.getSourceInfo().makeChild(BuildDeclMapVisitor.class,
                   "enclosing instance"), enclosingInstance));
         } else {
@@ -455,7 +450,7 @@
                   "Argument " + param.getName()),
               param.getName().toCharArray(), param.getType(), true, false,
               synthetic);
-          args.add(new JParameterRef(program,
+          call.addArg(new JParameterRef(program,
               syntheticParam.getSourceInfo().makeChild(
                   BuildDeclMapVisitor.class, "reference"), syntheticParam));
         }
@@ -471,8 +466,7 @@
 
       // Add the return statement to the method body
       JMethodBody body = (JMethodBody) synthetic.getBody();
-      List<JStatement> statements = body.getStatements();
-      statements.add(ret);
+      body.getBlock().addStmt(ret);
 
       // Done
       return synthetic;
@@ -542,16 +536,6 @@
       method.freezeParamTypes();
     }
 
-    private void mapThrownExceptions(JMethod method, MethodBinding b) {
-      if (b.thrownExceptions != null) {
-        for (int i = 0; i < b.thrownExceptions.length; ++i) {
-          ReferenceBinding refBinding = b.thrownExceptions[i];
-          JClassType thrownException = (JClassType) typeMap.get(refBinding);
-          method.thrownExceptions.add(thrownException);
-        }
-      }
-    }
-
     /**
      * Add synthetic fields, setup super types. You'll notice that we DON'T have
      * any concept of "inner" or "outer" types in our AST. Truth is, we found it
@@ -674,7 +658,6 @@
           returnType, b.isAbstract(), b.isStatic(), b.isFinal(), b.isPrivate(),
           b.isNative());
 
-      mapThrownExceptions(newMethod, b);
       typeMap.put(b, newMethod);
       return newMethod;
     }
@@ -717,8 +700,8 @@
       //
       String syntheticFnHeader = "function (";
       boolean first = true;
-      for (int i = 0; i < newMethod.params.size(); ++i) {
-        JParameter param = newMethod.params.get(i);
+      for (int i = 0; i < newMethod.getParams().size(); ++i) {
+        JParameter param = newMethod.getParams().get(i);
         if (first) {
           first = false;
         } else {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
index 0f2a55d..ed0c1cb 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
@@ -369,14 +369,14 @@
           // Replace with Cast.charToString(c)
           JMethodCall call = new JMethodCall(program, expr.getSourceInfo(),
               null, program.getIndexedMethod("Cast.charToString"));
-          call.getArgs().add(expr);
+          call.addArg(expr);
           return call;
         }
       } else if (expr.getType() == program.getTypePrimitiveLong()) {
         // Replace with LongLib.toString(l)
         JMethodCall call = new JMethodCall(program, expr.getSourceInfo(), null,
             program.getIndexedMethod("LongLib.toString"));
-        call.getArgs().add(expr);
+        call.addArg(expr);
         return call;
       }
       return expr;
@@ -404,7 +404,7 @@
         JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
             castMethod, type);
         x.setType(program.getTypePrimitiveDouble());
-        call.getArgs().add(x);
+        call.addArg(x);
         ctx.replaceMe(call);
       }
     }
@@ -445,7 +445,7 @@
          */
         JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
             method, program.getTypeNull());
-        call.getArgs().add(expr);
+        call.addArg(expr);
         replaceExpr = call;
       } else if (toType instanceof JReferenceType) {
         JExpression curExpr = expr;
@@ -471,10 +471,10 @@
           // override the type of the called method with the target cast type
           JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
               method, toType);
-          call.getArgs().add(curExpr);
+          call.addArg(curExpr);
           if (!isJsoCast) {
             JIntLiteral qId = program.getLiteralInt(queryIds.get(refType));
-            call.getArgs().add(qId);
+            call.addArg(qId);
           }
           replaceExpr = call;
         }
@@ -505,7 +505,7 @@
             JMethod castMethod = program.getIndexedMethod("LongLib.toInt");
             JMethodCall call = new JMethodCall(program, x.getSourceInfo(),
                 null, castMethod);
-            call.getArgs().add(expr);
+            call.addArg(expr);
             expr = call;
             fromType = tInt;
           } else if (tInt == toType) {
@@ -550,7 +550,7 @@
           JMethod castMethod = program.getIndexedMethod(methodName);
           JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
               castMethod, toType);
-          call.getArgs().add(expr);
+          call.addArg(expr);
           replaceExpr = call;
         } else {
           // Just remove the cast
@@ -583,10 +583,10 @@
         }
         JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
             method);
-        call.getArgs().add(x.getExpr());
+        call.addArg(x.getExpr());
         if (!isJsoCast) {
           JIntLiteral qId = program.getLiteralInt(queryIds.get(toType));
-          call.getArgs().add(qId);
+          call.addArg(qId);
         }
         ctx.replaceMe(call);
       }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CatchBlockNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CatchBlockNormalizer.java
index 14aa9f9..87eb406 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CatchBlockNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CatchBlockNormalizer.java
@@ -70,10 +70,10 @@
       // $e = Exceptions.caught($e)
       JMethod caughtMethod = program.getIndexedMethod("Exceptions.caught");
       JMethodCall call = new JMethodCall(program, catchInfo, null, caughtMethod);
-      call.getArgs().add(exRef);
+      call.addArg(exRef);
       JExpressionStatement asg = program.createAssignmentStmt(catchInfo, exRef,
           call);
-      newCatchBlock.statements.add(asg);
+      newCatchBlock.addStmt(asg);
 
       /*
        * Build up a series of if, else if statements to test the type of the
@@ -91,15 +91,15 @@
         // if ($e instanceof ArgType) { userVar = $e; <user code> }
         JExpression ifTest = new JInstanceOf(program, catchInfo, argType, exRef);
         asg = program.createAssignmentStmt(catchInfo, arg, exRef);
-        if (!block.statements.isEmpty()) {
+        if (!block.getStatements().isEmpty()) {
           // Only bother adding the assignment if the block is non-empty
-          block.statements.add(0, asg);
+          block.addStmt(0, asg);
         }
         // nest the previous as an else for me
         cur = new JIfStatement(program, catchInfo, ifTest, block, cur);
       }
 
-      newCatchBlock.statements.add(cur);
+      newCatchBlock.addStmt(cur);
       x.getCatchArgs().clear();
       x.getCatchArgs().add(exRef);
       x.getCatchBlocks().clear();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
index 7e3455c..c7d6e6b 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
@@ -223,7 +223,7 @@
       newMethodCall.setCannotBePolymorphic();
     }
 
-    newMethodCall.getArgs().addAll(cloneExpressions(x.getArgs()));
+    newMethodCall.addArgs(cloneExpressions(x.getArgs()));
 
     expression = newMethodCall;
     return false;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
index 5158466..33547fe 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
@@ -316,7 +316,7 @@
               // JParameter
               int index = func.getParameters().indexOf(ident.getStaticRef());
               if (index != -1) {
-                rescue(x.params.get(index));
+                rescue(x.getParams().get(index));
               }
             }
           }
@@ -404,7 +404,7 @@
        * SPECIAL: each argument of the call passes a value from JavaScript into
        * Java.
        */
-      ArrayList<JParameter> params = x.getTarget().params;
+      List<JParameter> params = x.getTarget().getParams();
       for (int i = 0, c = params.size(); i < c; ++i) {
         JParameter param = params.get(i);
         maybeRescueJavaScriptObjectPassingIntoJava(param.getType());
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
index 81370c1..006a167 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
@@ -84,8 +84,8 @@
    * operations in favor of pure side effects.
    * 
    * TODO(spoon): move more simplifications into methods like
-   * {@link #cast(JExpression, SourceInfo, JType, JExpression) simplifyCast}, so
-   * that more simplifications can be made on a single pass through a tree.
+   * {@link #cast(JExpression, SourceInfo, JType, JExpression) simplifyCast},
+   * so that more simplifications can be made on a single pass through a tree.
    */
   public class DeadCodeVisitor extends JModVisitor {
 
@@ -94,8 +94,8 @@
     /**
      * Expressions whose result does not matter. A parent node should add any
      * children whose result does not matter to this set during the parent's
-     * <code>visit()</code> method. It should then remove those children during
-     * its own <code>endVisit()</code>.
+     * <code>visit()</code> method. It should then remove those children
+     * during its own <code>endVisit()</code>.
      * 
      * TODO: there's a latent bug here: some immutable nodes (such as literals)
      * can be multiply referenced in the AST. In theory, one reference to that
@@ -199,8 +199,8 @@
        * Remove any dead statements after an abrupt change in code flow and
        * promote safe statements within nested blocks to this block.
        */
-      for (int i = 0; i < x.statements.size(); i++) {
-        JStatement stmt = x.statements.get(i);
+      for (int i = 0; i < x.getStatements().size(); i++) {
+        JStatement stmt = x.getStatements().get(i);
 
         if (stmt instanceof JBlock) {
           /*
@@ -209,8 +209,8 @@
            */
           JBlock block = (JBlock) stmt;
           if (canPromoteBlock(block)) {
-            x.statements.remove(i);
-            x.statements.addAll(i, block.statements);
+            x.removeStmt(i);
+            x.addStmts(i, block.getStatements());
             i--;
             didChange = true;
             continue;
@@ -221,11 +221,11 @@
           JExpressionStatement stmtExpr = (JExpressionStatement) stmt;
           if (stmtExpr.getExpr() instanceof JMultiExpression) {
             // Promote a multi's expressions to the current block
-            x.statements.remove(i);
+            x.removeStmt(i);
             int start = i;
             JMultiExpression multi = ((JMultiExpression) stmtExpr.getExpr());
             for (JExpression expr : multi.exprs) {
-              x.statements.add(i++, expr.makeStatement());
+              x.addStmt(i++, expr.makeStatement());
             }
             i = start - 1;
             continue;
@@ -234,14 +234,14 @@
 
         if (stmt.unconditionalControlBreak()) {
           // Abrupt change in flow, chop the remaining items from this block
-          for (int j = i + 1; j < x.statements.size();) {
-            x.statements.remove(j);
+          for (int j = i + 1; j < x.getStatements().size();) {
+            x.removeStmt(j);
             didChange = true;
           }
         }
       }
 
-      if (ctx.canRemove() && x.statements.size() == 0) {
+      if (ctx.canRemove() && x.getStatements().size() == 0) {
         // Remove blocks with no effect
         ctx.removeMe();
       }
@@ -349,7 +349,7 @@
         // If false, replace the for statement with its initializers
         if (!booleanLiteral.getValue()) {
           JBlock block = new JBlock(program, x.getSourceInfo());
-          block.statements.addAll(x.getInitializers());
+          block.addStmts(x.getInitializers());
           ctx.replaceMe(block);
         }
       }
@@ -386,16 +386,13 @@
       if (target.isStatic() && x.getInstance() != null) {
         ignoringExpressionOutput.remove(x.getInstance());
       }
-      List<JExpression> args = x.getArgs();
-      int paramCount = target.params.size();
-      List<JExpression> ignoredArgs = args.subList(paramCount, args.size());
-      ignoringExpressionOutput.removeAll(ignoredArgs);
 
-      for (int i = 0; i < ignoredArgs.size(); ++i) {
-        JExpression arg = ignoredArgs.get(i);
+      int paramCount = target.getParams().size();
+      for (int i = paramCount; i < x.getArgs().size(); ++i) {
+        JExpression arg = x.getArgs().get(i);
+        ignoringExpressionOutput.remove(arg);
         if (!arg.hasSideEffects()) {
-          ignoredArgs.remove(i);
-          --i;
+          x.removeArg(i--);
           didChange = true;
         }
       }
@@ -608,7 +605,7 @@
         ignoringExpressionOutput.add(x.getInstance());
       }
       List<JExpression> args = x.getArgs();
-      List<JExpression> ignoredArgs = args.subList(target.params.size(),
+      List<JExpression> ignoredArgs = args.subList(target.getParams().size(),
           args.size());
       ignoringExpressionOutput.addAll(ignoredArgs);
       return true;
@@ -651,7 +648,7 @@
      * when the block contains no local declarations.
      */
     private boolean canPromoteBlock(JBlock block) {
-      for (JStatement nestedStmt : block.statements) {
+      for (JStatement nestedStmt : block.getStatements()) {
         if (nestedStmt instanceof JDeclarationStatement) {
           JDeclarationStatement decl = (JDeclarationStatement) nestedStmt;
           if (decl.getVariableRef() instanceof JLocalRef) {
@@ -1013,7 +1010,7 @@
         return (JBreakStatement) statement;
       } else if (statement instanceof JBlock) {
         JBlock block = (JBlock) statement;
-        List<JStatement> blockStmts = block.statements;
+        List<JStatement> blockStmts = block.getStatements();
         if (blockStmts.size() > 0 && isUnconditionalBreak(blockStmts.get(0))) {
           return (JBreakStatement) blockStmts.get(0);
         }
@@ -1024,7 +1021,7 @@
     private boolean hasNoDefaultCase(JSwitchStatement x) {
       JBlock body = x.getBody();
       boolean inDefault = false;
-      for (JStatement statement : body.statements) {
+      for (JStatement statement : body.getStatements()) {
         if (statement instanceof JCaseStatement) {
           JCaseStatement caseStmt = (JCaseStatement) statement;
           if (caseStmt.getExpr() == null) {
@@ -1210,20 +1207,20 @@
     private void removeDoubleBreaks(JSwitchStatement x) {
       JBlock body = x.getBody();
       boolean lastWasBreak = true;
-      for (Iterator<JStatement> it = body.statements.iterator(); it.hasNext();) {
-        JStatement statement = it.next();
+      for (int i = 0; i < body.getStatements().size(); ++i) {
+        JStatement statement = body.getStatements().get(i);
         boolean isBreak = isUnconditionalBreak(statement);
         if (isBreak && lastWasBreak) {
-          it.remove();
+          body.removeStmt(i--);
           didChange = true;
         }
         lastWasBreak = isBreak;
       }
 
       // Remove a trailing break statement from a case block
-      if (body.statements.size() > 0
-          && isUnconditionalUnlabeledBreak(last(body.statements))) {
-        body.statements.remove(body.statements.size() - 1);
+      if (body.getStatements().size() > 0
+          && isUnconditionalUnlabeledBreak(last(body.getStatements()))) {
+        body.removeStmt(body.getStatements().size() - 1);
         didChange = true;
       }
     }
@@ -1239,7 +1236,7 @@
        * A case statement has no effect if there is no code between it and
        * either an unconditional break or the end of the switch.
        */
-      for (JStatement statement : body.statements) {
+      for (JStatement statement : body.getStatements()) {
         if (statement instanceof JCaseStatement) {
           potentialNoOpCaseStatements.add(statement);
         } else if (isUnconditionalUnlabeledBreak(statement)) {
@@ -1256,7 +1253,7 @@
 
       if (noOpCaseStatements.size() > 0) {
         for (JStatement statement : noOpCaseStatements) {
-          body.statements.remove(statement);
+          body.removeStmt(body.getStatements().indexOf(statement));
           didChange = true;
         }
       }
@@ -1346,8 +1343,8 @@
     }
 
     /**
-     * Simplify <code>exp == bool</code>, where <code>bool</code> is a boolean
-     * literal.
+     * Simplify <code>exp == bool</code>, where <code>bool</code> is a
+     * boolean literal.
      */
     private void simplifyBooleanEq(JExpression exp, boolean bool, Context ctx) {
       if (bool) {
@@ -1361,8 +1358,8 @@
     /**
      * Simplify <code>lhs == rhs</code>, where <code>lhs</code> and
      * <code>rhs</code> are known to be boolean. If <code>negate</code> is
-     * <code>true</code>, then treat it as <code>lhs != rhs</code> instead of
-     * <code>lhs == rhs</code>. Assumes that the case where both sides are
+     * <code>true</code>, then treat it as <code>lhs != rhs</code> instead
+     * of <code>lhs == rhs</code>. Assumes that the case where both sides are
      * literals has already been checked.
      */
     private void simplifyBooleanEq(JExpression lhs, JExpression rhs,
@@ -1394,8 +1391,8 @@
     }
 
     /**
-     * Simplify <code>lhs == rhs</code>. If <code>negate</code> is true, then
-     * it's actually static evaluation of <code>lhs != rhs</code>.
+     * Simplify <code>lhs == rhs</code>. If <code>negate</code> is true,
+     * then it's actually static evaluation of <code>lhs != rhs</code>.
      */
     private void simplifyEq(JExpression lhs, JExpression rhs, Context ctx,
         boolean negated) {
@@ -1579,7 +1576,7 @@
         return;
       }
 
-      if (method.getOriginalParamTypes().size() != method.params.size()) {
+      if (method.getOriginalParamTypes().size() != method.getParams().size()) {
         // One or more parameters were pruned, abort.
         return;
       }
@@ -1609,7 +1606,7 @@
       List<JType> params = method.getOriginalParamTypes();
       Class<?> paramTypes[] = new Class<?>[params.size()];
       Object paramValues[] = new Object[params.size()];
-      ArrayList<JExpression> args = x.getArgs();
+      List<JExpression> args = x.getArgs();
       for (int i = 0; i != params.size(); ++i) {
         paramTypes[i] = mapType(params.get(i));
         if (paramTypes[i] == null) {
@@ -1644,10 +1641,10 @@
 
     private void tryRemoveSwitch(JSwitchStatement x, Context ctx) {
       JBlock body = x.getBody();
-      if (body.statements.size() == 0) {
+      if (body.getStatements().size() == 0) {
         // Empty switch; just run the switch condition.
         ctx.replaceMe(x.getExpr().makeStatement());
-      } else if (body.statements.size() == 2) {
+      } else if (body.getStatements().size() == 2) {
         /*
          * If there are only two statements, we know it's a case statement and
          * something with an effect.
@@ -1667,8 +1664,9 @@
          * 
          * becomes if (i == 1) { a(); b(); } else { c(); d(); }
          */
-        JCaseStatement caseStatement = (JCaseStatement) body.statements.get(0);
-        JStatement statement = body.statements.get(1);
+        JCaseStatement caseStatement = (JCaseStatement) body.getStatements().get(
+            0);
+        JStatement statement = body.getStatements().get(1);
 
         FindBreakContinueStatementsVisitor visitor = new FindBreakContinueStatementsVisitor();
         visitor.accept(statement);
@@ -1683,15 +1681,15 @@
               x.getSourceInfo(), program.getTypePrimitiveBoolean(),
               JBinaryOperator.EQ, x.getExpr(), caseStatement.getExpr());
           JBlock block = new JBlock(program, x.getSourceInfo());
-          block.statements.add(statement);
+          block.addStmt(statement);
           JIfStatement ifStatement = new JIfStatement(program,
               x.getSourceInfo(), compareOperation, block, null);
           ctx.replaceMe(ifStatement);
         } else {
           // All we have is a default case; convert to a JBlock.
           JBlock block = new JBlock(program, x.getSourceInfo());
-          block.statements.add(x.getExpr().makeStatement());
-          block.statements.add(statement);
+          block.addStmt(x.getExpr().makeStatement());
+          block.addStmt(statement);
           ctx.replaceMe(block);
         }
       }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/EqualityNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/EqualityNormalizer.java
index 4c3e437..56145f5 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/EqualityNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/EqualityNormalizer.java
@@ -110,7 +110,7 @@
           JMethod isNullMethod = program.getIndexedMethod(methodName);
           JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
               isNullMethod);
-          call.getArgs().add(lhsNullLit ? rhs : lhs);
+          call.addArg(lhsNullLit ? rhs : lhs);
           ctx.replaceMe(call);
         } else {
           // Replace with a call to Cast.jsEquals, which does a == internally.
@@ -123,8 +123,7 @@
           JMethod eqMethod = program.getIndexedMethod(methodName);
           JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
               eqMethod);
-          call.getArgs().add(lhs);
-          call.getArgs().add(rhs);
+          call.addArgs(lhs, rhs);
           ctx.replaceMe(call);
         }
       }
@@ -147,7 +146,7 @@
       JMethod maskMethod = program.getIndexedMethod("Cast.maskUndefined");
       JMethodCall lhsCall = new JMethodCall(program, lhs.getSourceInfo(), null,
           maskMethod, lhs.getType());
-      lhsCall.getArgs().add(lhs);
+      lhsCall.addArg(lhs);
       return lhsCall;
     }
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Finalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Finalizer.java
index b442d0a..f0595be 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Finalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Finalizer.java
@@ -97,7 +97,9 @@
 
     @Override
     public boolean visit(JMethodBody x, Context ctx) {
-      accept(x.locals);
+      for (JLocal local : x.getLocals()) {
+        maybeFinalize(local);
+      }
       return false;
     }
 
@@ -139,8 +141,8 @@
 
     @Override
     public void endVisit(JMethod x, Context ctx) {
-      for (int i = 0; i < x.overrides.size(); ++i) {
-        JMethod it = x.overrides.get(i);
+      for (int i = 0; i < x.getOverrides().size(); ++i) {
+        JMethod it = x.getOverrides().get(i);
         isOverriden.add(it);
       }
     }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
index 10d0c95..54db41e 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
@@ -339,16 +339,16 @@
       for (JMethod method : type.methods) {
         currentMethod = method;
         if ("values".equals(method.getName())) {
-          if (method.params.size() != 0) {
+          if (method.getParams().size() != 0) {
             continue;
           }
           currentMethodBody = (JMethodBody) method.getBody();
           writeEnumValuesMethod(type);
         } else if ("valueOf".equals(method.getName())) {
-          if (method.params.size() != 1) {
+          if (method.getParams().size() != 1) {
             continue;
           }
-          if (method.params.get(0).getType() != program.getTypeJavaLangString()) {
+          if (method.getParams().get(0).getType() != program.getTypeJavaLangString()) {
             continue;
           }
           currentMethodBody = (JMethodBody) method.getBody();
@@ -385,7 +385,7 @@
           JMethodCall superClinitCall = new JMethodCall(program,
               myClinit.getSourceInfo(), null, superClinit);
           JMethodBody body = (JMethodBody) myClinit.getBody();
-          body.getStatements().add(0, superClinitCall.makeStatement());
+          body.getBlock().addStmt(0, superClinitCall.makeStatement());
         }
 
         if (x.fields != null) {
@@ -678,8 +678,8 @@
         JMethodCall clinitCall = new JMethodCall(program, info, null,
             clinitMethod);
         JMethodBody body = (JMethodBody) ctor.getBody();
-        List<JStatement> statements = body.getStatements();
-        statements.add(clinitCall.makeStatement());
+        JBlock block = body.getBlock();
+        block.addStmt(clinitCall.makeStatement());
 
         /*
          * All synthetic fields must be assigned, unless we have an explicit
@@ -697,7 +697,7 @@
                 JParameter param = paramIt.next();
                 if (arg.matchingField != null) {
                   JField field = (JField) typeMap.get(arg);
-                  statements.add(program.createAssignmentStmt(info,
+                  block.addStmt(program.createAssignmentStmt(info,
                       createVariableRef(info, field), createVariableRef(info,
                           param)));
                 }
@@ -709,7 +709,7 @@
                 SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
                 JParameter param = paramIt.next();
                 JField field = (JField) typeMap.get(arg);
-                statements.add(program.createAssignmentStmt(info,
+                block.addStmt(program.createAssignmentStmt(info,
                     createVariableRef(info, field), createVariableRef(info,
                         param)));
               }
@@ -721,16 +721,16 @@
         if (enclosingType.isEnumOrSubclass() != null) {
           assert (superOrThisCall != null);
           JVariableRef enumNameRef = createVariableRef(
-              superOrThisCall.getSourceInfo(), ctor.params.get(0));
-          superOrThisCall.getArgs().add(0, enumNameRef);
+              superOrThisCall.getSourceInfo(), ctor.getParams().get(0));
+          superOrThisCall.addArg(0, enumNameRef);
           JVariableRef enumOrdinalRef = createVariableRef(
-              superOrThisCall.getSourceInfo(), ctor.params.get(1));
-          superOrThisCall.getArgs().add(1, enumOrdinalRef);
+              superOrThisCall.getSourceInfo(), ctor.getParams().get(1));
+          superOrThisCall.addArg(1, enumOrdinalRef);
         }
 
         // optional this or super constructor call
         if (superOrThisCall != null) {
-          statements.add(superOrThisCall.makeStatement());
+          block.addStmt(superOrThisCall.makeStatement());
         }
 
         JExpression thisRef = createThisRef(info, enclosingType);
@@ -744,7 +744,7 @@
           JMethod initMethod = enclosingType.methods.get(1);
           JMethodCall initCall = new JMethodCall(program, info, thisRef,
               initMethod);
-          statements.add(initCall.makeStatement());
+          block.addStmt(initCall.makeStatement());
         }
 
         // user code (finally!)
@@ -753,7 +753,7 @@
             Statement origStmt = x.statements[i];
             JStatement jstmt = dispProcessStatement(origStmt);
             if (jstmt != null) {
-              statements.add(jstmt);
+              block.addStmt(jstmt);
             }
           }
         }
@@ -762,7 +762,7 @@
         currentMethod = null;
 
         // synthesize a return statement to emulate returning the new object
-        statements.add(new JReturnStatement(program, info, thisRef));
+        block.addStmt(new JReturnStatement(program, info, thisRef));
       } catch (Throwable e) {
         throw translateException(ctor, e);
       }
@@ -790,15 +790,15 @@
          * constructor calls. We find a method named _String() whose signature
          * matches the requested constructor
          */
-        int ctorArgc = ctor.params.size();
+        int ctorArgc = ctor.getParams().size();
         JMethod targetMethod = null;
         outer : for (int j = 0; j < javaLangString.methods.size(); ++j) {
           JMethod method = javaLangString.methods.get(j);
           if (method.getName().equals("_String")
-              && method.params.size() == ctorArgc) {
+              && method.getParams().size() == ctorArgc) {
             for (int i = 0; i < ctorArgc; ++i) {
-              JParameter mparam = method.params.get(i);
-              JParameter cparam = ctor.params.get(i);
+              JParameter mparam = method.getParams().get(i);
+              JParameter cparam = ctor.getParams().get(i);
               if (mparam.getType() != cparam.getType()) {
                 continue outer;
               }
@@ -819,8 +819,7 @@
 
       // Enums: hidden arguments for the name and id.
       if (x.enumConstant != null) {
-        call.getArgs().add(program.getLiteralString(info, x.enumConstant.name));
-        call.getArgs().add(
+        call.addArgs(program.getLiteralString(info, x.enumConstant.name),
             program.getLiteralInt(x.enumConstant.binding.original().id));
       }
 
@@ -836,7 +835,7 @@
           for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
             SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
             JClassType syntheticThisType = (JClassType) typeMap.get(arg.type);
-            call.getArgs().add(createThisRef(info, syntheticThisType));
+            call.addArg(createThisRef(info, syntheticThisType));
           }
         }
         // Synthetic locals for local classes
@@ -844,8 +843,8 @@
           for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
             SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
             JVariable variable = (JVariable) typeMap.get(arg.actualOuterLocalVariable);
-            call.getArgs().add(
-                createVariableRef(info, variable, arg.actualOuterLocalVariable));
+            call.addArg(createVariableRef(info, variable,
+                arg.actualOuterLocalVariable));
           }
         }
       }
@@ -1261,7 +1260,7 @@
           for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
             SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
             JClassType syntheticThisType = (JClassType) typeMap.get(arg.type);
-            call.getArgs().add(createThisRef(syntheticThisType, qualList));
+            call.addArg(createThisRef(syntheticThisType, qualList));
           }
         }
         // Synthetic locals for local classes
@@ -1269,8 +1268,8 @@
           for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
             SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
             JVariable variable = (JVariable) typeMap.get(arg.actualOuterLocalVariable);
-            call.getArgs().add(
-                createVariableRef(info, variable, arg.actualOuterLocalVariable));
+            call.addArg(createVariableRef(info, variable,
+                arg.actualOuterLocalVariable));
           }
         }
       }
@@ -1462,7 +1461,7 @@
           JStatement decl = new JDeclarationStatement(program, info,
               createVariableRef(info, field), initializer);
           // will either be init or clinit
-          currentMethodBody.getStatements().add(decl);
+          currentMethodBody.getBlock().addStmt(decl);
         }
       } catch (Throwable e) {
         throw translateException(field, e);
@@ -1473,7 +1472,7 @@
       JBlock block = (JBlock) dispProcessStatement(initializer.block);
       try {
         // will either be init or clinit
-        currentMethodBody.getStatements().add(block);
+        currentMethodBody.getBlock().addStmt(block);
       } catch (Throwable e) {
         throw translateException(initializer, e);
       }
@@ -1501,7 +1500,7 @@
             Statement origStmt = x.statements[i];
             JStatement jstmt = dispProcessStatement(origStmt);
             if (jstmt != null) {
-              currentMethodBody.getStatements().add(jstmt);
+              currentMethodBody.getBlock().addStmt(jstmt);
             }
           }
         }
@@ -1537,7 +1536,7 @@
         for (int i = 0, n = x.statements.length; i < n; ++i) {
           JStatement jstmt = dispProcessStatement(x.statements[i]);
           if (jstmt != null) {
-            block.statements.add(jstmt);
+            block.addStmt(jstmt);
           }
         }
       }
@@ -1593,7 +1592,7 @@
         body = (JBlock) action;
       } else {
         body = new JBlock(program, info);
-        body.statements.add(action);
+        body.addStmt(action);
       }
 
       JLocal elementVar = (JLocal) typeMap.get(x.elementVariable.binding);
@@ -1647,7 +1646,7 @@
         elementDecl.initializer = new JArrayRef(program, info,
             createVariableRef(info, arrayVar),
             createVariableRef(info, indexVar));
-        body.statements.add(0, elementDecl);
+        body.addStmt(0, elementDecl);
 
         result = new JForStatement(program, info, initializers, condition,
             increments, body);
@@ -1697,7 +1696,7 @@
           elementDecl.initializer = maybeCast(toType, elementDecl.initializer);
         }
 
-        body.statements.add(0, elementDecl);
+        body.addStmt(0, elementDecl);
 
         result = new JForStatement(program, info, initializers, condition,
             Collections.<JExpressionStatement> emptyList(), body);
@@ -1797,14 +1796,14 @@
             program.getIndexedMethod("Enum.ordinal"));
       }
       JBlock block = new JBlock(program, info);
-      block.statements = processStatements(x.statements);
+      block.addStmts(processStatements(x.statements));
       return new JSwitchStatement(program, info, expression, block);
     }
 
     JStatement processStatement(SynchronizedStatement x) {
       JBlock block = (JBlock) dispProcessStatement(x.block);
       JExpression expr = dispProcessExpression(x.expression);
-      block.statements.add(0, expr.makeStatement());
+      block.addStmt(0, expr.makeStatement());
       return block;
     }
 
@@ -1899,9 +1898,9 @@
               for (ReferenceBinding b : myBinding.syntheticEnclosingInstanceTypes()) {
                 workList.add(createVariableRef(info, paramIt.next()));
               }
-              call.getArgs().add(createThisRef(classType, workList));
+              call.addArg(createThisRef(classType, workList));
             } else {
-              call.getArgs().add(createThisRef(classType, qualifier));
+              call.addArg(createThisRef(classType, qualifier));
             }
           }
         }
@@ -1913,8 +1912,8 @@
             JType varType = (JType) typeMap.get(arg.type);
             String varName = String.valueOf(arg.name);
             JParameter param = null;
-            for (int i = 0; i < currentMethod.params.size(); ++i) {
-              JParameter paramIt = currentMethod.params.get(i);
+            for (int i = 0; i < currentMethod.getParams().size(); ++i) {
+              JParameter paramIt = currentMethod.getParams().get(i);
               if (varType == paramIt.getType()
                   && varName.equals(paramIt.getName())) {
                 param = paramIt;
@@ -1924,7 +1923,7 @@
               throw new InternalCompilerException(
                   "Could not find matching local arg for explicit super ctor call.");
             }
-            call.getArgs().add(createVariableRef(info, param));
+            call.addArg(createVariableRef(info, param));
           }
         }
       }
@@ -1949,12 +1948,12 @@
         NestedTypeBinding nestedBinding = (NestedTypeBinding) erasure(declaringClass);
         if (nestedBinding.enclosingInstances != null) {
           for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
-            call.getArgs().add(createVariableRef(info, paramIt.next()));
+            call.addArg(createVariableRef(info, paramIt.next()));
           }
         }
         if (nestedBinding.outerLocalVariables != null) {
           for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
-            call.getArgs().add(createVariableRef(info, paramIt.next()));
+            call.addArg(createVariableRef(info, paramIt.next()));
           }
         }
       }
@@ -2000,10 +1999,8 @@
         return;
       }
 
-      ArrayList<JExpression> callArgs = call.getArgs();
-
       for (int i = 0; i < n; ++i) {
-        callArgs.add(dispProcessExpression(args[i]));
+        call.addArg(dispProcessExpression(args[i]));
       }
 
       if (binding.isVarargs()) {
@@ -2017,7 +2014,7 @@
             JArrayType lastArgArrayType = (JArrayType) lastArgType;
             if (lastArgArrayType.getDims() == type.getDims()) {
               // Looks like it's already an array.
-              callArgs.add(dispProcessExpression(args[n]));
+              call.addArg(dispProcessExpression(args[n]));
               return;
             }
           }
@@ -2029,13 +2026,13 @@
         }
         JNewArray newArray = JNewArray.createInitializers(program,
             call.getSourceInfo(), type, initializers);
-        callArgs.add(newArray);
+        call.addArg(newArray);
       }
     }
 
     private boolean classHasMethodOverriding(JClassType clazz, JMethod over) {
       for (JMethod meth : clazz.methods) {
-        if (meth.overrides.contains(over)) {
+        if (meth.getOverrides().contains(over)) {
           return true;
         }
       }
@@ -2050,12 +2047,13 @@
     /**
      * Create a bridge method. It calls a same-named method with the same
      * arguments, but with a different type signature.
+     * 
      * @param clazz The class to put the bridge method in
      * @param jdtBridgeMethod The corresponding bridge method added in the JDT
      * @param implmeth The implementation method to bridge to
      */
-    private void createBridgeMethod(JClassType clazz, SyntheticMethodBinding jdtBridgeMethod,
-        JMethod implmeth) {
+    private void createBridgeMethod(JClassType clazz,
+        SyntheticMethodBinding jdtBridgeMethod, JMethod implmeth) {
       SourceInfo info = program.createSourceInfoSynthetic(
           GenerateJavaAST.class, "bridge method");
 
@@ -2081,13 +2079,12 @@
               program.createSourceInfoSynthetic(GenerateJavaAST.class,
                   "part of a bridge method"), clazz), implmeth);
 
-      for (int i = 0; i < bridgeMethod.params.size(); i++) {
-        JParameter param = bridgeMethod.params.get(i);
+      for (int i = 0; i < bridgeMethod.getParams().size(); i++) {
+        JParameter param = bridgeMethod.getParams().get(i);
         JParameterRef paramRef = new JParameterRef(program,
             program.createSourceInfoSynthetic(GenerateJavaAST.class,
                 "part of a bridge method"), param);
-        call.getArgs().add(
-            maybeCast(implmeth.params.get(i).getType(), paramRef));
+        call.addArg(maybeCast(implmeth.getParams().get(i).getType(), paramRef));
       }
 
       // wrap it in a return if necessary
@@ -2102,7 +2099,7 @@
 
       // create a body that is just that call
       JMethodBody body = (JMethodBody) bridgeMethod.getBody();
-      body.getStatements().add(callOrReturn);
+      body.getBlock().addStmt(callOrReturn);
 
       // add overrides, but only for interface methods that the class does not
       // already override
@@ -2110,8 +2107,8 @@
       tryFindUpRefs(bridgeMethod, overrides);
       for (JMethod over : overrides) {
         if (!classHasMethodOverriding(clazz, over)) {
-          bridgeMethod.overrides.add(over);
-          bridgeMethod.overrides.addAll(over.overrides);
+          bridgeMethod.addOverride(over);
+          bridgeMethod.addOverrides(over.getOverrides());
         }
       }
     }
@@ -2142,7 +2139,7 @@
       JMethodBody clinitBody = (JMethodBody) type.methods.get(0).getBody();
       JExpressionStatement assignment = program.createAssignmentStmt(
           sourceInfo, createVariableRef(sourceInfo, mapField), map);
-      clinitBody.getStatements().add(assignment);
+      clinitBody.getBlock().addStmt(assignment);
       return mapField;
     }
 
@@ -2344,7 +2341,7 @@
      * parameters.
      */
     private Iterator<JParameter> getSyntheticsIterator() {
-      Iterator<JParameter> it = currentMethod.params.iterator();
+      Iterator<JParameter> it = currentMethod.getParams().iterator();
       for (int i = 0, c = currentMethod.getOriginalParamTypes().size(); i < c; ++i) {
         it.next();
       }
@@ -2354,17 +2351,17 @@
     private void implementMethod(JMethod method, JExpression returnValue) {
       assert method != null;
       JMethodBody body = (JMethodBody) method.getBody();
-      List<JStatement> statements = body.getStatements();
+      JBlock block = body.getBlock();
 
       SourceInfo info;
-      if (statements.size() > 0) {
-        info = statements.get(0).getSourceInfo();
+      if (block.getStatements().size() > 0) {
+        info = block.getStatements().get(0).getSourceInfo();
       } else {
         info = method.getSourceInfo();
       }
 
-      statements.clear();
-      statements.add(new JReturnStatement(program, info, returnValue));
+      block.clear();
+      block.addStmt(new JReturnStatement(program, info, returnValue));
     }
 
     /*
@@ -2372,8 +2369,8 @@
      * expression. Beware that when autoboxing, the type of the expression is
      * not necessarily the same as the type of the box to be created. The JDT
      * figures out what the necessary conversion is, depending on the context
-     * the expression appears in, and stores it in
-     * <code>x.implicitConversion</code>, so extract it from there.
+     * the expression appears in, and stores it in <code>x.implicitConversion</code>,
+     * so extract it from there.
      */
     private JPrimitiveType implicitConversionTargetType(Expression x)
         throws InternalCompilerException {
@@ -2458,8 +2455,8 @@
           if (varBinding instanceof SyntheticArgumentBinding) {
             JType type = (JType) typeMap.get(varBinding.type);
             String name = String.valueOf(varBinding.name);
-            for (int i = 0; i < currentMethod.params.size(); ++i) {
-              JParameter param = currentMethod.params.get(i);
+            for (int i = 0; i < currentMethod.getParams().size(); ++i) {
+              JParameter param = currentMethod.getParams().get(i);
               if (type == param.getType() && name.equals(param.getName())) {
                 variable = param;
                 break;
@@ -2544,7 +2541,9 @@
      * This version does not use JDT.
      */
     private void tryFindUpRefs(JMethod method) {
-      tryFindUpRefs(method, method.overrides);
+      List<JMethod> overrides = new ArrayList<JMethod>();
+      tryFindUpRefs(method, overrides);
+      method.addOverrides(overrides);
     }
 
     private void tryFindUpRefs(JMethod method, List<JMethod> overrides) {
@@ -2602,8 +2601,8 @@
         for (MethodBinding tryMethod : searchThisType.getMethods(binding.selector)) {
           if (binding.areParameterErasuresEqual(tryMethod)) {
             JMethod upRef = (JMethod) typeMap.get(tryMethod);
-            if (!method.overrides.contains(upRef)) {
-              method.overrides.add(upRef);
+            if (!method.getOverrides().contains(upRef)) {
+              method.addOverride(upRef);
               break;
             }
           }
@@ -2637,7 +2636,7 @@
       for (Object element : wrapperType.methods) {
         JMethod method = (JMethod) element;
         if (method.getName().equals(valueMethodName)) {
-          if (method.params.isEmpty()) {
+          if (method.getParams().isEmpty()) {
             // It's a match!
             valueMethod = method;
             break;
@@ -2664,12 +2663,11 @@
       JFieldRef mapRef = new JFieldRef(program, sourceInfo, null, mapField,
           type);
       JVariableRef nameRef = createVariableRef(sourceInfo,
-          currentMethod.params.get(0));
+          currentMethod.getParams().get(0));
       JMethod delegateTo = program.getIndexedMethod("Enum.valueOf");
       JMethodCall call = new JMethodCall(program, sourceInfo, null, delegateTo);
-      call.getArgs().add(mapRef);
-      call.getArgs().add(nameRef);
-      currentMethodBody.getStatements().add(
+      call.addArgs(mapRef, nameRef);
+      currentMethodBody.getBlock().addStmt(
           new JReturnStatement(program, sourceInfo, call));
     }
 
@@ -2685,7 +2683,7 @@
       }
       JNewArray newExpr = JNewArray.createInitializers(program, sourceInfo,
           program.getTypeArray(type, 1), initializers);
-      currentMethodBody.getStatements().add(
+      currentMethodBody.getBlock().addStmt(
           new JReturnStatement(program, sourceInfo, newExpr));
     }
   }
@@ -2868,7 +2866,7 @@
         // Normal: create a jsniRef.
         JsniFieldRef fieldRef = new JsniFieldRef(program, info,
             nameRef.getIdent(), field, currentClass, ctx.isLvalue());
-        nativeMethodBody.jsniFieldRefs.add(fieldRef);
+        nativeMethodBody.addJsniRef(fieldRef);
       }
 
       private void processMethod(JsNameRef nameRef, SourceInfo info,
@@ -2910,7 +2908,7 @@
 
         JsniMethodRef methodRef = new JsniMethodRef(program, info,
             nameRef.getIdent(), method);
-        nativeMethodBody.jsniMethodRefs.add(methodRef);
+        nativeMethodBody.addJsniRef(methodRef);
       }
 
       private void processNameRef(JsNameRef nameRef, JsContext<JsExpression> ctx) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index 5ee7364..60cc6fa 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -499,7 +499,7 @@
     public void endVisit(JBlock x, Context ctx) {
       JsBlock jsBlock = new JsBlock(x.getSourceInfo());
       List<JsStatement> stmts = jsBlock.getStatements();
-      popList(stmts, x.statements.size()); // stmts
+      popList(stmts, x.getStatements().size()); // stmts
       Iterator<JsStatement> iterator = stmts.iterator();
       while (iterator.hasNext()) {
         JsStatement stmt = iterator.next();
@@ -883,7 +883,7 @@
       }
 
       JsFunction jsFunc = (JsFunction) pop(); // body
-      List<JsParameter> params = popList(x.params.size()); // params
+      List<JsParameter> params = popList(x.getParams().size()); // params
 
       if (!x.isNative()) {
         // Setup params on the generated function. A native method already got
@@ -917,7 +917,7 @@
     public void endVisit(JMethodBody x, Context ctx) {
 
       JsBlock body = (JsBlock) pop();
-      List<JsNameRef> locals = popList(x.locals.size()); // locals
+      List<JsNameRef> locals = popList(x.getLocals().size()); // locals
 
       JsFunction jsFunc = methodBodyMap.get(x);
       jsFunc.setBody(body); // body
@@ -937,7 +937,7 @@
       JsVars vars = new JsVars(x.getSourceInfo());
       Set<String> alreadySeen = new HashSet<String>();
       for (int i = 0; i < locals.size(); ++i) {
-        JsName name = names.get(x.locals.get(i));
+        JsName name = names.get(x.getLocals().get(i));
         String ident = name.getIdent();
         if (!alreadySeen.contains(ident)) {
           alreadySeen.add(ident);
@@ -1297,7 +1297,7 @@
       accept(x.getExpr());
       jsSwitch.setExpr((JsExpression) pop()); // expr
 
-      List<JStatement> bodyStmts = x.getBody().statements;
+      List<JStatement> bodyStmts = x.getBody().getStatements();
       if (bodyStmts.size() > 0) {
         List<JsStatement> curStatements = null;
         for (int i = 0; i < bodyStmts.size(); ++i) {
@@ -1791,7 +1791,7 @@
 
     @Override
     public void endVisit(JMethodBody x, Context ctx) {
-      Collections.sort(x.locals, hasNameSort);
+      x.sortLocals(hasNameSort);
     }
 
     @Override
@@ -1931,7 +1931,7 @@
     if (specialObfuscatedTypes.contains(x.getEnclosingType())) {
       return true;
     }
-    for (Object element : x.overrides) {
+    for (Object element : x.getOverrides()) {
       JMethod override = (JMethod) element;
       if (specialObfuscatedTypes.contains(override.getEnclosingType())) {
         return true;
@@ -1961,11 +1961,11 @@
   }
 
   String mangleNameForPoly(JMethod x) {
-    if (x.overrides.isEmpty()) {
+    if (x.getOverrides().isEmpty()) {
       return mangleNameForPolyImpl(x);
     } else {
-      for (JMethod override : x.overrides) {
-        if (override.overrides.isEmpty()) {
+      for (JMethod override : x.getOverrides()) {
+        if (override.getOverrides().isEmpty()) {
           return mangleNameForPolyImpl(override);
         }
       }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
index 4a793c0..67346c9 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
@@ -132,7 +132,7 @@
           // instance.method(arg, arg)
           JMethodCall localCall = new JMethodCall(program, info, instance,
               x.getTarget());
-          localCall.getArgs().addAll(x.getArgs());
+          localCall.addArgs(x.getArgs());
 
           // We need a second copy of the arguments for the else expression
           CloneExpressionVisitor cloner = new CloneExpressionVisitor(program);
@@ -140,7 +140,7 @@
           // instance.jsoMethod(arg, arg)
           JMethodCall jsoCall = new JMethodCall(program, info,
               cloner.cloneExpression(instance), jsoMethod);
-          jsoCall.getArgs().addAll(cloner.cloneExpressions(x.getArgs()));
+          jsoCall.addArgs(cloner.cloneExpressions(x.getArgs()));
 
           // Cast.isJavaScriptObject() ? instance.jsoMethod() :
           // instance.method();
@@ -157,7 +157,7 @@
            */
           JMethodCall jsoCall = new JMethodCall(program, info, x.getInstance(),
               jsoMethod);
-          jsoCall.getArgs().addAll(x.getArgs());
+          jsoCall.addArgs(x.getArgs());
           ctx.replaceMe(jsoCall);
         }
       }
@@ -200,7 +200,7 @@
       JMethod isJavaScriptObjectMethod = program.getIndexedMethod("Cast.isJavaScriptObjectOrString");
       JMethodCall isJavaScriptObjectExpr = new JMethodCall(program, info, null,
           isJavaScriptObjectMethod);
-      isJavaScriptObjectExpr.getArgs().add(instance);
+      isJavaScriptObjectExpr.addArg(instance);
       return new JConditional(program, info, conditionalType,
           isJavaScriptObjectExpr, isJsoExpr, notJsoExpr);
     }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
index c2e737e..ce50ebc 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
@@ -138,7 +138,7 @@
     JParameter thisParam = program.createParameter(sourceInfo,
         "this$static".toCharArray(), program.getTypeJavaLangObject(), true,
         true, newMethod);
-    for (JParameter oldParam : objectMethod.params) {
+    for (JParameter oldParam : objectMethod.getParams()) {
       program.createParameter(sourceInfo, oldParam.getName().toCharArray(),
           oldParam.getType(), true, false, newMethod);
     }
@@ -147,19 +147,19 @@
     // Build from bottom up.
     JMethodCall condition = new JMethodCall(program, sourceInfo, null,
         isJavaObjectMethod);
-    condition.getArgs().add(new JParameterRef(program, sourceInfo, thisParam));
+    condition.addArg(new JParameterRef(program, sourceInfo, thisParam));
 
     JMethodCall thenValue = new JMethodCall(program, sourceInfo,
         new JParameterRef(program, sourceInfo, thisParam), objectMethod);
-    for (JParameter param : newMethod.params) {
+    for (JParameter param : newMethod.getParams()) {
       if (param != thisParam) {
-        thenValue.getArgs().add(new JParameterRef(program, sourceInfo, param));
+        thenValue.addArg(new JParameterRef(program, sourceInfo, param));
       }
     }
 
     JMethodCall elseValue = new JMethodCall(program, sourceInfo, null, jsoImpl);
-    for (JParameter param : newMethod.params) {
-      elseValue.getArgs().add(new JParameterRef(program, sourceInfo, param));
+    for (JParameter param : newMethod.getParams()) {
+      elseValue.addArg(new JParameterRef(program, sourceInfo, param));
     }
 
     JConditional conditional = new JConditional(program, sourceInfo,
@@ -167,7 +167,7 @@
 
     JReturnStatement returnStatement = new JReturnStatement(program,
         sourceInfo, conditional);
-    ((JMethodBody) newMethod.getBody()).getStatements().add(returnStatement);
+    ((JMethodBody) newMethod.getBody()).getBlock().addStmt(returnStatement);
     return newMethod;
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/LongCastNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/LongCastNormalizer.java
index 74ba0cb..4788ef1 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/LongCastNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/LongCastNormalizer.java
@@ -129,14 +129,13 @@
 
     @Override
     public void endVisit(JMethodCall x, Context ctx) {
-      List<JParameter> params = x.getTarget().params;
-      List<JExpression> args = x.getArgs();
+      List<JParameter> params = x.getTarget().getParams();
       for (int i = 0; i < params.size(); ++i) {
         JParameter param = params.get(i);
-        JExpression arg = args.get(i);
+        JExpression arg = x.getArgs().get(i);
         JExpression newArg = checkAndReplace(arg, param.getType());
         if (arg != newArg) {
-          args.set(i, newArg);
+          x.setArg(i, newArg);
           this.didChange = true;
         }
       }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/LongEmulationNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/LongEmulationNormalizer.java
index fc3bc02..6fa52a6 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/LongEmulationNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/LongEmulationNormalizer.java
@@ -85,8 +85,7 @@
       JMethod method = program.getIndexedMethod("LongLib." + methodName);
       JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
           method, x.getType());
-      call.getArgs().add(x.getLhs());
-      call.getArgs().add(x.getRhs());
+      call.addArgs(x.getLhs(), x.getRhs());
       ctx.replaceMe(call);
     }
 
@@ -110,7 +109,7 @@
       JMethod method = program.getIndexedMethod("LongLib." + methodName);
       JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
           method, x.getType());
-      call.getArgs().add(x.getArg());
+      call.addArg(x.getArg());
       ctx.replaceMe(call);
     }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
index fed1cd4..1273266 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
@@ -154,8 +154,8 @@
           CreateStaticImplsVisitor.class, "Instance parameter"),
           "this$static".toCharArray(), enclosingType, true, true, newMethod);
       Map<JParameter, JParameter> varMap = new IdentityHashMap<JParameter, JParameter>();
-      for (int i = 0; i < x.params.size(); ++i) {
-        JParameter oldVar = x.params.get(i);
+      for (int i = 0; i < x.getParams().size(); ++i) {
+        JParameter oldVar = x.getParams().get(i);
         JParameter newVar = program.createParameter(oldVar.getSourceInfo(),
             oldVar.getName().toCharArray(), oldVar.getType(), oldVar.isFinal(),
             false, newMethod);
@@ -179,11 +179,11 @@
       x.setBody(newBody);
       JMethodCall newCall = new JMethodCall(program, delegateCallSourceInfo,
           null, newMethod);
-      newCall.getArgs().add(
+      newCall.addArg(
           program.getExprThisRef(delegateCallSourceInfo, enclosingType));
-      for (int i = 0; i < x.params.size(); ++i) {
-        JParameter param = x.params.get(i);
-        newCall.getArgs().add(
+      for (int i = 0; i < x.getParams().size(); ++i) {
+        JParameter param = x.getParams().get(i);
+        newCall.addArg(
             new JParameterRef(program, delegateCallSourceInfo, param));
       }
       JStatement statement;
@@ -193,7 +193,7 @@
         statement = new JReturnStatement(program, delegateCallSourceInfo,
             newCall);
       }
-      newBody.getStatements().add(statement);
+      newBody.getBlock().addStmt(statement);
 
       /*
        * Rewrite the method body. Update all thisRefs to paramRefs. Update
@@ -300,8 +300,8 @@
             "Devirtualized function call"), null, newMethod);
 
     // The qualifier becomes the first arg
-    newCall.getArgs().add(x.getInstance());
-    newCall.getArgs().addAll(x.getArgs());
+    newCall.addArg(x.getInstance());
+    newCall.addArgs(x.getArgs());
     return newCall;
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodCallTightener.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodCallTightener.java
index 3a33dcd..08d304e 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodCallTightener.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodCallTightener.java
@@ -103,7 +103,7 @@
        */
       JMethodCall call = new JMethodCall(program, x.getSourceInfo(),
           x.getInstance(), foundMethod);
-      call.getArgs().addAll(x.getArgs());
+      call.addArgs(x.getArgs());
       ctx.replaceMe(call);
     }
 
@@ -118,7 +118,7 @@
      * 
      */
     private boolean methodOverrides(JMethod subMethod, JMethod supMethod) {
-      if (subMethod.params.size() != supMethod.params.size()) {
+      if (subMethod.getParams().size() != supMethod.getParams().size()) {
         // short cut: check the number of parameters
         return false;
       }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java
index 3a86ae0..e223c2b 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java
@@ -35,7 +35,6 @@
 import com.google.gwt.dev.jjs.ast.JVisitor;
 import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
 
-import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -116,7 +115,7 @@
             && !stmts.isEmpty()) {
           // clinit() calls cannot be inlined unless they are empty
           possibleToInline = false;
-        } else if (!body.locals.isEmpty()) {
+        } else if (!body.getLocals().isEmpty()) {
           // methods with local variables cannot be inlined
           possibleToInline = false;
         } else {
@@ -273,9 +272,6 @@
      */
     private boolean tryInlineExpression(JMethodCall x, Context ctx,
         JMultiExpression targetExpr) {
-      List<JParameter> params = x.getTarget().params;
-      ArrayList<JExpression> args = x.getArgs();
-
       /*
        * Limit inlined methods to multiexpressions of length 2 for now. This
        * handles the simple { return JVariableRef; } or { expression; return
@@ -315,7 +311,7 @@
        * 
        * TODO: would this be possible in the trivial delegation case?
        */
-      if (params.size() != args.size()) {
+      if (x.getTarget().getParams().size() != x.getArgs().size()) {
         return true;
       }
 
@@ -330,7 +326,7 @@
        * Ensure correct evaluation order or params relative to each other and to
        * other expressions.
        */
-      OrderVisitor orderVisitor = new OrderVisitor(x.getTarget().params);
+      OrderVisitor orderVisitor = new OrderVisitor(x.getTarget().getParams());
       orderVisitor.accept(targetExpr);
 
       /*
@@ -449,7 +445,7 @@
 
     @Override
     public void endVisit(JParameterRef x, Context ctx) {
-      int paramIndex = methodCall.getTarget().params.indexOf(x.getParameter());
+      int paramIndex = methodCall.getTarget().getParams().indexOf(x.getParameter());
       assert paramIndex != -1;
 
       // Replace with a cloned call argument.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
index 44b85f4..2e315aa 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
@@ -27,7 +27,6 @@
 import com.google.gwt.dev.jjs.ast.JField;
 import com.google.gwt.dev.jjs.ast.JFieldRef;
 import com.google.gwt.dev.jjs.ast.JInterfaceType;
-import com.google.gwt.dev.jjs.ast.JLocal;
 import com.google.gwt.dev.jjs.ast.JMethod;
 import com.google.gwt.dev.jjs.ast.JMethodBody;
 import com.google.gwt.dev.jjs.ast.JMethodCall;
@@ -173,12 +172,10 @@
           newCall.setCannotBePolymorphic();
         }
 
-        ArrayList<JExpression> args = x.getArgs();
-        ArrayList<JParameter> originalParams = methodToOriginalParamsMap.get(method);
-
+        List<JParameter> originalParams = methodToOriginalParamsMap.get(method);
         JMultiExpression currentMulti = null;
-        for (int i = 0, c = args.size(); i < c; ++i) {
-          JExpression arg = args.get(i);
+        for (int i = 0, c = x.getArgs().size(); i < c; ++i) {
+          JExpression arg = x.getArgs().get(i);
           JParameter param = null;
           if (i < originalParams.size()) {
             param = originalParams.get(i);
@@ -188,10 +185,10 @@
             // If there is an existing multi, terminate it.
             if (currentMulti != null) {
               currentMulti.exprs.add(arg);
-              newCall.getArgs().add(currentMulti);
+              newCall.addArg(currentMulti);
               currentMulti = null;
             } else {
-              newCall.getArgs().add(arg);
+              newCall.addArg(arg);
             }
           } else if (arg.hasSideEffects()) {
             // The argument is only needed for side effects, add it to a multi.
@@ -204,7 +201,7 @@
 
         // Add any orphaned parameters on the end. Extra params are OK.
         if (currentMulti != null) {
-          newCall.getArgs().add(currentMulti);
+          newCall.addArg(currentMulti);
         }
 
         ctx.replaceMe(newCall);
@@ -414,12 +411,12 @@
             ? ((JsniMethodBody) x.getBody()).getFunc() : null;
 
         ArrayList<JParameter> originalParams = new ArrayList<JParameter>(
-            x.params);
+            x.getParams());
 
-        for (int i = 0; i < x.params.size(); ++i) {
-          JParameter param = x.params.get(i);
+        for (int i = 0; i < x.getParams().size(); ++i) {
+          JParameter param = x.getParams().get(i);
           if (!referencedNonTypes.contains(param)) {
-            x.params.remove(i);
+            x.removeParam(i);
             didChange = true;
             // Remove the associated JSNI parameter
             if (func != null) {
@@ -436,10 +433,9 @@
 
     @Override
     public boolean visit(JMethodBody x, Context ctx) {
-      for (Iterator<JLocal> it = x.locals.iterator(); it.hasNext();) {
-        JLocal local = it.next();
-        if (!referencedNonTypes.contains(local)) {
-          it.remove();
+      for (int i = 0; i < x.getLocals().size(); ++i) {
+        if (!referencedNonTypes.contains(x.getLocals().get(i))) {
+          x.removeLocal(i--);
           didChange = true;
         }
       }
@@ -575,7 +571,7 @@
     JMethodCall newCall = new JMethodCall(program, x.getSourceInfo(), instance,
         program.getNullMethod(), primitiveTypeOrNullType(program, x.getType()));
     // Retain the original arguments, they will be evaluated for side effects.
-    newCall.getArgs().addAll(args);
+    newCall.addArgs(args);
     return newCall;
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
index ef63635..f5d2257 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
@@ -70,7 +70,7 @@
 
         JMethodCall methodCall = new JMethodCall(program, x.getSourceInfo(),
             null, loadMethod);
-        methodCall.getArgs().add(asyncCallback);
+        methodCall.addArg(asyncCallback);
 
         program.addEntryMethod(getOnLoadMethod(loader), entryNumber);
 
@@ -127,7 +127,7 @@
     for (JMethod method : loaderType.methods) {
       if (method.getName().equals("onLoad")) {
         assert (method.isStatic());
-        assert (method.params.size() == 0);
+        assert (method.getParams().size() == 0);
         return method;
       }
     }
@@ -141,8 +141,8 @@
     for (JMethod method : loaderType.methods) {
       if (method.getName().equals("runAsync")) {
         assert (method.isStatic());
-        assert (method.params.size() == 1);
-        assert (method.params.get(0).getType().getName().equals(FragmentLoaderCreator.RUN_ASYNC_CALLBACK));
+        assert (method.getParams().size() == 1);
+        assert (method.getParams().get(0).getType().getName().equals(FragmentLoaderCreator.RUN_ASYNC_CALLBACK));
         return method;
       }
     }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Simplifier.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Simplifier.java
index aa7f3fc..260b91f 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Simplifier.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Simplifier.java
@@ -50,7 +50,7 @@
     if (stmt == null) {
       return true;
     }
-    return (stmt instanceof JBlock && ((JBlock) stmt).statements.isEmpty());
+    return (stmt instanceof JBlock && ((JBlock) stmt).getStatements().isEmpty());
   }
 
   /**
@@ -194,9 +194,9 @@
       JMultiExpression condMulti = (JMultiExpression) condExpr;
       JBlock newBlock = new JBlock(program, sourceInfo);
       for (JExpression expr : allButLast(condMulti.exprs)) {
-        newBlock.statements.add(expr.makeStatement());
+        newBlock.addStmt(expr.makeStatement());
       }
-      newBlock.statements.add(ifStatement(null, sourceInfo,
+      newBlock.addStmt(ifStatement(null, sourceInfo,
           last(condMulti.exprs), thenStmt, elseStmt));
       // TODO(spoon): immediately simplify the resulting block
       return newBlock;
@@ -303,7 +303,7 @@
   private JStatement ensureBlock(JStatement stmt) {
     if (!(stmt instanceof JBlock)) {
       JBlock block = new JBlock(program, stmt.getSourceInfo());
-      block.statements.add(stmt);
+      block.addStmt(stmt);
       stmt = block;
     }
     return stmt;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
index bf5965e..2848db1 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
@@ -210,8 +210,8 @@
   @Override
   public boolean visit(JBlock x, Context ctx) {
     openBlock();
-    for (int i = 0; i < x.statements.size(); ++i) {
-      JStatement statement = x.statements.get(i);
+    for (int i = 0; i < x.getStatements().size(); ++i) {
+      JStatement statement = x.getStatements().get(i);
       needSemi = true;
       accept(statement);
       if (needSemi) {
@@ -1028,7 +1028,7 @@
 
   protected void printParameterList(JMethod x) {
     lparen();
-    visitCollectionWithCommas(x.params.iterator());
+    visitCollectionWithCommas(x.getParams().iterator());
     rparen();
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
index ac9815c..6aa1af7 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
@@ -131,13 +131,13 @@
         if (!instance.hasSideEffects()) {
           JMethodCall newCall = new JMethodCall(program, x.getSourceInfo(),
               null, x.getTarget());
-          newCall.getArgs().addAll(x.getArgs());
+          newCall.addArgs(x.getArgs());
           ctx.replaceMe(newCall);
         }
       } else if (!isStatic && instance.getType() == typeNull) {
         ctx.replaceMe(Pruner.transformToNullMethodCall(x, program));
-      } else if (isStaticImpl && method.params.size() > 0
-          && method.params.get(0).isThis() && x.getArgs().size() > 0
+      } else if (isStaticImpl && method.getParams().size() > 0
+          && method.getParams().get(0).isThis() && x.getArgs().size() > 0
           && x.getArgs().get(0).getType() == typeNull) {
         // bind null instance calls to the null method for static impls
         ctx.replaceMe(Pruner.transformToNullMethodCall(x, program));
@@ -217,7 +217,7 @@
       // All of the params in the target method are considered to be assigned by
       // the arguments from the caller
       Iterator<JExpression> argIt = x.getArgs().iterator();
-      ArrayList<JParameter> params = x.getTarget().params;
+      List<JParameter> params = x.getTarget().getParams();
       for (int i = 0; i < params.size(); ++i) {
         JParameter param = params.get(i);
         JExpression arg = argIt.next();
@@ -248,7 +248,7 @@
       // If this happens in JSNI, we can't make any type-tightening assumptions
       // Fake an assignment-to-self on all args to prevent tightening
       JMethod method = x.getTarget();
-      for (JParameter param : method.params) {
+      for (JParameter param : method.getParams()) {
         addAssignment(param, new JParameterRef(program,
             program.createSourceInfoSynthetic(RecordVisitor.class,
                 "Fake assignment"), param));
@@ -281,15 +281,15 @@
         if (overrides.isEmpty()) {
           return true;
         }
-        for (int j = 0, c = x.params.size(); j < c; ++j) {
-          JParameter param = x.params.get(j);
+        for (int j = 0, c = x.getParams().size(); j < c; ++j) {
+          JParameter param = x.getParams().get(j);
           Set<JParameter> set = paramUpRefs.get(param);
           if (set == null) {
             set = new HashSet<JParameter>();
             paramUpRefs.put(param, set);
           }
           for (JMethod baseMethod : overrides) {
-            JParameter baseParam = baseMethod.params.get(j);
+            JParameter baseParam = baseMethod.getParams().get(j);
             set.add(baseParam);
           }
         }
@@ -310,9 +310,9 @@
           // The instance method has already been pruned.
           return true;
         }
-        assert (x.params.size() == staticImplFor.params.size() + 1);
-        for (int j = 0, c = x.params.size(); j < c; ++j) {
-          JParameter param = x.params.get(j);
+        assert (x.getParams().size() == staticImplFor.getParams().size() + 1);
+        for (int j = 0, c = x.getParams().size(); j < c; ++j) {
+          JParameter param = x.getParams().get(j);
           Set<JParameter> set = paramUpRefs.get(param);
           if (set == null) {
             set = new HashSet<JParameter>();
@@ -324,7 +324,7 @@
             assert (param.isThis());
             set.add(param);
           } else {
-            JParameter baseParam = staticImplFor.params.get(j - 1);
+            JParameter baseParam = staticImplFor.getParams().get(j - 1);
             set.add(baseParam);
           }
         }
@@ -571,7 +571,7 @@
       if (concreteMethod != null) {
         JMethodCall newCall = new JMethodCall(program, x.getSourceInfo(),
             x.getInstance(), concreteMethod);
-        newCall.getArgs().addAll(x.getArgs());
+        newCall.addArgs(x.getArgs());
         ctx.replaceMe(newCall);
         target = concreteMethod;
         x = newCall;
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsScope.java b/dev/core/src/com/google/gwt/dev/js/ast/JsScope.java
index 1a6a5f9..71489d6 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsScope.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsScope.java
@@ -16,9 +16,11 @@
 package com.google.gwt.dev.js.ast;
 
 import com.google.gwt.dev.js.JsKeywords;
+import com.google.gwt.dev.util.collect.Lists;
+import com.google.gwt.dev.util.collect.Maps;
 
 import java.io.Serializable;
-import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -26,8 +28,8 @@
 
 /**
  * A scope is a factory for creating and allocating
- * {@link com.google.gwt.dev.js.ast.JsName}s. A JavaScript AST is built
- * in terms of abstract name objects without worrying about obfuscation,
+ * {@link com.google.gwt.dev.js.ast.JsName}s. A JavaScript AST is built in
+ * terms of abstract name objects without worrying about obfuscation,
  * keyword/identifier blacklisting, and so on.
  * 
  * <p>
@@ -61,9 +63,9 @@
     return ident;
   }
 
-  private final List<JsScope> children = new ArrayList<JsScope>();
+  private List<JsScope> children = Collections.emptyList();
   private final String description;
-  private final Map<String, JsName> names = new TreeMap<String, JsName>();
+  private Map<String, JsName> names = Collections.emptyMap();
   private final JsScope parent;
 
   /**
@@ -73,7 +75,7 @@
     assert (parent != null);
     this.description = description;
     this.parent = parent;
-    this.parent.children.add(this);
+    parent.children = Lists.add(parent.children, this);
   }
 
   /**
@@ -160,7 +162,11 @@
    * Returns an iterator for all the names defined by this scope.
    */
   public Iterator<JsName> getAllNames() {
-    return names.values().iterator();
+    if (names.size() > 1) {
+      return new TreeMap<String, JsName>(names).values().iterator();
+    } else {
+      return names.values().iterator();
+    }
   }
 
   /**
@@ -200,7 +206,7 @@
    */
   protected JsName doCreateName(String ident, String shortIdent) {
     JsName name = new JsName(this, ident, shortIdent);
-    names.put(ident, name);
+    names = Maps.put(names, ident, name);
     return name;
   }