Version 3.0.0.

Improved performance by (partially) addressing issue 957 on IA-32. Still needs more work for the other architectures.


git-svn-id: http://v8.googlecode.com/svn/trunk@5932 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index fbe66ec..aa5fe59 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -511,7 +511,7 @@
     if (!maybe_a->ToObject(&a)) continue;
     CHECK(a->IsSymbol());
     Object* b;
-    MaybeObject* maybe_b = Heap::LookupAsciiSymbol(string);
+    MaybeObject *maybe_b = Heap::LookupAsciiSymbol(string);
     if (!maybe_b->ToObject(&b)) continue;
     CHECK_EQ(b, a);
     CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
@@ -978,7 +978,9 @@
   Handle<String> foo_name = Factory::LookupAsciiSymbol("foo");
 
   // This compile will add the code to the compilation cache.
-  CompileRun(source);
+  { v8::HandleScope scope;
+    CompileRun(source);
+  }
 
   // Check function is compiled.
   Object* func_value =
@@ -1000,8 +1002,8 @@
   Heap::CollectAllGarbage(true);
 
   // foo should no longer be in the compilation cache
-  CHECK(!function->shared()->is_compiled());
-  CHECK(!function->is_compiled());
+  CHECK(!function->shared()->is_compiled() || function->IsOptimized());
+  CHECK(!function->is_compiled() || function->IsOptimized());
   // Call foo to get it recompiled.
   CompileRun("foo()");
   CHECK(function->shared()->is_compiled());
@@ -1021,6 +1023,20 @@
 }
 
 
+// Count the number of user functions in the weak list of optimized
+// functions attached to a global context.
+static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
+  int count = 0;
+  Handle<Context> icontext = v8::Utils::OpenHandle(*context);
+  Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
+  while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
+    count++;
+    object = JSFunction::cast(object)->next_function_link();
+  }
+  return count;
+}
+
+
 TEST(TestInternalWeakLists) {
   static const int kNumTestContexts = 10;
 
@@ -1032,9 +1048,63 @@
   // Create a number of global contests which gets linked together.
   for (int i = 0; i < kNumTestContexts; i++) {
     ctx[i] = v8::Context::New();
+
+    bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
+
     CHECK_EQ(i + 1, CountGlobalContexts());
 
     ctx[i]->Enter();
+
+    // Create a handle scope so no function objects get stuch in the outer
+    // handle scope
+    v8::HandleScope scope;
+    const char* source = "function f1() { };"
+                         "function f2() { };"
+                         "function f3() { };"
+                         "function f4() { };"
+                         "function f5() { };";
+    CompileRun(source);
+    CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
+    CompileRun("f1()");
+    CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
+    CompileRun("f2()");
+    CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
+    CompileRun("f3()");
+    CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
+    CompileRun("f4()");
+    CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
+    CompileRun("f5()");
+    CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
+
+    // Remove function f1, and
+    CompileRun("f1=null");
+
+    // Scavenge treats these references as strong.
+    for (int j = 0; j < 10; j++) {
+      Heap::PerformScavenge();
+      CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
+    }
+
+    // Mark compact handles the weak references.
+    Heap::CollectAllGarbage(true);
+    CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
+
+    // Get rid of f3 and f5 in the same way.
+    CompileRun("f3=null");
+    for (int j = 0; j < 10; j++) {
+      Heap::PerformScavenge();
+      CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
+    }
+    Heap::CollectAllGarbage(true);
+    CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
+    CompileRun("f5=null");
+    for (int j = 0; j < 10; j++) {
+      Heap::PerformScavenge();
+      CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
+    }
+    Heap::CollectAllGarbage(true);
+    CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
+
     ctx[i]->Exit();
   }
 
@@ -1076,6 +1146,25 @@
 }
 
 
+// Count the number of user functions in the weak list of optimized
+// functions attached to a global context causing a GC after the
+// specified number of elements.
+static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
+                                             int n) {
+  int count = 0;
+  Handle<Context> icontext = v8::Utils::OpenHandle(*context);
+  Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
+  while (object->IsJSFunction() &&
+         !Handle<JSFunction>::cast(object)->IsBuiltin()) {
+    count++;
+    if (count == n) Heap::CollectAllGarbage(true);
+    object = Handle<Object>(
+        Object::cast(JSFunction::cast(*object)->next_function_link()));
+  }
+  return count;
+}
+
+
 TEST(TestInternalWeakListsTraverseWithGC) {
   static const int kNumTestContexts = 10;
 
@@ -1090,10 +1179,37 @@
     ctx[i] = v8::Context::New();
     CHECK_EQ(i + 1, CountGlobalContexts());
     CHECK_EQ(i + 1, CountGlobalContextsWithGC(i / 2 + 1));
-
-    ctx[i]->Enter();
-    ctx[i]->Exit();
   }
+
+  bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
+
+  // Compile a number of functions the length of the weak list of optimized
+  // functions both with and without GCs while iterating the list.
+  ctx[0]->Enter();
+  const char* source = "function f1() { };"
+                       "function f2() { };"
+                       "function f3() { };"
+                       "function f4() { };"
+                       "function f5() { };";
+  CompileRun(source);
+  CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
+  CompileRun("f1()");
+  CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
+  CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
+  CompileRun("f2()");
+  CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
+  CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
+  CompileRun("f3()");
+  CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
+  CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
+  CompileRun("f4()");
+  CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
+  CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
+  CompileRun("f5()");
+  CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
+  CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
+
+  ctx[0]->Exit();
 }