Make com.google.gwt.lang.Array's instance methods always be in the
initial download.
Review by: cromwellian
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7407 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
index 0095722..a40f2c7 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
@@ -453,6 +453,7 @@
ControlFlowAnalyzer cfa = new ControlFlowAnalyzer(jprogram);
cfa.setDependencyRecorder(dependencyRecorder);
traverseEntry(jprogram, cfa, 0);
+ traverseClassArray(jprogram, cfa);
dependencyRecorder.endDependencyGraph();
return cfa;
@@ -579,6 +580,28 @@
}
/**
+ * Any instance method in the magic Array class must be in the initial
+ * download. The methods of that class are copied to a separate object the
+ * first time class Array is touched, and any methods added later won't be
+ * part of the copy.
+ */
+ private static void traverseClassArray(JProgram jprogram,
+ ControlFlowAnalyzer cfa) {
+ JDeclaredType typeArray = jprogram.getFromTypeMap("com.google.gwt.lang.Array");
+ if (typeArray == null) {
+ // It was pruned; nothing to do
+ return;
+ }
+
+ cfa.traverseFromInstantiationOf(typeArray);
+ for (JMethod method : typeArray.getMethods()) {
+ if (!method.isStatic()) {
+ cfa.traverseFrom(method);
+ }
+ }
+ }
+
+ /**
* Traverse all code in the program that is reachable via split point
* <code>splitPoint</code>.
*/
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 6abc9de..ab86a8c 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
@@ -790,6 +790,14 @@
rescuer.rescue(method);
}
+ /**
+ * Assume <code>type</code> is instantiated, and find out what else will
+ * execute as a result.
+ */
+ public void traverseFromInstantiationOf(JDeclaredType type) {
+ rescuer.rescue(type, true, true);
+ }
+
public void traverseFromLeftoversFragmentHasLoaded() {
if (program.entryMethods.size() > 1) {
traverseFrom(program.getIndexedMethod("AsyncFragmentLoader.browserLoaderLeftoversFragmentHasLoaded"));
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/CodeSplitterTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/CodeSplitterTest.java
new file mode 100644
index 0000000..0720b80
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/CodeSplitterTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.jjs.impl;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.javac.impl.MockJavaResource;
+import com.google.gwt.dev.jjs.ast.JProgram;
+
+/**
+ * Tests class {@link CodeSplitter}.
+ */
+public class CodeSplitterTest extends OptimizerTestBase {
+ /**
+ * Tests that everything in the magic Array class is considered initially
+ * live.
+ */
+ public void testArrayIsInitial() throws UnableToCompleteException {
+ sourceOracle.addOrReplace(new MockJavaResource("com.google.gwt.lang.Array") {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package com.google.gwt.lang;\n");
+ code.append("public class Array {\n");
+ code.append(" private Class type;\n");
+ code.append(" public Class getClass() { return type; }\n");
+ code.append("}\n");
+ return code;
+ }
+ });
+
+ JProgram program = compileSnippet("void", "");
+ ControlFlowAnalyzer cfa = CodeSplitter.computeInitiallyLive(program);
+
+ assertTrue(cfa.getInstantiatedTypes().contains(
+ findType(program, "com.google.gwt.lang.Array")));
+ assertTrue(cfa.getLiveFieldsAndMethods().contains(
+ findMethod(program, "com.google.gwt.lang.Array::getClass()")));;
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java b/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
index 4c437a3..37b9202 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
@@ -26,6 +26,8 @@
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.impl.JsniRefLookup.ErrorReporter;
+import com.google.gwt.dev.util.JsniRef;
import com.google.gwt.dev.util.log.AbstractTreeLogger;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
@@ -80,9 +82,24 @@
}
/**
+ * Find a method, given a JSNI reference to it.
+ */
+ public static JMethod findMethod(JProgram program, final String methodJsniRef) {
+ JsniRef ref = JsniRef.parse(methodJsniRef);
+ assertNotNull(ref);
+ assertTrue(ref.isMethod());
+ return (JMethod) JsniRefLookup.findJsniRefTarget(ref, program,
+ new ErrorReporter() {
+ public void reportError(String error) {
+ // ignore errors and return null
+ }
+ });
+ }
+
+ /**
* Finds a type by name. The type name may be short, e.g. <code>"Foo"</code>,
- * or fully-qualified, e.g. <code>"com.google.example.Foo"</code>. If a
- * short name is used, it must be unambiguous.
+ * or fully-qualified, e.g. <code>"com.google.example.Foo"</code>. If a short
+ * name is used, it must be unambiguous.
*/
public static JDeclaredType findType(JProgram program, String typeName) {
JDeclaredType type = program.getFromTypeMap(typeName);