Skip to content

Commit

Permalink
Introduces special handling of namespace = "window".
Browse files Browse the repository at this point in the history
Namespace JsPackage.GLOBAL references elements in the main window
scope,  which in GWT applications refer through '$wnd'.

This cl introduces namespace = "window" that allows to reference
the (iframe) top scope.

This is mainly done so that some operations (like String.fromCharCode)
are called through the iframe definition to address performance
implications in some browsers if the accesses where made through the
main window.

Bug: #9405
Bug-Link: #9405
Change-Id: Ic5b7e9d492aa0795ed8d3f6e3041bc7915e3c99a
  • Loading branch information
rluble committed Aug 29, 2016
1 parent 7da4bf3 commit c511029
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 57 deletions.
69 changes: 35 additions & 34 deletions dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
Expand Up @@ -527,7 +527,6 @@ private class GenerateJavaScriptTransformer extends JTransformer<JsNode> {
private final JsName arrayLength = objectScope.declareUnobfuscatableName("length");
private final JsName globalTemp = topScope.declareUnobfuscatableName("_");
private final JsName prototype = objectScope.declareUnobfuscatableName("prototype");
private final JsName call = objectScope.declareUnobfuscatableName("call");

@Override
public JsExpression transformArrayLength(JArrayLength expression) {
Expand Down Expand Up @@ -898,7 +897,7 @@ private JsExpression dispatchToSuper(
JsNameRef methodNameRef;
if (method.isJsNative()) {
// Construct Constructor.prototype.jsname or Constructor.
methodNameRef = createGlobalQualifier(method.getQualifiedJsName(), sourceInfo);
methodNameRef = createGlobalQualifier(method, sourceInfo);
} else if (method.isConstructor()) {
/*
* Constructor calls through {@code this} and {@code super} are always dispatched statically
Expand Down Expand Up @@ -980,7 +979,7 @@ public JsNode transformNewInstance(JNewInstance newInstance) {
JConstructor ctor = newInstance.getTarget();
JsName ctorName = names.get(ctor);
JsNameRef reference = ctor.isJsNative()
? createGlobalQualifier(ctor.getQualifiedJsName(), sourceInfo)
? createGlobalQualifier(ctor, sourceInfo)
: ctorName.makeRef(sourceInfo);
List<JsExpression> arguments = transform(newInstance.getArgs());

Expand Down Expand Up @@ -1105,7 +1104,7 @@ public JsNameRef transformJsniMethodRef(JsniMethodRef jsniMethodRef) {
JMethod method = jsniMethodRef.getTarget();
if (method.isJsNative()) {
// Construct Constructor.prototype.jsname or Constructor.
return createGlobalQualifier(method.getQualifiedJsName(), jsniMethodRef.getSourceInfo());
return createGlobalQualifier(method, jsniMethodRef.getSourceInfo());
}
return names.get(method).makeRef(jsniMethodRef.getSourceInfo());
}
Expand Down Expand Up @@ -1688,7 +1687,7 @@ private JsExpression buildJsCastMapLiteral(List<JsExpression> runtimeTypeIdLiter
}

private JsExpression buildClosureStyleCastMapFromArrayLiteral(
List<JsExpression> runtimeTypeIdLiterals, SourceInfo sourceInfo) {
List<JsExpression> runtimeTypeIdLiterals, SourceInfo sourceInfo) {
/*
* goog.object.createSet('foo', 'bar', 'baz') is optimized by closure compiler into
* {'foo': !0, 'bar': !0, baz: !0}
Expand Down Expand Up @@ -1720,7 +1719,7 @@ private void checkForDuplicateMethods(JDeclaredType type) {
private JsNameRef createStaticReference(JMember member, SourceInfo sourceInfo) {
assert member.isStatic();
return member.isJsNative()
? createGlobalQualifier(member.getQualifiedJsName(), sourceInfo)
? createGlobalQualifier(member, sourceInfo)
: names.get(member).makeRef(sourceInfo);
}

Expand Down Expand Up @@ -2015,8 +2014,7 @@ private void generateCallToDefineClass(JClassType type, List<JsNameRef> construc
private void maybeCopyObjProperties(
JDeclaredType type, JsExpression toPrototype, JsExpression fromPrototype) {
if (getSuperPrototype(type) != null && !type.isJsFunctionImplementation()) {
JsStatement statement =
constructInvocation(type.getSourceInfo(),
JsStatement statement = constructInvocation(type.getSourceInfo(),
RuntimeConstants.RUNTIME_COPY_OBJECT_PROPERTIES,
fromPrototype,
toPrototype)
Expand All @@ -2037,7 +2035,7 @@ private String getSuperPrototype(JDeclaredType type) {
}

private void generateClassDefinition(JDeclaredType type) {
assert !program.isRepresentedAsNativeJsPrimitive(type);
assert !program.isRepresentedAsNativeJsPrimitive(type);

if (closureCompilerFormatEnabled) {
generateClosureTypeDefinition(type);
Expand Down Expand Up @@ -2242,10 +2240,10 @@ private void generatePrototypeAssignment(JMethod method, JsName name, JsExpressi
generatePrototypeAssignment(method, name, rhs, method.getJsMemberType());
}

/**
* Create a vtable assignment of the form _.polyname = rhs; and register the line as
* created for {@code method}.
*/
/**
* Create a vtable assignment of the form _.polyname = rhs; and register the line as
* created for {@code method}.
*/
private void generatePrototypeAssignment(JMethod method, JsName name, JsExpression rhs,
JsMemberType memberType) {
SourceInfo sourceInfo = method.getSourceInfo();
Expand Down Expand Up @@ -2275,9 +2273,9 @@ private void emitPropertyImplementation(JMethod method, JsNameRef prototype, JsN

JsObjectLiteral definePropertyLiteral =
JsObjectLiteral.builder(sourceInfo)
// {name: {get: function() { ..... }} or {set : function (v) {....}}}
// {name: {get: function() { ..... }} or {set : function (v) {....}}}
.add(name, JsObjectLiteral.builder(sourceInfo)
// {get: function() { ..... }} or {set : function (v) {....}}
// {get: function() { ..... }} or {set : function (v) {....}}
.add(method.getJsMemberType().getPropertyAccessorKey(), methodDefinitionStatement)
.build())
.build();
Expand Down Expand Up @@ -2335,7 +2333,7 @@ private String getDisplayName(JMethod method) {
* variable _ points the JavaScript prototype for {@code type}.
*/
private void generatePrototypeDefinitions(JDeclaredType type) {
assert !program.isRepresentedAsNativeJsPrimitive(type);
assert !program.isRepresentedAsNativeJsPrimitive(type);

// Emit synthetic methods first. In JsInterop we allow a more user written method to be named
// with the same name as a synthetic bridge (required due to generics) relying that the
Expand Down Expand Up @@ -2392,24 +2390,6 @@ private void generatePrototypeDefinition(JMethod method, JsExpression functionDe
}
}

public JsNameRef createGlobalQualifier(String qualifier, SourceInfo sourceInfo) {
assert !qualifier.isEmpty();

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);
}

/**
* Returns either _ or ClassCtor.prototype depending on output mode.
*/
Expand Down Expand Up @@ -3088,4 +3068,25 @@ private JsName getIndexedMethodJsName(String indexedName) {
private JsName getIndexedFieldJsName(String indexedName) {
return names.get(program.getIndexedField(indexedName));
}

private static final String WINDOW = "window";

private static boolean isWindow(String jsNamespace) {
return jsNamespace != null
&& (WINDOW.equals(jsNamespace) || jsNamespace.startsWith(WINDOW + "."));
}

private static JsNameRef createGlobalQualifier(JMember member, SourceInfo sourceInfo) {
if (isWindow(member.getJsNamespace())) {
return JsUtils.createQualifiedNameRef(
member.getQualifiedJsName().substring(WINDOW.length() + 1), sourceInfo);
}
return createGlobalQualifier(member.getQualifiedJsName(), sourceInfo);
}

private static JsNameRef createGlobalQualifier(String qualifier, SourceInfo sourceInfo) {
assert !qualifier.isEmpty();

return JsUtils.createQualifiedNameRef("$wnd." + qualifier, sourceInfo);
}
}
@@ -1,11 +1,11 @@
/*
* Copyright 2015 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
Expand Down Expand Up @@ -567,13 +567,10 @@ private void checkMemberQualifiedJsName(JMember member) {
private <T extends HasJsName & HasSourceInfo & CanBeJsNative> void checkJsName(T item) {
if (item.getJsName().isEmpty()) {
logError(item, "%s cannot have an empty name.", getDescription(item));
} else if (JsInteropUtil.isGlobal(item.getJsNamespace()) && item.isJsNative()) {
} else if ((item.isJsNative() && !JsUtils.isValidJsQualifiedName(item.getJsName()))
|| (!item.isJsNative() && !JsUtils.isValidJsIdentifier(item.getJsName()))) {
// Allow qualified names in the name field for JsPackage.GLOBAL native items for future
// compatibility
if (!JsUtils.isValidJsQualifiedName(item.getJsName())) {
logError(item, "%s has invalid name '%s'.", getDescription(item), item.getJsName());
}
} else if (!JsUtils.isValidJsIdentifier(item.getJsName())) {
logError(item, "%s has invalid name '%s'.", getDescription(item), item.getJsName());
}
}
Expand Down
4 changes: 0 additions & 4 deletions dev/core/src/com/google/gwt/dev/jjs/impl/TypeCategory.java
Expand Up @@ -135,10 +135,6 @@ public static TypeCategory typeCategoryForType(JType type, JProgram program) {
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)
Expand Down
18 changes: 9 additions & 9 deletions user/super/com/google/gwt/emul/java/lang/String.java
Expand Up @@ -157,12 +157,12 @@ private static String fromCharCode(Object[] array) {
}

@JsType(isNative = true, name = "Function", namespace = JsPackage.GLOBAL)
private static class NativeFunction {
public native String apply(String thisContext, Object[] argsArray);
private static class NativeFunction<T> {
public native T apply(Object thisContext, Object[] argsArray);
}

@JsProperty(name = "fromCharCode", namespace = "String")
private static native NativeFunction getFromCharCodeFunction();
@JsProperty(name = "String.fromCharCode", namespace = "window")
private static native NativeFunction<String> getFromCharCodeFunction();

public static String valueOf(char[] x) {
return valueOf(x, 0, x.length);
Expand Down Expand Up @@ -410,7 +410,7 @@ public boolean endsWith(String suffix) {
public boolean equals(Object other) {
// Java equality is translated into triple equality which is a quick to compare strings for
// equality without any instanceOf checks.
return checkNotNull(this) == other;
return this == other;
}

public boolean equalsIgnoreCase(String other) {
Expand Down Expand Up @@ -489,11 +489,11 @@ public int lastIndexOf(int codePoint, int startIndex) {
public int lastIndexOf(String str) {
return asNativeString().lastIndexOf(str);
}

public int lastIndexOf(String str, int start) {
return asNativeString().lastIndexOf(str, start);
}

@Override
public int length() {
return asNativeString().length;
Expand Down Expand Up @@ -724,7 +724,7 @@ public String toLowerCase(Locale locale) {
public String toUpperCase() {
return asNativeString().toLocaleUpperCase();
}

// See the notes in lowerCase pair.
public String toUpperCase(Locale locale) {
return locale == Locale.getDefault()
Expand Down Expand Up @@ -753,7 +753,7 @@ public String trim() {
return start > 0 || end < length ? substring(start, end) : this;
}

@JsType(isNative = true, name = "String", namespace = JsPackage.GLOBAL)
@JsType(isNative = true, name = "String", namespace = "window")
private static class NativeString {
public static native String fromCharCode(char x);
public int length;
Expand Down
Expand Up @@ -31,7 +31,7 @@ private static String createString() {
private static native String getGeneratedFunctionDefintionThatTriggersStringClinit() /*-{
return function() {
tmp = @StringOptimizationTest::createString()();
}.toString();
}.toString();
}-*/;

public void testStringClinitIsRemoved() throws Exception {
Expand All @@ -53,5 +53,4 @@ private static native String getGeneratedFunctionDefintionThatCallsStringFromCha
String functionDef = getGeneratedFunctionDefintionThatCallsStringFromCharCode();
assertFunctionMatches(functionDef, "tmp=String.fromCharCode('c')");
}

}

0 comments on commit c511029

Please sign in to comment.