Convert PatchCache (and related methods) to use types rather than objects/maps.
R=rossberg@chromium.org Review URL: https://chromiumcodereview.appspot.com/75413002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17847 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
6c72c29506
commit
38630a765f
@ -3051,7 +3051,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
|
|||||||
|
|
||||||
|
|
||||||
Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
|
Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
|
||||||
MapHandleList* receiver_maps,
|
TypeHandleList* types,
|
||||||
CodeHandleList* handlers,
|
CodeHandleList* handlers,
|
||||||
Handle<Name> name,
|
Handle<Name> name,
|
||||||
Code::StubType type,
|
Code::StubType type,
|
||||||
@ -3063,22 +3063,22 @@ Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Label number_case;
|
Label number_case;
|
||||||
Label* smi_target = HasHeapNumberMap(receiver_maps) ? &number_case : &miss;
|
Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
|
||||||
__ JumpIfSmi(receiver(), smi_target);
|
__ JumpIfSmi(receiver(), smi_target);
|
||||||
|
|
||||||
Register map_reg = scratch1();
|
Register map_reg = scratch1();
|
||||||
|
|
||||||
int receiver_count = receiver_maps->length();
|
int receiver_count = types->length();
|
||||||
int number_of_handled_maps = 0;
|
int number_of_handled_maps = 0;
|
||||||
__ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
|
__ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
|
||||||
Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
|
|
||||||
for (int current = 0; current < receiver_count; ++current) {
|
for (int current = 0; current < receiver_count; ++current) {
|
||||||
Handle<Map> map = receiver_maps->at(current);
|
Handle<Type> type = types->at(current);
|
||||||
|
Handle<Map> map = IC::TypeToMap(*type, isolate());
|
||||||
if (!map->is_deprecated()) {
|
if (!map->is_deprecated()) {
|
||||||
number_of_handled_maps++;
|
number_of_handled_maps++;
|
||||||
__ mov(ip, Operand(receiver_maps->at(current)));
|
__ mov(ip, Operand(map));
|
||||||
__ cmp(map_reg, ip);
|
__ cmp(map_reg, ip);
|
||||||
if (map.is_identical_to(heap_number_map)) {
|
if (type->Is(Type::Number())) {
|
||||||
ASSERT(!number_case.is_unused());
|
ASSERT(!number_case.is_unused());
|
||||||
__ bind(&number_case);
|
__ bind(&number_case);
|
||||||
}
|
}
|
||||||
|
@ -3156,7 +3156,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
|
|||||||
|
|
||||||
|
|
||||||
Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
|
Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
|
||||||
MapHandleList* receiver_maps,
|
TypeHandleList* types,
|
||||||
CodeHandleList* handlers,
|
CodeHandleList* handlers,
|
||||||
Handle<Name> name,
|
Handle<Name> name,
|
||||||
Code::StubType type,
|
Code::StubType type,
|
||||||
@ -3168,20 +3168,20 @@ Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Label number_case;
|
Label number_case;
|
||||||
Label* smi_target = HasHeapNumberMap(receiver_maps) ? &number_case : &miss;
|
Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
|
||||||
__ JumpIfSmi(receiver(), smi_target);
|
__ JumpIfSmi(receiver(), smi_target);
|
||||||
|
|
||||||
Register map_reg = scratch1();
|
Register map_reg = scratch1();
|
||||||
__ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
|
__ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
|
||||||
int receiver_count = receiver_maps->length();
|
int receiver_count = types->length();
|
||||||
int number_of_handled_maps = 0;
|
int number_of_handled_maps = 0;
|
||||||
Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
|
|
||||||
for (int current = 0; current < receiver_count; ++current) {
|
for (int current = 0; current < receiver_count; ++current) {
|
||||||
Handle<Map> map = receiver_maps->at(current);
|
Handle<Type> type = types->at(current);
|
||||||
|
Handle<Map> map = IC::TypeToMap(*type, isolate());
|
||||||
if (!map->is_deprecated()) {
|
if (!map->is_deprecated()) {
|
||||||
number_of_handled_maps++;
|
number_of_handled_maps++;
|
||||||
__ cmp(map_reg, map);
|
__ cmp(map_reg, map);
|
||||||
if (map.is_identical_to(heap_number_map)) {
|
if (type->Is(Type::Number())) {
|
||||||
ASSERT(!number_case.is_unused());
|
ASSERT(!number_case.is_unused());
|
||||||
__ bind(&number_case);
|
__ bind(&number_case);
|
||||||
}
|
}
|
||||||
|
33
src/ic-inl.h
33
src/ic-inl.h
@ -120,6 +120,39 @@ HeapObject* IC::GetCodeCacheHolder(Isolate* isolate,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
InlineCacheHolderFlag IC::GetCodeCacheFlag(Type* type) {
|
||||||
|
if (type->Is(Type::Boolean()) ||
|
||||||
|
type->Is(Type::Number()) ||
|
||||||
|
type->Is(Type::String()) ||
|
||||||
|
type->Is(Type::Symbol())) {
|
||||||
|
return PROTOTYPE_MAP;
|
||||||
|
}
|
||||||
|
return OWN_MAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Handle<Map> IC::GetCodeCacheHolder(InlineCacheHolderFlag flag,
|
||||||
|
Type* type,
|
||||||
|
Isolate* isolate) {
|
||||||
|
if (flag == PROTOTYPE_MAP) {
|
||||||
|
Context* context = isolate->context()->native_context();
|
||||||
|
JSFunction* constructor;
|
||||||
|
if (type->Is(Type::Boolean())) {
|
||||||
|
constructor = context->boolean_function();
|
||||||
|
} else if (type->Is(Type::Number())) {
|
||||||
|
constructor = context->number_function();
|
||||||
|
} else if (type->Is(Type::String())) {
|
||||||
|
constructor = context->string_function();
|
||||||
|
} else {
|
||||||
|
ASSERT(type->Is(Type::Symbol()));
|
||||||
|
constructor = context->symbol_function();
|
||||||
|
}
|
||||||
|
return handle(JSObject::cast(constructor->instance_prototype())->map());
|
||||||
|
}
|
||||||
|
return type->AsClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} } // namespace v8::internal
|
} } // namespace v8::internal
|
||||||
|
|
||||||
#endif // V8_IC_INL_H_
|
#endif // V8_IC_INL_H_
|
||||||
|
104
src/ic.cc
104
src/ic.cc
@ -783,7 +783,7 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
|
|||||||
: Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())),
|
: Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())),
|
||||||
isolate());
|
isolate());
|
||||||
|
|
||||||
PatchCache(cache_object, name, code);
|
PatchCache(handle(Type::CurrentOf(cache_object), isolate()), name, code);
|
||||||
TRACE_IC("CallIC", name);
|
TRACE_IC("CallIC", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -967,79 +967,94 @@ static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IC::UpdatePolymorphicIC(Handle<Object> receiver,
|
bool IC::UpdatePolymorphicIC(Handle<Type> type,
|
||||||
Handle<String> name,
|
Handle<String> name,
|
||||||
Handle<Code> code) {
|
Handle<Code> code) {
|
||||||
if (!code->is_handler()) return false;
|
if (!code->is_handler()) return false;
|
||||||
MapHandleList receiver_maps;
|
TypeHandleList types;
|
||||||
CodeHandleList handlers;
|
CodeHandleList handlers;
|
||||||
|
|
||||||
int number_of_valid_maps;
|
int number_of_valid_types;
|
||||||
int handler_to_overwrite = -1;
|
int handler_to_overwrite = -1;
|
||||||
Handle<Map> new_receiver_map(receiver->GetMarkerMap(isolate()));
|
|
||||||
|
|
||||||
target()->FindAllMaps(&receiver_maps);
|
target()->FindAllTypes(&types);
|
||||||
int number_of_maps = receiver_maps.length();
|
int number_of_types = types.length();
|
||||||
number_of_valid_maps = number_of_maps;
|
number_of_valid_types = number_of_types;
|
||||||
|
|
||||||
for (int i = 0; i < number_of_maps; i++) {
|
for (int i = 0; i < number_of_types; i++) {
|
||||||
Handle<Map> map = receiver_maps.at(i);
|
Handle<Type> current_type = types.at(i);
|
||||||
// Filter out deprecated maps to ensure its instances get migrated.
|
// Filter out deprecated maps to ensure their instances get migrated.
|
||||||
if (map->is_deprecated()) {
|
if (current_type->IsClass() && current_type->AsClass()->is_deprecated()) {
|
||||||
number_of_valid_maps--;
|
number_of_valid_types--;
|
||||||
// If the receiver map is already in the polymorphic IC, this indicates
|
// If the receiver type is already in the polymorphic IC, this indicates
|
||||||
// there was a prototoype chain failure. In that case, just overwrite the
|
// there was a prototoype chain failure. In that case, just overwrite the
|
||||||
// handler.
|
// handler.
|
||||||
} else if (map.is_identical_to(new_receiver_map)) {
|
} else if (type->Is(current_type)) {
|
||||||
number_of_valid_maps--;
|
ASSERT(handler_to_overwrite == -1);
|
||||||
|
number_of_valid_types--;
|
||||||
handler_to_overwrite = i;
|
handler_to_overwrite = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (number_of_valid_maps >= 4) return false;
|
if (number_of_valid_types >= 4) return false;
|
||||||
if (number_of_maps == 0) return false;
|
if (number_of_types == 0) return false;
|
||||||
|
if (!target()->FindHandlers(&handlers, types.length())) return false;
|
||||||
|
|
||||||
if (!target()->FindHandlers(&handlers, receiver_maps.length())) {
|
number_of_valid_types++;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
number_of_valid_maps++;
|
|
||||||
if (handler_to_overwrite >= 0) {
|
if (handler_to_overwrite >= 0) {
|
||||||
handlers.Set(handler_to_overwrite, code);
|
handlers.Set(handler_to_overwrite, code);
|
||||||
} else {
|
} else {
|
||||||
receiver_maps.Add(new_receiver_map);
|
types.Add(type);
|
||||||
handlers.Add(code);
|
handlers.Add(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
|
Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
|
||||||
&receiver_maps, &handlers, number_of_valid_maps, name, strict_mode());
|
&types, &handlers, number_of_valid_types, name, strict_mode());
|
||||||
set_target(*ic);
|
set_target(*ic);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IC::UpdateMonomorphicIC(Handle<Object> receiver,
|
Handle<Map> IC::TypeToMap(Type* type, Isolate* isolate) {
|
||||||
|
if (type->Is(Type::Number())) return isolate->factory()->heap_number_map();
|
||||||
|
if (type->Is(Type::Boolean())) return isolate->factory()->oddball_map();
|
||||||
|
ASSERT(type->IsClass());
|
||||||
|
return type->AsClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Type* IC::MapToType(Handle<Map> map) {
|
||||||
|
if (map->instance_type() == HEAP_NUMBER_TYPE) return Type::Number();
|
||||||
|
// The only oddballs that can be recorded in ICs are booleans.
|
||||||
|
if (map->instance_type() == ODDBALL_TYPE) return Type::Boolean();
|
||||||
|
return Type::Class(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void IC::UpdateMonomorphicIC(Handle<Type> type,
|
||||||
Handle<Code> handler,
|
Handle<Code> handler,
|
||||||
Handle<String> name) {
|
Handle<String> name) {
|
||||||
if (!handler->is_handler()) return set_target(*handler);
|
if (!handler->is_handler()) return set_target(*handler);
|
||||||
Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
|
Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
|
||||||
name, receiver, handler, strict_mode());
|
name, type, handler, strict_mode());
|
||||||
set_target(*ic);
|
set_target(*ic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IC::CopyICToMegamorphicCache(Handle<String> name) {
|
void IC::CopyICToMegamorphicCache(Handle<String> name) {
|
||||||
MapHandleList receiver_maps;
|
TypeHandleList types;
|
||||||
CodeHandleList handlers;
|
CodeHandleList handlers;
|
||||||
target()->FindAllMaps(&receiver_maps);
|
target()->FindAllTypes(&types);
|
||||||
if (!target()->FindHandlers(&handlers, receiver_maps.length())) return;
|
if (!target()->FindHandlers(&handlers, types.length())) return;
|
||||||
for (int i = 0; i < receiver_maps.length(); i++) {
|
for (int i = 0; i < types.length(); i++) {
|
||||||
UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i));
|
UpdateMegamorphicCache(*types.at(i), *name, *handlers.at(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) {
|
bool IC::IsTransitionOfMonomorphicTarget(Type* type) {
|
||||||
|
if (!type->IsClass()) return false;
|
||||||
|
Map* receiver_map = *type->AsClass();
|
||||||
Map* current_map = target()->FindFirstMap();
|
Map* current_map = target()->FindFirstMap();
|
||||||
ElementsKind receiver_elements_kind = receiver_map->elements_kind();
|
ElementsKind receiver_elements_kind = receiver_map->elements_kind();
|
||||||
bool more_general_transition =
|
bool more_general_transition =
|
||||||
@ -1053,14 +1068,14 @@ bool IC::IsTransitionedMapOfMonomorphicTarget(Map* receiver_map) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IC::PatchCache(Handle<Object> object,
|
void IC::PatchCache(Handle<Type> type,
|
||||||
Handle<String> name,
|
Handle<String> name,
|
||||||
Handle<Code> code) {
|
Handle<Code> code) {
|
||||||
switch (state()) {
|
switch (state()) {
|
||||||
case UNINITIALIZED:
|
case UNINITIALIZED:
|
||||||
case PREMONOMORPHIC:
|
case PREMONOMORPHIC:
|
||||||
case MONOMORPHIC_PROTOTYPE_FAILURE:
|
case MONOMORPHIC_PROTOTYPE_FAILURE:
|
||||||
UpdateMonomorphicIC(object, code, name);
|
UpdateMonomorphicIC(type, code, name);
|
||||||
break;
|
break;
|
||||||
case MONOMORPHIC: {
|
case MONOMORPHIC: {
|
||||||
// For now, call stubs are allowed to rewrite to the same stub. This
|
// For now, call stubs are allowed to rewrite to the same stub. This
|
||||||
@ -1069,23 +1084,21 @@ void IC::PatchCache(Handle<Object> object,
|
|||||||
target()->is_keyed_call_stub() ||
|
target()->is_keyed_call_stub() ||
|
||||||
!target().is_identical_to(code));
|
!target().is_identical_to(code));
|
||||||
Code* old_handler = target()->FindFirstHandler();
|
Code* old_handler = target()->FindFirstHandler();
|
||||||
if (old_handler == *code &&
|
if (old_handler == *code && IsTransitionOfMonomorphicTarget(*type)) {
|
||||||
IsTransitionedMapOfMonomorphicTarget(
|
UpdateMonomorphicIC(type, code, name);
|
||||||
object->GetMarkerMap(isolate()))) {
|
|
||||||
UpdateMonomorphicIC(object, code, name);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Fall through.
|
// Fall through.
|
||||||
}
|
}
|
||||||
case POLYMORPHIC:
|
case POLYMORPHIC:
|
||||||
if (!target()->is_keyed_stub()) {
|
if (!target()->is_keyed_stub()) {
|
||||||
if (UpdatePolymorphicIC(object, name, code)) break;
|
if (UpdatePolymorphicIC(type, name, code)) break;
|
||||||
CopyICToMegamorphicCache(name);
|
CopyICToMegamorphicCache(name);
|
||||||
}
|
}
|
||||||
set_target(*megamorphic_stub());
|
set_target(*megamorphic_stub());
|
||||||
// Fall through.
|
// Fall through.
|
||||||
case MEGAMORPHIC:
|
case MEGAMORPHIC:
|
||||||
UpdateMegamorphicCache(object->GetMarkerMap(isolate()), *name, *code);
|
UpdateMegamorphicCache(*type, *name, *code);
|
||||||
break;
|
break;
|
||||||
case DEBUG_STUB:
|
case DEBUG_STUB:
|
||||||
break;
|
break;
|
||||||
@ -1135,14 +1148,15 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
|
|||||||
code = ComputeHandler(lookup, object, name);
|
code = ComputeHandler(lookup, object, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
PatchCache(object, name, code);
|
PatchCache(handle(Type::CurrentOf(object), isolate()), name, code);
|
||||||
TRACE_IC("LoadIC", name);
|
TRACE_IC("LoadIC", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
|
void IC::UpdateMegamorphicCache(Type* type, Name* name, Code* code) {
|
||||||
// Cache code holding map should be consistent with
|
// Cache code holding map should be consistent with
|
||||||
// GenerateMonomorphicCacheProbe.
|
// GenerateMonomorphicCacheProbe.
|
||||||
|
Map* map = *TypeToMap(type, isolate());
|
||||||
isolate()->stub_cache()->Set(name, map, code);
|
isolate()->stub_cache()->Set(name, map, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1598,7 +1612,7 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
|
|||||||
|
|
||||||
Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
|
Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
|
||||||
|
|
||||||
PatchCache(receiver, name, code);
|
PatchCache(handle(Type::CurrentOf(receiver), isolate()), name, code);
|
||||||
TRACE_IC("StoreIC", name);
|
TRACE_IC("StoreIC", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1744,7 +1758,7 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
|
|||||||
transitioned_receiver_map =
|
transitioned_receiver_map =
|
||||||
ComputeTransitionedMap(receiver, store_mode);
|
ComputeTransitionedMap(receiver, store_mode);
|
||||||
}
|
}
|
||||||
if (IsTransitionedMapOfMonomorphicTarget(*transitioned_receiver_map)) {
|
if (IsTransitionOfMonomorphicTarget(MapToType(transitioned_receiver_map))) {
|
||||||
// Element family is the same, use the "worst" case map.
|
// Element family is the same, use the "worst" case map.
|
||||||
store_mode = GetNonTransitioningStoreMode(store_mode);
|
store_mode = GetNonTransitioningStoreMode(store_mode);
|
||||||
return isolate()->stub_cache()->ComputeKeyedStoreElement(
|
return isolate()->stub_cache()->ComputeKeyedStoreElement(
|
||||||
|
29
src/ic.h
29
src/ic.h
@ -148,11 +148,24 @@ class IC {
|
|||||||
Object* object,
|
Object* object,
|
||||||
InlineCacheHolderFlag holder);
|
InlineCacheHolderFlag holder);
|
||||||
|
|
||||||
|
static inline InlineCacheHolderFlag GetCodeCacheFlag(Type* type);
|
||||||
|
static inline Handle<Map> GetCodeCacheHolder(InlineCacheHolderFlag flag,
|
||||||
|
Type* type,
|
||||||
|
Isolate* isolate);
|
||||||
|
|
||||||
static bool IsCleared(Code* code) {
|
static bool IsCleared(Code* code) {
|
||||||
InlineCacheState state = code->ic_state();
|
InlineCacheState state = code->ic_state();
|
||||||
return state == UNINITIALIZED || state == PREMONOMORPHIC;
|
return state == UNINITIALIZED || state == PREMONOMORPHIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Utility functions to convert maps to types and back. There are two special
|
||||||
|
// cases:
|
||||||
|
// - The heap_number_map is used as a marker which includes heap numbers as
|
||||||
|
// well as smis.
|
||||||
|
// - The oddball map is only used for booleans.
|
||||||
|
static Handle<Map> TypeToMap(Type* type, Isolate* isolate);
|
||||||
|
static Type* MapToType(Handle<Map> type);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Get the call-site target; used for determining the state.
|
// Get the call-site target; used for determining the state.
|
||||||
Handle<Code> target() const { return target_; }
|
Handle<Code> target() const { return target_; }
|
||||||
@ -204,20 +217,22 @@ class IC {
|
|||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return Handle<Code>::null();
|
return Handle<Code>::null();
|
||||||
}
|
}
|
||||||
void UpdateMonomorphicIC(Handle<Object> receiver,
|
|
||||||
|
void UpdateMonomorphicIC(Handle<Type> type,
|
||||||
Handle<Code> handler,
|
Handle<Code> handler,
|
||||||
Handle<String> name);
|
Handle<String> name);
|
||||||
|
|
||||||
bool UpdatePolymorphicIC(Handle<Object> receiver,
|
bool UpdatePolymorphicIC(Handle<Type> type,
|
||||||
Handle<String> name,
|
Handle<String> name,
|
||||||
Handle<Code> code);
|
Handle<Code> code);
|
||||||
|
|
||||||
|
virtual void UpdateMegamorphicCache(Type* type, Name* name, Code* code);
|
||||||
|
|
||||||
void CopyICToMegamorphicCache(Handle<String> name);
|
void CopyICToMegamorphicCache(Handle<String> name);
|
||||||
bool IsTransitionedMapOfMonomorphicTarget(Map* receiver_map);
|
bool IsTransitionOfMonomorphicTarget(Type* type);
|
||||||
void PatchCache(Handle<Object> object,
|
void PatchCache(Handle<Type> type,
|
||||||
Handle<String> name,
|
Handle<String> name,
|
||||||
Handle<Code> code);
|
Handle<Code> code);
|
||||||
virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code);
|
|
||||||
virtual Code::Kind kind() const {
|
virtual Code::Kind kind() const {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return Code::STUB;
|
return Code::STUB;
|
||||||
@ -512,7 +527,7 @@ class KeyedLoadIC: public LoadIC {
|
|||||||
return isolate()->builtins()->KeyedLoadIC_Slow();
|
return isolate()->builtins()->KeyedLoadIC_Slow();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code) { }
|
virtual void UpdateMegamorphicCache(Type* type, Name* name, Code* code) { }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Stub accessors.
|
// Stub accessors.
|
||||||
@ -693,7 +708,7 @@ class KeyedStoreIC: public StoreIC {
|
|||||||
protected:
|
protected:
|
||||||
virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
|
virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
|
||||||
|
|
||||||
virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code) { }
|
virtual void UpdateMegamorphicCache(Type* type, Name* name, Code* code) { }
|
||||||
|
|
||||||
virtual Handle<Code> pre_monomorphic_stub() {
|
virtual Handle<Code> pre_monomorphic_stub() {
|
||||||
return pre_monomorphic_stub(isolate(), strict_mode());
|
return pre_monomorphic_stub(isolate(), strict_mode());
|
||||||
|
@ -197,11 +197,13 @@ class List {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Map;
|
class Map;
|
||||||
|
class Type;
|
||||||
class Code;
|
class Code;
|
||||||
template<typename T> class Handle;
|
template<typename T> class Handle;
|
||||||
typedef List<Map*> MapList;
|
typedef List<Map*> MapList;
|
||||||
typedef List<Code*> CodeList;
|
typedef List<Code*> CodeList;
|
||||||
typedef List<Handle<Map> > MapHandleList;
|
typedef List<Handle<Map> > MapHandleList;
|
||||||
|
typedef List<Handle<Type> > TypeHandleList;
|
||||||
typedef List<Handle<Code> > CodeHandleList;
|
typedef List<Handle<Code> > CodeHandleList;
|
||||||
|
|
||||||
// Perform binary search for an element in an already sorted
|
// Perform binary search for an element in an already sorted
|
||||||
|
@ -10550,7 +10550,23 @@ void Code::FindAllMaps(MapHandleList* maps) {
|
|||||||
for (RelocIterator it(this, mask); !it.done(); it.next()) {
|
for (RelocIterator it(this, mask); !it.done(); it.next()) {
|
||||||
RelocInfo* info = it.rinfo();
|
RelocInfo* info = it.rinfo();
|
||||||
Object* object = info->target_object();
|
Object* object = info->target_object();
|
||||||
if (object->IsMap()) maps->Add(Handle<Map>(Map::cast(object)));
|
if (object->IsMap()) maps->Add(handle(Map::cast(object)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Code::FindAllTypes(TypeHandleList* types) {
|
||||||
|
ASSERT(is_inline_cache_stub());
|
||||||
|
DisallowHeapAllocation no_allocation;
|
||||||
|
int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
|
||||||
|
Isolate* isolate = GetIsolate();
|
||||||
|
for (RelocIterator it(this, mask); !it.done(); it.next()) {
|
||||||
|
RelocInfo* info = it.rinfo();
|
||||||
|
Object* object = info->target_object();
|
||||||
|
if (object->IsMap()) {
|
||||||
|
Handle<Map> map(Map::cast(object));
|
||||||
|
types->Add(handle(IC::MapToType(map), isolate));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5238,6 +5238,7 @@ class Code: public HeapObject {
|
|||||||
// Find the first map in an IC stub.
|
// Find the first map in an IC stub.
|
||||||
Map* FindFirstMap();
|
Map* FindFirstMap();
|
||||||
void FindAllMaps(MapHandleList* maps);
|
void FindAllMaps(MapHandleList* maps);
|
||||||
|
void FindAllTypes(TypeHandleList* types);
|
||||||
void ReplaceFirstMap(Map* replace);
|
void ReplaceFirstMap(Map* replace);
|
||||||
|
|
||||||
// Find the first handler in an IC stub.
|
// Find the first handler in an IC stub.
|
||||||
|
@ -134,37 +134,40 @@ Handle<Code> StubCache::FindHandler(Handle<Name> name,
|
|||||||
|
|
||||||
|
|
||||||
Handle<Code> StubCache::ComputeMonomorphicIC(Handle<Name> name,
|
Handle<Code> StubCache::ComputeMonomorphicIC(Handle<Name> name,
|
||||||
Handle<Object> object,
|
Handle<Type> type,
|
||||||
Handle<Code> handler,
|
Handle<Code> handler,
|
||||||
StrictModeFlag strict_mode) {
|
StrictModeFlag strict_mode) {
|
||||||
Code::Kind kind = handler->handler_kind();
|
Code::Kind kind = handler->handler_kind();
|
||||||
// Use the same cache holder for the IC as for the handler.
|
InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type);
|
||||||
InlineCacheHolderFlag cache_holder =
|
|
||||||
Code::ExtractCacheHolderFromFlags(handler->flags());
|
Handle<Map> stub_holder;
|
||||||
Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
|
Handle<Code> ic;
|
||||||
isolate(), *object, cache_holder));
|
// There are multiple string maps that all use the same prototype. That
|
||||||
Handle<Map> stub_holder_map(stub_holder->map());
|
// prototype cannot hold multiple handlers, one for each of the string maps,
|
||||||
Handle<Code> ic = FindIC(
|
// for a single name. Hence, turn off caching of the IC.
|
||||||
name, stub_holder_map, kind, strict_mode, cache_holder);
|
bool can_be_cached = !type->Is(Type::String());
|
||||||
if (!ic.is_null()) return ic;
|
if (can_be_cached) {
|
||||||
|
stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate());
|
||||||
|
ic = FindIC(name, stub_holder, kind, strict_mode, flag);
|
||||||
|
if (!ic.is_null()) return ic;
|
||||||
|
}
|
||||||
|
|
||||||
Handle<Map> map(object->GetMarkerMap(isolate()));
|
|
||||||
if (kind == Code::LOAD_IC) {
|
if (kind == Code::LOAD_IC) {
|
||||||
LoadStubCompiler ic_compiler(isolate(), cache_holder);
|
LoadStubCompiler ic_compiler(isolate(), flag);
|
||||||
ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
|
ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
|
||||||
} else if (kind == Code::KEYED_LOAD_IC) {
|
} else if (kind == Code::KEYED_LOAD_IC) {
|
||||||
KeyedLoadStubCompiler ic_compiler(isolate(), cache_holder);
|
KeyedLoadStubCompiler ic_compiler(isolate(), flag);
|
||||||
ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
|
ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
|
||||||
} else if (kind == Code::STORE_IC) {
|
} else if (kind == Code::STORE_IC) {
|
||||||
StoreStubCompiler ic_compiler(isolate(), strict_mode);
|
StoreStubCompiler ic_compiler(isolate(), strict_mode);
|
||||||
ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
|
ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
|
||||||
} else {
|
} else {
|
||||||
ASSERT(kind == Code::KEYED_STORE_IC);
|
ASSERT(kind == Code::KEYED_STORE_IC);
|
||||||
KeyedStoreStubCompiler ic_compiler(isolate(), strict_mode, STANDARD_STORE);
|
KeyedStoreStubCompiler ic_compiler(isolate(), strict_mode, STANDARD_STORE);
|
||||||
ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
|
ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
HeapObject::UpdateMapCodeCache(stub_holder, name, ic);
|
if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic);
|
||||||
return ic;
|
return ic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -584,6 +587,7 @@ Handle<Code> StubCache::ComputeCompareNil(Handle<Map> receiver_map,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO(verwaest): Change this method so it takes in a TypeHandleList.
|
||||||
Handle<Code> StubCache::ComputeLoadElementPolymorphic(
|
Handle<Code> StubCache::ComputeLoadElementPolymorphic(
|
||||||
MapHandleList* receiver_maps) {
|
MapHandleList* receiver_maps) {
|
||||||
Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
|
Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
|
||||||
@ -592,12 +596,15 @@ Handle<Code> StubCache::ComputeLoadElementPolymorphic(
|
|||||||
Handle<Object> probe = cache->Lookup(receiver_maps, flags);
|
Handle<Object> probe = cache->Lookup(receiver_maps, flags);
|
||||||
if (probe->IsCode()) return Handle<Code>::cast(probe);
|
if (probe->IsCode()) return Handle<Code>::cast(probe);
|
||||||
|
|
||||||
|
TypeHandleList types(receiver_maps->length());
|
||||||
|
for (int i = 0; i < receiver_maps->length(); i++) {
|
||||||
|
types.Add(handle(Type::Class(receiver_maps->at(i)), isolate()));
|
||||||
|
}
|
||||||
CodeHandleList handlers(receiver_maps->length());
|
CodeHandleList handlers(receiver_maps->length());
|
||||||
KeyedLoadStubCompiler compiler(isolate_);
|
KeyedLoadStubCompiler compiler(isolate_);
|
||||||
compiler.CompileElementHandlers(receiver_maps, &handlers);
|
compiler.CompileElementHandlers(receiver_maps, &handlers);
|
||||||
Handle<Code> code = compiler.CompilePolymorphicIC(
|
Handle<Code> code = compiler.CompilePolymorphicIC(
|
||||||
receiver_maps, &handlers, factory()->empty_string(),
|
&types, &handlers, factory()->empty_string(), Code::NORMAL, ELEMENT);
|
||||||
Code::NORMAL, ELEMENT);
|
|
||||||
|
|
||||||
isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
|
isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
|
||||||
|
|
||||||
@ -606,24 +613,24 @@ Handle<Code> StubCache::ComputeLoadElementPolymorphic(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Handle<Code> StubCache::ComputePolymorphicIC(MapHandleList* receiver_maps,
|
Handle<Code> StubCache::ComputePolymorphicIC(TypeHandleList* types,
|
||||||
CodeHandleList* handlers,
|
CodeHandleList* handlers,
|
||||||
int number_of_valid_maps,
|
int number_of_valid_types,
|
||||||
Handle<Name> name,
|
Handle<Name> name,
|
||||||
StrictModeFlag strict_mode) {
|
StrictModeFlag strict_mode) {
|
||||||
Handle<Code> handler = handlers->at(0);
|
Handle<Code> handler = handlers->at(0);
|
||||||
Code::Kind kind = handler->handler_kind();
|
Code::Kind kind = handler->handler_kind();
|
||||||
Code::StubType type = number_of_valid_maps == 1 ? handler->type()
|
Code::StubType type = number_of_valid_types == 1 ? handler->type()
|
||||||
: Code::NORMAL;
|
: Code::NORMAL;
|
||||||
if (kind == Code::LOAD_IC) {
|
if (kind == Code::LOAD_IC) {
|
||||||
LoadStubCompiler ic_compiler(isolate_);
|
LoadStubCompiler ic_compiler(isolate_);
|
||||||
return ic_compiler.CompilePolymorphicIC(
|
return ic_compiler.CompilePolymorphicIC(
|
||||||
receiver_maps, handlers, name, type, PROPERTY);
|
types, handlers, name, type, PROPERTY);
|
||||||
} else {
|
} else {
|
||||||
ASSERT(kind == Code::STORE_IC);
|
ASSERT(kind == Code::STORE_IC);
|
||||||
StoreStubCompiler ic_compiler(isolate_, strict_mode);
|
StoreStubCompiler ic_compiler(isolate_, strict_mode);
|
||||||
return ic_compiler.CompilePolymorphicIC(
|
return ic_compiler.CompilePolymorphicIC(
|
||||||
receiver_maps, handlers, name, type, PROPERTY);
|
types, handlers, name, type, PROPERTY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1181,12 +1188,9 @@ Register StoreStubCompiler::HandlerFrontendHeader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool BaseLoadStoreStubCompiler::HasHeapNumberMap(MapHandleList* receiver_maps) {
|
bool BaseLoadStoreStubCompiler::IncludesNumberType(TypeHandleList* types) {
|
||||||
for (int i = 0; i < receiver_maps->length(); ++i) {
|
for (int i = 0; i < types->length(); ++i) {
|
||||||
Handle<Map> map = receiver_maps->at(i);
|
if (types->at(i)->Is(Type::Number())) return true;
|
||||||
if (map.is_identical_to(isolate()->factory()->heap_number_map())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1353,15 +1357,15 @@ void LoadStubCompiler::GenerateLoadPostInterceptor(
|
|||||||
|
|
||||||
|
|
||||||
Handle<Code> BaseLoadStoreStubCompiler::CompileMonomorphicIC(
|
Handle<Code> BaseLoadStoreStubCompiler::CompileMonomorphicIC(
|
||||||
Handle<Map> receiver_map,
|
Handle<Type> type,
|
||||||
Handle<Code> handler,
|
Handle<Code> handler,
|
||||||
Handle<Name> name) {
|
Handle<Name> name) {
|
||||||
MapHandleList receiver_maps(1);
|
TypeHandleList types(1);
|
||||||
receiver_maps.Add(receiver_map);
|
|
||||||
CodeHandleList handlers(1);
|
CodeHandleList handlers(1);
|
||||||
|
types.Add(type);
|
||||||
handlers.Add(handler);
|
handlers.Add(handler);
|
||||||
Code::StubType type = handler->type();
|
Code::StubType stub_type = handler->type();
|
||||||
return CompilePolymorphicIC(&receiver_maps, &handlers, name, type, PROPERTY);
|
return CompilePolymorphicIC(&types, &handlers, name, stub_type, PROPERTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ class StubCache {
|
|||||||
StrictModeFlag strict_mode = kNonStrictMode);
|
StrictModeFlag strict_mode = kNonStrictMode);
|
||||||
|
|
||||||
Handle<Code> ComputeMonomorphicIC(Handle<Name> name,
|
Handle<Code> ComputeMonomorphicIC(Handle<Name> name,
|
||||||
Handle<Object> receiver,
|
Handle<Type> type,
|
||||||
Handle<Code> handler,
|
Handle<Code> handler,
|
||||||
StrictModeFlag strict_mode);
|
StrictModeFlag strict_mode);
|
||||||
|
|
||||||
@ -173,7 +173,7 @@ class StubCache {
|
|||||||
KeyedAccessStoreMode store_mode,
|
KeyedAccessStoreMode store_mode,
|
||||||
StrictModeFlag strict_mode);
|
StrictModeFlag strict_mode);
|
||||||
|
|
||||||
Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
|
Handle<Code> ComputePolymorphicIC(TypeHandleList* types,
|
||||||
CodeHandleList* handlers,
|
CodeHandleList* handlers,
|
||||||
int number_of_valid_maps,
|
int number_of_valid_maps,
|
||||||
Handle<Name> name,
|
Handle<Name> name,
|
||||||
@ -532,11 +532,11 @@ class BaseLoadStoreStubCompiler: public StubCompiler {
|
|||||||
}
|
}
|
||||||
virtual ~BaseLoadStoreStubCompiler() { }
|
virtual ~BaseLoadStoreStubCompiler() { }
|
||||||
|
|
||||||
Handle<Code> CompileMonomorphicIC(Handle<Map> receiver_map,
|
Handle<Code> CompileMonomorphicIC(Handle<Type> type,
|
||||||
Handle<Code> handler,
|
Handle<Code> handler,
|
||||||
Handle<Name> name);
|
Handle<Name> name);
|
||||||
|
|
||||||
Handle<Code> CompilePolymorphicIC(MapHandleList* receiver_maps,
|
Handle<Code> CompilePolymorphicIC(TypeHandleList* types,
|
||||||
CodeHandleList* handlers,
|
CodeHandleList* handlers,
|
||||||
Handle<Name> name,
|
Handle<Name> name,
|
||||||
Code::StubType type,
|
Code::StubType type,
|
||||||
@ -608,7 +608,7 @@ class BaseLoadStoreStubCompiler: public StubCompiler {
|
|||||||
|
|
||||||
void InitializeRegisters();
|
void InitializeRegisters();
|
||||||
|
|
||||||
bool HasHeapNumberMap(MapHandleList* receiver_maps);
|
bool IncludesNumberType(TypeHandleList* types);
|
||||||
|
|
||||||
Code::Kind kind_;
|
Code::Kind kind_;
|
||||||
InlineCacheHolderFlag cache_holder_;
|
InlineCacheHolderFlag cache_holder_;
|
||||||
|
@ -3068,7 +3068,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
|
|||||||
|
|
||||||
|
|
||||||
Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
|
Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
|
||||||
MapHandleList* receiver_maps,
|
TypeHandleList* types,
|
||||||
CodeHandleList* handlers,
|
CodeHandleList* handlers,
|
||||||
Handle<Name> name,
|
Handle<Name> name,
|
||||||
Code::StubType type,
|
Code::StubType type,
|
||||||
@ -3080,21 +3080,21 @@ Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Label number_case;
|
Label number_case;
|
||||||
Label* smi_target = HasHeapNumberMap(receiver_maps) ? &number_case : &miss;
|
Label* smi_target = IncludesNumberType(types) ? &number_case : &miss;
|
||||||
__ JumpIfSmi(receiver(), smi_target);
|
__ JumpIfSmi(receiver(), smi_target);
|
||||||
|
|
||||||
Register map_reg = scratch1();
|
Register map_reg = scratch1();
|
||||||
__ movq(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
|
__ movq(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
|
||||||
int receiver_count = receiver_maps->length();
|
int receiver_count = types->length();
|
||||||
int number_of_handled_maps = 0;
|
int number_of_handled_maps = 0;
|
||||||
Handle<Map> heap_number_map = isolate()->factory()->heap_number_map();
|
|
||||||
for (int current = 0; current < receiver_count; ++current) {
|
for (int current = 0; current < receiver_count; ++current) {
|
||||||
Handle<Map> map = receiver_maps->at(current);
|
Handle<Type> type = types->at(current);
|
||||||
|
Handle<Map> map = IC::TypeToMap(*type, isolate());
|
||||||
if (!map->is_deprecated()) {
|
if (!map->is_deprecated()) {
|
||||||
number_of_handled_maps++;
|
number_of_handled_maps++;
|
||||||
// Check map and tail call if there's a match
|
// Check map and tail call if there's a match
|
||||||
__ Cmp(map_reg, receiver_maps->at(current));
|
__ Cmp(map_reg, map);
|
||||||
if (map.is_identical_to(heap_number_map)) {
|
if (type->Is(Type::Number())) {
|
||||||
ASSERT(!number_case.is_unused());
|
ASSERT(!number_case.is_unused());
|
||||||
__ bind(&number_case);
|
__ bind(&number_case);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user