Author: [email protected]
Date: Mon Jun 22 01:09:57 2009
New Revision: 2230

Modified:
    branches/bleeding_edge/src/contexts.cc
    branches/bleeding_edge/src/heap.cc
    branches/bleeding_edge/src/heap.h
    branches/bleeding_edge/src/runtime.cc
    branches/bleeding_edge/src/scopeinfo.cc
    branches/bleeding_edge/src/scopeinfo.h

Log:
Implemented a ContextSlotCache for compiled code.

Review URL: http://codereview.chromium.org/141038

Modified: branches/bleeding_edge/src/contexts.cc
==============================================================================
--- branches/bleeding_edge/src/contexts.cc      (original)
+++ branches/bleeding_edge/src/contexts.cc      Mon Jun 22 01:09:57 2009
@@ -149,7 +149,7 @@
        // 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(),

Modified: branches/bleeding_edge/src/heap.cc
==============================================================================
--- branches/bleeding_edge/src/heap.cc  (original)
+++ branches/bleeding_edge/src/heap.cc  Mon Jun 22 01:09:57 2009
@@ -501,6 +501,7 @@
    // 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 @@
    // Initialize keyed lookup cache.
    KeyedLookupCache::Clear();

+  // Initialize context slot cache.
+  ContextSlotCache::Clear();
+
    // Initialize compilation cache.
    CompilationCache::Clear();

@@ -3548,7 +3552,9 @@
    for (int index = 0; index < kLength; index++) keys_[index].map = NULL;
  }

+
  KeyedLookupCache::Key KeyedLookupCache::keys_[KeyedLookupCache::kLength];
+

  int KeyedLookupCache::field_offsets_[KeyedLookupCache::kLength];


Modified: branches/bleeding_edge/src/heap.h
==============================================================================
--- branches/bleeding_edge/src/heap.h   (original)
+++ branches/bleeding_edge/src/heap.h   Mon Jun 22 01:09:57 2009
@@ -444,17 +444,6 @@
    // 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 @@
    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;

Modified: branches/bleeding_edge/src/runtime.cc
==============================================================================
--- branches/bleeding_edge/src/runtime.cc       (original)
+++ branches/bleeding_edge/src/runtime.cc       Mon Jun 22 01:09:57 2009
@@ -124,7 +124,8 @@
        }
      }
      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);

Modified: branches/bleeding_edge/src/scopeinfo.cc
==============================================================================
--- branches/bleeding_edge/src/scopeinfo.cc     (original)
+++ branches/bleeding_edge/src/scopeinfo.cc     Mon Jun 22 01:09:57 2009
@@ -432,10 +432,13 @@
                                             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 @@
      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 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,

Modified: branches/bleeding_edge/src/scopeinfo.h
==============================================================================
--- branches/bleeding_edge/src/scopeinfo.h      (original)
+++ branches/bleeding_edge/src/scopeinfo.h      Mon Jun 22 01:09:57 2009
@@ -163,6 +163,74 @@
  };


+// 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_

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

Reply via email to