Revision: 8401
Author: [email protected]
Date: Wed Jul 21 05:01:19 2010
Log: Add first-class support for [array].length in the compiler.
Review at http://gwt-code-reviews.appspot.com/702801
http://code.google.com/p/google-web-toolkit/source/detail?r=8401
Added:
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayLength.java
Modified:
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ExpressionAnalyzer.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/JavaPrecedenceVisitor.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
/trunk/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
/trunk/tools/api-checker/config/gwt20_21userApi.conf
=======================================
--- /dev/null
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayLength.java Wed
Jul 21 05:01:19 2010
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010 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
+ * the License.
+ */
+package com.google.gwt.dev.jjs.ast;
+
+import com.google.gwt.dev.jjs.SourceInfo;
+
+/**
+ * Java array length expression.
+ */
+public class JArrayLength extends JExpression {
+
+ private JExpression instance;
+
+ public JArrayLength(SourceInfo info, JExpression instance) {
+ super(info);
+ assert (instance != null);
+ this.instance = instance;
+ }
+
+ public JExpression getInstance() {
+ return instance;
+ }
+
+ public JType getType() {
+ return JPrimitiveType.INT;
+ }
+
+ @Override
+ public boolean hasSideEffects() {
+ return instance.hasSideEffects();
+ }
+
+ public void traverse(JVisitor visitor, Context ctx) {
+ if (visitor.visit(this, ctx)) {
+ instance = visitor.accept(instance);
+ }
+ visitor.endVisit(this, ctx);
+ }
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java Thu Jul 8
09:38:20 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java Wed Jul 21
05:01:19 2010
@@ -189,6 +189,10 @@
public void endVisit(JAnnotation.Property x, Context ctx) {
endVisit((JNode) x, ctx);
}
+
+ public void endVisit(JArrayLength x, Context ctx) {
+ endVisit((JExpression) x, ctx);
+ }
public void endVisit(JArrayRef x, Context ctx) {
endVisit((JExpression) x, ctx);
@@ -505,6 +509,10 @@
public boolean visit(JAnnotation.Property x, Context ctx) {
return visit((JNode) x, ctx);
}
+
+ public boolean visit(JArrayLength x, Context ctx) {
+ return visit((JExpression) x, ctx);
+ }
public boolean visit(JArrayRef x, Context ctx) {
return visit((JExpression) x, ctx);
=======================================
---
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
Fri Apr 2 14:35:01 2010
+++
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
Wed Jul 21 05:01:19 2010
@@ -18,6 +18,7 @@
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JAbsentArrayDimension;
+import com.google.gwt.dev.jjs.ast.JArrayLength;
import com.google.gwt.dev.jjs.ast.JArrayRef;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
import com.google.gwt.dev.jjs.ast.JBooleanLiteral;
@@ -97,6 +98,13 @@
expression = x;
return false;
}
+
+ @Override
+ public boolean visit(JArrayLength x, Context ctx) {
+ expression = new JArrayLength(x.getSourceInfo(), cloneExpression(
+ x.getInstance()));
+ return false;
+ }
@Override
public boolean visit(JArrayRef x, Context ctx) {
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ExpressionAnalyzer.java
Tue Jul 20 11:02:21 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ExpressionAnalyzer.java
Wed Jul 21 05:01:19 2010
@@ -16,6 +16,7 @@
package com.google.gwt.dev.jjs.impl;
import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JArrayLength;
import com.google.gwt.dev.jjs.ast.JArrayRef;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
import com.google.gwt.dev.jjs.ast.JBinaryOperator;
@@ -92,6 +93,15 @@
public boolean createsObject() {
return createsObject;
}
+
+ @Override
+ public void endVisit(JArrayLength x, Context ctx) {
+ // TODO: Is setting accessesField necessary for array.length access?
+ accessesField = true;
+ // Can throw an NPE when the array instance is null at runtime.
+ JReferenceType refType = (JReferenceType) x.getInstance().getType();
+ canThrowException = refType.canBeNull();
+ }
@Override
public void endVisit(JArrayRef x, Context ctx) {
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
Tue Jul 13 15:21:54 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
Wed Jul 21 05:01:19 2010
@@ -25,6 +25,7 @@
import com.google.gwt.dev.jjs.ast.HasEnclosingType;
import com.google.gwt.dev.jjs.ast.JAnnotation;
import com.google.gwt.dev.jjs.ast.JAnnotationArgument;
+import com.google.gwt.dev.jjs.ast.JArrayLength;
import com.google.gwt.dev.jjs.ast.JArrayRef;
import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JAssertStatement;
@@ -230,6 +231,13 @@
// Reflective invocation causes unused warnings.
@SuppressWarnings("unused")
private static class JavaASTGenerationVisitor {
+
+ /**
+ * The literal for the JLS identifier that represents the length
+ * field on an array.
+ */
+ private static final String ARRAY_LENGTH_FIELD = "length";
+
private static InternalCompilerException translateException(JNode node,
Throwable e) {
if (e instanceof VirtualMachineError) {
@@ -1074,19 +1082,18 @@
JExpression processExpression(FieldReference x) {
FieldBinding fieldBinding = x.binding;
- JField field;
+ SourceInfo info = makeSourceInfo(x);
+ JExpression instance = dispProcessExpression(x.receiver);
+ JExpression expr;
if (fieldBinding.declaringClass == null) {
- // probably array.length
- field = program.getIndexedField("Array.length");
- if (!field.getName().equals(String.valueOf(fieldBinding.name))) {
- throw new InternalCompilerException("Error matching
fieldBinding.");
- }
+ if (!ARRAY_LENGTH_FIELD.equals(String.valueOf(fieldBinding.name)))
{
+ throw new InternalCompilerException("Expected [array].length.");
+ }
+ expr = new JArrayLength(info, instance);
} else {
- field = (JField) typeMap.get(fieldBinding);
- }
- SourceInfo info = makeSourceInfo(x);
- JExpression instance = dispProcessExpression(x.receiver);
- JExpression fieldRef = new JFieldRef(info, instance, field,
currentClass);
+ JField field = (JField) typeMap.get(fieldBinding);
+ expr = new JFieldRef(info, instance, field, currentClass);
+ }
if (x.genericCast != null) {
JType castType = (JType) typeMap.get(x.genericCast);
@@ -1094,9 +1101,9 @@
* Note, this may result in an invalid AST due to an LHS cast
operation.
* We fix this up in FixAssignmentToUnbox.
*/
- return maybeCast(castType, fieldRef);
- }
- return fieldRef;
+ return maybeCast(castType, expr);
+ }
+ return expr;
}
JExpression processExpression(InstanceOfExpression x) {
@@ -1291,18 +1298,16 @@
if (x.otherBindings != null) {
for (int i = 0; i < x.otherBindings.length; ++i) {
FieldBinding fieldBinding = x.otherBindings[i];
- JField field;
if (fieldBinding.declaringClass == null) {
// probably array.length
- field = program.getIndexedField("Array.length");
- if
(!field.getName().equals(String.valueOf(fieldBinding.name))) {
- throw new InternalCompilerException(
- "Error matching fieldBinding.");
- }
+ if
(!ARRAY_LENGTH_FIELD.equals(String.valueOf(fieldBinding.name))) {
+ throw new InternalCompilerException("Expected
[array].length.");
+ }
+ curRef = new JArrayLength(info, curRef);
} else {
- field = (JField) typeMap.get(fieldBinding);
- }
- curRef = new JFieldRef(info, curRef, field, currentClass);
+ JField field = (JField) typeMap.get(fieldBinding);
+ curRef = new JFieldRef(info, curRef, field, currentClass);
+ }
if (x.otherGenericCasts != null && x.otherGenericCasts[i] !=
null) {
JType castType = (JType) typeMap.get(x.otherGenericCasts[i]);
curRef = maybeCast(castType, curRef);
@@ -1615,9 +1620,8 @@
initializers.add(createDeclaration(info, indexVar,
program.getLiteralInt(0)));
// int i$max = i$array.length
- initializers.add(createDeclaration(info, maxVar, new
JFieldRef(info,
- createVariableRef(info, arrayVar),
- program.getIndexedField("Array.length"), currentClass)));
+ initializers.add(createDeclaration(info, maxVar, new
JArrayLength(info,
+ new JLocalRef(info, arrayVar))));
// i$index < i$max
JExpression condition = new JBinaryOperation(info,
=======================================
---
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
Thu Jul 8 08:08:57 2010
+++
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
Wed Jul 21 05:01:19 2010
@@ -26,6 +26,7 @@
import com.google.gwt.dev.jjs.ast.HasName;
import com.google.gwt.dev.jjs.ast.JAbsentArrayDimension;
import com.google.gwt.dev.jjs.ast.JAbstractMethodBody;
+import com.google.gwt.dev.jjs.ast.JArrayLength;
import com.google.gwt.dev.jjs.ast.JArrayRef;
import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JAssertStatement;
@@ -160,8 +161,6 @@
private class CreateNamesAndScopesVisitor extends JVisitor {
- private final JField arrayLengthField =
program.getIndexedField("Array.length");
-
/**
* Cache of computed Java source file names to URI strings for symbol
* export. By using a cache we also ensure the miminum number of String
@@ -193,10 +192,7 @@
recordSymbol(x, jsName);
} else {
JsName jsName;
- if (x == arrayLengthField) {
- jsName = peek().declareName(name);
- jsName.setObfuscatable(false);
- } else if (belongsToSpecialObfuscatedType(x)) {
+ if (belongsToSpecialObfuscatedType(x)) {
jsName = peek().declareName(mangleNameSpecialObfuscate(x));
jsName.setObfuscatable(false);
} else {
@@ -516,6 +512,8 @@
*/
private Map<JMethod, Integer> entryMethodToIndex;
+ private final JsName arrayLength = objectScope.declareName("length");
+
private final JsName globalTemp = topScope.declareName("_");
private final JsName prototype = objectScope.declareName("prototype");
@@ -523,6 +521,7 @@
{
globalTemp.setObfuscatable(false);
prototype.setObfuscatable(false);
+ arrayLength.setObfuscatable(false);
}
public GenerateJavaScriptVisitor() {
@@ -533,6 +532,15 @@
public void endVisit(JAbsentArrayDimension x, Context ctx) {
throw new InternalCompilerException("Should not get here.");
}
+
+ @Override
+ public void endVisit(JArrayLength x, Context ctx) {
+ assert x.getInstance() != null : "Can't access the length of a null
array";
+ JsExpression qualifier = (JsExpression) pop();
+ JsNameRef ref = arrayLength.makeRef(x.getSourceInfo());
+ ref.setQualifier(qualifier);
+ push(ref);
+ }
@Override
public void endVisit(JArrayRef x, Context ctx) {
=======================================
---
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/JavaPrecedenceVisitor.java
Tue Mar 9 10:54:56 2010
+++
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/JavaPrecedenceVisitor.java
Wed Jul 21 05:01:19 2010
@@ -18,6 +18,7 @@
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JAbsentArrayDimension;
+import com.google.gwt.dev.jjs.ast.JArrayLength;
import com.google.gwt.dev.jjs.ast.JArrayRef;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
import com.google.gwt.dev.jjs.ast.JBooleanLiteral;
@@ -74,6 +75,12 @@
answer = 0;
return false;
}
+
+ @Override
+ public boolean visit(JArrayLength x, Context ctx) {
+ answer = 0;
+ return false;
+ }
@Override
public boolean visit(JArrayRef x, Context ctx) {
=======================================
---
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
Thu Mar 11 17:23:20 2010
+++
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
Wed Jul 21 05:01:19 2010
@@ -24,6 +24,7 @@
import com.google.gwt.dev.jjs.ast.HasType;
import com.google.gwt.dev.jjs.ast.JAbsentArrayDimension;
import com.google.gwt.dev.jjs.ast.JAnnotation;
+import com.google.gwt.dev.jjs.ast.JArrayLength;
import com.google.gwt.dev.jjs.ast.JArrayRef;
import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JAssertStatement;
@@ -187,6 +188,16 @@
}
return false;
}
+
+ @Override
+ public boolean visit(JArrayLength x, Context ctx) {
+ JExpression instance = x.getInstance();
+ parenPush(x, instance);
+ accept(instance);
+ parenPop(x, instance);
+ print(".length");
+ return false;
+ }
@Override
public boolean visit(JArrayRef x, Context ctx) {
=======================================
---
/trunk/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
Thu Jun 24 15:39:22 2010
+++
/trunk/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
Wed Jul 21 05:01:19 2010
@@ -266,12 +266,6 @@
* ExpandoWrapper.initExpandos().
*/
- /**
- * Represents the array length. References to this field are magically
- * translated.
- */
- public volatile int length = 0;
-
/**
* Holds the real type-specific Class object for a given array instance.
The
* compiler produces a magic implementation of getClass() which returns
this
=======================================
--- /trunk/tools/api-checker/config/gwt20_21userApi.conf Mon Jun 14
12:28:42 2010
+++ /trunk/tools/api-checker/config/gwt20_21userApi.conf Wed Jul 21
05:01:19 2010
@@ -139,6 +139,9 @@
com.google.gwt.lang.LongLib::typeChange(J) MISSING
com.google.gwt.lang.LongLib::xor([D[D) MISSING
+# Array.length is now intrinsic to the compiler
+com.google.gwt.lang.Array::length MISSING
+
# Add DateTimeFormatInfo, PredefinedFormat overrides
com.google.gwt.i18n.client.DateTimeFormat::DateTimeFormat(Ljava/lang/String;Lcom/google/gwt/i18n/client/constants/DateTimeConstants;)
OVERLOADED_METHOD_CALL
com.google.gwt.i18n.client.DateTimeFormat::getFormat(Ljava/lang/String;)
OVERLOADED_METHOD_CALL
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors