summaryrefslogtreecommitdiff
path: root/deps/v8/src/stub-cache.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/stub-cache.cc')
-rw-r--r--deps/v8/src/stub-cache.cc1175
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;
}