Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 68b913b3707f846877039686a8a8b3a9635de8d2..b98b3049b0d48d3398b6d9a1d33fab1478d536ce 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -15066,4 +15066,135 @@ void JSDate::SetLocalFields(int64_t local_time_ms, DateCache* date_cache) { |
set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); |
} |
+ |
+class LookupCacheEntry { |
+ public: |
+ LookupCacheEntry(Isolate* isolate, Map* map, LookupResult* result, int depth) |
+ : map_(Handle<Map>::cast(isolate->global_handles()->Create(map))), |
+ result_(*result), |
+ depth_(depth) { |
+ } |
+ |
+ Handle<Map> map_; |
+ LookupResult result_; |
+ int depth_; |
+}; |
+ |
+ |
+LookupCache::LookupCache(Isolate* isolate) : isolate_(isolate), |
+ count_(0), |
+ hidden_count_(0) { |
+#ifdef DEBUG |
+ for (int i = 0; i < kCacheEntryCount; i++) { |
+ entries_[i] = NULL; |
+ hidden_entries_[i] = NULL; |
+ } |
+#endif |
+} |
+ |
+ |
+LookupCache::~LookupCache() { |
+ for (int i = 0; i < count_; i++) { |
+ delete entries_[i]; |
+ entries_[i] = NULL; |
+ } |
+ count_ = 0; |
+ for (int i = 0; i < hidden_count_; i++) { |
+ delete hidden_entries_[i]; |
+ hidden_entries_[i] = NULL; |
+ } |
+ hidden_count_ = 0; |
+} |
+ |
+ |
+void LookupCache::Lookup(Handle<Object> obj, |
+ Handle<Name> name, |
+ LookupResult* result, |
+ bool set_property) { |
+ if (!obj->IsJSReceiver()) return obj->Lookup(*name, result); |
+ |
+ JSReceiver* receiver = JSReceiver::cast(*obj); |
+ Heap* heap = receiver->GetHeap(); |
+ Map* map = receiver->map(); |
+ |
+ int count = set_property ? hidden_count_ : count_; |
+ LookupCacheEntry** entries = set_property ? hidden_entries_ : entries_; |
+ for (int i = 0; i < count; i++) { |
+ LookupCacheEntry* entry = entries[i]; |
+ if (*entry->map_ != map) continue; |
+ |
+ // Hit! Dive into prototype chain if needed |
+ Object* current = *obj; |
+ int depth = entry->depth_; |
+ for (int j = 0; j < depth; j++) { |
+ // XXX: Probably this is a fatal condition |
+ if (current == heap->null_value()) break; |
+ |
+ current = JSObject::cast(current)->GetPrototype(); |
+ } |
+ result->CopyFrom(&entry->result_, JSObject::cast(receiver)); |
+ |
+ return; |
+ } |
+ |
+ // Miss |
+ // Ecma-262 3rd 8.6.2.4 |
+ int depth = 0; |
+ if (set_property) { |
+ receiver->LocalLookup(*name, result, true); |
+ if (!result->IsFound()) { |
+ map->LookupTransition(JSObject::cast(*obj), |
+ *name, |
+ result); |
+ } |
+ } else { |
+ Object* current; |
+ for (current = *obj; |
+ current != heap->null_value(); |
+ current = JSObject::cast(current)->GetPrototype(), depth++) { |
+ JSReceiver::cast(current)->LocalLookup(*name, result, false); |
+ if (result->IsFound()) break; |
+ } |
+ if (current == heap->null_value()) result->NotFound(); |
+ } |
+ |
+ // If property wasn't found, or is not cacheable |
+ if (!result->IsFound() && result->IsCacheable()) return; |
+ |
+ // Cache is full, just return result |
+ if (count == kCacheEntryCount) return; |
+ |
+ // Insert new cache entry |
+ entries[count++] = new LookupCacheEntry(isolate_, map, result, depth); |
+ |
+ // Update count |
+ if (set_property) { |
+ hidden_count_ = count; |
+ } else { |
+ count_ = count; |
+ } |
+} |
+ |
+ |
+MUST_USE_RESULT MaybeObject* LookupCache::GetProperty(Handle<Object> obj, |
+ Handle<Name> name) { |
+ PropertyAttributes attributes; |
+ LookupResult result(isolate_); |
+ Lookup(obj, name, &result); |
+ MaybeObject* value = obj->GetProperty(*obj, &result, *name, &attributes); |
+ ASSERT(attributes <= ABSENT); |
+ return value; |
+} |
+ |
+ |
+MUST_USE_RESULT MaybeObject* LookupCache::SetProperty(Handle<Object> obj, |
+ Handle<Name> name, |
+ Handle<Object> value) { |
+ ASSERT(obj->IsJSReceiver()); |
+ LookupResult result(isolate_); |
+ Lookup(obj, name, &result, true); |
+ JSReceiver* receiver = JSReceiver::cast(*obj); |
+ return receiver->SetProperty(&result, *name, *value, NONE, kNonStrictMode); |
+} |
+ |
} } // namespace v8::internal |