Remove magicness around nullMethod.
(1) Removes JSNI syntax @null::nullMethod and @null::nullField.
(2) Declares a noop function JCHSU.emptyFunction() that is used
in the places where null.nullMethod() was used for that
purpose, e.g. to make clinits idempotent.
(3) Declares an typeMarker function in JCHSU.typeMarker() to be used
where the null.nullMethod was used as a typeMarker.
(4) Moves the setting of typeMarker at Object from code generation at
GenerateJavaScriptAst to intrinsic in library JCHSU.defineClass.
Change-Id: Ifc309a782a2fc2af675e4645adb9cee4e95a1a40
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniReferenceResolver.java b/dev/core/src/com/google/gwt/dev/javac/JsniReferenceResolver.java
index ffd1c61..ace13a9 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniReferenceResolver.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniReferenceResolver.java
@@ -257,8 +257,6 @@
return;
}
- resolveClassReference(jsniRef);
-
Binding binding = resolveReference(x.getSourceInfo(), jsniRef, x.getQualifier() != null,
ctx.isLvalue());
@@ -442,18 +440,9 @@
private Binding resolveReference(SourceInfo errorInfo, JsniRef jsniRef, boolean hasQualifier,
boolean isLvalue) {
+
+ resolveClassReference(jsniRef);
String className = jsniRef.getResolvedClassName();
- if ("null".equals(className)) {
- // Do not emit errors for null.nullField or null.nullMethod.
- // TODO(rluble): Why should these ever reach resolveReference()?
- if (jsniRef.isField() && !"nullField".equals(jsniRef.memberName())) {
- emitError(ERR_ILLEGAL_FIELD_ACCESS_ON_NULL, errorInfo, jsniRef);
- } else if (jsniRef.isMethod() && !"nullMethod()".equals(jsniRef.memberSignature())) {
- emitError(ERR_ILLEGAL_METHOD_ACCESS_ON_NULL, errorInfo, jsniRef);
- }
- jsniRef.setResolvedMemberWithSignature(jsniRef.memberSignature());
- return null;
- }
boolean isPrimitive;
ReferenceBinding clazz;
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 dfa83ba..e77cdae 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
@@ -463,19 +463,6 @@
names.put(nullField, nullFieldName);
/*
- * put nullMethod in the global scope, too; it's the replacer for clinits.
- */
- if (!program.isReferenceOnly(program.getIndexedType("Cast"))) {
- // This is the module that contains the intrinsics, hence define the null function.
- // TODO(rluble): this should be cleaner. Ideally there is a bootstrap library that
- // is minimal and has all compiler support code.
- nullFunctionJsName = createNullFunction(nullMethod.getName());
- } else {
- nullFunctionJsName = topScope.declareName(nullMethod.getName());
- }
- names.put(nullMethod, nullFunctionJsName);
-
- /*
* Create names for instantiable array types since JProgram.traverse()
* doesn't iterate over them.
*/
@@ -1957,7 +1944,8 @@
if (jsName == null) {
// this can occur when JSNI references an instance method on a
// type that was never actually instantiated.
- jsName = nullFunctionJsName;
+ jsName =
+ indexedFunctions.get("JavaClassHierarchySetupUtil.emptyMethod").getName();
}
x.resolve(jsName);
}
@@ -2126,8 +2114,6 @@
if (x == program.getTypeJavaLangObject()) {
// special: setup a "toString" alias for java.lang.Object.toString()
generateToStringAlias(x, globalStmts);
- // special: setup the identifying typeMarker field
- generateTypeMarker(globalStmts);
// Set up the artificial castmap for string.
setupStringCastMap(program.getTypeJavaLangString(), globalStmts);
@@ -2551,22 +2537,6 @@
}
}
- private void generateTypeMarker(List<JsStatement> globalStmts) {
- JField typeMarkerField = program.getIndexedField("Object.typeMarker");
- JsName typeMarkerName = names.get(typeMarkerField);
- if (typeMarkerName == null) {
- // Was pruned; this compilation must have no JSO instanceof tests.
- return;
- }
- SourceInfo sourceInfo = jsProgram.createSourceInfoSynthetic(GenerateJavaScriptAST.class);
- JsNameRef fieldRef = typeMarkerName.makeRef(sourceInfo);
- fieldRef.setQualifier(globalTemp.makeRef(sourceInfo));
- JsExpression asg = createAssignment(fieldRef, nullFunctionJsName.makeRef(sourceInfo));
- JsExprStmt stmt = asg.makeStmt();
- globalStmts.add(stmt);
- typeForStatMap.put(stmt, program.getTypeJavaLangObject());
- }
-
/**
* Create a vtable assignment of the form _.polyname = rhs; and register the line as
* created for {@code method}.
@@ -2727,9 +2697,12 @@
clinitFunc.setImpliedExecute(superClinit);
List<JsStatement> statements = clinitFunc.getBody().getStatements();
SourceInfo sourceInfo = clinitFunc.getSourceInfo();
- // self-assign to the null method immediately (to prevent reentrancy)
+ // self-assign to the global noop method immediately (to prevent reentrancy)
+
+ JsFunction emptyFunctionFn =
+ indexedFunctions.get("JavaClassHierarchySetupUtil.emptyMethod");
JsExpression asg = createAssignment(clinitFunc.getName().makeRef(sourceInfo),
- nullFunctionJsName.makeRef(sourceInfo));
+ emptyFunctionFn.getName().makeRef(sourceInfo));
statements.add(0, asg.makeStmt());
}
@@ -3158,7 +3131,6 @@
private final Map<JsName, JsExpression> longObjects = Maps.newIdentityHashMap();
private final Map<JAbstractMethodBody, JsFunction> methodBodyMap = Maps.newIdentityHashMap();
private final Map<HasName, JsName> names = Maps.newIdentityHashMap();
- private JsName nullFunctionJsName;
/**
* Contains JsNames for the Object instance methods, such as equals, hashCode,
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index eff46e2..83fa141 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -261,15 +261,8 @@
String ident = x.getIdent();
Binding binding = jsniRefs.get(ident);
SourceInfo info = x.getSourceInfo();
- if (binding == null) {
- assert ident.startsWith("@null::");
- if ("@null::nullMethod()".equals(ident)) {
- processMethod(x, info, JMethod.NULL_METHOD);
- } else {
- assert "@null::nullField".equals(ident);
- processField(x, info, JField.NULL_FIELD, ctx);
- }
- } else if (binding instanceof TypeBinding) {
+ assert binding != null;
+ if (binding instanceof TypeBinding) {
JType type = typeMap.get((TypeBinding) binding);
processClassLiteral(x, info, type, ctx);
} else if (binding instanceof FieldBinding) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java
index a6cd491..1ff00c0 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsniRefLookup.java
@@ -1,12 +1,12 @@
/*
* Copyright 2009 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
@@ -35,7 +35,7 @@
/**
* A utility class that can look up a {@link JsniRef} in a {@link JProgram}.
- *
+ *
* @deprecated find alternatives, only a couple of corner cases use this now.
*/
@Deprecated
@@ -49,7 +49,7 @@
/**
* Look up a JSNI reference.
- *
+ *
* @param ref The reference to look up
* @param program The program to look up the reference in
* @param errorReporter A callback used to indicate the reason for a failed
@@ -61,24 +61,18 @@
public static JNode findJsniRefTarget(JsniRef ref, JProgram program,
JsniRefLookup.ErrorReporter errorReporter) {
String className = ref.className();
- JType type = null;
- if (!className.equals("null")) {
- type = program.getTypeFromJsniRef(className);
- if (type == null) {
- errorReporter.reportError("Unresolvable native reference to type '" + className + "'");
- return null;
- }
+ JType type = program.getTypeFromJsniRef(className);
+
+ if (type == null) {
+ errorReporter.reportError("Unresolvable native reference to type '" + className + "'");
+ return null;
}
if (!ref.isMethod()) {
// look for a field
String fieldName = ref.memberName();
- if (type == null) {
- if (fieldName.equals("nullField")) {
- return program.getNullField();
- }
- } else if (fieldName.equals(JsniRef.CLASS)) {
+ if (fieldName.equals(JsniRef.CLASS)) {
return type;
} else if (type instanceof JPrimitiveType) {
@@ -109,26 +103,20 @@
new LinkedHashMap<String, LinkedHashMap<String, JMethod>>();
String methodName = ref.memberName();
String jsniSig = ref.memberSignature();
- if (type == null) {
- if (jsniSig.equals("nullMethod()")) {
- return program.getNullMethod();
- }
- } else {
- findMostDerivedMembers(matchesBySig, (JDeclaredType) type, methodName, true);
- LinkedHashMap<String, JMethod> matches = matchesBySig.get(jsniSig);
- if (matches != null && matches.size() == 1) {
- /*
- * Backward compatibility: allow accessing bridge methods with full
- * qualification
- */
- return matches.values().iterator().next();
- }
+ findMostDerivedMembers(matchesBySig, (JDeclaredType) type, methodName, true);
+ LinkedHashMap<String, JMethod> matches = matchesBySig.get(jsniSig);
+ if (matches != null && matches.size() == 1) {
+ /*
+ * Backward compatibility: allow accessing bridge methods with full
+ * qualification
+ */
+ return matches.values().iterator().next();
+ }
- removeSyntheticMembers(matchesBySig);
- matches = matchesBySig.get(jsniSig);
- if (matches != null && matches.size() == 1) {
- return matches.values().iterator().next();
- }
+ removeSyntheticMembers(matchesBySig);
+ matches = matchesBySig.get(jsniSig);
+ if (matches != null && matches.size() == 1) {
+ return matches.values().iterator().next();
}
// Not found; signal an error
@@ -159,7 +147,7 @@
/**
* Add a member to the table of most derived members.
- *
+ *
* @param matchesBySig The table so far of most derived members
* @param member The member to add to it
* @param refSig The string used to refer to that member, possibly shortened
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
index b2f38ea..74dab04 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
@@ -144,7 +144,7 @@
JavaScriptObject elementTypeId, int elementTypeClass, Array array) {
setClass(array, arrayClass);
Util.setCastableTypeMap(array, castableTypeMap);
- Util.setTypeMarker(array, Cast.getNullMethod());
+ Util.setTypeMarker(array);
Array.setElementTypeId(array, elementTypeId);
Array.setElementTypeClass(array, elementTypeClass);
return array;
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
index d4b1ccd..6e6dcbd 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
@@ -113,11 +113,11 @@
}
static boolean isJavaScriptObject(Object src) {
- return !isJavaString(src) && !hasTypeMarker(src);
+ return !isJavaString(src) && !Util.hasTypeMarker(src);
}
static boolean isJavaScriptObjectOrString(Object src) {
- return !hasTypeMarker(src);
+ return !Util.hasTypeMarker(src);
}
/**
@@ -156,7 +156,7 @@
}
// early out for non-Java types because this check is expensive
- if (typeof(obj) === 'string' || @com.google.gwt.lang.Cast::hasTypeMarker(Ljava/lang/Object;)(obj)) {
+ if (typeof(obj) === 'string' || @Util::hasTypeMarker(Ljava/lang/Object;)(obj)) {
return false;
}
@@ -273,10 +273,6 @@
return o;
}
- public static native JavaScriptObject getNullMethod() /*-{
- return @null::nullMethod();
- }-*/;
-
/**
* Returns whether the Object is a Java String.
*
@@ -300,7 +296,7 @@
*/
// Visible for getIndexedMethod()
static boolean hasJavaObjectVirtualDispatch(Object src) {
- return !instanceofArray(src) && hasTypeMarker(src);
+ return !instanceofArray(src) && Util.hasTypeMarker(src);
}
/**
@@ -308,15 +304,13 @@
*
* All regular Java objects and arrays are tagged.
*/
- static boolean hasTypeMarker(Object src) {
- return Util.getTypeMarker(src) == getNullMethod();
- }
+
/**
* Returns true if {@code src} is a Java array.
*/
static boolean isJavaArray(Object src) {
- return instanceofArray(src) && hasTypeMarker(src);
+ return instanceofArray(src) && Util.hasTypeMarker(src);
}
/**
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/JavaClassHierarchySetupUtil.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/JavaClassHierarchySetupUtil.java
index cb763b6..6f95756 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/JavaClassHierarchySetupUtil.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/JavaClassHierarchySetupUtil.java
@@ -61,6 +61,12 @@
_ = prototypesByTypeId[typeId] = (!superTypeId) ? {} : createSubclassPrototype(superTypeId);
_.@java.lang.Object::castableTypeMap = castableTypeMap;
_.constructor = _;
+ if (!superTypeId) {
+ // Set the typeMarker on java.lang.Object's prototype, implicitly setting it for all
+ // Java subclasses (String and Arrays have special handling in Cast and Array respectively).
+ _.@java.lang.Object::typeMarker =
+ @JavaClassHierarchySetupUtil::typeMarkerFn(*);
+ }
}
for (var i = 3; i < arguments.length; ++i) {
// Assign the type prototype to each constructor.
@@ -196,4 +202,17 @@
@com.google.gwt.lang.JavaClassHierarchySetupUtil::prototypesByTypeId[typeId];
return prototypeForTypeId;
}-*/;
+
+ /**
+ * Marker function. All Java Objects (except Strings) have a typeMarker field pointing to
+ * this function.
+ */
+ static native void typeMarkerFn() /*-{
+ }-*/;
+
+ /**
+ * A global noop function. Replaces clinits after execution.
+ */
+ static native void emptyMethod() /*-{
+ }-*/;
}
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Util.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Util.java
index 350a7e1..ea84eb5 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Util.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Util.java
@@ -27,16 +27,17 @@
return o.@java.lang.Object::castableTypeMap;
}-*/;
- static native JavaScriptObject getTypeMarker(Object o) /*-{
- return o.@java.lang.Object::typeMarker;
+ static native void setTypeMarker(Object o) /*-{
+ o.@java.lang.Object::typeMarker =
+ @com.google.gwt.lang.JavaClassHierarchySetupUtil::typeMarkerFn(*);
}-*/;
- static native void setTypeMarker(Object o, JavaScriptObject object) /*-{
- return o.@java.lang.Object::typeMarker = object;
+ static native boolean hasTypeMarker(Object o) /*-{
+ return o.@java.lang.Object::typeMarker ===
+ @com.google.gwt.lang.JavaClassHierarchySetupUtil::typeMarkerFn(*);
}-*/;
static native void setCastableTypeMap(Object o, JavaScriptObject castableTypeMap) /*-{
o.@java.lang.Object::castableTypeMap = castableTypeMap;
}-*/;
-
}
diff --git a/dev/core/test/com/google/gwt/dev/javac/JsniReferenceResolverTest.java b/dev/core/test/com/google/gwt/dev/javac/JsniReferenceResolverTest.java
index 279e71d..e3b298f 100644
--- a/dev/core/test/com/google/gwt/dev/javac/JsniReferenceResolverTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/JsniReferenceResolverTest.java
@@ -1023,14 +1023,17 @@
shouldGenerateNoWarning(buggy);
}
- public void testNullField() {
+ public void testOldStyleNullField() {
MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy",
"class Buggy {",
" static native Object main() /*-{",
" return @null::nullField;",
" }-*/;",
"}");
- shouldGenerateNoWarning(buggy);
+ shouldGenerateError(
+ buggy,
+ 3,
+ "Referencing class 'null': unable to resolve class");
buggy = JavaResourceBase.createMockJavaResource("Buggy",
"class Buggy {",
@@ -1041,17 +1044,20 @@
shouldGenerateError(
buggy,
3,
- "Referencing field 'null.foo': 'nullField' is the only legal field reference for 'null'");
+ "Referencing class 'null': unable to resolve class");
}
- public void testNullMethod() {
+ public void testOldStyleNullMethod() {
MockJavaResource buggy = JavaResourceBase.createMockJavaResource("Buggy",
"class Buggy {",
" static native Object main() /*-{",
" return @null::nullMethod()();",
" }-*/;",
"}");
- shouldGenerateNoWarning(buggy);
+ shouldGenerateError(
+ buggy,
+ 3,
+ "Referencing class 'null': unable to resolve class");
buggy = JavaResourceBase.createMockJavaResource("Buggy",
"class Buggy {",
@@ -1062,7 +1068,7 @@
shouldGenerateError(
buggy,
3,
- "Referencing method 'null.foo()': 'nullMethod()' is the only legal method for 'null'");
+ "Referencing class 'null': unable to resolve class");
}
public void testOverloadedMethodWithNoWarning() {
diff --git a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
index f39a068..0b10b30 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
@@ -254,6 +254,7 @@
" return null;",
" }",
" public static void modernizeBrowser() {}",
+ " public static void emptyMethod() {}",
"}"
);
}