Revision: 7516
Author: sp...@google.com
Date: Mon Feb 1 07:58:03 2010
Log: Fixes issue 4512. In JsStackEmulation, avoid rewriting references to
non-references. For example, don't rewrite bar['foo']() to
(line="123",bar['foo'])(), because that will result in
"this" being set incorrectly in the invoked function.
http://code.google.com/p/google-web-toolkit/source/detail?r=7516
Added:
/trunk/user/test/com/google/gwt/core/StackTraceLineNumbersTest.gwt.xml
/trunk/user/test/com/google/gwt/core/client/impl/StackTraceLineNumbersTest.java
Modified:
/trunk/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java
/trunk/dev/core/src/com/google/gwt/dev/js/ast/JsForIn.java
/trunk/user/test/com/google/gwt/dev/jjs/CompilerSuite.java
=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/core/StackTraceLineNumbersTest.gwt.xml
Mon Feb 1 07:58:03 2010
@@ -0,0 +1,28 @@
+<!--
-->
+<!-- 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 -->
+<!-- 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. License for the specific language governing permissions
and -->
+<!-- limitations under the
License. -->
+
+<!-- Types and resources required to support primitive system
operation. -->
+<!--
-->
+<!-- Types from this module are visible to and imported into user
code. -->
+<!-- Every module should directly or indirectly inherit this
module. -->
+<!--
-->
+
+<module>
+ <inherits name="com.google.gwt.core.Core" />
+
+ <set-configuration-property
name="compiler.emulatedStack.recordLineNumbers"
+ value="true" />
+ <set-configuration-property name="compiler.emulatedStack.recordFileNames"
+ value="true" />
+</module>
=======================================
--- /dev/null
+++
/trunk/user/test/com/google/gwt/core/client/impl/StackTraceLineNumbersTest.java
Mon Feb 1 07:58:03 2010
@@ -0,0 +1,61 @@
+/*
+ * 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.core.client.impl;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests that stack traces work properly with line numbers turned on.
+ */
+public class StackTraceLineNumbersTest extends GWTTestCase {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.core.StackTraceLineNumbersTest";
+ }
+
+ /**
+ * Tests that the rewrites do not change a reference to a comma
+ * expression, in contexts where a reference is needed and
+ * not just a value. See issue 4512.
+ */
+ public native void testRefBreakups() /*-{
+ var assertTrue =
@junit.framework.Assert::assertTrue(Ljava/lang/String;Z);
+
+ // Check breakups in an invocation context
+ var bar = {
+ foo: function() {
+ return this === bar;
+ }
+ }
+
+ assertTrue("bar['foo']", bar['foo']());
+ assertTrue("bar.foo", bar.foo());
+
+ // Check breakups in for-in statements
+ var c = null;
+ for (a in [0, 1, 2]) {
+ c = a;
+ }
+ assertTrue("for-in", c==2);
+
+ // typeOf works on bad references
+ assertTrue("typeOf", (typeof someNameThatDoesNotExist301402172)
== 'undefined');
+
+ // delete needs a reference, not a value
+ delete bar.foo;
+ }-*/;
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java Wed Oct
28 09:10:53 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/js/JsStackEmulator.java Mon Feb
1 07:58:03 2010
@@ -38,6 +38,7 @@
import com.google.gwt.dev.js.ast.JsName;
import com.google.gwt.dev.js.ast.JsNameRef;
import com.google.gwt.dev.js.ast.JsNew;
+import com.google.gwt.dev.js.ast.JsNode;
import com.google.gwt.dev.js.ast.JsPostfixOperation;
import com.google.gwt.dev.js.ast.JsPrefixOperation;
import com.google.gwt.dev.js.ast.JsProgram;
@@ -56,8 +57,10 @@
import com.google.gwt.dev.util.collect.Maps;
import java.io.File;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Emulates the JS stack in order to provide useful stack traces on
browers that
@@ -67,8 +70,6 @@
*/
public class JsStackEmulator {
- private static final String PROPERTY_NAME = "compiler.emulatedStack";
-
/**
* Resets the global stack depth to the local stack index and top stack
frame
* after calls to Exceptions.caught. This is created by
@@ -593,6 +594,14 @@
private String lastFile;
private int lastLine;
+ /**
+ * Nodes in this set are used in a context that expects a reference,
not
+ * just an arbitrary expression. For example, <code>delete</code>
takes a
+ * reference. These are tracked because it wouldn't be safe to rewrite
+ * <code>delete foo.bar</code> to <code>delete
(line='123',foo).bar</code>.
+ */
+ private final Set<JsNode<?>> nodesInRefContext = new
HashSet<JsNode<?>>();
+
public LocationVisitor(JsFunction function) {
super(function);
resetPosition();
@@ -612,8 +621,14 @@
@Override
public void endVisit(JsInvocation x, JsContext<JsExpression> ctx) {
+ nodesInRefContext.remove(x.getQualifier());
record(x, ctx);
}
+
+ @Override
+ public void endVisit(JsNameRef x, JsContext<JsExpression> ctx) {
+ record(x, ctx);
+ }
@Override
public void endVisit(JsNew x, JsContext<JsExpression> ctx) {
@@ -622,16 +637,13 @@
@Override
public void endVisit(JsPostfixOperation x, JsContext<JsExpression>
ctx) {
- if (x.getOperator().isModifying()) {
- record(x, ctx);
- }
+ record(x, ctx);
}
@Override
public void endVisit(JsPrefixOperation x, JsContext<JsExpression> ctx)
{
- if (x.getOperator().isModifying()) {
- record(x, ctx);
- }
+ record(x, ctx);
+ nodesInRefContext.remove(x.getArg());
}
/**
@@ -663,12 +675,16 @@
}
@Override
- public boolean visit(JsNameRef x, JsContext<JsExpression> ctx) {
- if (ctx.isLvalue()) {
- if (x.getQualifier() != null) {
- accept(x.getQualifier());
- }
- return false;
+ public boolean visit(JsInvocation x, JsContext<JsExpression> ctx) {
+ nodesInRefContext.add(x.getQualifier());
+ return true;
+ }
+
+ @Override
+ public boolean visit(JsPrefixOperation x, JsContext<JsExpression> ctx)
{
+ if (x.getOperator() == JsUnaryOperator.DELETE
+ || x.getOperator() == JsUnaryOperator.TYPEOF) {
+ nodesInRefContext.add(x.getArg());
}
return true;
}
@@ -706,6 +722,9 @@
if (ctx.isLvalue()) {
// Assignments to comma expressions aren't legal
return;
+ } else if (nodesInRefContext.contains(x)) {
+ // Don't modify references into non-references
+ return;
} else if (x.getSourceInfo().getStartLine() == lastLine
&& (!recordFileNames || x.getSourceInfo().getFileName().equals(
lastFile))) {
@@ -750,13 +769,13 @@
* with references to our locally-defined, obfuscatable names.
*/
private class ReplaceUnobfuscatableNames extends JsModVisitor {
+ private final JsName rootLineNumbers =
program.getRootScope().findExistingUnobfuscatableName(
+ "$location");
// See JsRootScope for the definition of these names
private final JsName rootStack =
program.getRootScope().findExistingUnobfuscatableName(
"$stack");
private final JsName rootStackDepth =
program.getRootScope().findExistingUnobfuscatableName(
"$stackDepth");
- private final JsName rootLineNumbers =
program.getRootScope().findExistingUnobfuscatableName(
- "$location");
@Override
public void endVisit(JsNameRef x, JsContext<JsExpression> ctx) {
@@ -779,6 +798,8 @@
ctx.replaceMe(newRef);
}
}
+
+ private static final String PROPERTY_NAME = "compiler.emulatedStack";
public static void exec(JsProgram program, PropertyOracle[]
propertyOracles) {
SelectionProperty property;
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/js/ast/JsForIn.java Fri Sep 26
08:20:00 2008
+++ /trunk/dev/core/src/com/google/gwt/dev/js/ast/JsForIn.java Mon Feb 1
07:58:03 2010
@@ -71,7 +71,7 @@
public void traverse(JsVisitor v, JsContext<JsStatement> ctx) {
if (v.visit(this, ctx)) {
if (iterExpr != null) {
- iterExpr = v.accept(iterExpr);
+ iterExpr = v.acceptLvalue(iterExpr);
}
objExpr = v.accept(objExpr);
body = v.accept(body);
=======================================
--- /trunk/user/test/com/google/gwt/dev/jjs/CompilerSuite.java Mon Jan 11
09:04:38 2010
+++ /trunk/user/test/com/google/gwt/dev/jjs/CompilerSuite.java Mon Feb 1
07:58:03 2010
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.jjs;
+import com.google.gwt.core.client.impl.StackTraceLineNumbersTest;
import com.google.gwt.dev.jjs.scriptonly.ScriptOnlyTest;
import com.google.gwt.dev.jjs.test.AnnotationsTest;
import com.google.gwt.dev.jjs.test.AutoboxTest;
@@ -93,6 +94,7 @@
suite.addTestSuite(RunAsyncTest.class);
suite.addTestSuite(ScriptOnlyTest.class);
suite.addTestSuite(SingleJsoImplTest.class);
+ suite.addTestSuite(StackTraceLineNumbersTest.class);
suite.addTestSuite(TypeHierarchyTest.class);
suite.addTestSuite(UnstableGeneratorTest.class);
suite.addTestSuite(VarargsTest.class);
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors