| 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
|
|
|