Implemented a ContextSlotCache for compiled code.
authorbak@chromium.org <bak@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 22 Jun 2009 08:09:57 +0000 (08:09 +0000)
committerbak@chromium.org <bak@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 22 Jun 2009 08:09:57 +0000 (08:09 +0000)
Review URL: http://codereview.chromium.org/141038

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

src/contexts.cc
src/heap.cc
src/heap.h
src/runtime.cc
src/scopeinfo.cc
src/scopeinfo.h

index 873c23ca54b6357c8a13d80f6584c4d3b138c933..ead73ee035025d06c62a6d7b1ae46dc4675efbdc 100644 (file)
@@ -149,7 +149,7 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
       // check parameter locals in context
       int param_index = ScopeInfo<>::ParameterIndex(*code, *name);
       if (param_index >= 0) {
-        // slot found
+        // slot found.
         int index =
             ScopeInfo<>::ContextSlotIndex(*code,
                                           Heap::arguments_shadow_symbol(),
index caf1274932a08266e53bd886f6f9165073276d06..879d6a16a5009d54695d2a55bfb1a4cd0d86098e 100644 (file)
@@ -501,6 +501,7 @@ void Heap::MarkCompactPrologue(bool is_compacting) {
   // At any old GC clear the keyed lookup cache to enable collection of unused
   // maps.
   KeyedLookupCache::Clear();
+  ContextSlotCache::Clear();
 
   CompilationCache::MarkCompactPrologue();
 
@@ -1388,6 +1389,9 @@ bool Heap::CreateInitialObjects() {
   // Initialize keyed lookup cache.
   KeyedLookupCache::Clear();
 
+  // Initialize context slot cache.
+  ContextSlotCache::Clear();
+
   // Initialize compilation cache.
   CompilationCache::Clear();
 
@@ -3548,8 +3552,10 @@ void KeyedLookupCache::Clear() {
   for (int index = 0; index < kLength; index++) keys_[index].map = NULL;
 }
 
+
 KeyedLookupCache::Key KeyedLookupCache::keys_[KeyedLookupCache::kLength];
 
+
 int KeyedLookupCache::field_offsets_[KeyedLookupCache::kLength];
 
 
index 9be3697768defc9d969fcf8713c7e5f724bd1a46..0191b69c292941ac8dea88ce8d2ecdc071f43227 100644 (file)
@@ -444,17 +444,6 @@ class Heap : public AllStatic {
   // Allocates a new utility object in the old generation.
   static Object* AllocateStruct(InstanceType type);
 
-
-  // Initializes a function with a shared part and prototype.
-  // Returns the function.
-  // Note: this code was factored out of AllocateFunction such that
-  // other parts of the VM could use it. Specifically, a function that creates
-  // instances of type JS_FUNCTION_TYPE benefit from the use of this function.
-  // Please note this does not perform a garbage collection.
-  static Object* InitializeFunction(JSFunction* function,
-                                    SharedFunctionInfo* shared,
-                                    Object* prototype);
-
   // Allocates a function initialized with a shared part.
   // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
   // failed.
@@ -984,7 +973,17 @@ class Heap : public AllStatic {
   static void ScavengeObjectSlow(HeapObject** p, HeapObject* object);
 
   // Copy memory from src to dst.
-  inline static void CopyBlock(Object** dst, Object** src, int byte_size);
+  static inline void CopyBlock(Object** dst, Object** src, int byte_size);
+
+  // Initializes a function with a shared part and prototype.
+  // Returns the function.
+  // Note: this code was factored out of AllocateFunction such that
+  // other parts of the VM could use it. Specifically, a function that creates
+  // instances of type JS_FUNCTION_TYPE benefit from the use of this function.
+  // Please note this does not perform a garbage collection.
+  static inline Object* InitializeFunction(JSFunction* function,
+                                           SharedFunctionInfo* shared,
+                                           Object* prototype);
 
   static const int kInitialSymbolTableSize = 2048;
   static const int kInitialEvalCacheSize = 64;
index 807abab9c29041daad75da064d7441562fb84fc0..ad02f5d5b400d34ff6942f20c174c12ee40dadf7 100644 (file)
@@ -124,7 +124,8 @@ static Object* DeepCopyBoilerplate(JSObject* boilerplate) {
       }
     }
     mode = copy->GetWriteBarrierMode();
-    for (int i = 0; i < copy->map()->inobject_properties(); i++) {
+    int nof = copy->map()->inobject_properties();
+    for (int i = 0; i < nof; i++) {
       Object* value = copy->InObjectPropertyAt(i);
       if (value->IsJSObject()) {
         JSObject* jsObject = JSObject::cast(value);
index fedfbd64fe4046a311d20416c1e8268fbd8cd1b1..8a237fd0ec916e8191c877817221e91cfbe2ffe5 100644 (file)
@@ -432,10 +432,13 @@ int ScopeInfo<Allocator>::ContextSlotIndex(Code* code,
                                            String* name,
                                            Variable::Mode* mode) {
   ASSERT(name->IsSymbol());
+  int result = ContextSlotCache::Lookup(code, name, mode);
+  if (result != ContextSlotCache::kNotFound) return result;
   if (code->sinfo_size() > 0) {
     // Loop below depends on the NULL sentinel after the context slot names.
     ASSERT(NumberOfContextSlots(code) >= Context::MIN_CONTEXT_SLOTS ||
            *(ContextEntriesAddr(code) + 1) == NULL);
+
     // slots start after length entry
     Object** p0 = ContextEntriesAddr(code) + 1;
     Object** p = p0;
@@ -443,14 +446,18 @@ int ScopeInfo<Allocator>::ContextSlotIndex(Code* code,
     while (*p != NULL) {
       if (*p == name) {
         ASSERT(((p - p0) & 1) == 0);
-        if (mode != NULL) {
-          ReadInt(p + 1, reinterpret_cast<int*>(mode));
-        }
-        return ((p - p0) >> 1) + Context::MIN_CONTEXT_SLOTS;
+        int v;
+        ReadInt(p + 1, &v);
+        Variable::Mode mode_value = static_cast<Variable::Mode>(v);
+        if (mode != NULL) *mode = mode_value;
+        result = ((p - p0) >> 1) + Context::MIN_CONTEXT_SLOTS;
+        ContextSlotCache::Update(code, name, mode_value, result);
+        return result;
       }
       p += 2;
     }
   }
+  ContextSlotCache::Update(code, name, Variable::INTERNAL, -1);
   return -1;
 }
 
@@ -526,7 +533,78 @@ int ScopeInfo<Allocator>::NumberOfLocals() const {
 }
 
 
+int ContextSlotCache::Hash(Code* code, String* name) {
+  // Uses only lower 32 bits if pointers are larger.
+  uintptr_t addr_hash =
+      static_cast<uint32_t>(reinterpret_cast<uintptr_t>(code)) >> 2;
+  return (addr_hash ^ name->Hash()) % kLength;
+}
+
+
+int ContextSlotCache::Lookup(Code* code,
+                             String* name,
+                             Variable::Mode* mode) {
+  int index = Hash(code, name);
+  Key& key = keys_[index];
+  if ((key.code == code) && key.name->Equals(name)) {
+    Value result(values_[index]);
+    if (mode != NULL) *mode = result.mode();
+    return result.index() + kNotFound;
+  }
+  return kNotFound;
+}
+
+
+void ContextSlotCache::Update(Code* code,
+                              String* name,
+                              Variable::Mode mode,
+                              int slot_index) {
+  String* symbol;
+  ASSERT(slot_index > kNotFound);
+  if (Heap::LookupSymbolIfExists(name, &symbol)) {
+    int index = Hash(code, symbol);
+    Key& key = keys_[index];
+    key.code = code;
+    key.name = symbol;
+    // Please note value only takes a uint as index.
+    values_[index] = Value(mode, slot_index - kNotFound).raw();
+#ifdef DEBUG
+    ValidateEntry(code, name, mode, slot_index);
+#endif
+  }
+}
+
+
+void ContextSlotCache::Clear() {
+  for (int index = 0; index < kLength; index++) keys_[index].code = NULL;
+}
+
+
+ContextSlotCache::Key ContextSlotCache::keys_[ContextSlotCache::kLength];
+
+
+uint32_t ContextSlotCache::values_[ContextSlotCache::kLength];
+
+
 #ifdef DEBUG
+
+void ContextSlotCache::ValidateEntry(Code* code,
+                                     String* name,
+                                     Variable::Mode mode,
+                                     int slot_index) {
+  String* symbol;
+  if (Heap::LookupSymbolIfExists(name, &symbol)) {
+    int index = Hash(code, name);
+    Key& key = keys_[index];
+    ASSERT(key.code == code);
+    ASSERT(key.name->Equals(name));
+    Value result(values_[index]);
+    ASSERT(result.mode() == mode);
+    ASSERT(result.index() + kNotFound == slot_index);
+  }
+}
+
+
 template <class Allocator>
 static void PrintList(const char* list_name,
                       int nof_internal_slots,
index a097d34f9f91f16066f36d6fb3887b970e1aa01c..28d169a394a56ae9021863481ab5353a135ad8f3 100644 (file)
@@ -163,6 +163,74 @@ class ZoneScopeInfo: public ScopeInfo<ZoneListAllocationPolicy> {
 };
 
 
+// Cache for mapping (code, property name) into context slot index.
+// The cache contains both positive and negative results.
+// Slot index equals -1 means the property is absent.
+// Cleared at startup and prior to mark sweep collection.
+class ContextSlotCache {
+ public:
+  // Lookup context slot index for (code, name).
+  // If absent, kNotFound is returned.
+  static int Lookup(Code* code,
+                    String* name,
+                    Variable::Mode* mode);
+
+  // Update an element in the cache.
+  static void Update(Code* code,
+                     String* name,
+                     Variable::Mode mode,
+                     int slot_index);
+
+  // Clear the cache.
+  static void Clear();
+
+  static const int kNotFound = -2;
+ private:
+  inline static int Hash(Code* code, String* name);
+
+#ifdef DEBUG
+  static void ValidateEntry(Code* code,
+                            String* name,
+                            Variable::Mode mode,
+                            int slot_index);
+#endif
+
+  static const int kLength = 256;
+  struct Key {
+    Code* code;
+    String* name;
+  };
+
+  struct Value {
+    Value(Variable::Mode mode, int index) {
+      ASSERT(ModeField::is_valid(mode));
+      ASSERT(IndexField::is_valid(index));
+      value_ = ModeField::encode(mode) | IndexField::encode(index);
+      ASSERT(mode == this->mode());
+      ASSERT(index == this->index());
+    }
+
+    inline Value(uint32_t value) : value_(value) {}
+
+    uint32_t raw() { return value_; }
+
+    Variable::Mode mode() { return ModeField::decode(value_); }
+
+    int index() { return IndexField::decode(value_); }
+
+    // Bit fields in value_ (type, shift, size). Must be public so the
+    // constants can be embedded in generated code.
+    class ModeField:  public BitField<Variable::Mode, 0, 3> {};
+    class IndexField: public BitField<int,            3, 32-3> {};
+   private:
+    uint32_t value_;
+  };
+
+  static Key keys_[kLength];
+  static uint32_t values_[kLength];
+};
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_SCOPEINFO_H_