A few runAsync-related code size improvements.
1) Removes the clinit, AsyncLoader__Supers, and loading fields from generated AsyncLoaders. PRETTY mode Showcase's initial fragment drops from 500k to 480k. Probably less impressive in OBF. A tiny improvement within the split fragments, too.
2) Removes the last couple uses of JRE collections from AsyncFragmentLoader in favor of arrays.
3) Removes a missed logEventProgress Integer -> int conversion that was begun in an earlier commit.
http://gwt-code-reviews.appspot.com/159811
Review by: spoon
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7732 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java b/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java
index adc86db..da27c6d 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java
@@ -26,7 +26,6 @@
import com.google.gwt.dev.jdt.FindDeferredBindingSitesVisitor;
import java.io.PrintWriter;
-import java.util.List;
/**
* Generates code for loading an island. The pattern of generated classes is
@@ -40,12 +39,12 @@
public static final String ASYNC_FRAGMENT_LOADER = "com.google.gwt.core.client.impl.AsyncFragmentLoader";
public static final String ASYNC_LOADER_CLASS_PREFIX = "AsyncLoader";
public static final String ASYNC_LOADER_PACKAGE = "com.google.gwt.lang.asyncloaders";
+ public static final String BROWSER_LOADER = "AsyncFragmentLoader.BROWSER_LOADER";
public static final String LOADER_METHOD_RUN_ASYNC = "runAsync";
public static final String RUN_ASYNC_CALLBACK = "com.google.gwt.core.client.RunAsyncCallback";
private static final String GWT_CLASS = FindDeferredBindingSitesVisitor.MAGIC_CLASS;
private static final String PROP_RUN_ASYNC_NEVER_RUNS = "gwt.jjs.runAsyncNeverRuns";
- private static final String UNCAUGHT_EXCEPTION_HANDLER_CLASS = GWT_CLASS
- + ".UncaughtExceptionHandler";
+ private static final String UNCAUGHT_EXCEPTION_HANDLER_CLASS = "GWT.UncaughtExceptionHandler";
private final StandardGeneratorContext context;
private int entryNumber = 0;
@@ -75,7 +74,6 @@
}
generateLoaderFields(loaderWriter);
- generateOnErrorMethod(loaderWriter);
generateOnLoadMethod(loaderWriter);
generateRunAsyncMethod(loaderWriter);
generateRunCallbacksMethod(loaderWriter);
@@ -86,22 +84,11 @@
context.commit(logger, loaderWriter);
writeCallbackListClass(logger, context);
- writeLoaderSuperclass(logger, context);
return getLoaderQualifiedName();
}
private void generateLoaderFields(PrintWriter srcWriter) {
- srcWriter.println("// Whether the code for this entry point has loaded");
- srcWriter.println("private static boolean loaded = false;");
-
- srcWriter.println("// Whether the code for this entry point is currently loading");
- srcWriter.println("private static boolean loading = false;");
-
- srcWriter.println("// A callback caller for this entry point");
- srcWriter.println("private static " + getLoaderSuperclassSimpleName()
- + " instance = new " + getLoaderSuperclassSimpleName() + "();");
-
srcWriter.println("// Callbacks that are pending");
srcWriter.println("private static " + getCallbackListSimpleName()
+ " callbacksHead = null;");
@@ -109,27 +96,23 @@
srcWriter.println("// The tail of the callbacks list");
srcWriter.println("private static " + getCallbackListSimpleName()
+ " callbacksTail = null;");
- }
- private void generateOnErrorMethod(PrintWriter srcWriter) {
- srcWriter.println("public static void onError(Throwable e) {");
- srcWriter.println("loading = false;");
- srcWriter.println("runCallbackOnFailures(e);");
- srcWriter.println("}");
+ srcWriter.println("// A callback caller for this entry point");
+ srcWriter.println("private static " + getLoaderSimpleName()
+ + " instance = null;");
}
private void generateOnLoadMethod(PrintWriter srcWriter) {
srcWriter.println("public static void onLoad() {");
- srcWriter.println("loaded = true;");
srcWriter.println("instance = new " + getLoaderSimpleName() + "();");
- srcWriter.println(ASYNC_FRAGMENT_LOADER + ".BROWSER_LOADER.fragmentHasLoaded("
- + entryNumber + ");");
+ srcWriter.println(BROWSER_LOADER + ".fragmentHasLoaded(" + entryNumber
+ + ");");
- srcWriter.println(ASYNC_FRAGMENT_LOADER
- + ".BROWSER_LOADER.logEventProgress(\"runCallbacks" + entryNumber + "\", \"begin\");");
+ srcWriter.println(BROWSER_LOADER + ".logEventProgress(\"runCallbacks"
+ + entryNumber + "\", \"begin\");");
srcWriter.println("instance.runCallbacks();");
- srcWriter.println(ASYNC_FRAGMENT_LOADER
- + ".BROWSER_LOADER.logEventProgress(\"runCallbacks" + entryNumber + "\", \"end\");");
+ srcWriter.println(BROWSER_LOADER + ".logEventProgress(\"runCallbacks"
+ + entryNumber + "\", \"end\");");
srcWriter.println("}");
}
@@ -154,16 +137,15 @@
srcWriter.println(" callbacksHead = newCallback;");
srcWriter.println("}");
- srcWriter.println("if (loaded) {");
- srcWriter.println("instance.runCallbacks();");
- srcWriter.println("return;");
+ srcWriter.println("if (instance != null) {");
+ srcWriter.println(" instance.runCallbacks();");
+ srcWriter.println(" return;");
srcWriter.println("}");
- srcWriter.println("if (!loading) {");
- srcWriter.println("loading = true;");
- srcWriter.println("AsyncFragmentLoader.BROWSER_LOADER.inject(" + entryNumber + ",");
+ srcWriter.println("if (!" + BROWSER_LOADER + ".isLoading(" + entryNumber
+ + ")) {");
+ srcWriter.println(" " + BROWSER_LOADER + ".inject(" + entryNumber + ",");
srcWriter.println(" new AsyncFragmentLoader.LoadErrorHandler() {");
srcWriter.println(" public void loadFailed(Throwable reason) {");
- srcWriter.println(" loading = false;");
srcWriter.println(" runCallbackOnFailures(reason);");
srcWriter.println(" }");
srcWriter.println(" });");
@@ -174,8 +156,8 @@
private void generateRunCallbackOnFailuresMethod(PrintWriter srcWriter) {
srcWriter.println("private static void runCallbackOnFailures(Throwable e) {");
srcWriter.println("while (callbacksHead != null) {");
- srcWriter.println("callbacksHead.callback.onFailure(e);");
- srcWriter.println("callbacksHead = callbacksHead.next;");
+ srcWriter.println(" callbacksHead.callback.onFailure(e);");
+ srcWriter.println(" callbacksHead = callbacksHead.next;");
srcWriter.println("}");
srcWriter.println("callbacksTail = null;");
srcWriter.println("}");
@@ -187,8 +169,7 @@
srcWriter.println("while (callbacksHead != null) {");
srcWriter.println(" " + UNCAUGHT_EXCEPTION_HANDLER_CLASS + " handler = "
- + FindDeferredBindingSitesVisitor.MAGIC_CLASS
- + ".getUncaughtExceptionHandler();");
+ + "GWT.getUncaughtExceptionHandler();");
srcWriter.println(" " + getCallbackListSimpleName()
+ " next = callbacksHead;");
@@ -231,14 +212,6 @@
return ASYNC_LOADER_CLASS_PREFIX + entryNumber;
}
- private String getLoaderSuperclassQualifiedName() {
- return ASYNC_LOADER_PACKAGE + getLoaderSuperclassSimpleName();
- }
-
- private String getLoaderSuperclassSimpleName() {
- return getLoaderSimpleName() + "__Super";
- }
-
private String getPackage() {
return ASYNC_LOADER_PACKAGE;
}
@@ -253,15 +226,12 @@
printWriter.println("package " + getPackage() + ";");
String[] imports = new String[] {
- RUN_ASYNC_CALLBACK, List.class.getCanonicalName(),
- ASYNC_FRAGMENT_LOADER};
+ GWT_CLASS, RUN_ASYNC_CALLBACK, ASYNC_FRAGMENT_LOADER};
for (String imp : imports) {
printWriter.println("import " + imp + ";");
}
- printWriter.println("public class " + getLoaderSimpleName() + " extends "
- + getLoaderSuperclassSimpleName() + " {");
-
+ printWriter.println("public class " + getLoaderSimpleName() + " {");
return printWriter;
}
@@ -284,31 +254,4 @@
printWriter.close();
ctx.commit(logger, printWriter);
}
-
- /**
- * Create a stand-in superclass of the actual loader. This is used to keep the
- * liveness analyzer from thinking the real <code>runCallbacks()</code>
- * method is available until <code>onLoad</code> has been called and the
- * real loader instantiated. A little work on TypeTightener could prevent the
- * need for this class.
- */
- private void writeLoaderSuperclass(TreeLogger logger, GeneratorContext ctx)
- throws UnableToCompleteException {
- PrintWriter printWriter = ctx.tryCreate(logger, getPackage(),
- getLoaderSuperclassSimpleName());
- if (printWriter == null) {
- logger.log(TreeLogger.ERROR, "Could not create type: "
- + getLoaderSuperclassQualifiedName());
- throw new UnableToCompleteException();
- }
-
- printWriter.println("package " + getPackage() + ";");
- printWriter.println("public class " + getLoaderSuperclassSimpleName()
- + " {");
- printWriter.println("public void runCallbacks() { }");
- printWriter.println("}");
-
- printWriter.close();
- ctx.commit(logger, printWriter);
- }
}
diff --git a/user/src/com/google/gwt/core/client/impl/AsyncFragmentLoader.java b/user/src/com/google/gwt/core/client/impl/AsyncFragmentLoader.java
index 8df3955..89119dc 100644
--- a/user/src/com/google/gwt/core/client/impl/AsyncFragmentLoader.java
+++ b/user/src/com/google/gwt/core/client/impl/AsyncFragmentLoader.java
@@ -18,10 +18,6 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
/**
* <p>
* Low-level support to download an extra fragment of code. This should not be
@@ -187,7 +183,8 @@
* Make a local list of the handlers to run, in case one of them calls
* another runAsync
*/
- List<LoadErrorHandler> handlersToRun = new ArrayList<LoadErrorHandler>();
+ LoadErrorHandler[] handlersToRun = pendingDownloadErrorHandlers;
+ pendingDownloadErrorHandlers = new LoadErrorHandler[numEntries + 1];
/*
* Call clear() here so that requestedExclusives makes all of its space
@@ -195,14 +192,6 @@
*/
requestedExclusives.clear();
- // add handlers for pending downloads
- for (LoadErrorHandler handler : pendingDownloadErrorHandlers) {
- if (handler != null) {
- handlersToRun.add(handler);
- }
- }
- pendingDownloadErrorHandlers.clear();
-
fragmentLoading = -1;
/*
@@ -212,10 +201,12 @@
RuntimeException lastException = null;
for (LoadErrorHandler handler : handlersToRun) {
- try {
- handler.loadFailed(reason);
- } catch (RuntimeException e) {
- lastException = e;
+ if (handler != null) {
+ try {
+ handler.loadFailed(reason);
+ } catch (RuntimeException e) {
+ lastException = e;
+ }
}
}
@@ -340,7 +331,7 @@
* Externally provided handlers for all outstanding and queued download
* requests.
*/
- private ArrayList<LoadErrorHandler> pendingDownloadErrorHandlers = new ArrayList<LoadErrorHandler>();
+ private LoadErrorHandler[] pendingDownloadErrorHandlers;
/**
* Whether prefetching is currently enabled.
@@ -373,8 +364,10 @@
this.initialLoadSequence = initialLoadSequence;
this.loadingStrategy = loadingStrategy;
this.logger = logger;
- requestedExclusives = new BoundedIntQueue(numEntries + 1);
- isLoaded = new boolean[numEntries + 1];
+ int numEntriesPlusOne = numEntries + 1;
+ requestedExclusives = new BoundedIntQueue(numEntriesPlusOne);
+ isLoaded = new boolean[numEntriesPlusOne];
+ pendingDownloadErrorHandlers = new LoadErrorHandler[numEntriesPlusOne];
}
/**
@@ -382,8 +375,8 @@
*/
public void fragmentHasLoaded(int fragment) {
logFragmentLoaded(fragment);
- if (fragment < pendingDownloadErrorHandlers.size()) {
- pendingDownloadErrorHandlers.set(fragment, null);
+ if (fragment < pendingDownloadErrorHandlers.length) {
+ pendingDownloadErrorHandlers[fragment] = null;
}
if (isInitial(fragment)) {
@@ -410,8 +403,7 @@
* @param splitPoint the split point whose code needs to be loaded
*/
public void inject(int splitPoint, LoadErrorHandler loadErrorHandler) {
- setCapacity(pendingDownloadErrorHandlers, splitPoint + 1);
- pendingDownloadErrorHandlers.set(splitPoint, loadErrorHandler);
+ pendingDownloadErrorHandlers[splitPoint] = loadErrorHandler;
if (!isInitial(splitPoint)) {
requestedExclusives.add(splitPoint);
}
@@ -422,6 +414,10 @@
return isLoaded[splitPoint];
}
+ public boolean isLoading(int splitPoint) {
+ return pendingDownloadErrorHandlers[splitPoint] != null;
+ }
+
public void leftoversFragmentHasLoaded() {
fragmentHasLoaded(leftoversFragment());
}
@@ -439,12 +435,12 @@
* whenever there is nothing else to download. Each call to this method
* overwrites the entire prefetch queue with the newly specified one.
*/
- public void setPrefetchQueue(Collection<? extends Integer> splitPoints) {
+ public void setPrefetchQueue(int... runAsyncSplitPoints) {
if (prefetchQueue == null) {
prefetchQueue = new BoundedIntQueue(numEntries);
}
prefetchQueue.clear();
- for (Integer sp : splitPoints) {
+ for (int sp : runAsyncSplitPoints) {
prefetchQueue.add(sp);
}
startLoadingNextFragment();
@@ -472,8 +468,8 @@
while (requestedExclusives.size() > 0
&& isLoaded[requestedExclusives.peek()]) {
int offset = requestedExclusives.remove();
- if (offset < pendingDownloadErrorHandlers.size()) {
- pendingDownloadErrorHandlers.set(offset, null);
+ if (offset < pendingDownloadErrorHandlers.length) {
+ pendingDownloadErrorHandlers[offset] = null;
}
}
@@ -512,12 +508,12 @@
}
/**
- * Return if the the ArrayList is empty.
- * @param list the list to check if empty
+ * Returns <code>true</code> if array contains only <code>null</code>
+ * elements.
*/
- private boolean isEmpty(ArrayList<?> list) {
- for (int i = 0; i < list.size(); i++) {
- if (list.get(i) != null) {
+ private boolean isEmpty(Object[] array) {
+ for (int i = 0; i < array.length; i++) {
+ if (array[i] != null) {
return false;
}
}
@@ -549,8 +545,8 @@
* <code>fragment</code> and <code>size</code> objects are allowed to be
* <code>null</code>.
*/
- private void logEventProgress(String eventGroup, String type,
- Integer fragment, Integer size) {
+ private void logEventProgress(String eventGroup, String type, int fragment,
+ int size) {
logger.logEventProgress(eventGroup, type, fragment, size);
}
@@ -559,17 +555,6 @@
logEventProgress(logGroup, LwmLabels.END, fragment, -1);
}
- /**
- * Set capacity ArrayList list.
- * @param list the list to add capacity to.
- * @param size the new size to increase the capacity to.
- */
- private void setCapacity(ArrayList<?> list, int size) {
- while (list.size() < size) {
- list.add(null);
- }
- }
-
private void startLoadingFragment(int fragment) {
assert (fragmentLoading < 0);
fragmentLoading = fragment;
diff --git a/user/src/com/google/gwt/core/client/prefetch/Prefetcher.java b/user/src/com/google/gwt/core/client/prefetch/Prefetcher.java
index ed17450..f91bb15 100644
--- a/user/src/com/google/gwt/core/client/prefetch/Prefetcher.java
+++ b/user/src/com/google/gwt/core/client/prefetch/Prefetcher.java
@@ -18,9 +18,7 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.impl.AsyncFragmentLoader;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
/**
* This class allows requesting the download of resources before they are
@@ -37,14 +35,15 @@
return;
}
- List<Integer> runAsyncSplitPoints = new ArrayList<Integer>();
-
+ // No range checking in web mode means we needn't precompute the size.
+ int[] runAsyncSplitPoints = new int[0];
+ int i = 0;
for (PrefetchableResource resource : resources) {
if (resource instanceof RunAsyncCode) {
RunAsyncCode resourceRunAsync = (RunAsyncCode) resource;
int splitPoint = resourceRunAsync.getSplitPoint();
if (splitPoint >= 0) { // Skip placeholders, which have a -1 split point
- runAsyncSplitPoints.add(splitPoint);
+ runAsyncSplitPoints[i++] = splitPoint;
}
continue;
}
diff --git a/user/test/com/google/gwt/core/client/impl/AsyncFragmentLoaderTest.java b/user/test/com/google/gwt/core/client/impl/AsyncFragmentLoaderTest.java
index 83eeee4..b14c3c2 100644
--- a/user/test/com/google/gwt/core/client/impl/AsyncFragmentLoaderTest.java
+++ b/user/test/com/google/gwt/core/client/impl/AsyncFragmentLoaderTest.java
@@ -21,8 +21,6 @@
import junit.framework.TestCase;
-import static java.util.Arrays.asList;
-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
@@ -454,7 +452,7 @@
1, 2, 3}, reqs, progress);
loader.startPrefetching();
// request a prefetch of something in the initial load sequence
- loader.setPrefetchQueue(asList(2));
+ loader.setPrefetchQueue(2);
reqs.assertFragmentsRequested(1);
progress.assertEvent("download1", BEGIN, 1);
@@ -468,7 +466,7 @@
progress.assertEvent("download2", END, 2);
progress.assertNoEvents();
// request a prefetch of an exclusive
- loader.setPrefetchQueue(asList(4));
+ loader.setPrefetchQueue(4);
reqs.assertFragmentsRequested(3);
progress.assertEvent("download3", BEGIN, 3);
@@ -487,7 +485,7 @@
progress.assertEvent("download4", END, 4);
progress.assertNoEvents();
// request a prefetch, but check that an inject call takes priority
- loader.setPrefetchQueue(asList(5,6));
+ loader.setPrefetchQueue(5, 6);
reqs.assertFragmentsRequested(5);
progress.assertEvent("download5", BEGIN, 5);
@@ -510,10 +508,10 @@
progress.assertEvent("download6", END, 6);
progress.assertNoEvents();
// request prefetches, then request different prefetches
- loader.setPrefetchQueue(asList(8,9));
+ loader.setPrefetchQueue(8, 9);
reqs.assertFragmentsRequested(8);
progress.assertEvent("download8", BEGIN, 8);
- loader.setPrefetchQueue(asList(10));
+ loader.setPrefetchQueue(10);
reqs.assertFragmentsRequested();
progress.assertNoEvents();
@@ -527,7 +525,7 @@
progress.assertEvent("download10", END, 10);
progress.assertNoEvents();
// request prefetches that have already been loaded
- loader.setPrefetchQueue(asList(1, 3, 7, 10));
+ loader.setPrefetchQueue(1, 3, 7, 10);
reqs.assertFragmentsRequested();
progress.assertNoEvents();
}
@@ -543,7 +541,7 @@
1, 2, 3}, reqs, progress);
loader.startPrefetching();
// request a prefetch of something in the initial load sequence
- loader.setPrefetchQueue(asList(3, 2, 1));
+ loader.setPrefetchQueue(3, 2, 1);
reqs.assertFragmentsRequested(1);
progress.assertEvent("download1", BEGIN, 1);
@@ -589,7 +587,7 @@
new int[] {}, reqs, progress);
loader.stopPrefetching();
// Prefetch 1, but leave prefetching off
- loader.setPrefetchQueue(asList(1));
+ loader.setPrefetchQueue(1);
reqs.assertFragmentsRequested();
progress.assertNoEvents();
@@ -646,7 +644,7 @@
progress.assertEvent("download1", END, 1);
progress.assertNoEvents();
// Start prefetching a fragment
- loader.setPrefetchQueue(asList(2));
+ loader.setPrefetchQueue(2);
reqs.assertFragmentsRequested(2);
progress.assertEvent("download2", BEGIN, 2);