Do now qualify String, Array, Function, Object and Number with $wnd.
Bug: #9389
Bug-Link: https://github.com/gwtproject/gwt/issues/9389
Change-Id: I27496f43a4cba060e2622bdd4ded95a1496b5098
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 4f01054..d44f2d0 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
@@ -898,7 +898,7 @@
JsNameRef methodNameRef;
if (method.isJsNative()) {
// Construct Constructor.prototype.jsname or Constructor.
- methodNameRef = createJsQualifier(method.getQualifiedJsName(), sourceInfo);
+ methodNameRef = createGlobalQualifier(method.getQualifiedJsName(), sourceInfo);
} else if (method.isConstructor()) {
/*
* Constructor calls through {@code this} and {@code super} are always dispatched statically
@@ -980,7 +980,7 @@
JConstructor ctor = newInstance.getTarget();
JsName ctorName = names.get(ctor);
JsNameRef reference = ctor.isJsNative()
- ? createJsQualifier(ctor.getQualifiedJsName(), sourceInfo)
+ ? createGlobalQualifier(ctor.getQualifiedJsName(), sourceInfo)
: ctorName.makeRef(sourceInfo);
List<JsExpression> arguments = transform(newInstance.getArgs());
@@ -1105,7 +1105,7 @@
JMethod method = jsniMethodRef.getTarget();
if (method.isJsNative()) {
// Construct Constructor.prototype.jsname or Constructor.
- return createJsQualifier(method.getQualifiedJsName(), jsniMethodRef.getSourceInfo());
+ return createGlobalQualifier(method.getQualifiedJsName(), jsniMethodRef.getSourceInfo());
}
return names.get(method).makeRef(jsniMethodRef.getSourceInfo());
}
@@ -1720,7 +1720,7 @@
private JsNameRef createStaticReference(JMember member, SourceInfo sourceInfo) {
assert member.isStatic();
return member.isJsNative()
- ? createJsQualifier(member.getQualifiedJsName(), sourceInfo)
+ ? createGlobalQualifier(member.getQualifiedJsName(), sourceInfo)
: names.get(member).makeRef(sourceInfo);
}
@@ -1997,7 +1997,7 @@
defineClassArguments.add(transform(getRuntimeTypeReference(type)));
defineClassArguments.add(jsPrototype == null ? transform(superTypeId) :
- createJsQualifier(jsPrototype, type.getSourceInfo()));
+ createGlobalQualifier(jsPrototype, type.getSourceInfo()));
defineClassArguments.add(generateCastableTypeMap(type));
defineClassArguments.addAll(constructorArgs);
@@ -2128,7 +2128,7 @@
String jsPrototype = getSuperPrototype(type);
SourceInfo info = type.getSourceInfo();
JsNameRef parentCtor = jsPrototype != null ?
- createJsQualifier(jsPrototype, info) :
+ createGlobalQualifier(jsPrototype, info) :
superClass != null ?
names.get(superClass).makeRef(info) :
null;
@@ -2392,9 +2392,22 @@
}
}
- public JsNameRef createJsQualifier(String qualifier, SourceInfo sourceInfo) {
+ public JsNameRef createGlobalQualifier(String qualifier, SourceInfo sourceInfo) {
assert !qualifier.isEmpty();
- return JsUtils.createQualifiedNameRef("$wnd." + qualifier, sourceInfo);
+
+ return JsUtils.createQualifiedNameRef(
+ isQualifiedThroughSpecialGlobalName(qualifier) ? qualifier : ("$wnd." + qualifier),
+ sourceInfo);
+ }
+
+ /*
+ * Some global names are considered special and should be used unqualified. Such names should
+ * not be emitted with the "$wnd." prefix as there seems to be runtime performance implications.
+ * {@see TypeCategory} for the full list.
+ */
+ private boolean isQualifiedThroughSpecialGlobalName(String qualifiedName) {
+ String topLevelName = qualifiedName.split("\\.")[0];
+ return TypeCategory.isSpecialGlobalName(topLevelName);
}
/**
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java
index 4f3e702..6ae81a0 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java
@@ -22,6 +22,9 @@
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReferenceType;
import com.google.gwt.dev.jjs.ast.JType;
+import com.google.gwt.thirdparty.guava.common.collect.ImmutableMap;
+
+import java.util.Map;
/**
* TypeCategory classifies Java types into different categories. <p>
@@ -132,6 +135,19 @@
return TypeCategory.TYPE_JAVA_OBJECT;
}
+ public static boolean isSpecialGlobalName(String name) {
+ return specialGlobalNames.containsKey(name);
+ }
+
+ private static Map<String, TypeCategory> specialGlobalNames =
+ ImmutableMap.<String,TypeCategory>builder()
+ .put("Object", TYPE_JS_OBJECT)
+ .put("Function", TYPE_JS_FUNCTION)
+ .put("Array", TYPE_JS_ARRAY)
+ .put("Number", TYPE_JAVA_LANG_DOUBLE)
+ .put("String", TYPE_JAVA_LANG_STRING)
+ .build();
+
private static TypeCategory getJsSpecialType(JType type) {
if (!(type instanceof JClassType) || !type.isJsNative()) {
return null;
@@ -142,19 +158,7 @@
return null;
}
- switch (classType.getJsName()) {
- case "Object":
- return TypeCategory.TYPE_JS_OBJECT;
- case "Function":
- return TypeCategory.TYPE_JS_FUNCTION;
- case "Array":
- return TypeCategory.TYPE_JS_ARRAY;
- case "Number":
- return TypeCategory.TYPE_JAVA_LANG_DOUBLE;
- case "String":
- return TypeCategory.TYPE_JAVA_LANG_STRING;
- }
- return null;
+ return specialGlobalNames.get(classType.getJsName());
}
private static boolean isJsoArray(JType type) {
diff --git a/user/test/com/google/gwt/dev/jjs/optimized/StringOptimizationTest.java b/user/test/com/google/gwt/dev/jjs/optimized/StringOptimizationTest.java
index bc11f17..a42b7a9 100644
--- a/user/test/com/google/gwt/dev/jjs/optimized/StringOptimizationTest.java
+++ b/user/test/com/google/gwt/dev/jjs/optimized/StringOptimizationTest.java
@@ -27,6 +27,7 @@
private static String createString() {
return new String();
}
+
private static native String getGeneratedFunctionDefintionThatTriggersStringClinit() /*-{
return function() {
tmp = @StringOptimizationTest::createString()();
@@ -38,4 +39,19 @@
assertFunctionMatches(functionDef, "tmp=''");
}
+ private static native String getGeneratedFunctionDefintionThatCallsStringFromCharCode() /*-{
+ return function() {
+ tmp = @java.lang.String::valueOf(C)('c');
+ }.toString();
+ }-*/;
+
+ /*
+ * Makes sure that static String functions are emitted without the $wnd qualifier because doing
+ * so causes runtime performance degradation.
+ */
+ public void testNativeStringDoesNotUse$wnd() throws Exception {
+ String functionDef = getGeneratedFunctionDefintionThatCallsStringFromCharCode();
+ assertFunctionMatches(functionDef, "tmp=String.fromCharCode('c')");
+ }
+
}