Fix sharing of literal boilerplates for optimized code.
authormstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 22 Jun 2012 13:55:15 +0000 (13:55 +0000)
committermstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 22 Jun 2012 13:55:15 +0000 (13:55 +0000)
This makes sure the literal boilerplates array is correctly shared
together with optimized code when caching of optimized code is enabled.
It also enabled said caching by default again.

R=ulan@chromium.org
BUG=v8:2193
TEST=mjsunit/regress/regress-2193

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

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

src/compiler.cc
src/factory.cc
src/flag-definitions.h
src/objects.cc
src/objects.h
src/runtime.cc
test/mjsunit/regress/regress-2193.js [new file with mode: 0644]

index f706c7d..d35532f 100644 (file)
@@ -623,17 +623,15 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
     Handle<JSFunction> function = info->closure();
     ASSERT(!function.is_null());
     Handle<Context> global_context(function->context()->global_context());
-    int index = function->shared()->SearchOptimizedCodeMap(*global_context);
+    int index = shared->SearchOptimizedCodeMap(*global_context);
     if (index > 0) {
       if (FLAG_trace_opt) {
-        PrintF("  [Found optimized code for");
+        PrintF("[found optimized code for: ");
         function->PrintName();
-        PrintF("\n");
+        PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(*function));
       }
-      Code* code = Code::cast(
-          FixedArray::cast(shared->optimized_code_map())->get(index));
-      ASSERT(code != NULL);
-      function->ReplaceCode(code);
+      // Caching of optimized code enabled and optimized code found.
+      shared->InstallFromOptimizedCodeMap(*function, index);
       return true;
     }
   }
@@ -672,20 +670,8 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
         if (FLAG_cache_optimized_code &&
             code->kind() == Code::OPTIMIZED_FUNCTION) {
           Handle<SharedFunctionInfo> shared(function->shared());
+          Handle<FixedArray> literals(function->literals());
           Handle<Context> global_context(function->context()->global_context());
-
-          // Create literals array that will be shared for this global context.
-          int number_of_literals = shared->num_literals();
-          Handle<FixedArray> literals =
-              isolate->factory()->NewFixedArray(number_of_literals);
-          if (number_of_literals > 0) {
-            // Store the object, regexp and array functions in the literals
-            // array prefix.  These functions will be used when creating
-            // object, regexp and array literals in this function.
-            literals->set(JSFunction::kLiteralGlobalContextIndex,
-                          function->context()->global_context());
-          }
-
           SharedFunctionInfo::AddToOptimizedCodeMap(
               shared, global_context, code, literals);
         }
index 682125e..c33b715 100644 (file)
@@ -555,40 +555,23 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
 
   result->set_context(*context);
 
-  int index = FLAG_cache_optimized_code
-      ? function_info->SearchOptimizedCodeMap(context->global_context())
-      : -1;
-  if (!function_info->bound()) {
-    if (index > 0) {
-      FixedArray* code_map =
-          FixedArray::cast(function_info->optimized_code_map());
-      FixedArray* cached_literals = FixedArray::cast(code_map->get(index + 1));
-      ASSERT(cached_literals != NULL);
-      ASSERT(function_info->num_literals() == 0 ||
-             (code_map->get(index - 1) ==
-              cached_literals->get(JSFunction::kLiteralGlobalContextIndex)));
-      result->set_literals(cached_literals);
-    } else {
-      int number_of_literals = function_info->num_literals();
-      Handle<FixedArray> literals =
-          NewFixedArray(number_of_literals, pretenure);
-      if (number_of_literals > 0) {
-        // Store the object, regexp and array functions in the literals
-        // array prefix.  These functions will be used when creating
-        // object, regexp and array literals in this function.
-        literals->set(JSFunction::kLiteralGlobalContextIndex,
-                      context->global_context());
-      }
-      result->set_literals(*literals);
+  int index = function_info->SearchOptimizedCodeMap(context->global_context());
+  if (!function_info->bound() && index < 0) {
+    int number_of_literals = function_info->num_literals();
+    Handle<FixedArray> literals = NewFixedArray(number_of_literals, pretenure);
+    if (number_of_literals > 0) {
+      // Store the global context in the literals array prefix. This
+      // context will be used when creating object, regexp and array
+      // literals in this function.
+      literals->set(JSFunction::kLiteralGlobalContextIndex,
+                    context->global_context());
     }
+    result->set_literals(*literals);
   }
 
   if (index > 0) {
     // Caching of optimized code enabled and optimized code found.
-    Code* code = Code::cast(
-        FixedArray::cast(function_info->optimized_code_map())->get(index));
-    ASSERT(code != NULL);
-    result->ReplaceCode(code);
+    function_info->InstallFromOptimizedCodeMap(*result, index);
     return result;
   }
 
index 7581d60..125d151 100644 (file)
@@ -209,7 +209,7 @@ DEFINE_bool(optimize_closures, true, "optimize closures")
 DEFINE_bool(lookup_sample_by_shared, true,
             "when picking a function to optimize, watch for shared function "
             "info, not JSFunction itself")
-DEFINE_bool(cache_optimized_code, false,
+DEFINE_bool(cache_optimized_code, true,
             "cache optimized code for closures")
 DEFINE_bool(inline_construct, true, "inline constructor calls")
 DEFINE_bool(inline_arguments, true, "inline functions with arguments object")
index 1d2cd69..78f83c4 100644 (file)
@@ -7546,6 +7546,23 @@ void SharedFunctionInfo::AddToOptimizedCodeMap(
 }
 
 
+void SharedFunctionInfo::InstallFromOptimizedCodeMap(JSFunction* function,
+                                                     int index) {
+  ASSERT(index > 0);
+  ASSERT(optimized_code_map()->IsFixedArray());
+  FixedArray* code_map = FixedArray::cast(optimized_code_map());
+  if (!bound()) {
+    FixedArray* cached_literals = FixedArray::cast(code_map->get(index + 1));
+    ASSERT(cached_literals != NULL);
+    function->set_literals(cached_literals);
+  }
+  Code* code = Code::cast(code_map->get(index));
+  ASSERT(code != NULL);
+  ASSERT(function->context()->global_context() == code_map->get(index - 1));
+  function->ReplaceCode(code);
+}
+
+
 bool JSFunction::CompileLazy(Handle<JSFunction> function,
                              ClearExceptionFlag flag) {
   bool result = true;
@@ -8097,6 +8114,7 @@ void SharedFunctionInfo::CompleteInobjectSlackTracking() {
 
 int SharedFunctionInfo::SearchOptimizedCodeMap(Context* global_context) {
   ASSERT(global_context->IsGlobalContext());
+  if (!FLAG_cache_optimized_code) return -1;
   Object* value = optimized_code_map();
   if (!value->IsSmi()) {
     FixedArray* optimized_code_map = FixedArray::cast(value);
index 692df44..9c3d0f8 100644 (file)
@@ -5227,6 +5227,10 @@ class SharedFunctionInfo: public HeapObject {
   // Returns -1 when no matching entry is found.
   int SearchOptimizedCodeMap(Context* global_context);
 
+  // Installs optimized code from the code map on the given closure. The
+  // index has to be consistent with a search result as defined above.
+  void InstallFromOptimizedCodeMap(JSFunction* function, int index);
+
   // Clear optimized code map.
   void ClearOptimizedCodeMap();
 
index df8e8d7..82206dd 100644 (file)
@@ -635,6 +635,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
   // Check if boilerplate exists. If not, create it first.
   Handle<Object> boilerplate(literals->get(literals_index), isolate);
   if (*boilerplate == isolate->heap()->undefined_value()) {
+    ASSERT(*elements != isolate->heap()->empty_fixed_array());
     boilerplate =
         Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
     if (boilerplate.is_null()) return Failure::Exception();
diff --git a/test/mjsunit/regress/regress-2193.js b/test/mjsunit/regress/regress-2193.js
new file mode 100644 (file)
index 0000000..50509bf
--- /dev/null
@@ -0,0 +1,58 @@
+// 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.
+
+// Flags: --allow-natives-syntax --cache-optimized-code
+
+function bozo() {};
+function MakeClosure() {
+  return function f(use_literals) {
+    if (use_literals) {
+      return [1,2,3,3,4,5,6,7,8,9,bozo];
+    } else {
+      return 0;
+    }
+  }
+}
+
+// Create two closures that share the same literal boilerplates.
+var closure1 = MakeClosure();
+var closure2 = MakeClosure();
+var expected = [1,2,3,3,4,5,6,7,8,9,bozo];
+
+// Make sure we generate optimized code for the first closure after
+// warming it up properly so that the literals boilerplate is generated
+// and the optimized code uses CreateArrayLiteralShallow runtime call.
+assertEquals(0, closure1(false));
+assertEquals(expected, closure1(true));
+%OptimizeFunctionOnNextCall(closure1);
+assertEquals(expected, closure1(true));
+
+// Optimize the second closure, which should reuse the optimized code
+// from the first closure with the same literal boilerplates.
+assertEquals(0, closure2(false));
+%OptimizeFunctionOnNextCall(closure2);
+assertEquals(expected, closure2(true));