Revision: 5174
Author: [email protected]
Date: Thu Aug  5 01:37:12 2010
Log: Avoid GC when compiling CallIC stubs.

In rare cases GC could be called from ComputeCallMiss function thus
breaking CallIC::LoadFunction.

Review URL: http://codereview.chromium.org/3047027
http://code.google.com/p/v8/source/detail?r=5174

Modified:
 /branches/bleeding_edge/src/arm/stub-cache-arm.cc
 /branches/bleeding_edge/src/heap-inl.h
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
 /branches/bleeding_edge/src/ic.cc
 /branches/bleeding_edge/src/stub-cache.cc
 /branches/bleeding_edge/src/stub-cache.h
 /branches/bleeding_edge/src/x64/stub-cache-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Wed Jul 14 23:17:45 2010 +++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Thu Aug 5 01:37:12 2010
@@ -1252,9 +1252,11 @@
 }


-void CallStubCompiler::GenerateMissBranch() {
-  Handle<Code> ic = ComputeCallMiss(arguments().immediate(), kind_);
-  __ Jump(ic, RelocInfo::CODE_TARGET);
+Object* CallStubCompiler::GenerateMissBranch() {
+  Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_);
+  if (obj->IsFailure()) return obj;
+  __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
+  return obj;
 }


@@ -1286,7 +1288,8 @@

   // Handle call cache miss.
   __ bind(&miss);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(FIELD, name);
@@ -1337,7 +1340,8 @@

   // Handle call cache miss.
   __ bind(&miss);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(function);
@@ -1388,7 +1392,8 @@

   // Handle call cache miss.
   __ bind(&miss);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(function);
@@ -1561,7 +1566,8 @@
   }

   __ bind(&miss_in_smi_check);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(function);
@@ -1610,7 +1616,8 @@

   // Handle call cache miss.
   __ bind(&miss);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(INTERCEPTOR, name);
@@ -1694,7 +1701,8 @@
   // Handle call cache miss.
   __ bind(&miss);
   __ IncrementCounter(&Counters::call_global_inline_miss, 1, r1, r3);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(NORMAL, name);
=======================================
--- /branches/bleeding_edge/src/heap-inl.h      Fri Jun 11 10:03:19 2010
+++ /branches/bleeding_edge/src/heap-inl.h      Thu Aug  5 01:37:12 2010
@@ -434,6 +434,12 @@
   allocation_allowed_ = new_state;
   return old;
 }
+
+inline bool Heap::allow_gc(bool new_state) {
+  bool old = gc_allowed_;
+  gc_allowed_ = new_state;
+  return old;
+}

 #endif

=======================================
--- /branches/bleeding_edge/src/heap.cc Mon Aug  2 08:08:17 2010
+++ /branches/bleeding_edge/src/heap.cc Thu Aug  5 01:37:12 2010
@@ -134,6 +134,7 @@

 #ifdef DEBUG
 bool Heap::allocation_allowed_ = true;
+bool Heap::gc_allowed_ = true;

 int Heap::allocation_timeout_ = 0;
 bool Heap::disallow_allocation_failure_ = false;
@@ -319,6 +320,9 @@


 void Heap::GarbageCollectionPrologue() {
+#ifdef DEBUG
+  ASSERT(gc_allowed_);
+#endif
   TranscendentalCache::Clear();
   ClearJSFunctionResultCaches();
   gc_count_++;
=======================================
--- /branches/bleeding_edge/src/heap.h  Mon Aug  2 08:08:17 2010
+++ /branches/bleeding_edge/src/heap.h  Thu Aug  5 01:37:12 2010
@@ -877,6 +877,8 @@
 #ifdef DEBUG
   static bool IsAllocationAllowed() { return allocation_allowed_; }
   static inline bool allow_allocation(bool enable);
+  static bool IsGCAllowed() { return gc_allowed_; }
+  static inline bool allow_gc(bool enable);

   static bool disallow_allocation_failure() {
     return disallow_allocation_failure_;
@@ -1078,6 +1080,7 @@

 #ifdef DEBUG
   static bool allocation_allowed_;
+  static bool gc_allowed_;

   // If the --gc-interval flag is set to a positive value, this
   // variable holds the value indicating the number of allocations
@@ -1675,6 +1678,20 @@
   ~AssertNoAllocation() {
     Heap::allow_allocation(old_state_);
   }
+
+ private:
+  bool old_state_;
+};
+
+class AssertNoGC {
+ public:
+  AssertNoGC() {
+    old_state_ = Heap::allow_gc(false);
+  }
+
+  ~AssertNoGC() {
+    Heap::allow_gc(old_state_);
+  }

  private:
   bool old_state_;
@@ -1702,6 +1719,12 @@
   ~AssertNoAllocation() { }
 };

+class AssertNoGC {
+ public:
+  AssertNoGC() { }
+  ~AssertNoGC() { }
+};
+
 class DisableAssertNoAllocation {
  public:
   DisableAssertNoAllocation() { }
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Wed Jul 28 02:36:53 2010 +++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Thu Aug 5 01:37:12 2010
@@ -1287,9 +1287,11 @@
 }


-void CallStubCompiler::GenerateMissBranch() {
-  Handle<Code> ic = ComputeCallMiss(arguments().immediate(), kind_);
-  __ jmp(ic, RelocInfo::CODE_TARGET);
+Object* CallStubCompiler::GenerateMissBranch() {
+  Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_);
+  if (obj->IsFailure()) return obj;
+  __ jmp(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
+  return obj;
 }


@@ -1340,7 +1342,8 @@

   // Handle call cache miss.
   __ bind(&miss);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(FIELD, name);
@@ -1487,7 +1490,8 @@
   }

   __ bind(&miss);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(function);
@@ -1570,7 +1574,8 @@
                                1);

   __ bind(&miss);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(function);
@@ -1633,8 +1638,8 @@
   __ ret((argc + 1) * kPointerSize);

   __ bind(&miss);
-
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(function);
@@ -1700,9 +1705,8 @@
   __ ret((argc + 1) * kPointerSize);

   __ bind(&miss);
-  // Restore function name in ecx.
-
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(function);
@@ -1856,7 +1860,8 @@
     FreeSpaceForFastApiCall(masm(), eax);
   }
   __ bind(&miss_in_smi_check);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(function);
@@ -1920,7 +1925,8 @@

   // Handle load cache miss.
   __ bind(&miss);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(INTERCEPTOR, name);
@@ -2005,7 +2011,8 @@
   // Handle call cache miss.
   __ bind(&miss);
   __ IncrementCounter(&Counters::call_global_inline_miss, 1);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(NORMAL, name);
=======================================
--- /branches/bleeding_edge/src/ic.cc   Tue Jul 20 23:59:34 2010
+++ /branches/bleeding_edge/src/ic.cc   Thu Aug  5 01:37:12 2010
@@ -501,20 +501,24 @@

   // Lookup the property in the object.
   LookupResult lookup;
-  LookupForRead(*object, *name, &lookup);
-
-  if (!lookup.IsProperty()) {
-    // If the object does not have the requested property, check which
-    // exception we need to throw.
-    if (IsContextual(object)) {
-      return ReferenceError("not_defined", name);
-    }
-    return TypeError("undefined_method", object, name);
-  }
-
-  // Lookup is valid: Update inline cache and stub cache.
-  if (FLAG_use_ic) {
-    UpdateCaches(&lookup, state, object, name);
+  {
+    AssertNoGC nogc;  // GC could invalidate the pointers held in lookup.
+
+    LookupForRead(*object, *name, &lookup);
+
+    if (!lookup.IsProperty()) {
+      // If the object does not have the requested property, check which
+      // exception we need to throw.
+      if (IsContextual(object)) {
+        return ReferenceError("not_defined", name);
+      }
+      return TypeError("undefined_method", object, name);
+    }
+
+    // Lookup is valid: Update inline cache and stub cache.
+    if (FLAG_use_ic) {
+      UpdateCaches(&lookup, state, object, name);
+    }
   }

   // Get the property.
@@ -787,68 +791,72 @@

   // Named lookup in the object.
   LookupResult lookup;
-  LookupForRead(*object, *name, &lookup);
-
-  // If we did not find a property, check if we need to throw an exception.
-  if (!lookup.IsProperty()) {
-    if (FLAG_strict || IsContextual(object)) {
-      return ReferenceError("not_defined", name);
-    }
-    LOG(SuspectReadEvent(*name, *object));
-  }
-
-  bool can_be_inlined =
-      FLAG_use_ic &&
-      state == PREMONOMORPHIC &&
-      lookup.IsProperty() &&
-      lookup.IsCacheable() &&
-      lookup.holder() == *object &&
-      lookup.type() == FIELD &&
-      !object->IsAccessCheckNeeded();
-
-  if (can_be_inlined) {
-    Map* map = lookup.holder()->map();
-    // Property's index in the properties array.  If negative we have
-    // an inobject property.
-    int index = lookup.GetFieldIndex() - map->inobject_properties();
-    if (index < 0) {
-      // Index is an offset from the end of the object.
-      int offset = map->instance_size() + (index * kPointerSize);
-      if (PatchInlinedLoad(address(), map, offset)) {
-        set_target(megamorphic_stub());
-#ifdef DEBUG
-        if (FLAG_trace_ic) {
-          PrintF("[LoadIC : inline patch %s]\n", *name->ToCString());
-        }
-#endif
-        return lookup.holder()->FastPropertyAt(lookup.GetFieldIndex());
-#ifdef DEBUG
+  {
+    AssertNoGC nogc;  // GC could invalidate the pointers held in lookup.
+
+    LookupForRead(*object, *name, &lookup);
+
+ // If we did not find a property, check if we need to throw an exception.
+    if (!lookup.IsProperty()) {
+      if (FLAG_strict || IsContextual(object)) {
+        return ReferenceError("not_defined", name);
+      }
+      LOG(SuspectReadEvent(*name, *object));
+    }
+
+    bool can_be_inlined =
+        FLAG_use_ic &&
+        state == PREMONOMORPHIC &&
+        lookup.IsProperty() &&
+        lookup.IsCacheable() &&
+        lookup.holder() == *object &&
+        lookup.type() == FIELD &&
+        !object->IsAccessCheckNeeded();
+
+    if (can_be_inlined) {
+      Map* map = lookup.holder()->map();
+      // Property's index in the properties array.  If negative we have
+      // an inobject property.
+      int index = lookup.GetFieldIndex() - map->inobject_properties();
+      if (index < 0) {
+        // Index is an offset from the end of the object.
+        int offset = map->instance_size() + (index * kPointerSize);
+        if (PatchInlinedLoad(address(), map, offset)) {
+          set_target(megamorphic_stub());
+  #ifdef DEBUG
+          if (FLAG_trace_ic) {
+            PrintF("[LoadIC : inline patch %s]\n", *name->ToCString());
+          }
+  #endif
+          return lookup.holder()->FastPropertyAt(lookup.GetFieldIndex());
+  #ifdef DEBUG
+        } else {
+          if (FLAG_trace_ic) {
+            PrintF("[LoadIC : no inline patch %s (patching failed)]\n",
+                   *name->ToCString());
+          }
+        }
       } else {
         if (FLAG_trace_ic) {
-          PrintF("[LoadIC : no inline patch %s (patching failed)]\n",
+          PrintF("[LoadIC : no inline patch %s (not inobject)]\n",
                  *name->ToCString());
         }
       }
     } else {
-      if (FLAG_trace_ic) {
-        PrintF("[LoadIC : no inline patch %s (not inobject)]\n",
-               *name->ToCString());
+      if (FLAG_use_ic && state == PREMONOMORPHIC) {
+        if (FLAG_trace_ic) {
+          PrintF("[LoadIC : no inline patch %s (not inlinable)]\n",
+                 *name->ToCString());
+  #endif
+        }
       }
     }
-  } else {
-    if (FLAG_use_ic && state == PREMONOMORPHIC) {
-      if (FLAG_trace_ic) {
-        PrintF("[LoadIC : no inline patch %s (not inlinable)]\n",
-               *name->ToCString());
-#endif
-      }
+
+    // Update inline cache and stub cache.
+    if (FLAG_use_ic) {
+      UpdateCaches(&lookup, state, object, name);
     }
   }
-
-  // Update inline cache and stub cache.
-  if (FLAG_use_ic) {
-    UpdateCaches(&lookup, state, object, name);
-  }

   PropertyAttributes attr;
   if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
@@ -1037,17 +1045,21 @@

     // Named lookup.
     LookupResult lookup;
-    LookupForRead(*object, *name, &lookup);
-
- // If we did not find a property, check if we need to throw an exception.
-    if (!lookup.IsProperty()) {
-      if (FLAG_strict || IsContextual(object)) {
-        return ReferenceError("not_defined", name);
-      }
-    }
-
-    if (FLAG_use_ic) {
-      UpdateCaches(&lookup, state, object, name);
+    {
+      AssertNoGC nogc;  // GC could invalidate the pointers held in lookup.
+
+      LookupForRead(*object, *name, &lookup);
+
+ // If we did not find a property, check if we need to throw an exception.
+      if (!lookup.IsProperty()) {
+        if (FLAG_strict || IsContextual(object)) {
+          return ReferenceError("not_defined", name);
+        }
+      }
+
+      if (FLAG_use_ic) {
+        UpdateCaches(&lookup, state, object, name);
+      }
     }

     PropertyAttributes attr;
@@ -1245,6 +1257,8 @@

   // Lookup the property locally in the receiver.
   if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) {
+    AssertNoGC nogc;  // GC could invalidate the pointers held in lookup.
+
     LookupResult lookup;

     if (LookupForWrite(*receiver, *name, &lookup)) {
@@ -1418,13 +1432,17 @@
       return *value;
     }

-    // Lookup the property locally in the receiver.
-    LookupResult lookup;
-    receiver->LocalLookup(*name, &lookup);
-
-    // Update inline cache and stub cache.
-    if (FLAG_use_ic) {
-      UpdateCaches(&lookup, state, receiver, name, value);
+    {
+      AssertNoGC nogc;  // GC could invalidate the pointers held in lookup.
+
+      // Lookup the property locally in the receiver.
+      LookupResult lookup;
+      receiver->LocalLookup(*name, &lookup);
+
+      // Update inline cache and stub cache.
+      if (FLAG_use_ic) {
+        UpdateCaches(&lookup, state, receiver, name, value);
+      }
     }

     // Set the property.
=======================================
--- /branches/bleeding_edge/src/stub-cache.cc   Tue Jul 13 06:06:33 2010
+++ /branches/bleeding_edge/src/stub-cache.cc   Thu Aug  5 01:37:12 2010
@@ -822,13 +822,6 @@
 // StubCompiler implementation.


-// Support function for computing call IC miss stubs.
-Handle<Code> ComputeCallMiss(int argc, Code::Kind kind) {
-  CALL_HEAP_FUNCTION(StubCache::ComputeCallMiss(argc, kind), Code);
-}
-
-
-
 Object* LoadCallbackProperty(Arguments args) {
   ASSERT(args[0]->IsJSObject());
   ASSERT(args[1]->IsJSObject());
=======================================
--- /branches/bleeding_edge/src/stub-cache.h    Tue Jul 13 03:02:11 2010
+++ /branches/bleeding_edge/src/stub-cache.h    Thu Aug  5 01:37:12 2010
@@ -336,10 +336,6 @@
 Object* KeyedLoadPropertyWithInterceptor(Arguments args);


-// Support function for computing call IC miss stubs.
-Handle<Code> ComputeCallMiss(int argc, Code::Kind kind);
-
-
 // The stub compiler compiles stubs for the stub cache.
 class StubCompiler BASE_EMBEDDED {
  public:
@@ -688,7 +684,9 @@

   void GenerateNameCheck(String* name, Label* miss);

-  void GenerateMissBranch();
+ // Generates a jump to CallIC miss stub. Returns Failure if the jump cannot
+  // be generated.
+  Object* GenerateMissBranch();
 };


=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Wed Jul 28 02:36:53 2010 +++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Thu Aug 5 01:37:12 2010
@@ -820,9 +820,11 @@
 }


-void CallStubCompiler::GenerateMissBranch() {
-  Handle<Code> ic = ComputeCallMiss(arguments().immediate(), kind_);
-  __ Jump(ic, RelocInfo::CODE_TARGET);
+Object* CallStubCompiler::GenerateMissBranch() {
+  Object* obj = StubCache::ComputeCallMiss(arguments().immediate(), kind_);
+  if (obj->IsFailure()) return obj;
+  __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
+  return obj;
 }


@@ -975,7 +977,8 @@

   // Handle call cache miss.
   __ bind(&miss_in_smi_check);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(function);
@@ -1029,7 +1032,8 @@

   // Handle call cache miss.
   __ bind(&miss);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(FIELD, name);
@@ -1186,8 +1190,8 @@
   }

   __ bind(&miss);
-
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(function);
@@ -1270,8 +1274,8 @@
                                argc + 1,
                                1);
   __ bind(&miss);
-
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(function);
@@ -1357,7 +1361,8 @@

   // Handle load cache miss.
   __ bind(&miss);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(INTERCEPTOR, name);
@@ -1442,7 +1447,8 @@
   // Handle call cache miss.
   __ bind(&miss);
   __ IncrementCounter(&Counters::call_global_inline_miss, 1);
-  GenerateMissBranch();
+  Object* obj = GenerateMissBranch();
+  if (obj->IsFailure()) return obj;

   // Return the generated code.
   return GetCode(NORMAL, name);

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to