diff options
Diffstat (limited to 'deps/v8/src/stub-cache.cc')
-rw-r--r-- | deps/v8/src/stub-cache.cc | 1175 |
1 files changed, 392 insertions, 783 deletions
diff --git a/deps/v8/src/stub-cache.cc b/deps/v8/src/stub-cache.cc index 1ec00d49bb..132ed711aa 100644 --- a/deps/v8/src/stub-cache.cc +++ b/deps/v8/src/stub-cache.cc @@ -35,6 +35,7 @@ #include "gdb-jit.h" #include "ic-inl.h" #include "stub-cache.h" +#include "type-info.h" #include "vm-state-inl.h" namespace v8 { @@ -100,124 +101,107 @@ Code* StubCache::Set(Name* name, Map* map, Code* code) { Handle<Code> StubCache::FindIC(Handle<Name> name, - Handle<Map> stub_holder_map, + Handle<Map> stub_holder, Code::Kind kind, - Code::ExtraICState extra_state) { - Code::Flags flags = Code::ComputeMonomorphicFlags(kind, extra_state); - Handle<Object> probe(stub_holder_map->FindInCodeCache(*name, flags), - isolate_); + ExtraICState extra_state, + InlineCacheHolderFlag cache_holder) { + Code::Flags flags = Code::ComputeMonomorphicFlags( + kind, extra_state, cache_holder); + Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); return Handle<Code>::null(); } -Handle<Code> StubCache::FindIC(Handle<Name> name, - Handle<JSObject> stub_holder, - Code::Kind kind, - Code::ExtraICState extra_ic_state) { - return FindIC(name, Handle<Map>(stub_holder->map()), kind, extra_ic_state); -} - - Handle<Code> StubCache::FindHandler(Handle<Name> name, - Handle<JSObject> receiver, + Handle<Map> stub_holder, Code::Kind kind, - StrictModeFlag strict_mode) { - Code::ExtraICState extra_ic_state = Code::kNoExtraICState; - if (kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC) { - extra_ic_state = Code::ComputeExtraICState( - STANDARD_STORE, strict_mode); - } + InlineCacheHolderFlag cache_holder) { Code::Flags flags = Code::ComputeMonomorphicFlags( - Code::HANDLER, extra_ic_state, Code::NORMAL, kind); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), - isolate_); + Code::HANDLER, kNoExtraICState, cache_holder, Code::NORMAL); + + Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); return Handle<Code>::null(); } -Handle<Code> StubCache::ComputeMonomorphicIC(Handle<HeapObject> receiver, - Handle<Code> handler, - Handle<Name> name, - StrictModeFlag strict_mode) { - Code::Kind kind = handler->handler_kind(); - Handle<Map> map(receiver->map()); - Handle<Code> ic = FindIC(name, map, kind, strict_mode); - if (!ic.is_null()) return ic; +Handle<Code> StubCache::ComputeMonomorphicIC( + Code::Kind kind, + Handle<Name> name, + Handle<HeapType> type, + Handle<Code> handler, + ExtraICState extra_ic_state) { + InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type); + + 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; + } if (kind == Code::LOAD_IC) { - LoadStubCompiler ic_compiler(isolate()); - ic = ic_compiler.CompileMonomorphicIC(map, handler, name); + LoadStubCompiler ic_compiler(isolate(), extra_ic_state, flag); + ic = ic_compiler.CompileMonomorphicIC(type, handler, name); } else if (kind == Code::KEYED_LOAD_IC) { - KeyedLoadStubCompiler ic_compiler(isolate()); - ic = ic_compiler.CompileMonomorphicIC(map, handler, name); + KeyedLoadStubCompiler ic_compiler(isolate(), extra_ic_state, flag); + ic = ic_compiler.CompileMonomorphicIC(type, handler, name); } else if (kind == Code::STORE_IC) { - StoreStubCompiler ic_compiler(isolate(), strict_mode); - ic = ic_compiler.CompileMonomorphicIC(map, handler, name); + StoreStubCompiler ic_compiler(isolate(), extra_ic_state); + ic = ic_compiler.CompileMonomorphicIC(type, handler, name); } else { ASSERT(kind == Code::KEYED_STORE_IC); - KeyedStoreStubCompiler ic_compiler(isolate(), strict_mode, STANDARD_STORE); - ic = ic_compiler.CompileMonomorphicIC(map, handler, name); + ASSERT(STANDARD_STORE == + KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state)); + KeyedStoreStubCompiler ic_compiler(isolate(), extra_ic_state); + ic = ic_compiler.CompileMonomorphicIC(type, handler, name); } - HeapObject::UpdateMapCodeCache(receiver, name, ic); + if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic); return ic; } Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name, - Handle<JSObject> receiver) { - // If no global 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 global objects involved, we need to check global - // property cells in the stub and therefore the stub will be - // specific to the name. - Handle<Name> cache_name = factory()->empty_string(); - Handle<JSObject> current; - Handle<Object> next = receiver; - Handle<JSGlobalObject> global; - do { - current = Handle<JSObject>::cast(next); - next = Handle<Object>(current->GetPrototype(), isolate_); - if (current->IsJSGlobalObject()) { - global = Handle<JSGlobalObject>::cast(current); - cache_name = name; - } else if (!current->HasFastProperties()) { - cache_name = name; - } - } while (!next->IsNull()); + Handle<HeapType> type) { + InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type); + Handle<Map> stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate()); + // 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()->empty_string()); + 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()); + if (current_map->is_dictionary_map()) cache_name = name; + } // 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, receiver, Code::LOAD_IC); + Handle<Code> handler = FindHandler( + cache_name, stub_holder, Code::LOAD_IC, flag); if (!handler.is_null()) return handler; - LoadStubCompiler compiler(isolate_); - handler = - compiler.CompileLoadNonexistent(receiver, current, cache_name, global); - HeapObject::UpdateMapCodeCache(receiver, cache_name, handler); + LoadStubCompiler compiler(isolate_, kNoExtraICState, flag); + handler = compiler.CompileLoadNonexistent(type, last, cache_name); + Map::UpdateCodeCache(stub_holder, cache_name, handler); return handler; } -Handle<Code> StubCache::ComputeLoadGlobal(Handle<Name> name, - Handle<JSObject> receiver, - Handle<GlobalObject> holder, - Handle<PropertyCell> cell, - bool is_dont_delete) { - Handle<Code> stub = FindIC(name, receiver, Code::LOAD_IC); - if (!stub.is_null()) return stub; - - LoadStubCompiler compiler(isolate_); - Handle<Code> ic = - compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete); - HeapObject::UpdateMapCodeCache(receiver, name, ic); - return ic; -} - - Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) { Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC); Handle<Name> name = @@ -238,8 +222,8 @@ Handle<Code> StubCache::ComputeKeyedStoreElement( Handle<Map> receiver_map, StrictModeFlag strict_mode, KeyedAccessStoreMode store_mode) { - Code::ExtraICState extra_state = - Code::ComputeExtraICState(store_mode, strict_mode); + ExtraICState extra_state = + KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode); Code::Flags flags = Code::ComputeMonomorphicFlags( Code::KEYED_STORE_IC, extra_state); @@ -253,208 +237,17 @@ Handle<Code> StubCache::ComputeKeyedStoreElement( Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_); if (probe->IsCode()) return Handle<Code>::cast(probe); - KeyedStoreStubCompiler compiler(isolate(), strict_mode, store_mode); + KeyedStoreStubCompiler compiler(isolate(), extra_state); Handle<Code> code = compiler.CompileStoreElement(receiver_map); Map::UpdateCodeCache(receiver_map, name, code); - ASSERT(Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == store_mode); - return code; -} - - -Handle<Code> StubCache::ComputeStoreGlobal(Handle<Name> name, - Handle<GlobalObject> receiver, - Handle<PropertyCell> cell, - Handle<Object> value, - StrictModeFlag strict_mode) { - Handle<Type> union_type = PropertyCell::UpdatedType(cell, value); - bool is_constant = union_type->IsConstant(); - StoreGlobalStub stub(strict_mode, is_constant); - - Handle<Code> code = FindIC( - name, Handle<JSObject>::cast(receiver), - Code::STORE_IC, stub.GetExtraICState()); - if (!code.is_null()) return code; - - // Replace the placeholder cell and global object map with the actual global - // cell and receiver map. - Handle<Map> meta_map(isolate_->heap()->meta_map()); - Handle<Object> receiver_map(receiver->map(), isolate_); - code = stub.GetCodeCopyFromTemplate(isolate_); - code->ReplaceNthObject(1, *meta_map, *receiver_map); - Handle<Map> cell_map(isolate_->heap()->global_property_cell_map()); - code->ReplaceNthObject(1, *cell_map, *cell); - - HeapObject::UpdateMapCodeCache(receiver, name, code); - + ASSERT(KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state()) + == store_mode); return code; } -#define CALL_LOGGER_TAG(kind, type) \ - (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type) - -Handle<Code> StubCache::ComputeCallConstant(int argc, - Code::Kind kind, - Code::ExtraICState extra_state, - Handle<Name> name, - Handle<Object> object, - Handle<JSObject> holder, - Handle<JSFunction> function) { - // Compute the check type and the map. - InlineCacheHolderFlag cache_holder = - IC::GetCodeCacheForObject(*object, *holder); - Handle<JSObject> stub_holder(IC::GetCodeCacheHolder( - isolate_, *object, cache_holder)); - - // Compute check type based on receiver/holder. - CheckType check = RECEIVER_MAP_CHECK; - if (object->IsString()) { - check = STRING_CHECK; - } else if (object->IsSymbol()) { - check = SYMBOL_CHECK; - } else if (object->IsNumber()) { - check = NUMBER_CHECK; - } else if (object->IsBoolean()) { - check = BOOLEAN_CHECK; - } - - if (check != RECEIVER_MAP_CHECK && - !function->IsBuiltin() && - function->shared()->is_classic_mode()) { - // Calling non-strict non-builtins with a value as the receiver - // requires boxing. - return Handle<Code>::null(); - } - - Code::Flags flags = Code::ComputeMonomorphicFlags( - kind, extra_state, Code::CONSTANT, argc, cache_holder); - Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags), - isolate_); - if (probe->IsCode()) return Handle<Code>::cast(probe); - - CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder); - Handle<Code> code = - compiler.CompileCallConstant(object, holder, name, check, function); - code->set_check_type(check); - ASSERT(flags == code->flags()); - PROFILE(isolate_, - CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); - GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); - - if (CallStubCompiler::CanBeCached(function)) { - HeapObject::UpdateMapCodeCache(stub_holder, name, code); - } - return code; -} - - -Handle<Code> StubCache::ComputeCallField(int argc, - Code::Kind kind, - Code::ExtraICState extra_state, - Handle<Name> name, - Handle<Object> object, - Handle<JSObject> holder, - PropertyIndex index) { - // Compute the check type and the map. - InlineCacheHolderFlag cache_holder = - IC::GetCodeCacheForObject(*object, *holder); - Handle<JSObject> stub_holder(IC::GetCodeCacheHolder( - isolate_, *object, cache_holder)); - - // TODO(1233596): We cannot do receiver map check for non-JS objects - // because they may be represented as immediates without a - // map. Instead, we check against the map in the holder. - if (object->IsNumber() || object->IsSymbol() || - object->IsBoolean() || object->IsString()) { - object = holder; - } - - Code::Flags flags = Code::ComputeMonomorphicFlags( - kind, extra_state, Code::FIELD, argc, cache_holder); - Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags), - isolate_); - if (probe->IsCode()) return Handle<Code>::cast(probe); - - CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder); - Handle<Code> code = - compiler.CompileCallField(Handle<JSObject>::cast(object), - holder, index, name); - ASSERT(flags == code->flags()); - PROFILE(isolate_, - CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); - GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); - HeapObject::UpdateMapCodeCache(stub_holder, name, code); - return code; -} - - -Handle<Code> StubCache::ComputeCallInterceptor(int argc, - Code::Kind kind, - Code::ExtraICState extra_state, - Handle<Name> name, - Handle<Object> object, - Handle<JSObject> holder) { - // Compute the check type and the map. - InlineCacheHolderFlag cache_holder = - IC::GetCodeCacheForObject(*object, *holder); - Handle<JSObject> stub_holder(IC::GetCodeCacheHolder( - isolate_, *object, cache_holder)); - - // TODO(1233596): We cannot do receiver map check for non-JS objects - // because they may be represented as immediates without a - // map. Instead, we check against the map in the holder. - if (object->IsNumber() || object->IsSymbol() || - object->IsBoolean() || object->IsString()) { - object = holder; - } - - Code::Flags flags = Code::ComputeMonomorphicFlags( - kind, extra_state, Code::INTERCEPTOR, argc, cache_holder); - Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags), - isolate_); - if (probe->IsCode()) return Handle<Code>::cast(probe); - - CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder); - Handle<Code> code = - compiler.CompileCallInterceptor(Handle<JSObject>::cast(object), - holder, name); - ASSERT(flags == code->flags()); - PROFILE(isolate(), - CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); - GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); - HeapObject::UpdateMapCodeCache(stub_holder, name, code); - return code; -} - - -Handle<Code> StubCache::ComputeCallGlobal(int argc, - Code::Kind kind, - Code::ExtraICState extra_state, - Handle<Name> name, - Handle<JSObject> receiver, - Handle<GlobalObject> holder, - Handle<PropertyCell> cell, - Handle<JSFunction> function) { - Code::Flags flags = Code::ComputeMonomorphicFlags( - kind, extra_state, Code::NORMAL, argc); - Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags), - isolate_); - if (probe->IsCode()) return Handle<Code>::cast(probe); - - CallStubCompiler compiler(isolate(), argc, kind, extra_state); - Handle<Code> code = - compiler.CompileCallGlobal(receiver, holder, cell, function, name); - ASSERT(flags == code->flags()); - PROFILE(isolate(), - CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name)); - GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code)); - if (CallStubCompiler::CanBeCached(function)) { - HeapObject::UpdateMapCodeCache(receiver, name, code); - } - return code; -} - +#define CALL_LOGGER_TAG(kind, type) (Logger::KEYED_##type) static void FillCache(Isolate* isolate, Handle<Code> code) { Handle<UnseededNumberDictionary> dictionary = @@ -465,14 +258,8 @@ static void FillCache(Isolate* isolate, Handle<Code> code) { } -Code* StubCache::FindCallInitialize(int argc, - RelocInfo::Mode mode, - Code::Kind kind) { - Code::ExtraICState extra_state = - CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) | - CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT); - Code::Flags flags = - Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc); +Code* StubCache::FindPreMonomorphicIC(Code::Kind kind, ExtraICState state) { + Code::Flags flags = Code::ComputeFlags(kind, PREMONOMORPHIC, state); UnseededNumberDictionary* dictionary = isolate()->heap()->non_monomorphic_cache(); int entry = dictionary->FindEntry(isolate(), flags); @@ -484,122 +271,52 @@ Code* StubCache::FindCallInitialize(int argc, } -Handle<Code> StubCache::ComputeCallInitialize(int argc, - RelocInfo::Mode mode, - Code::Kind kind) { - Code::ExtraICState extra_state = - CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) | - CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT); - Code::Flags flags = - Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc); - Handle<UnseededNumberDictionary> cache = - isolate_->factory()->non_monomorphic_cache(); - int entry = cache->FindEntry(isolate_, flags); - if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); - - StubCompiler compiler(isolate_); - Handle<Code> code = compiler.CompileCallInitialize(flags); - FillCache(isolate_, code); - return code; -} - - -Handle<Code> StubCache::ComputeCallInitialize(int argc, RelocInfo::Mode mode) { - return ComputeCallInitialize(argc, mode, Code::CALL_IC); -} - - -Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc) { - return ComputeCallInitialize(argc, RelocInfo::CODE_TARGET, - Code::KEYED_CALL_IC); -} - - -Handle<Code> StubCache::ComputeCallPreMonomorphic( - int argc, - Code::Kind kind, - Code::ExtraICState extra_state) { - Code::Flags flags = - Code::ComputeFlags(kind, PREMONOMORPHIC, extra_state, Code::NORMAL, argc); - Handle<UnseededNumberDictionary> cache = - isolate_->factory()->non_monomorphic_cache(); - int entry = cache->FindEntry(isolate_, flags); - if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); - - StubCompiler compiler(isolate_); - Handle<Code> code = compiler.CompileCallPreMonomorphic(flags); - FillCache(isolate_, code); - return code; -} - - -Handle<Code> StubCache::ComputeCallNormal(int argc, - Code::Kind kind, - Code::ExtraICState extra_state) { - Code::Flags flags = - Code::ComputeFlags(kind, MONOMORPHIC, extra_state, Code::NORMAL, argc); - Handle<UnseededNumberDictionary> cache = - isolate_->factory()->non_monomorphic_cache(); - int entry = cache->FindEntry(isolate_, flags); - if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); - - StubCompiler compiler(isolate_); - Handle<Code> code = compiler.CompileCallNormal(flags); - FillCache(isolate_, code); - return code; -} - - -Handle<Code> StubCache::ComputeCallArguments(int argc) { - Code::Flags flags = - Code::ComputeFlags(Code::KEYED_CALL_IC, MEGAMORPHIC, - Code::kNoExtraICState, Code::NORMAL, argc); +Handle<Code> StubCache::ComputeLoad(InlineCacheState ic_state, + ExtraICState extra_state) { + Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, ic_state, extra_state); Handle<UnseededNumberDictionary> cache = isolate_->factory()->non_monomorphic_cache(); int entry = cache->FindEntry(isolate_, flags); if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); StubCompiler compiler(isolate_); - Handle<Code> code = compiler.CompileCallArguments(flags); + Handle<Code> code; + if (ic_state == UNINITIALIZED) { + code = compiler.CompileLoadInitialize(flags); + } else if (ic_state == PREMONOMORPHIC) { + code = compiler.CompileLoadPreMonomorphic(flags); + } else if (ic_state == MEGAMORPHIC) { + code = compiler.CompileLoadMegamorphic(flags); + } else { + UNREACHABLE(); + } FillCache(isolate_, code); return code; } -Handle<Code> StubCache::ComputeCallMegamorphic( - int argc, - Code::Kind kind, - Code::ExtraICState extra_state) { - Code::Flags flags = - Code::ComputeFlags(kind, MEGAMORPHIC, extra_state, - Code::NORMAL, argc); +Handle<Code> StubCache::ComputeStore(InlineCacheState ic_state, + ExtraICState extra_state) { + Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, ic_state, extra_state); Handle<UnseededNumberDictionary> cache = isolate_->factory()->non_monomorphic_cache(); int entry = cache->FindEntry(isolate_, flags); if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); StubCompiler compiler(isolate_); - Handle<Code> code = compiler.CompileCallMegamorphic(flags); - FillCache(isolate_, code); - return code; -} - - -Handle<Code> StubCache::ComputeCallMiss(int argc, - Code::Kind kind, - Code::ExtraICState extra_state) { - // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs - // and monomorphic stubs are not mixed up together in the stub cache. - Code::Flags flags = - Code::ComputeFlags(kind, MONOMORPHIC_PROTOTYPE_FAILURE, extra_state, - Code::NORMAL, argc, OWN_MAP); - Handle<UnseededNumberDictionary> cache = - isolate_->factory()->non_monomorphic_cache(); - int entry = cache->FindEntry(isolate_, flags); - if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); + Handle<Code> code; + if (ic_state == UNINITIALIZED) { + code = compiler.CompileStoreInitialize(flags); + } else if (ic_state == PREMONOMORPHIC) { + code = compiler.CompileStorePreMonomorphic(flags); + } else if (ic_state == GENERIC) { + code = compiler.CompileStoreGeneric(flags); + } else if (ic_state == MEGAMORPHIC) { + code = compiler.CompileStoreMegamorphic(flags); + } else { + UNREACHABLE(); + } - StubCompiler compiler(isolate_); - Handle<Code> code = compiler.CompileCallMiss(flags); FillCache(isolate_, code); return code; } @@ -625,6 +342,7 @@ Handle<Code> StubCache::ComputeCompareNil(Handle<Map> receiver_map, } +// TODO(verwaest): Change this method so it takes in a TypeHandleList. Handle<Code> StubCache::ComputeLoadElementPolymorphic( MapHandleList* receiver_maps) { Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC); @@ -633,12 +351,15 @@ Handle<Code> StubCache::ComputeLoadElementPolymorphic( Handle<Object> probe = cache->Lookup(receiver_maps, flags); if (probe->IsCode()) return Handle<Code>::cast(probe); + TypeHandleList types(receiver_maps->length()); + for (int i = 0; i < receiver_maps->length(); i++) { + types.Add(HeapType::Class(receiver_maps->at(i), isolate())); + } CodeHandleList handlers(receiver_maps->length()); KeyedLoadStubCompiler compiler(isolate_); compiler.CompileElementHandlers(receiver_maps, &handlers); Handle<Code> code = compiler.CompilePolymorphicIC( - receiver_maps, &handlers, factory()->empty_string(), - Code::NORMAL, ELEMENT); + &types, &handlers, factory()->empty_string(), Code::NORMAL, ELEMENT); isolate()->counters()->keyed_load_polymorphic_stubs()->Increment(); @@ -647,24 +368,25 @@ Handle<Code> StubCache::ComputeLoadElementPolymorphic( } -Handle<Code> StubCache::ComputePolymorphicIC(MapHandleList* receiver_maps, - CodeHandleList* handlers, - int number_of_valid_maps, - Handle<Name> name, - StrictModeFlag strict_mode) { +Handle<Code> StubCache::ComputePolymorphicIC( + Code::Kind kind, + TypeHandleList* types, + CodeHandleList* handlers, + int number_of_valid_types, + Handle<Name> name, + ExtraICState extra_ic_state) { Handle<Code> handler = handlers->at(0); - Code::Kind kind = handler->handler_kind(); - Code::StubType type = number_of_valid_maps == 1 ? handler->type() - : Code::NORMAL; + Code::StubType type = number_of_valid_types == 1 ? handler->type() + : Code::NORMAL; if (kind == Code::LOAD_IC) { - LoadStubCompiler ic_compiler(isolate_); + LoadStubCompiler ic_compiler(isolate_, extra_ic_state); return ic_compiler.CompilePolymorphicIC( - receiver_maps, handlers, name, type, PROPERTY); + types, handlers, name, type, PROPERTY); } else { ASSERT(kind == Code::STORE_IC); - StoreStubCompiler ic_compiler(isolate_, strict_mode); + StoreStubCompiler ic_compiler(isolate_, extra_ic_state); return ic_compiler.CompilePolymorphicIC( - receiver_maps, handlers, name, type, PROPERTY); + types, handlers, name, type, PROPERTY); } } @@ -679,60 +401,20 @@ Handle<Code> StubCache::ComputeStoreElementPolymorphic( store_mode == STORE_NO_TRANSITION_HANDLE_COW); Handle<PolymorphicCodeCache> cache = isolate_->factory()->polymorphic_code_cache(); - Code::ExtraICState extra_state = Code::ComputeExtraICState(store_mode, - strict_mode); + ExtraICState extra_state = KeyedStoreIC::ComputeExtraICState( + strict_mode, store_mode); Code::Flags flags = Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state); Handle<Object> probe = cache->Lookup(receiver_maps, flags); if (probe->IsCode()) return Handle<Code>::cast(probe); - KeyedStoreStubCompiler compiler(isolate_, strict_mode, store_mode); + KeyedStoreStubCompiler compiler(isolate_, extra_state); Handle<Code> code = compiler.CompileStoreElementPolymorphic(receiver_maps); PolymorphicCodeCache::Update(cache, receiver_maps, flags, code); return code; } -#ifdef ENABLE_DEBUGGER_SUPPORT -Handle<Code> StubCache::ComputeCallDebugBreak(int argc, - Code::Kind kind) { - // Extra IC state is irrelevant for debug break ICs. They jump to - // the actual call ic to carry out the work. - Code::Flags flags = - Code::ComputeFlags(kind, DEBUG_STUB, DEBUG_BREAK, - Code::NORMAL, argc); - Handle<UnseededNumberDictionary> cache = - isolate_->factory()->non_monomorphic_cache(); - int entry = cache->FindEntry(isolate_, flags); - if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); - - StubCompiler compiler(isolate_); - Handle<Code> code = compiler.CompileCallDebugBreak(flags); - FillCache(isolate_, code); - return code; -} - - -Handle<Code> StubCache::ComputeCallDebugPrepareStepIn(int argc, - Code::Kind kind) { - // Extra IC state is irrelevant for debug break ICs. They jump to - // the actual call ic to carry out the work. - Code::Flags flags = - Code::ComputeFlags(kind, DEBUG_STUB, DEBUG_PREPARE_STEP_IN, - Code::NORMAL, argc); - Handle<UnseededNumberDictionary> cache = - isolate_->factory()->non_monomorphic_cache(); - int entry = cache->FindEntry(isolate_, flags); - if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); - - StubCompiler compiler(isolate_); - Handle<Code> code = compiler.CompileCallDebugPrepareStepIn(flags); - FillCache(isolate_, code); - return code; -} -#endif - - void StubCache::Clear() { Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal); for (int i = 0; i < kPrimaryTableSize; i++) { @@ -794,24 +476,25 @@ void StubCache::CollectMatchingMaps(SmallMapList* types, RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) { - JSObject* recv = JSObject::cast(args[0]); - ExecutableAccessorInfo* callback = ExecutableAccessorInfo::cast(args[1]); + JSObject* receiver = JSObject::cast(args[0]); + JSObject* holder = JSObject::cast(args[1]); + ExecutableAccessorInfo* callback = ExecutableAccessorInfo::cast(args[2]); Address setter_address = v8::ToCData<Address>(callback->setter()); v8::AccessorSetterCallback fun = FUNCTION_CAST<v8::AccessorSetterCallback>(setter_address); ASSERT(fun != NULL); - ASSERT(callback->IsCompatibleReceiver(recv)); - Handle<Name> name = args.at<Name>(2); - Handle<Object> value = args.at<Object>(3); + ASSERT(callback->IsCompatibleReceiver(receiver)); + Handle<Name> name = args.at<Name>(3); + Handle<Object> value = args.at<Object>(4); HandleScope scope(isolate); // TODO(rossberg): Support symbols in the API. if (name->IsSymbol()) return *value; Handle<String> str = Handle<String>::cast(name); - LOG(isolate, ApiNamedPropertyAccess("store", recv, *name)); + LOG(isolate, ApiNamedPropertyAccess("store", receiver, *name)); PropertyCallbackArguments - custom_args(isolate, callback->data(), recv, recv); + custom_args(isolate, callback->data(), receiver, holder); custom_args.Call(fun, v8::Utils::ToLocal(str), v8::Utils::ToLocal(value)); RETURN_IF_SCHEDULED_EXCEPTION(isolate); return *value; @@ -867,12 +550,12 @@ RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) { static MaybeObject* ThrowReferenceError(Isolate* isolate, Name* name) { // If the load is non-contextual, just return the undefined result. - // Note that both keyed and non-keyed loads may end up here, so we - // can't use either LoadIC or KeyedLoadIC constructors. + // Note that both keyed and non-keyed loads may end up here. HandleScope scope(isolate); - IC ic(IC::NO_EXTRA_FRAME, isolate); - ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub()); - if (!ic.SlowIsUndeclaredGlobal()) return isolate->heap()->undefined_value(); + LoadIC ic(IC::NO_EXTRA_FRAME, isolate); + if (ic.contextual_mode() != CONTEXTUAL) { + return isolate->heap()->undefined_value(); + } // Throw a reference error. Handle<Name> name_handle(name); @@ -963,16 +646,15 @@ RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) { RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) { HandleScope scope(isolate); - ASSERT(args.length() == 4); - Handle<JSObject> recv(JSObject::cast(args[0])); - Handle<Name> name(Name::cast(args[1])); - Handle<Object> value(args[2], isolate); - ASSERT(args.smi_at(3) == kStrictMode || args.smi_at(3) == kNonStrictMode); - StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3)); - ASSERT(recv->HasNamedInterceptor()); + ASSERT(args.length() == 3); + StoreIC ic(IC::NO_EXTRA_FRAME, isolate); + Handle<JSObject> receiver = args.at<JSObject>(0); + Handle<Name> name = args.at<Name>(1); + Handle<Object> value = args.at<Object>(2); + ASSERT(receiver->HasNamedInterceptor()); PropertyAttributes attr = NONE; Handle<Object> result = JSObject::SetPropertyWithInterceptor( - recv, name, value, attr, strict_mode); + receiver, name, value, attr, ic.strict_mode()); RETURN_IF_EMPTY_HANDLE(isolate, result); return *result; } @@ -986,151 +668,78 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) { } -Handle<Code> StubCompiler::CompileCallInitialize(Code::Flags flags) { - int argc = Code::ExtractArgumentsCountFromFlags(flags); - Code::Kind kind = Code::ExtractKindFromFlags(flags); - Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); - if (kind == Code::CALL_IC) { - CallIC::GenerateInitialize(masm(), argc, extra_state); - } else { - KeyedCallIC::GenerateInitialize(masm(), argc); - } - Handle<Code> code = GetCodeWithFlags(flags, "CompileCallInitialize"); - isolate()->counters()->call_initialize_stubs()->Increment(); +Handle<Code> StubCompiler::CompileLoadInitialize(Code::Flags flags) { + LoadIC::GenerateInitialize(masm()); + Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadInitialize"); PROFILE(isolate(), - CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG), - *code, code->arguments_count())); - GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, *code)); + CodeCreateEvent(Logger::LOAD_INITIALIZE_TAG, *code, 0)); + GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *code)); return code; } -Handle<Code> StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) { - int argc = Code::ExtractArgumentsCountFromFlags(flags); - // The code of the PreMonomorphic stub is the same as the code - // of the Initialized stub. They just differ on the code object flags. - Code::Kind kind = Code::ExtractKindFromFlags(flags); - Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); - if (kind == Code::CALL_IC) { - CallIC::GenerateInitialize(masm(), argc, extra_state); - } else { - KeyedCallIC::GenerateInitialize(masm(), argc); - } - Handle<Code> code = GetCodeWithFlags(flags, "CompileCallPreMonomorphic"); - isolate()->counters()->call_premonomorphic_stubs()->Increment(); +Handle<Code> StubCompiler::CompileLoadPreMonomorphic(Code::Flags flags) { + LoadIC::GeneratePreMonomorphic(masm()); + Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadPreMonomorphic"); PROFILE(isolate(), - CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG), - *code, code->arguments_count())); - GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, *code)); + CodeCreateEvent(Logger::LOAD_PREMONOMORPHIC_TAG, *code, 0)); + GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *code)); return code; } -Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags) { - int argc = Code::ExtractArgumentsCountFromFlags(flags); - Code::Kind kind = Code::ExtractKindFromFlags(flags); - if (kind == Code::CALL_IC) { - // Call normal is always with a explict receiver. - ASSERT(!CallIC::Contextual::decode( - Code::ExtractExtraICStateFromFlags(flags))); - CallIC::GenerateNormal(masm(), argc); - } else { - KeyedCallIC::GenerateNormal(masm(), argc); - } - Handle<Code> code = GetCodeWithFlags(flags, "CompileCallNormal"); - isolate()->counters()->call_normal_stubs()->Increment(); +Handle<Code> StubCompiler::CompileLoadMegamorphic(Code::Flags flags) { + LoadIC::GenerateMegamorphic(masm()); + Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadMegamorphic"); PROFILE(isolate(), - CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG), - *code, code->arguments_count())); - GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, *code)); + CodeCreateEvent(Logger::LOAD_MEGAMORPHIC_TAG, *code, 0)); + GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *code)); return code; } -Handle<Code> StubCompiler::CompileCallMegamorphic(Code::Flags flags) { - int argc = Code::ExtractArgumentsCountFromFlags(flags); - Code::Kind kind = Code::ExtractKindFromFlags(flags); - Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); - if (kind == Code::CALL_IC) { - CallIC::GenerateMegamorphic(masm(), argc, extra_state); - } else { - KeyedCallIC::GenerateMegamorphic(masm(), argc); - } - Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMegamorphic"); - isolate()->counters()->call_megamorphic_stubs()->Increment(); +Handle<Code> StubCompiler::CompileStoreInitialize(Code::Flags flags) { + StoreIC::GenerateInitialize(masm()); + Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize"); PROFILE(isolate(), - CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG), - *code, code->arguments_count())); - GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code)); + CodeCreateEvent(Logger::STORE_INITIALIZE_TAG, *code, 0)); + GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code)); return code; } -Handle<Code> StubCompiler::CompileCallArguments(Code::Flags flags) { - int argc = Code::ExtractArgumentsCountFromFlags(flags); - KeyedCallIC::GenerateNonStrictArguments(masm(), argc); - Handle<Code> code = GetCodeWithFlags(flags, "CompileCallArguments"); +Handle<Code> StubCompiler::CompileStorePreMonomorphic(Code::Flags flags) { + StoreIC::GeneratePreMonomorphic(masm()); + Handle<Code> code = GetCodeWithFlags(flags, "CompileStorePreMonomorphic"); PROFILE(isolate(), - CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags), - CALL_MEGAMORPHIC_TAG), - *code, code->arguments_count())); - GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code)); + CodeCreateEvent(Logger::STORE_PREMONOMORPHIC_TAG, *code, 0)); + GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code)); return code; } -Handle<Code> StubCompiler::CompileCallMiss(Code::Flags flags) { - int argc = Code::ExtractArgumentsCountFromFlags(flags); - Code::Kind kind = Code::ExtractKindFromFlags(flags); - Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); - if (kind == Code::CALL_IC) { - CallIC::GenerateMiss(masm(), argc, extra_state); - } else { - KeyedCallIC::GenerateMiss(masm(), argc); - } - Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMiss"); - isolate()->counters()->call_megamorphic_stubs()->Increment(); +Handle<Code> StubCompiler::CompileStoreGeneric(Code::Flags flags) { + ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags); + StrictModeFlag strict_mode = StoreIC::GetStrictMode(extra_state); + StoreIC::GenerateRuntimeSetProperty(masm(), strict_mode); + Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreGeneric"); PROFILE(isolate(), - CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG), - *code, code->arguments_count())); - GDBJIT(AddCode(GDBJITInterface::CALL_MISS, *code)); + CodeCreateEvent(Logger::STORE_GENERIC_TAG, *code, 0)); + GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code)); return code; } -#ifdef ENABLE_DEBUGGER_SUPPORT -Handle<Code> StubCompiler::CompileCallDebugBreak(Code::Flags flags) { - Debug::GenerateCallICDebugBreak(masm()); - Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugBreak"); +Handle<Code> StubCompiler::CompileStoreMegamorphic(Code::Flags flags) { + StoreIC::GenerateMegamorphic(masm()); + Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic"); PROFILE(isolate(), - CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags), - CALL_DEBUG_BREAK_TAG), - *code, code->arguments_count())); + CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0)); + GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code)); return code; } -Handle<Code> StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) { - // Use the same code for the the step in preparations as we do for the - // miss case. - int argc = Code::ExtractArgumentsCountFromFlags(flags); - Code::Kind kind = Code::ExtractKindFromFlags(flags); - if (kind == Code::CALL_IC) { - // For the debugger extra ic state is irrelevant. - CallIC::GenerateMiss(masm(), argc, Code::kNoExtraICState); - } else { - KeyedCallIC::GenerateMiss(masm(), argc); - } - Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn"); - PROFILE(isolate(), - CodeCreateEvent( - CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG), - *code, - code->arguments_count())); - return code; -} -#endif // ENABLE_DEBUGGER_SUPPORT - #undef CALL_LOGGER_TAG @@ -1140,6 +749,9 @@ Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags, CodeDesc desc; masm_.GetCode(&desc); Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject()); + if (code->has_major_key()) { + code->set_major_key(CodeStub::NoCache); + } #ifdef ENABLE_DISASSEMBLER if (FLAG_print_code_stubs) code->Disassemble(name); #endif @@ -1150,7 +762,7 @@ Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags, Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags, Handle<Name> name) { return (FLAG_print_code_stubs && !name.is_null() && name->IsString()) - ? GetCodeWithFlags(flags, *Handle<String>::cast(name)->ToCString()) + ? GetCodeWithFlags(flags, Handle<String>::cast(name)->ToCString().get()) : GetCodeWithFlags(flags, NULL); } @@ -1169,167 +781,195 @@ void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder, Register LoadStubCompiler::HandlerFrontendHeader( - Handle<JSObject> object, + Handle<HeapType> type, Register object_reg, Handle<JSObject> holder, Handle<Name> name, Label* miss) { - return CheckPrototypes(object, object_reg, holder, - scratch1(), scratch2(), scratch3(), - name, miss, SKIP_RECEIVER); + PrototypeCheckType check_type = CHECK_ALL_MAPS; + int function_index = -1; + if (type->Is(HeapType::String())) { + function_index = Context::STRING_FUNCTION_INDEX; + } else if (type->Is(HeapType::Symbol())) { + function_index = Context::SYMBOL_FUNCTION_INDEX; + } else if (type->Is(HeapType::Number())) { + function_index = Context::NUMBER_FUNCTION_INDEX; + } else if (type->Is(HeapType::Boolean())) { + // Booleans use the generic oddball map, so an additional check is needed to + // ensure the receiver is really a boolean. + GenerateBooleanCheck(object_reg, miss); + function_index = Context::BOOLEAN_FUNCTION_INDEX; + } else { + check_type = SKIP_RECEIVER; + } + + if (check_type == CHECK_ALL_MAPS) { + GenerateDirectLoadGlobalFunctionPrototype( + masm(), function_index, scratch1(), miss); + Object* function = isolate()->native_context()->get(function_index); + Object* prototype = JSFunction::cast(function)->instance_prototype(); + type = IC::CurrentTypeOf(handle(prototype, isolate()), isolate()); + object_reg = scratch1(); + } + + // Check that the maps starting from the prototype haven't changed. + return CheckPrototypes( + type, object_reg, holder, scratch1(), scratch2(), scratch3(), + name, miss, check_type); } // HandlerFrontend for store uses the name register. It has to be restored // before a miss. Register StoreStubCompiler::HandlerFrontendHeader( - Handle<JSObject> object, + Handle<HeapType> type, Register object_reg, Handle<JSObject> holder, Handle<Name> name, Label* miss) { - return CheckPrototypes(object, object_reg, holder, - this->name(), scratch1(), scratch2(), - name, miss, SKIP_RECEIVER); + return CheckPrototypes(type, object_reg, holder, this->name(), + scratch1(), scratch2(), name, miss, SKIP_RECEIVER); +} + + +bool BaseLoadStoreStubCompiler::IncludesNumberType(TypeHandleList* types) { + for (int i = 0; i < types->length(); ++i) { + if (types->at(i)->Is(HeapType::Number())) return true; + } + return false; } -Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<JSObject> object, +Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<HeapType> type, Register object_reg, Handle<JSObject> holder, - Handle<Name> name, - Label* success) { + Handle<Name> name) { Label miss; - Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss); + Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss); + + HandlerFrontendFooter(name, &miss); - HandlerFrontendFooter(name, success, &miss); return reg; } -void LoadStubCompiler::NonexistentHandlerFrontend( - Handle<JSObject> object, - Handle<JSObject> last, - Handle<Name> name, - Label* success, - Handle<JSGlobalObject> global) { +void LoadStubCompiler::NonexistentHandlerFrontend(Handle<HeapType> type, + Handle<JSObject> last, + Handle<Name> name) { Label miss; - Register holder = - HandlerFrontendHeader(object, receiver(), last, name, &miss); + Register holder; + Handle<Map> last_map; + if (last.is_null()) { + holder = receiver(); + last_map = IC::TypeToMap(*type, isolate()); + // If |type| has null as its prototype, |last| is Handle<JSObject>::null(). + ASSERT(last_map->prototype() == isolate()->heap()->null_value()); + } else { + holder = HandlerFrontendHeader(type, receiver(), last, name, &miss); + last_map = handle(last->map()); + } - if (!last->HasFastProperties() && - !last->IsJSGlobalObject() && - !last->IsJSGlobalProxy()) { + if (last_map->is_dictionary_map() && + !last_map->IsJSGlobalObjectMap() && + !last_map->IsJSGlobalProxyMap()) { if (!name->IsUniqueName()) { ASSERT(name->IsString()); name = factory()->InternalizeString(Handle<String>::cast(name)); } - ASSERT(last->property_dictionary()->FindEntry(*name) == - NameDictionary::kNotFound); + ASSERT(last.is_null() || + last->property_dictionary()->FindEntry(*name) == + NameDictionary::kNotFound); GenerateDictionaryNegativeLookup(masm(), &miss, holder, name, scratch2(), scratch3()); } // If the last object in the prototype chain is a global object, // check that the global property cell is empty. - if (!global.is_null()) { + if (last_map->IsJSGlobalObjectMap()) { + Handle<JSGlobalObject> global = last.is_null() + ? Handle<JSGlobalObject>::cast(type->AsConstant()) + : Handle<JSGlobalObject>::cast(last); GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss); } - HandlerFrontendFooter(name, success, &miss); + HandlerFrontendFooter(name, &miss); } Handle<Code> LoadStubCompiler::CompileLoadField( - Handle<JSObject> object, + Handle<HeapType> type, Handle<JSObject> holder, Handle<Name> name, PropertyIndex field, Representation representation) { - Label miss; - - Register reg = HandlerFrontendHeader(object, receiver(), holder, name, &miss); - + Register reg = HandlerFrontend(type, receiver(), holder, name); GenerateLoadField(reg, holder, field, representation); - __ bind(&miss); - TailCallBuiltin(masm(), MissBuiltin(kind())); - // Return the generated code. - return GetCode(kind(), Code::FIELD, name); + return GetCode(kind(), Code::FAST, name); } Handle<Code> LoadStubCompiler::CompileLoadConstant( - Handle<JSObject> object, + Handle<HeapType> type, Handle<JSObject> holder, Handle<Name> name, Handle<Object> value) { - Label success; - HandlerFrontend(object, receiver(), holder, name, &success); - __ bind(&success); + HandlerFrontend(type, receiver(), holder, name); GenerateLoadConstant(value); // Return the generated code. - return GetCode(kind(), Code::CONSTANT, name); + return GetCode(kind(), Code::FAST, name); } Handle<Code> LoadStubCompiler::CompileLoadCallback( - Handle<JSObject> object, + Handle<HeapType> type, Handle<JSObject> holder, Handle<Name> name, Handle<ExecutableAccessorInfo> callback) { - Label success; - Register reg = CallbackHandlerFrontend( - object, receiver(), holder, name, &success, callback); - __ bind(&success); + type, receiver(), holder, name, callback); GenerateLoadCallback(reg, callback); // Return the generated code. - return GetCode(kind(), Code::CALLBACKS, name); + return GetCode(kind(), Code::FAST, name); } Handle<Code> LoadStubCompiler::CompileLoadCallback( - Handle<JSObject> object, + Handle<HeapType> type, Handle<JSObject> holder, Handle<Name> name, const CallOptimization& call_optimization) { ASSERT(call_optimization.is_simple_api_call()); - Label success; - Handle<JSFunction> callback = call_optimization.constant_function(); - CallbackHandlerFrontend( - object, receiver(), holder, name, &success, callback); - __ bind(&success); - GenerateLoadCallback(call_optimization); - + CallbackHandlerFrontend(type, receiver(), holder, name, callback); + Handle<Map>receiver_map = IC::TypeToMap(*type, isolate()); + GenerateFastApiCall( + masm(), call_optimization, receiver_map, + receiver(), scratch1(), false, 0, NULL); // Return the generated code. - return GetCode(kind(), Code::CALLBACKS, name); + return GetCode(kind(), Code::FAST, name); } Handle<Code> LoadStubCompiler::CompileLoadInterceptor( - Handle<JSObject> object, + Handle<HeapType> type, Handle<JSObject> holder, Handle<Name> name) { - Label success; - LookupResult lookup(isolate()); LookupPostInterceptor(holder, name, &lookup); - Register reg = HandlerFrontend(object, receiver(), holder, name, &success); - __ bind(&success); + Register reg = HandlerFrontend(type, receiver(), holder, name); // TODO(368): Compile in the whole chain: all the interceptors in // prototypes and ultimate answer. - GenerateLoadInterceptor(reg, object, holder, &lookup, name); + GenerateLoadInterceptor(reg, type, holder, &lookup, name); // Return the generated code. - return GetCode(kind(), Code::INTERCEPTOR, name); + return GetCode(kind(), Code::FAST, name); } @@ -1338,7 +978,6 @@ void LoadStubCompiler::GenerateLoadPostInterceptor( Handle<JSObject> interceptor_holder, Handle<Name> name, LookupResult* lookup) { - Label success; Handle<JSObject> holder(lookup->holder()); if (lookup->IsField()) { PropertyIndex field = lookup->GetFieldIndex(); @@ -1349,8 +988,8 @@ void LoadStubCompiler::GenerateLoadPostInterceptor( // We found FIELD property in prototype chain of interceptor's holder. // Retrieve a field from field's holder. Register reg = HandlerFrontend( - interceptor_holder, interceptor_reg, holder, name, &success); - __ bind(&success); + IC::CurrentTypeOf(interceptor_holder, isolate()), + interceptor_reg, holder, name); GenerateLoadField( reg, holder, field, lookup->representation()); } @@ -1363,39 +1002,36 @@ void LoadStubCompiler::GenerateLoadPostInterceptor( ASSERT(callback->getter() != NULL); Register reg = CallbackHandlerFrontend( - interceptor_holder, interceptor_reg, holder, name, &success, callback); - __ bind(&success); + IC::CurrentTypeOf(interceptor_holder, isolate()), + interceptor_reg, holder, name, callback); GenerateLoadCallback(reg, callback); } } Handle<Code> BaseLoadStoreStubCompiler::CompileMonomorphicIC( - Handle<Map> receiver_map, + Handle<HeapType> type, Handle<Code> handler, Handle<Name> name) { - MapHandleList receiver_maps(1); - receiver_maps.Add(receiver_map); + TypeHandleList types(1); CodeHandleList handlers(1); + types.Add(type); handlers.Add(handler); - Code::StubType type = handler->type(); - return CompilePolymorphicIC(&receiver_maps, &handlers, name, type, PROPERTY); + Code::StubType stub_type = handler->type(); + return CompilePolymorphicIC(&types, &handlers, name, stub_type, PROPERTY); } Handle<Code> LoadStubCompiler::CompileLoadViaGetter( - Handle<JSObject> object, + Handle<HeapType> type, Handle<JSObject> holder, Handle<Name> name, Handle<JSFunction> getter) { - Label success; - HandlerFrontend(object, receiver(), holder, name, &success); - - __ bind(&success); - GenerateLoadViaGetter(masm(), receiver(), getter); + HandlerFrontend(type, receiver(), holder, name); + GenerateLoadViaGetter(masm(), type, receiver(), getter); // Return the generated code. - return GetCode(kind(), Code::CALLBACKS, name); + return GetCode(kind(), Code::FAST, name); } @@ -1423,8 +1059,8 @@ Handle<Code> StoreStubCompiler::CompileStoreTransition( } while (holder->GetPrototype()->IsJSObject()); } - Register holder_reg = - HandlerFrontendHeader(object, receiver(), holder, name, &miss); + Register holder_reg = HandlerFrontendHeader( + IC::CurrentTypeOf(object, isolate()), receiver(), holder, name, &miss); // If no property was found, and the holder (the last object in the // prototype chain) is in slow mode, we need to do a negative lookup on the @@ -1452,7 +1088,7 @@ Handle<Code> StoreStubCompiler::CompileStoreTransition( TailCallBuiltin(masm(), SlowBuiltin(kind())); // Return the generated code. - return GetCode(kind(), Code::TRANSITION, name); + return GetCode(kind(), Code::FAST, name); } @@ -1461,7 +1097,8 @@ Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object, Handle<Name> name) { Label miss; - HandlerFrontendHeader(object, receiver(), object, name, &miss); + HandlerFrontendHeader(IC::CurrentTypeOf(object, isolate()), + receiver(), object, name, &miss); // Generate store field code. GenerateStoreField(masm(), @@ -1475,7 +1112,7 @@ Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object, TailCallBuiltin(masm(), MissBuiltin(kind())); // Return the generated code. - return GetCode(kind(), Code::FIELD, name); + return GetCode(kind(), Code::FAST, name); } @@ -1484,13 +1121,27 @@ Handle<Code> StoreStubCompiler::CompileStoreViaSetter( Handle<JSObject> holder, Handle<Name> name, Handle<JSFunction> setter) { - Label success; - HandlerFrontend(object, receiver(), holder, name, &success); + Handle<HeapType> type = IC::CurrentTypeOf(object, isolate()); + HandlerFrontend(type, receiver(), holder, name); + GenerateStoreViaSetter(masm(), type, setter); + + return GetCode(kind(), Code::FAST, name); +} - __ bind(&success); - GenerateStoreViaSetter(masm(), setter); - return GetCode(kind(), Code::CALLBACKS, name); +Handle<Code> StoreStubCompiler::CompileStoreCallback( + Handle<JSObject> object, + Handle<JSObject> holder, + Handle<Name> name, + const CallOptimization& call_optimization) { + HandlerFrontend(IC::CurrentTypeOf(object, isolate()), + receiver(), holder, name); + Register values[] = { value() }; + GenerateFastApiCall( + masm(), call_optimization, handle(object->map()), + receiver(), scratch1(), true, 1, values); + // Return the generated code. + return GetCode(kind(), Code::FAST, name); } @@ -1498,14 +1149,16 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( Handle<Map> receiver_map) { ElementsKind elements_kind = receiver_map->elements_kind(); if (receiver_map->has_fast_elements() || - receiver_map->has_external_array_elements()) { + receiver_map->has_external_array_elements() || + receiver_map->has_fixed_typed_array_elements()) { Handle<Code> stub = KeyedLoadFastElementStub( receiver_map->instance_type() == JS_ARRAY_TYPE, elements_kind).GetCode(isolate()); __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); } else { - Handle<Code> stub = - KeyedLoadDictionaryElementStub().GetCode(isolate()); + Handle<Code> stub = FLAG_compiled_keyed_dictionary_loads + ? KeyedLoadDictionaryElementStub().GetCode(isolate()) + : KeyedLoadDictionaryElementPlatformStub().GetCode(isolate()); __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); } @@ -1522,15 +1175,16 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElement( bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE; Handle<Code> stub; if (receiver_map->has_fast_elements() || - receiver_map->has_external_array_elements()) { + receiver_map->has_external_array_elements() || + receiver_map->has_fixed_typed_array_elements()) { stub = KeyedStoreFastElementStub( is_jsarray, elements_kind, - store_mode_).GetCode(isolate()); + store_mode()).GetCode(isolate()); } else { stub = KeyedStoreElementStub(is_jsarray, elements_kind, - store_mode_).GetCode(isolate()); + store_mode()).GetCode(isolate()); } __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK); @@ -1596,9 +1250,8 @@ Handle<Code> BaseLoadStoreStubCompiler::GetICCode(Code::Kind kind, Handle<Code> BaseLoadStoreStubCompiler::GetCode(Code::Kind kind, Code::StubType type, Handle<Name> name) { - ASSERT(type != Code::NORMAL); - Code::Flags flags = Code::ComputeFlags( - Code::HANDLER, MONOMORPHIC, extra_state(), type, kind); + ASSERT_EQ(kNoExtraICState, extra_state()); + Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder_); Handle<Code> code = GetCodeWithFlags(flags, name); PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name)); JitEvent(name, code); @@ -1614,12 +1267,15 @@ void KeyedLoadStubCompiler::CompileElementHandlers(MapHandleList* receiver_maps, if ((receiver_map->instance_type() & kNotStringTag) == 0) { cached_stub = isolate()->builtins()->KeyedLoadIC_String(); + } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) { + cached_stub = isolate()->builtins()->KeyedLoadIC_Slow(); } else { bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; ElementsKind elements_kind = receiver_map->elements_kind(); if (IsFastElementsKind(elements_kind) || - IsExternalArrayElementsKind(elements_kind)) { + IsExternalArrayElementsKind(elements_kind) || + IsFixedTypedArrayElementsKind(elements_kind)) { cached_stub = KeyedLoadFastElementStub(is_js_array, elements_kind).GetCode(isolate()); @@ -1657,19 +1313,22 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic( elements_kind, transitioned_map->elements_kind(), is_js_array, - store_mode_).GetCode(isolate()); + store_mode()).GetCode(isolate()); + } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) { + cached_stub = isolate()->builtins()->KeyedStoreIC_Slow(); } else { if (receiver_map->has_fast_elements() || - receiver_map->has_external_array_elements()) { + receiver_map->has_external_array_elements() || + receiver_map->has_fixed_typed_array_elements()) { cached_stub = KeyedStoreFastElementStub( is_js_array, elements_kind, - store_mode_).GetCode(isolate()); + store_mode()).GetCode(isolate()); } else { cached_stub = KeyedStoreElementStub( is_js_array, elements_kind, - store_mode_).GetCode(isolate()); + store_mode()).GetCode(isolate()); } } ASSERT(!cached_stub.is_null()); @@ -1691,99 +1350,6 @@ void KeyedStoreStubCompiler::GenerateStoreDictionaryElement( } -CallStubCompiler::CallStubCompiler(Isolate* isolate, - int argc, - Code::Kind kind, - Code::ExtraICState extra_state, - InlineCacheHolderFlag cache_holder) - : StubCompiler(isolate), - arguments_(argc), - kind_(kind), - extra_state_(extra_state), - cache_holder_(cache_holder) { -} - - -bool CallStubCompiler::HasCustomCallGenerator(Handle<JSFunction> function) { - if (function->shared()->HasBuiltinFunctionId()) { - BuiltinFunctionId id = function->shared()->builtin_function_id(); -#define CALL_GENERATOR_CASE(name) if (id == k##name) return true; - CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE) -#undef CALL_GENERATOR_CASE - } - - CallOptimization optimization(function); - return optimization.is_simple_api_call(); -} - - -bool CallStubCompiler::CanBeCached(Handle<JSFunction> function) { - if (function->shared()->HasBuiltinFunctionId()) { - BuiltinFunctionId id = function->shared()->builtin_function_id(); -#define CALL_GENERATOR_CASE(name) if (id == k##name) return false; - SITE_SPECIFIC_CALL_GENERATORS(CALL_GENERATOR_CASE) -#undef CALL_GENERATOR_CASE - } - - return true; -} - - -Handle<Code> CallStubCompiler::CompileCustomCall( - Handle<Object> object, - Handle<JSObject> holder, - Handle<Cell> cell, - Handle<JSFunction> function, - Handle<String> fname, - Code::StubType type) { - ASSERT(HasCustomCallGenerator(function)); - - if (function->shared()->HasBuiltinFunctionId()) { - BuiltinFunctionId id = function->shared()->builtin_function_id(); -#define CALL_GENERATOR_CASE(name) \ - if (id == k##name) { \ - return CallStubCompiler::Compile##name##Call(object, \ - holder, \ - cell, \ - function, \ - fname, \ - type); \ - } - CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE) -#undef CALL_GENERATOR_CASE - } - CallOptimization optimization(function); - ASSERT(optimization.is_simple_api_call()); - return CompileFastApiCall(optimization, - object, - holder, - cell, - function, - fname); -} - - -Handle<Code> CallStubCompiler::GetCode(Code::StubType type, - Handle<Name> name) { - int argc = arguments_.immediate(); - Code::Flags flags = Code::ComputeMonomorphicFlags(kind_, - extra_state_, - type, - argc, - cache_holder_); - return GetCodeWithFlags(flags, name); -} - - -Handle<Code> CallStubCompiler::GetCode(Handle<JSFunction> function) { - Handle<String> function_name; - if (function->shared()->name()->IsString()) { - function_name = Handle<String>(String::cast(function->shared()->name())); - } - return GetCode(Code::CONSTANT, function_name); -} - - CallOptimization::CallOptimization(LookupResult* lookup) { if (lookup->IsFound() && lookup->IsCacheable() && @@ -1801,20 +1367,63 @@ CallOptimization::CallOptimization(Handle<JSFunction> function) { } -int CallOptimization::GetPrototypeDepthOfExpectedType( - Handle<JSObject> object, - Handle<JSObject> holder) const { +Handle<JSObject> CallOptimization::LookupHolderOfExpectedType( + Handle<Map> object_map, + HolderLookup* holder_lookup) const { + ASSERT(is_simple_api_call()); + if (!object_map->IsJSObjectMap()) { + *holder_lookup = kHolderNotFound; + return Handle<JSObject>::null(); + } + if (expected_receiver_type_.is_null() || + expected_receiver_type_->IsTemplateFor(*object_map)) { + *holder_lookup = kHolderIsReceiver; + return Handle<JSObject>::null(); + } + while (true) { + if (!object_map->prototype()->IsJSObject()) break; + Handle<JSObject> prototype(JSObject::cast(object_map->prototype())); + if (!prototype->map()->is_hidden_prototype()) break; + object_map = handle(prototype->map()); + if (expected_receiver_type_->IsTemplateFor(*object_map)) { + *holder_lookup = kHolderFound; + return prototype; + } + } + *holder_lookup = kHolderNotFound; + return Handle<JSObject>::null(); +} + + +bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver, + Handle<JSObject> holder) const { ASSERT(is_simple_api_call()); - if (expected_receiver_type_.is_null()) return 0; - int depth = 0; - while (!object.is_identical_to(holder)) { - if (object->IsInstanceOf(*expected_receiver_type_)) return depth; - object = Handle<JSObject>(JSObject::cast(object->GetPrototype())); - if (!object->map()->is_hidden_prototype()) return kInvalidProtoDepth; - ++depth; + if (!receiver->IsJSObject()) return false; + Handle<Map> map(JSObject::cast(*receiver)->map()); + HolderLookup holder_lookup; + Handle<JSObject> api_holder = + LookupHolderOfExpectedType(map, &holder_lookup); + switch (holder_lookup) { + case kHolderNotFound: + return false; + case kHolderIsReceiver: + return true; + case kHolderFound: + if (api_holder.is_identical_to(holder)) return true; + // Check if holder is in prototype chain of api_holder. + { + JSObject* object = *api_holder; + while (true) { + Object* prototype = object->map()->prototype(); + if (!prototype->IsJSObject()) return false; + if (prototype == *holder) return true; + object = JSObject::cast(prototype); + } + } + break; } - if (holder->IsInstanceOf(*expected_receiver_type_)) return depth; - return kInvalidProtoDepth; + UNREACHABLE(); + return false; } |