Index: src/stub-cache.cc |
diff --git a/src/stub-cache.cc b/src/stub-cache.cc |
index 0c9f4512326eaef114b11cbbf97b7564d5bdeea2..bc12dc836b5e8c64aefe4bcfd858ba9d1ad38036 100644 |
--- a/src/stub-cache.cc |
+++ b/src/stub-cache.cc |
@@ -33,13 +33,13 @@ void StubCache::Initialize() { |
} |
-Code* StubCache::Set(Name* name, Map* map, Code* code) { |
- // Get the flags from the code. |
- Code::Flags flags = Code::RemoveTypeFromFlags(code->flags()); |
+static Code::Flags CommonStubCacheChecks(Name* name, Map* map, |
+ Code::Flags flags, Heap* heap) { |
+ flags = Code::RemoveTypeAndHolderFromFlags(flags); |
// Validate that the name does not move on scavenge, and that we |
// can use identity checks instead of structural equality checks. |
- ASSERT(!heap()->InNewSpace(name)); |
+ ASSERT(!heap->InNewSpace(name)); |
ASSERT(name->IsUniqueName()); |
// The state bits are not important to the hash function because |
@@ -49,8 +49,16 @@ Code* StubCache::Set(Name* name, Map* map, Code* code) { |
ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC); |
STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1); |
- // Make sure that the code type is not included in the hash. |
+ // Make sure that the code type and cache holder are not included in the hash. |
ASSERT(Code::ExtractTypeFromFlags(flags) == 0); |
+ ASSERT(Code::ExtractCacheHolderFromFlags(flags) == 0); |
+ |
+ return flags; |
+} |
+ |
+ |
+Code* StubCache::Set(Name* name, Map* map, Code* code) { |
+ Code::Flags flags = CommonStubCacheChecks(name, map, code->flags(), heap()); |
// Compute the primary entry. |
int primary_offset = PrimaryOffset(name, flags, map); |
@@ -61,7 +69,8 @@ Code* StubCache::Set(Name* name, Map* map, Code* code) { |
// secondary cache before overwriting it. |
if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) { |
Map* old_map = primary->map; |
- Code::Flags old_flags = Code::RemoveTypeFromFlags(old_code->flags()); |
+ Code::Flags old_flags = |
+ Code::RemoveTypeAndHolderFromFlags(old_code->flags()); |
int seed = PrimaryOffset(primary->key, old_flags, old_map); |
int secondary_offset = SecondaryOffset(primary->key, old_flags, seed); |
Entry* secondary = entry(secondary_, secondary_offset); |
@@ -77,11 +86,25 @@ Code* StubCache::Set(Name* name, Map* map, Code* code) { |
} |
-Handle<Code> StubCache::FindIC(Handle<Name> name, |
- Handle<Map> stub_holder, |
- Code::Kind kind, |
- ExtraICState extra_state, |
- InlineCacheHolderFlag cache_holder) { |
+Code* StubCache::Get(Name* name, Map* map, Code::Flags flags) { |
+ flags = CommonStubCacheChecks(name, map, flags, heap()); |
+ int primary_offset = PrimaryOffset(name, flags, map); |
+ Entry* primary = entry(primary_, primary_offset); |
+ if (primary->key == name && primary->map == map) { |
+ return primary->value; |
+ } |
+ int secondary_offset = SecondaryOffset(name, flags, primary_offset); |
+ Entry* secondary = entry(secondary_, secondary_offset); |
+ if (secondary->key == name && secondary->map == map) { |
+ return secondary->value; |
+ } |
+ return NULL; |
+} |
+ |
+ |
+Handle<Code> StubCache::FindIC(Handle<Name> name, Handle<Map> stub_holder, |
+ Code::Kind kind, ExtraICState extra_state, |
+ CacheHolderFlag cache_holder) { |
Code::Flags flags = Code::ComputeMonomorphicFlags( |
kind, extra_state, cache_holder); |
Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_); |
@@ -90,10 +113,9 @@ Handle<Code> StubCache::FindIC(Handle<Name> name, |
} |
-Handle<Code> StubCache::FindHandler(Handle<Name> name, |
- Handle<Map> stub_holder, |
+Handle<Code> StubCache::FindHandler(Handle<Name> name, Handle<Map> stub_holder, |
Code::Kind kind, |
- InlineCacheHolderFlag cache_holder, |
+ CacheHolderFlag cache_holder, |
Code::StubType type) { |
Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder); |
@@ -109,16 +131,15 @@ Handle<Code> StubCache::ComputeMonomorphicIC( |
Handle<HeapType> type, |
Handle<Code> handler, |
ExtraICState extra_ic_state) { |
- InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type); |
+ CacheHolderFlag flag; |
+ Handle<Map> stub_holder = IC::GetICCacheHolder(*type, isolate(), &flag); |
- Handle<Map> stub_holder; |
Handle<Code> ic; |
// There are multiple string maps that all use the same prototype. That |
// prototype cannot hold multiple handlers, one for each of the string maps, |
// for a single name. Hence, turn off caching of the IC. |
bool can_be_cached = !type->Is(HeapType::String()); |
if (can_be_cached) { |
- stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate()); |
ic = FindIC(name, stub_holder, kind, extra_ic_state, flag); |
if (!ic.is_null()) return ic; |
} |
@@ -147,36 +168,45 @@ Handle<Code> StubCache::ComputeMonomorphicIC( |
Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name, |
Handle<HeapType> type) { |
- InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type); |
- Handle<Map> stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate()); |
+ Handle<Map> receiver_map = IC::TypeToMap(*type, isolate()); |
+ if (receiver_map->prototype()->IsNull()) { |
+ // TODO(jkummerow/verwaest): If there is no prototype and the property |
+ // is nonexistent, introduce a builtin to handle this (fast properties |
+ // -> return undefined, dictionary properties -> do negative lookup). |
+ return Handle<Code>(); |
+ } |
+ CacheHolderFlag flag; |
+ Handle<Map> stub_holder_map = |
+ IC::GetHandlerCacheHolder(*type, false, isolate(), &flag); |
+ |
// If no dictionary mode objects are present in the prototype chain, the load |
// nonexistent IC stub can be shared for all names for a given map and we use |
// the empty string for the map cache in that case. If there are dictionary |
// mode objects involved, we need to do negative lookups in the stub and |
// therefore the stub will be specific to the name. |
- Handle<Map> current_map = stub_holder; |
- Handle<Name> cache_name = current_map->is_dictionary_map() |
- ? name : Handle<Name>::cast(isolate()->factory()->nonexistent_symbol()); |
- Handle<Object> next(current_map->prototype(), isolate()); |
- Handle<JSObject> last = Handle<JSObject>::null(); |
- while (!next->IsNull()) { |
- last = Handle<JSObject>::cast(next); |
- next = handle(current_map->prototype(), isolate()); |
- current_map = handle(Handle<HeapObject>::cast(next)->map()); |
+ Handle<Name> cache_name = |
+ receiver_map->is_dictionary_map() |
+ ? name |
+ : Handle<Name>::cast(isolate()->factory()->nonexistent_symbol()); |
+ Handle<Map> current_map = stub_holder_map; |
+ Handle<JSObject> last(JSObject::cast(receiver_map->prototype())); |
+ while (true) { |
if (current_map->is_dictionary_map()) cache_name = name; |
+ if (current_map->prototype()->IsNull()) break; |
+ last = handle(JSObject::cast(current_map->prototype())); |
+ current_map = handle(last->map()); |
} |
- |
// Compile the stub that is either shared for all names or |
// name specific if there are global objects involved. |
- Handle<Code> handler = FindHandler( |
- cache_name, stub_holder, Code::LOAD_IC, flag, Code::FAST); |
+ Handle<Code> handler = |
+ FindHandler(cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST); |
if (!handler.is_null()) { |
return handler; |
} |
LoadStubCompiler compiler(isolate_, kNoExtraICState, flag); |
handler = compiler.CompileLoadNonexistent(type, last, cache_name); |
- Map::UpdateCodeCache(stub_holder, cache_name, handler); |
+ Map::UpdateCodeCache(stub_holder_map, cache_name, handler); |
return handler; |
} |
@@ -203,8 +233,8 @@ Handle<Code> StubCache::ComputeKeyedStoreElement( |
KeyedAccessStoreMode store_mode) { |
ExtraICState extra_state = |
KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode); |
- Code::Flags flags = Code::ComputeMonomorphicFlags( |
- Code::KEYED_STORE_IC, extra_state); |
+ Code::Flags flags = |
+ Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, extra_state); |
ASSERT(store_mode == STANDARD_STORE || |
store_mode == STORE_AND_GROW_NO_TRANSITION || |