Revision: 8829
Author: sp...@google.com
Date: Tue Sep 21 05:23:10 2010
Log: Gets the code splitter to be effective even in draft compile mode.
Review at http://gwt-code-reviews.appspot.com/875801
Review by: sco...@google.com
http://code.google.com/p/google-web-toolkit/source/detail?r=8829
Modified:
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/MethodCallTightener.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
/trunk/dev/core/test/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncsErrorMessagesTest.java
=======================================
---
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java
Mon Jun 7 12:20:31 2010
+++
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java
Tue Sep 21 05:23:10 2010
@@ -40,6 +40,7 @@
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 CALLBACK_LIST_SUFFIX = "__Callback";
public static final String LOADER_METHOD_RUN_ASYNC = "runAsync";
public static final String RUN_ASYNC_CALLBACK
= "com.google.gwt.core.client.RunAsyncCallback";
public static final String RUN_CALLBACKS = "runCallbacks";
@@ -198,11 +199,11 @@
}
private String getCallbackListQualifiedName() {
- return ASYNC_LOADER_PACKAGE + "__Callback";
+ return ASYNC_LOADER_PACKAGE + getCallbackListSimpleName();
}
private String getCallbackListSimpleName() {
- return getLoaderSimpleName() + "__Callback";
+ return getLoaderSimpleName() + CALLBACK_LIST_SUFFIX;
}
private String getLoaderQualifiedName() {
=======================================
---
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/MethodCallTightener.java
Thu Sep 9 00:20:17 2010
+++
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/MethodCallTightener.java
Tue Sep 21 05:23:10 2010
@@ -24,6 +24,7 @@
import com.google.gwt.dev.jjs.ast.JMethodCall;
import com.google.gwt.dev.jjs.ast.JModVisitor;
import com.google.gwt.dev.jjs.ast.JNewInstance;
+import com.google.gwt.dev.jjs.ast.JNode;
import com.google.gwt.dev.jjs.ast.JNullType;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReferenceType;
@@ -148,6 +149,13 @@
optimizeEvent.end("didChange", "" + stats.didChange());
return stats;
}
+
+ /**
+ * Tighten method calls that occur within <code>node</code> and its
children.
+ */
+ public static void exec(JProgram program, JNode node) {
+ new MethodCallTightener(program).execImpl(node);
+ }
private final JProgram program;
@@ -160,4 +168,9 @@
tightener.accept(program);
return new OptimizerStats(NAME).recordModified(tightener.getNumMods());
}
-}
+
+ private void execImpl(JNode node) {
+ MethodCallTighteningVisitor tightener = new
MethodCallTighteningVisitor();
+ tightener.accept(node);
+ }
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
Fri Aug 6 12:01:02 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
Tue Sep 21 05:23:10 2010
@@ -1,12 +1,12 @@
/*
* 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
@@ -140,6 +140,8 @@
loadMethod);
methodCall.addArg(asyncCallback);
+ tightenCallbackType(entryNumber, asyncCallback.getType());
+
program.addEntryMethod(getOnLoadMethod(loader), entryNumber);
ctx.replaceMe(methodCall);
@@ -159,6 +161,51 @@
return method.getEnclosingType() == program.getIndexedType("GWT")
&& method.getName().equals("runAsync");
}
+
+ /**
+ * Tighten some types and method calls immediately, in case the
optimizer is
+ * not run. Without a little bit of tightening, code splitting will be
+ * completely ineffective.
+ *
+ * Note that {...@link FragmentLoaderCreator} can't simply generate the
tighter
+ * types to begin with, because when it runs, it doesn't know which
runAsync
+ * call it is generating a loader for.
+ *
+ * This method can be deleted if {...@link FragmentLoaderCreator} is
+ * eliminated.
+ */
+ private void tightenCallbackType(int entryNumber, JType callbackType) {
+ JClassType loaderClass = getFragmentLoader(entryNumber);
+
+ /*
+ * Before: class AsyncLoader3 { static void
runAsync(RunAsyncCallback cb)
+ * { ... } }
+ *
+ * After: class AsyncLoader3 { static void
runAsync(RunAsyncCallback$3 cb)
+ * { ... } }
+ */
+ JMethod loadMethod = getRunAsyncMethod(loaderClass);
+ loadMethod.getParams().get(0).setType(callbackType);
+
+ /*
+ * Before: class AsyncLoader3__Callback { RunAsyncCallback callback;
}
+ *
+ * After: class AsyncLoader3__Callback { RunAsyncCallback$3
callback; }
+ */
+ JClassType callbackListType =
getFragmentLoaderCallbackList(entryNumber);
+ JField callbackField = getField(callbackListType, "callback");
+
+ /*
+ * The method AsyncLoaderNNN.runCallbacks has a lot of calls to
onSuccess
+ * methods where the target is onSuccess in the RunAsyncCallback
+ * interface. Use MethodCallTightener to tighten those calls down to
+ * target the onSuccess method of a specific callback class.
+ */
+ callbackField.setType(callbackType);
+ JMethod runCallbacksMethod = getMethod(loaderClass,
+ FragmentLoaderCreator.RUN_CALLBACKS);
+ MethodCallTightener.exec(program, runCallbacksMethod);
+ }
}
private class ReplaceRunAsyncResources extends JModVisitor {
private Map<String, List<RunAsyncReplacement>> replacementsByName;
@@ -229,8 +276,8 @@
public static void exec(TreeLogger logger, JProgram program)
throws UnableToCompleteException {
- Event codeSplitterEvent =
-
SpeedTracerLogger.start(CompilerEventType.CODE_SPLITTER, "phase", "ReplaceRunAsyncs");
+ Event codeSplitterEvent = SpeedTracerLogger.start(
+ CompilerEventType.CODE_SPLITTER, "phase", "ReplaceRunAsyncs");
TreeLogger branch = logger.branch(TreeLogger.TRACE,
"Replacing GWT.runAsync with island loader calls");
new ReplaceRunAsyncs(branch, program).execImpl();
@@ -247,6 +294,35 @@
assert initializerCall.getArgs().size() == 2;
return initializerCall;
}
+
+ private static JMethod getMethod(JClassType type, String name) {
+ for (JMethod method : type.getMethods()) {
+ if (method.getName().equals(name)) {
+ return method;
+ }
+ }
+ throw new InternalCompilerException("Method not found: " +
type.getName()
+ + "." + name);
+ }
+
+ private static JMethod getOnLoadMethod(JClassType loaderType) {
+ assert loaderType != null;
+ assert loaderType.getMethods() != null;
+ JMethod method = getMethod(loaderType, "onLoad");
+ assert method.isStatic();
+ assert method.getParams().size() == 0;
+ return method;
+ }
+
+ private static JMethod getRunAsyncMethod(JClassType loaderType) {
+ assert loaderType != null;
+ assert loaderType.getMethods() != null;
+ JMethod method = getMethod(loaderType, "runAsync");
+ assert (method.isStatic());
+ assert (method.getParams().size() == 1);
+ assert
(method.getParams().get(0).getType().getName().equals(FragmentLoaderCreator.RUN_ASYNC_CALLBACK));
+ return method;
+ }
/**
* Convert a class literal to a runAsync name.
@@ -288,6 +364,16 @@
throw new UnableToCompleteException();
}
}
+
+ private JField getField(JClassType type, String name) {
+ for (JField field : type.getFields()) {
+ if (field.getName().equals(name)) {
+ return field;
+ }
+ }
+ throw new InternalCompilerException("Field not found: " +
type.getName()
+ + "." + name);
+ }
private JClassType getFragmentLoader(int fragmentNumber) {
String fragmentLoaderClassName =
FragmentLoaderCreator.ASYNC_LOADER_PACKAGE
@@ -299,32 +385,13 @@
return (JClassType) result;
}
- private JMethod getOnLoadMethod(JClassType loaderType) {
- assert loaderType != null;
- assert loaderType.getMethods() != null;
- for (JMethod method : loaderType.getMethods()) {
- if (method.getName().equals("onLoad")) {
- assert (method.isStatic());
- assert (method.getParams().size() == 0);
- return method;
- }
- }
- assert false;
- return null;
- }
-
- private JMethod getRunAsyncMethod(JClassType loaderType) {
- assert loaderType != null;
- assert loaderType.getMethods() != null;
- for (JMethod method : loaderType.getMethods()) {
- if (method.getName().equals("runAsync")) {
- assert (method.isStatic());
- assert (method.getParams().size() == 1);
- assert
(method.getParams().get(0).getType().getName().equals(FragmentLoaderCreator.RUN_ASYNC_CALLBACK));
- return method;
- }
- }
- return null;
+ private JClassType getFragmentLoaderCallbackList(int fragmentNumber) {
+ String className = FragmentLoaderCreator.ASYNC_LOADER_PACKAGE + "."
+ + FragmentLoaderCreator.ASYNC_LOADER_CLASS_PREFIX + fragmentNumber
+ + FragmentLoaderCreator.CALLBACK_LIST_SUFFIX;
+ JType result = program.getFromTypeMap(className);
+ assert (result != null);
+ return (JClassType) result;
}
private void setNumEntriesInAsyncFragmentLoader(int entryCount) {
=======================================
---
/trunk/dev/core/test/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncsErrorMessagesTest.java
Mon Jun 7 12:20:31 2010
+++
/trunk/dev/core/test/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncsErrorMessagesTest.java
Tue Sep 21 05:23:10 2010
@@ -52,7 +52,7 @@
});
addSnippetImport("test.SplitPoint3");
- expectError("Line 12: Multiple runAsync calls are named
test.SplitPoint1");
+ expectError("Line 15: Multiple runAsync calls are named
test.SplitPoint1");
expectError("One call is in test.SplitPoint1.doStuff
(/mock/test/SplitPoint1.java:4)");
expectError("One call is in test.SplitPoint3.doStuff
(/mock/test/SplitPoint3.java:4)");
@@ -60,12 +60,12 @@
}
public void testNonClassLiteral() {
- expectError("Line 11: Only a class literal may be passed to
runAsyncCode");
+ expectError("Line 14: Only a class literal may be passed to
runAsyncCode");
testSnippet("RunAsyncCode.runAsyncCode(new
SplitPoint1().getClass());");
}
public void testNonExistentSplitPoint() {
- expectError("Line 11: No runAsync call is named java.lang.String");
+ expectError("Line 14: No runAsync call is named java.lang.String");
testSnippet("RunAsyncCode.runAsyncCode(String.class);");
}
@@ -80,12 +80,32 @@
code.append("public class AsyncLoader" + sp + " {\n");
code.append(" public static void onLoad() { }\n");
code.append(" public static void runAsync(RunAsyncCallback cb) {
}\n");
+ code.append(" public static void runCallbacks() { }\n");
code.append("}\n");
return code;
}
});
addSnippetImport("com.google.gwt.lang.asyncloaders.AsyncLoader" + sp);
+
+ sourceOracle.addOrReplace(new MockJavaResource(
+ "com.google.gwt.lang.asyncloaders.AsyncLoader" + sp
+ + FragmentLoaderCreator.CALLBACK_LIST_SUFFIX) {
+ @Override
+ protected CharSequence getContent() {
+ StringBuffer code = new StringBuffer();
+ code.append("package com.google.gwt.lang.asyncloaders;\n");
+ code.append("import com.google.gwt.core.client.RunAsyncCallback;");
+ code.append("public class AsyncLoader" + sp
+ + FragmentLoaderCreator.CALLBACK_LIST_SUFFIX + "{\n");
+ code.append(" RunAsyncCallback callback;\n");
+ code.append("}\n");
+ return code;
+ }
+ });
+
+ addSnippetImport("com.google.gwt.lang.asyncloaders.AsyncLoader" + sp
+ + FragmentLoaderCreator.CALLBACK_LIST_SUFFIX);
}
private void addCommonTestCode() {
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors