Disable optimization for functions that have scopes that cannot be reconstructed...
authorulan@chromium.org <ulan@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 18 May 2012 13:06:16 +0000 (13:06 +0000)
committerulan@chromium.org <ulan@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 18 May 2012 13:06:16 +0000 (13:06 +0000)
BUG=v8:2071
TEST=mjsunit/regress/regress-2071.js

Review URL: https://chromiumcodereview.appspot.com/10388164

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11592 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/compiler.cc
src/full-codegen.cc
src/scopes.cc
src/scopes.h
test/mjsunit/regress/regress-2071.js [new file with mode: 0644]

index c9c2480..ecac5cb 100644 (file)
@@ -118,7 +118,7 @@ bool CompilationInfo::ShouldSelfOptimize() {
       FLAG_crankshaft &&
       !function()->flags()->Contains(kDontSelfOptimize) &&
       !function()->flags()->Contains(kDontOptimize) &&
-      function()->scope()->allows_lazy_recompilation() &&
+      function()->scope()->AllowsLazyRecompilation() &&
       (shared_info().is_null() || !shared_info()->optimization_disabled());
 }
 
index b8794c0..9b1df4e 100644 (file)
@@ -314,7 +314,8 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
   Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
   Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
   code->set_optimizable(info->IsOptimizable() &&
-                        !info->function()->flags()->Contains(kDontOptimize));
+                        !info->function()->flags()->Contains(kDontOptimize) &&
+                        info->function()->scope()->AllowsLazyRecompilation());
   cgen.PopulateDeoptimizationData(code);
   cgen.PopulateTypeFeedbackInfo(code);
   cgen.PopulateTypeFeedbackCells(code);
index 6f6032a..2c61a75 100644 (file)
@@ -658,6 +658,26 @@ bool Scope::HasTrivialOuterContext() const {
 }
 
 
+bool Scope::AllowsLazyRecompilation() const {
+  return !force_eager_compilation_ &&
+         !TrivialDeclarationScopesBeforeWithScope();
+}
+
+
+bool Scope::TrivialDeclarationScopesBeforeWithScope() const {
+  Scope* outer = outer_scope_;
+  if (outer == NULL) return false;
+  outer = outer->DeclarationScope();
+  while (outer != NULL) {
+    if (outer->is_with_scope()) return true;
+    if (outer->is_declaration_scope() && outer->num_heap_slots() > 0)
+      return false;
+    outer = outer->outer_scope_;
+  }
+  return false;
+}
+
+
 int Scope::ContextChainLength(Scope* scope) {
   int n = 0;
   for (Scope* s = this; s != scope; s = s->outer_scope_) {
index e1a658a..be6705b 100644 (file)
@@ -362,13 +362,16 @@ class Scope: public ZoneObject {
   bool AllowsLazyCompilation() const;
 
   // True if we can lazily recompile functions with this scope.
-  bool allows_lazy_recompilation() const {
-    return !force_eager_compilation_;
-  }
+  bool AllowsLazyRecompilation() const;
 
   // True if the outer context of this scope is always the global context.
   bool HasTrivialOuterContext() const;
 
+  // True if this scope is inside a with scope and all declaration scopes
+  // between them have empty contexts. Such declaration scopes become
+  // invisible during scope info deserialization.
+  bool TrivialDeclarationScopesBeforeWithScope() const;
+
   // The number of contexts between this and scope; zero if this == scope.
   int ContextChainLength(Scope* scope);
 
diff --git a/test/mjsunit/regress/regress-2071.js b/test/mjsunit/regress/regress-2071.js
new file mode 100644 (file)
index 0000000..91ae2a7
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+a = {};
+
+a.b = 42;
+
+with(a) {
+  a.f = (function f1() {
+    function f2() {
+      return b;
+    };
+    return f2;
+  })();
+}
+
+for(var i = 0; i < 10000; i++) {
+  assertEquals(42, a.f());
+}
+
+with(a) {
+  a.g = (function f1() {
+    function f2() {
+      function f3() {
+        return b;
+      }
+      return f3;
+    };
+    return f2();
+  })();
+}
+
+for(var i = 0; i < 10000; i++) {
+  assertEquals(42, a.g());
+}
+
+function outer() {
+  with(a) {
+    a.h = (function f1() {
+      function f2() {
+        function f3() {
+          return b;
+        }
+        return f3;
+      };
+      return f2();
+    })();
+  }
+};
+
+outer();
+
+for(var i = 0; i < 10000; i++) {
+  assertEquals(42, a.h());
+}