// 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(),
// At any old GC clear the keyed lookup cache to enable collection of unused
// maps.
KeyedLookupCache::Clear();
+ ContextSlotCache::Clear();
CompilationCache::MarkCompactPrologue();
// Initialize keyed lookup cache.
KeyedLookupCache::Clear();
+ // Initialize context slot cache.
+ ContextSlotCache::Clear();
+
// Initialize compilation cache.
CompilationCache::Clear();
for (int index = 0; index < kLength; index++) keys_[index].map = NULL;
}
+
KeyedLookupCache::Key KeyedLookupCache::keys_[KeyedLookupCache::kLength];
+
int KeyedLookupCache::field_offsets_[KeyedLookupCache::kLength];
// 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.
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;
}
}
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);
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;
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;
}
}
+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,
};
+// 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_