ASSERT(name.is(r2));
// Probe the stub cache.
- Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
+ Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+ Code::ComputeHandlerFlags(Code::LOAD_IC));
masm->isolate()->stub_cache()->GenerateProbe(
masm, flags, receiver, name, r3, r4, r5, r6);
ASSERT(ValueRegister().is(r0));
// Get the receiver from the stack and probe the stub cache.
- Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
+ Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+ Code::ComputeHandlerFlags(Code::STORE_IC));
masm->isolate()->stub_cache()->GenerateProbe(
masm, flags, receiver, name, r3, r4, r5, r6);
reg = holder_reg; // From now on the object will be in holder_reg.
- if (heap()->InNewSpace(*prototype)) {
- // The prototype is in new space; we cannot store a reference to it
- // in the code. Load it from the map.
+ // Two possible reasons for loading the prototype from the map:
+ // (1) Can't store references to new space in code.
+ // (2) Handler is shared for all receivers with the same prototype
+ // map (but not necessarily the same prototype instance).
+ bool load_prototype_from_map =
+ heap()->InNewSpace(*prototype) || depth == 1;
+ if (load_prototype_from_map) {
__ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
} else {
- // The prototype is in old space; load it directly.
__ mov(reg, Operand(prototype));
}
}
ASSERT(name.is(x2));
// Probe the stub cache.
- Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
+ Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+ Code::ComputeHandlerFlags(Code::LOAD_IC));
masm->isolate()->stub_cache()->GenerateProbe(
masm, flags, receiver, name, x3, x4, x5, x6);
ASSERT(!AreAliased(receiver, name, ValueRegister(), x3, x4, x5, x6));
// Probe the stub cache.
- Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
+ Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+ Code::ComputeHandlerFlags(Code::STORE_IC));
masm->isolate()->stub_cache()->GenerateProbe(
masm, flags, receiver, name, x3, x4, x5, x6);
reg = holder_reg; // From now on the object will be in holder_reg.
__ Ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
} else {
- bool need_map = (depth != 1 || check == CHECK_ALL_MAPS) ||
- heap()->InNewSpace(*prototype);
- Register map_reg = NoReg;
- if (need_map) {
- map_reg = scratch1;
- __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
- }
+ // Two possible reasons for loading the prototype from the map:
+ // (1) Can't store references to new space in code.
+ // (2) Handler is shared for all receivers with the same prototype
+ // map (but not necessarily the same prototype instance).
+ bool load_prototype_from_map =
+ heap()->InNewSpace(*prototype) || depth == 1;
+ Register map_reg = scratch1;
+ __ Ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
if (depth != 1 || check == CHECK_ALL_MAPS) {
__ CheckMap(map_reg, current_map, miss, DONT_DO_SMI_CHECK);
reg = holder_reg; // From now on the object will be in holder_reg.
- if (heap()->InNewSpace(*prototype)) {
- // The prototype is in new space; we cannot store a reference to it
- // in the code. Load it from the map.
+ if (load_prototype_from_map) {
__ Ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
} else {
- // The prototype is in old space; load it directly.
__ Mov(reg, Operand(prototype));
}
}
PREMONOMORPHIC,
// Has been executed and only one receiver type has been seen.
MONOMORPHIC,
- // Like MONOMORPHIC but check failed due to prototype.
- MONOMORPHIC_PROTOTYPE_FAILURE,
+ // Check failed due to prototype (or map deprecation).
+ PROTOTYPE_FAILURE,
// Multiple receiver types have been seen.
POLYMORPHIC,
// Many receiver types have been seen.
};
-enum InlineCacheHolderFlag {
- OWN_MAP, // For fast properties objects.
- PROTOTYPE_MAP // For slow properties objects (except GlobalObjects).
+enum CacheHolderFlag {
+ kCacheOnPrototype,
+ kCacheOnPrototypeReceiverIsDictionary,
+ kCacheOnPrototypeReceiverIsPrimitive,
+ kCacheOnReceiver
};
}
+Handle<Map> HOptimizedGraphBuilder::PropertyAccessInfo::map() {
+ JSFunction* ctor = IC::GetRootConstructor(
+ type_, current_info()->closure()->context()->native_context());
+ if (ctor != NULL) return handle(ctor->initial_map());
+ return type_->AsClass()->Map();
+}
+
+
static bool NeedsWrappingFor(Type* type, Handle<JSFunction> target) {
return type->Is(Type::NumberOrString()) &&
target->shared()->strict_mode() == SLOPPY &&
// PropertyAccessInfo is built for types->first().
bool CanAccessAsMonomorphic(SmallMapList* types);
- Handle<Map> map() {
- if (type_->Is(Type::Number())) {
- Context* context = current_info()->closure()->context();
- context = context->native_context();
- return handle(context->number_function()->initial_map());
- } else if (type_->Is(Type::Boolean())) {
- Context* context = current_info()->closure()->context();
- context = context->native_context();
- return handle(context->boolean_function()->initial_map());
- } else if (type_->Is(Type::String())) {
- Context* context = current_info()->closure()->context();
- context = context->native_context();
- return handle(context->string_function()->initial_map());
- } else {
- return type_->AsClass()->Map();
- }
- }
+ Handle<Map> map();
Type* type() const { return type_; }
Handle<String> name() const { return name_; }
ASSERT(name.is(ecx));
// Probe the stub cache.
- Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
+ Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+ Code::ComputeHandlerFlags(Code::LOAD_IC));
masm->isolate()->stub_cache()->GenerateProbe(
masm, flags, receiver, name, ebx, eax);
void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
// Return address is on the stack.
- Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
+ Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+ Code::ComputeHandlerFlags(Code::STORE_IC));
masm->isolate()->stub_cache()->GenerateProbe(
masm, flags, ReceiverRegister(), NameRegister(),
ebx, no_reg);
__ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
} else {
bool in_new_space = heap()->InNewSpace(*prototype);
+ // Two possible reasons for loading the prototype from the map:
+ // (1) Can't store references to new space in code.
+ // (2) Handler is shared for all receivers with the same prototype
+ // map (but not necessarily the same prototype instance).
+ bool load_prototype_from_map = in_new_space || depth == 1;
if (depth != 1 || check == CHECK_ALL_MAPS) {
__ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
}
scratch2, miss);
}
- if (in_new_space) {
+ if (load_prototype_from_map) {
// Save the map in scratch1 for later.
__ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
}
reg = holder_reg; // From now on the object will be in holder_reg.
- if (in_new_space) {
- // The prototype is in new space; we cannot store a reference to it
- // in the code. Load it from the map.
+ if (load_prototype_from_map) {
__ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
} else {
- // The prototype is in old space; load it directly.
__ mov(reg, prototype);
}
}
}
-InlineCacheHolderFlag IC::GetCodeCacheForObject(Object* object) {
- if (object->IsJSObject()) return OWN_MAP;
-
- // If the object is a value, we use the prototype map for the cache.
- ASSERT(object->IsString() || object->IsSymbol() ||
- object->IsNumber() || object->IsBoolean());
- return PROTOTYPE_MAP;
-}
-
-
-HeapObject* IC::GetCodeCacheHolder(Isolate* isolate,
- Object* object,
- InlineCacheHolderFlag holder) {
- if (object->IsSmi()) holder = PROTOTYPE_MAP;
- PrototypeIterator iter(isolate, object,
- holder == OWN_MAP
- ? PrototypeIterator::START_AT_RECEIVER
- : PrototypeIterator::START_AT_PROTOTYPE);
- return HeapObject::cast(iter.GetCurrent());
+template <class TypeClass>
+JSFunction* IC::GetRootConstructor(TypeClass* type, Context* native_context) {
+ if (type->Is(TypeClass::Boolean())) {
+ return native_context->boolean_function();
+ } else if (type->Is(TypeClass::Number())) {
+ return native_context->number_function();
+ } else if (type->Is(TypeClass::String())) {
+ return native_context->string_function();
+ } else if (type->Is(TypeClass::Symbol())) {
+ return native_context->symbol_function();
+ } else {
+ return NULL;
+ }
}
-InlineCacheHolderFlag IC::GetCodeCacheFlag(HeapType* type) {
- if (type->Is(HeapType::Boolean()) ||
- type->Is(HeapType::Number()) ||
- type->Is(HeapType::String()) ||
- type->Is(HeapType::Symbol())) {
- return PROTOTYPE_MAP;
+Handle<Map> IC::GetHandlerCacheHolder(HeapType* type, bool receiver_is_holder,
+ Isolate* isolate, CacheHolderFlag* flag) {
+ Handle<Map> receiver_map = TypeToMap(type, isolate);
+ if (receiver_is_holder) {
+ *flag = kCacheOnReceiver;
+ return receiver_map;
+ }
+ Context* native_context = *isolate->native_context();
+ JSFunction* builtin_ctor = GetRootConstructor(type, native_context);
+ if (builtin_ctor != NULL) {
+ *flag = kCacheOnPrototypeReceiverIsPrimitive;
+ return handle(HeapObject::cast(builtin_ctor->instance_prototype())->map());
}
- return OWN_MAP;
+ *flag = receiver_map->is_dictionary_map()
+ ? kCacheOnPrototypeReceiverIsDictionary
+ : kCacheOnPrototype;
+ // Callers must ensure that the prototype is non-null.
+ return handle(JSObject::cast(receiver_map->prototype())->map());
}
-Handle<Map> IC::GetCodeCacheHolder(InlineCacheHolderFlag flag,
- HeapType* type,
- Isolate* isolate) {
- if (flag == PROTOTYPE_MAP) {
- Context* context = *isolate->native_context();
- JSFunction* constructor;
- if (type->Is(HeapType::Boolean())) {
- constructor = context->boolean_function();
- } else if (type->Is(HeapType::Number())) {
- constructor = context->number_function();
- } else if (type->Is(HeapType::String())) {
- constructor = context->string_function();
- } else {
- ASSERT(type->Is(HeapType::Symbol()));
- constructor = context->symbol_function();
- }
- return handle(JSObject::cast(constructor->instance_prototype())->map());
+Handle<Map> IC::GetICCacheHolder(HeapType* type, Isolate* isolate,
+ CacheHolderFlag* flag) {
+ Context* native_context = *isolate->native_context();
+ JSFunction* builtin_ctor = GetRootConstructor(type, native_context);
+ if (builtin_ctor != NULL) {
+ *flag = kCacheOnPrototype;
+ return handle(builtin_ctor->initial_map());
}
+ *flag = kCacheOnReceiver;
return TypeToMap(type, isolate);
}
-
} } // namespace v8::internal
#endif // V8_IC_INL_H_
case UNINITIALIZED: return '0';
case PREMONOMORPHIC: return '.';
case MONOMORPHIC: return '1';
- case MONOMORPHIC_PROTOTYPE_FAILURE: return '^';
+ case PROTOTYPE_FAILURE:
+ return '^';
case POLYMORPHIC: return 'P';
case MEGAMORPHIC: return 'N';
case GENERIC: return 'G';
bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
Handle<String> name) {
- if (!IsNameCompatibleWithMonomorphicPrototypeFailure(name)) return false;
-
- InlineCacheHolderFlag cache_holder =
- Code::ExtractCacheHolderFromFlags(target()->flags());
-
- switch (cache_holder) {
- case OWN_MAP:
- // The stub was generated for JSObject but called for non-JSObject.
- // IC::GetCodeCacheHolder is not applicable.
- if (!receiver->IsJSObject()) return false;
- break;
- case PROTOTYPE_MAP:
- // IC::GetCodeCacheHolder is not applicable.
- PrototypeIterator iter(isolate(), receiver);
- if (iter.IsAtEnd()) return false;
- break;
+ if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
+ Handle<Map> receiver_map = TypeToMap(*receiver_type(), isolate());
+ maybe_handler_ = target()->FindHandlerForMap(*receiver_map);
+
+ // The current map wasn't handled yet. There's no reason to stay monomorphic,
+ // *unless* we're moving from a deprecated map to its replacement, or
+ // to a more general elements kind.
+ // TODO(verwaest): Check if the current map is actually what the old map
+ // would transition to.
+ if (maybe_handler_.is_null()) {
+ if (!receiver_map->IsJSObjectMap()) return false;
+ Map* first_map = FirstTargetMap();
+ if (first_map == NULL) return false;
+ Handle<Map> old_map(first_map);
+ if (old_map->is_deprecated()) return true;
+ if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
+ receiver_map->elements_kind())) {
+ return true;
+ }
+ return false;
}
- Handle<Map> map(
- IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map());
-
- // Decide whether the inline cache failed because of changes to the
- // receiver itself or changes to one of its prototypes.
- //
- // If there are changes to the receiver itself, the map of the
- // receiver will have changed and the current target will not be in
- // the receiver map's code cache. Therefore, if the current target
- // is in the receiver map's code cache, the inline cache failed due
- // to prototype check failure.
- int index = map->IndexInCodeCache(*name, *target());
- if (index >= 0) {
- map->RemoveFromCodeCache(*name, *target(), index);
- // Handlers are stored in addition to the ICs on the map. Remove those, too.
- TryRemoveInvalidHandlers(map, name);
- return true;
- }
+ CacheHolderFlag flag;
+ Handle<Map> ic_holder_map(
+ GetICCacheHolder(*receiver_type(), isolate(), &flag));
- // The stub is not in the cache. We've ruled out all other kinds of failure
- // except for proptotype chain changes, a deprecated map, a map that's
- // different from the one that the stub expects, elements kind changes, or a
- // constant global property that will become mutable. Threat all those
- // situations as prototype failures (stay monomorphic if possible).
-
- // If the IC is shared between multiple receivers (slow dictionary mode), then
- // the map cannot be deprecated and the stub invalidated.
- if (cache_holder == OWN_MAP) {
- Map* old_map = FirstTargetMap();
- if (old_map == *map) return true;
- if (old_map != NULL) {
- if (old_map->is_deprecated()) return true;
- if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
- map->elements_kind())) {
- return true;
- }
+ ASSERT(flag != kCacheOnReceiver || receiver->IsJSObject());
+ ASSERT(flag != kCacheOnPrototype || !receiver->IsJSReceiver());
+ ASSERT(flag != kCacheOnPrototypeReceiverIsDictionary);
+
+ if (state() == MONOMORPHIC) {
+ int index = ic_holder_map->IndexInCodeCache(*name, *target());
+ if (index >= 0) {
+ ic_holder_map->RemoveFromCodeCache(*name, *target(), index);
}
}
return cell->type()->IsConstant();
}
- return false;
-}
-
-
-void IC::TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name) {
- CodeHandleList handlers;
- target()->FindHandlers(&handlers);
- for (int i = 0; i < handlers.length(); i++) {
- Handle<Code> handler = handlers.at(i);
- int index = map->IndexInCodeCache(*name, *handler);
- if (index >= 0) {
- map->RemoveFromCodeCache(*name, *handler, index);
- return;
- }
- }
+ return true;
}
-bool IC::IsNameCompatibleWithMonomorphicPrototypeFailure(Handle<Object> name) {
+bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
if (target()->is_keyed_stub()) {
// Determine whether the failure is due to a name failure.
if (!name->IsName()) return false;
void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
+ receiver_type_ = CurrentTypeOf(receiver, isolate());
if (!name->IsString()) return;
- if (state() != MONOMORPHIC) {
- if (state() == POLYMORPHIC && receiver->IsHeapObject()) {
- TryRemoveInvalidHandlers(
- handle(Handle<HeapObject>::cast(receiver)->map()),
- Handle<String>::cast(name));
- }
- return;
- }
+ if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
if (receiver->IsUndefined() || receiver->IsNull()) return;
// Remove the target from the code cache if it became invalid
// because of changes in the prototype chain to avoid hitting it
// again.
- if (TryRemoveInvalidPrototypeDependentStub(
- receiver, Handle<String>::cast(name)) &&
- TryMarkMonomorphicPrototypeFailure(name)) {
+ if (TryRemoveInvalidPrototypeDependentStub(receiver,
+ Handle<String>::cast(name))) {
+ MarkPrototypeFailure(name);
return;
}
}
-bool IC::UpdatePolymorphicIC(Handle<HeapType> type,
- Handle<String> name,
- Handle<Code> code) {
+bool IC::UpdatePolymorphicIC(Handle<String> name, Handle<Code> code) {
if (!code->is_handler()) return false;
+ if (target()->is_keyed_stub() && state() != PROTOTYPE_FAILURE) return false;
+ Handle<HeapType> type = receiver_type();
TypeHandleList types;
CodeHandleList handlers;
if (!target()->FindHandlers(&handlers, types.length())) return false;
number_of_valid_types++;
- if (handler_to_overwrite >= 0) {
- handlers.Set(handler_to_overwrite, code);
- if (!type->NowIs(types.at(handler_to_overwrite))) {
- types.Set(handler_to_overwrite, type);
- }
+ if (number_of_valid_types > 1 && target()->is_keyed_stub()) return false;
+ Handle<Code> ic;
+ if (number_of_valid_types == 1) {
+ ic = isolate()->stub_cache()->ComputeMonomorphicIC(kind(), name, type, code,
+ extra_ic_state());
} else {
- types.Add(type);
- handlers.Add(code);
+ if (handler_to_overwrite >= 0) {
+ handlers.Set(handler_to_overwrite, code);
+ if (!type->NowIs(types.at(handler_to_overwrite))) {
+ types.Set(handler_to_overwrite, type);
+ }
+ } else {
+ types.Add(type);
+ handlers.Add(code);
+ }
+ ic = isolate()->stub_cache()->ComputePolymorphicIC(
+ kind(), &types, &handlers, number_of_valid_types, name,
+ extra_ic_state());
}
-
- Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
- kind(), &types, &handlers, number_of_valid_types, name, extra_ic_state());
set_target(*ic);
return true;
}
Handle<HeapType> IC::MapToType<HeapType>(Handle<Map> map, Isolate* region);
-void IC::UpdateMonomorphicIC(Handle<HeapType> type,
- Handle<Code> handler,
- Handle<String> name) {
+void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<String> name) {
if (!handler->is_handler()) return set_target(*handler);
Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
- kind(), name, type, handler, extra_ic_state());
+ kind(), name, receiver_type(), handler, extra_ic_state());
set_target(*ic);
}
}
-void IC::PatchCache(Handle<HeapType> type,
- Handle<String> name,
- Handle<Code> code) {
+void IC::PatchCache(Handle<String> name, Handle<Code> code) {
switch (state()) {
case UNINITIALIZED:
case PREMONOMORPHIC:
- case MONOMORPHIC_PROTOTYPE_FAILURE:
- UpdateMonomorphicIC(type, code, name);
+ UpdateMonomorphicIC(code, name);
break;
- case MONOMORPHIC: // Fall through.
+ case PROTOTYPE_FAILURE:
+ case MONOMORPHIC:
case POLYMORPHIC:
- if (!target()->is_keyed_stub()) {
- if (UpdatePolymorphicIC(type, name, code)) break;
+ if (!target()->is_keyed_stub() || state() == PROTOTYPE_FAILURE) {
+ if (UpdatePolymorphicIC(name, code)) break;
CopyICToMegamorphicCache(name);
}
if (FLAG_compiled_keyed_generic_loads && (kind() == Code::LOAD_IC)) {
set_target(*megamorphic_stub());
// Fall through.
case MEGAMORPHIC:
- UpdateMegamorphicCache(*type, *name, *code);
+ UpdateMegamorphicCache(*receiver_type(), *name, *code);
break;
case DEBUG_STUB:
break;
return;
}
- Handle<HeapType> type = CurrentTypeOf(object, isolate());
Handle<Code> code;
if (!lookup->IsCacheable()) {
// Bail out if the result is not cacheable.
code = slow_stub();
} else if (!lookup->IsProperty()) {
if (kind() == Code::LOAD_IC) {
- code = isolate()->stub_cache()->ComputeLoadNonexistent(name, type);
+ code = isolate()->stub_cache()->ComputeLoadNonexistent(name,
+ receiver_type());
+ // TODO(jkummerow/verwaest): Introduce a builtin that handles this case.
+ if (code.is_null()) code = slow_stub();
} else {
code = slow_stub();
}
code = ComputeHandler(lookup, object, name);
}
- PatchCache(type, name, code);
+ PatchCache(name, code);
TRACE_IC("LoadIC", name);
}
Handle<Object> object,
Handle<String> name,
Handle<Object> value) {
- InlineCacheHolderFlag cache_holder = GetCodeCacheForObject(*object);
- Handle<HeapObject> stub_holder(GetCodeCacheHolder(
- isolate(), *object, cache_holder));
+ bool receiver_is_holder = lookup->ReceiverIsHolder(object);
+ CacheHolderFlag flag;
+ Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
+ *receiver_type(), receiver_is_holder, isolate(), &flag);
Handle<Code> code = isolate()->stub_cache()->FindHandler(
- name, handle(stub_holder->map()), kind(), cache_holder,
+ name, stub_holder_map, kind(), flag,
lookup->holder()->HasFastProperties() ? Code::FAST : Code::NORMAL);
+ // Use the cached value if it exists, and if it is different from the
+ // handler that just missed.
if (!code.is_null()) {
- return code;
+ if (!maybe_handler_.is_null() &&
+ !maybe_handler_.ToHandleChecked().is_identical_to(code)) {
+ return code;
+ }
+ if (maybe_handler_.is_null()) {
+ // maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
+ // In MEGAMORPHIC case, check if the handler in the megamorphic stub
+ // cache (which just missed) is different from the cached handler.
+ if (state() == MEGAMORPHIC && object->IsHeapObject()) {
+ Map* map = Handle<HeapObject>::cast(object)->map();
+ Code* megamorphic_cached_code =
+ isolate()->stub_cache()->Get(*name, map, code->flags());
+ if (megamorphic_cached_code != *code) return code;
+ } else {
+ return code;
+ }
+ }
}
- code = CompileHandler(lookup, object, name, value, cache_holder);
+ code = CompileHandler(lookup, object, name, value, flag);
ASSERT(code->is_handler());
if (code->type() != Code::NORMAL) {
- HeapObject::UpdateMapCodeCache(stub_holder, name, code);
+ Map::UpdateCodeCache(stub_holder_map, name, code);
}
return code;
}
-Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
- Handle<Object> object,
- Handle<String> name,
- Handle<Object> unused,
- InlineCacheHolderFlag cache_holder) {
+Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, Handle<Object> object,
+ Handle<String> name, Handle<Object> unused,
+ CacheHolderFlag cache_holder) {
if (object->IsString() &&
String::Equals(isolate()->factory()->length_string(), name)) {
FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
}
}
- Handle<HeapType> type = CurrentTypeOf(object, isolate());
+ Handle<HeapType> type = receiver_type();
Handle<JSObject> holder(lookup->holder());
+ bool receiver_is_holder = object.is_identical_to(holder);
LoadStubCompiler compiler(isolate(), kNoExtraICState, cache_holder, kind());
switch (lookup->type()) {
case FIELD: {
FieldIndex field = lookup->GetFieldIndex();
- if (object.is_identical_to(holder)) {
+ if (receiver_is_holder) {
return SimpleFieldLoad(field);
}
return compiler.CompileLoadField(
Handle<Code> code = compiler.CompileLoadGlobal(
type, global, cell, name, lookup->IsDontDelete());
// TODO(verwaest): Move caching of these NORMAL stubs outside as well.
- Handle<HeapObject> stub_holder(GetCodeCacheHolder(
- isolate(), *object, cache_holder));
- HeapObject::UpdateMapCodeCache(stub_holder, name, code);
+ CacheHolderFlag flag;
+ Handle<Map> stub_holder_map =
+ GetHandlerCacheHolder(*type, receiver_is_holder, isolate(), &flag);
+ Map::UpdateCodeCache(stub_holder_map, name, code);
return code;
}
// There is only one shared stub for loading normalized
// properties. It does not traverse the prototype chain, so the
// property must be found in the object for the stub to be
// applicable.
- if (!object.is_identical_to(holder)) break;
+ if (!receiver_is_holder) break;
return isolate()->builtins()->LoadIC_Normal();
case CALLBACKS: {
// Use simple field loads for some well-known callback properties.
- if (object->IsJSObject()) {
+ if (receiver_is_holder) {
+ ASSERT(object->IsJSObject());
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
- Handle<Map> map(receiver->map());
- Handle<HeapType> type = IC::MapToType<HeapType>(
- handle(receiver->map()), isolate());
int object_offset;
if (Accessors::IsJSObjectFieldAccessor<HeapType>(
type, name, &object_offset)) {
// entirely by the migration above.
receiver->map()->LookupTransition(*holder, *name, lookup);
if (!lookup->IsTransition()) return false;
- return ic->TryMarkMonomorphicPrototypeFailure(name);
+ if (!ic->IsNameCompatibleWithPrototypeFailure(name)) return false;
+ ic->MarkPrototypeFailure(name);
+ return true;
}
return true;
Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
- PatchCache(CurrentTypeOf(receiver, isolate()), name, code);
+ PatchCache(name, code);
TRACE_IC("StoreIC", name);
}
Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
- Handle<Object> object,
- Handle<String> name,
+ Handle<Object> object, Handle<String> name,
Handle<Object> value,
- InlineCacheHolderFlag cache_holder) {
+ CacheHolderFlag cache_holder) {
if (object->IsAccessCheckNeeded()) return slow_stub();
- ASSERT(cache_holder == OWN_MAP);
+ ASSERT(cache_holder == kCacheOnReceiver || lookup->type() == CALLBACKS ||
+ (object->IsJSGlobalProxy() && lookup->holder()->IsJSGlobalObject()));
// This is currently guaranteed by checks in StoreIC::Store.
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
// Compute the current IC state based on the target stub, receiver and name.
void UpdateState(Handle<Object> receiver, Handle<Object> name);
- bool IsNameCompatibleWithMonomorphicPrototypeFailure(Handle<Object> name);
- bool TryMarkMonomorphicPrototypeFailure(Handle<Object> name) {
- if (IsNameCompatibleWithMonomorphicPrototypeFailure(name)) {
- state_ = MONOMORPHIC_PROTOTYPE_FAILURE;
- return true;
- }
- return false;
+ bool IsNameCompatibleWithPrototypeFailure(Handle<Object> name);
+ void MarkPrototypeFailure(Handle<Object> name) {
+ ASSERT(IsNameCompatibleWithPrototypeFailure(name));
+ state_ = PROTOTYPE_FAILURE;
}
// If the stub contains weak maps then this function adds the stub to
}
#endif
- // Determines which map must be used for keeping the code stub.
- // These methods should not be called with undefined or null.
- static inline InlineCacheHolderFlag GetCodeCacheForObject(Object* object);
- // TODO(verwaest): This currently returns a HeapObject rather than JSObject*
- // since loading the IC for loading the length from strings are stored on
- // the string map directly, rather than on the JSObject-typed prototype.
- static inline HeapObject* GetCodeCacheHolder(Isolate* isolate,
- Object* object,
- InlineCacheHolderFlag holder);
-
- static inline InlineCacheHolderFlag GetCodeCacheFlag(HeapType* type);
- static inline Handle<Map> GetCodeCacheHolder(InlineCacheHolderFlag flag,
- HeapType* type,
- Isolate* isolate);
+ template <class TypeClass>
+ static JSFunction* GetRootConstructor(TypeClass* type,
+ Context* native_context);
+ static inline Handle<Map> GetHandlerCacheHolder(HeapType* type,
+ bool receiver_is_holder,
+ Isolate* isolate,
+ CacheHolderFlag* flag);
+ static inline Handle<Map> GetICCacheHolder(HeapType* type, Isolate* isolate,
+ CacheHolderFlag* flag);
static bool IsCleared(Code* code) {
InlineCacheState state = code->ic_state();
Handle<Object> value = Handle<Code>::null());
virtual Handle<Code> CompileHandler(LookupResult* lookup,
Handle<Object> object,
- Handle<String> name,
- Handle<Object> value,
- InlineCacheHolderFlag cache_holder) {
+ Handle<String> name, Handle<Object> value,
+ CacheHolderFlag cache_holder) {
UNREACHABLE();
return Handle<Code>::null();
}
- void UpdateMonomorphicIC(Handle<HeapType> type,
- Handle<Code> handler,
- Handle<String> name);
+ void UpdateMonomorphicIC(Handle<Code> handler, Handle<String> name);
- bool UpdatePolymorphicIC(Handle<HeapType> type,
- Handle<String> name,
- Handle<Code> code);
+ bool UpdatePolymorphicIC(Handle<String> name, Handle<Code> code);
virtual void UpdateMegamorphicCache(HeapType* type, Name* name, Code* code);
void CopyICToMegamorphicCache(Handle<String> name);
bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
- void PatchCache(Handle<HeapType> type,
- Handle<String> name,
- Handle<Code> code);
+ void PatchCache(Handle<String> name, Handle<Code> code);
virtual Code::Kind kind() const {
UNREACHABLE();
return Code::STUB;
bool TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
Handle<String> name);
- void TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name);
ExtraICState extra_ic_state() const { return extra_ic_state_; }
void set_extra_ic_state(ExtraICState state) {
extra_ic_state_ = state;
}
+ Handle<HeapType> receiver_type() { return receiver_type_; }
+
void TargetMaps(MapHandleList* list) {
FindTargetMaps();
for (int i = 0; i < target_maps_.length(); i++) {
// The original code target that missed.
Handle<Code> target_;
- State state_;
bool target_set_;
+ State state_;
+ Handle<HeapType> receiver_type_;
+ MaybeHandle<Code> maybe_handler_;
ExtraICState extra_ic_state_;
MapHandleList target_maps_;
Handle<Object> object,
Handle<String> name,
Handle<Object> unused,
- InlineCacheHolderFlag cache_holder);
+ CacheHolderFlag cache_holder);
private:
// Stub accessors.
Handle<Object> value);
virtual Handle<Code> CompileHandler(LookupResult* lookup,
Handle<Object> object,
- Handle<String> name,
- Handle<Object> value,
- InlineCacheHolderFlag cache_holder);
+ Handle<String> name, Handle<Object> value,
+ CacheHolderFlag cache_holder);
private:
void set_target(Code* code) {
}
-Code::Flags Code::ComputeFlags(Kind kind,
- InlineCacheState ic_state,
- ExtraICState extra_ic_state,
- StubType type,
- InlineCacheHolderFlag holder) {
+Code::Flags Code::ComputeFlags(Kind kind, InlineCacheState ic_state,
+ ExtraICState extra_ic_state, StubType type,
+ CacheHolderFlag holder) {
// Compute the bit mask.
unsigned int bits = KindField::encode(kind)
| ICStateField::encode(ic_state)
Code::Flags Code::ComputeMonomorphicFlags(Kind kind,
ExtraICState extra_ic_state,
- InlineCacheHolderFlag holder,
+ CacheHolderFlag holder,
StubType type) {
return ComputeFlags(kind, MONOMORPHIC, extra_ic_state, type, holder);
}
-Code::Flags Code::ComputeHandlerFlags(Kind handler_kind,
- StubType type,
- InlineCacheHolderFlag holder) {
+Code::Flags Code::ComputeHandlerFlags(Kind handler_kind, StubType type,
+ CacheHolderFlag holder) {
return ComputeFlags(Code::HANDLER, MONOMORPHIC, handler_kind, type, holder);
}
}
-InlineCacheHolderFlag Code::ExtractCacheHolderFromFlags(Flags flags) {
+CacheHolderFlag Code::ExtractCacheHolderFromFlags(Flags flags) {
return CacheHolderField::decode(flags);
}
}
+Code::Flags Code::RemoveTypeAndHolderFromFlags(Flags flags) {
+ int bits = flags & ~TypeField::kMask & ~CacheHolderField::kMask;
+ return static_cast<Flags>(bits);
+}
+
+
Code* Code::GetCodeFromTargetAddress(Address address) {
HeapObject* code = HeapObject::FromAddress(address - Code::kHeaderSize);
// GetCodeFromTargetAddress might be called when marking objects during mark
}
+MaybeHandle<Code> Code::FindHandlerForMap(Map* map) {
+ ASSERT(is_inline_cache_stub());
+ int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
+ RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+ bool return_next = false;
+ for (RelocIterator it(this, mask); !it.done(); it.next()) {
+ RelocInfo* info = it.rinfo();
+ if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
+ Object* object = info->target_object();
+ if (object == map) return_next = true;
+ } else if (return_next) {
+ Code* code = Code::GetCodeFromTargetAddress(info->target_address());
+ ASSERT(code->kind() == Code::HANDLER);
+ return handle(code);
+ }
+ }
+ return MaybeHandle<Code>();
+}
+
+
Name* Code::FindFirstName() {
ASSERT(is_inline_cache_stub());
DisallowHeapAllocation no_allocation;
case UNINITIALIZED: return "UNINITIALIZED";
case PREMONOMORPHIC: return "PREMONOMORPHIC";
case MONOMORPHIC: return "MONOMORPHIC";
- case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
+ case PROTOTYPE_FAILURE:
+ return "PROTOTYPE_FAILURE";
case POLYMORPHIC: return "POLYMORPHIC";
case MEGAMORPHIC: return "MEGAMORPHIC";
case GENERIC: return "GENERIC";
// enough handlers can be found.
bool FindHandlers(CodeHandleList* code_list, int length = -1);
+ // Find the handler for |map|.
+ MaybeHandle<Code> FindHandlerForMap(Map* map);
+
// Find the first name in an IC stub.
Name* FindFirstName();
// Flags operations.
static inline Flags ComputeFlags(
- Kind kind,
- InlineCacheState ic_state = UNINITIALIZED,
- ExtraICState extra_ic_state = kNoExtraICState,
- StubType type = NORMAL,
- InlineCacheHolderFlag holder = OWN_MAP);
+ Kind kind, InlineCacheState ic_state = UNINITIALIZED,
+ ExtraICState extra_ic_state = kNoExtraICState, StubType type = NORMAL,
+ CacheHolderFlag holder = kCacheOnReceiver);
static inline Flags ComputeMonomorphicFlags(
- Kind kind,
- ExtraICState extra_ic_state = kNoExtraICState,
- InlineCacheHolderFlag holder = OWN_MAP,
- StubType type = NORMAL);
+ Kind kind, ExtraICState extra_ic_state = kNoExtraICState,
+ CacheHolderFlag holder = kCacheOnReceiver, StubType type = NORMAL);
static inline Flags ComputeHandlerFlags(
- Kind handler_kind,
- StubType type = NORMAL,
- InlineCacheHolderFlag holder = OWN_MAP);
+ Kind handler_kind, StubType type = NORMAL,
+ CacheHolderFlag holder = kCacheOnReceiver);
static inline InlineCacheState ExtractICStateFromFlags(Flags flags);
static inline StubType ExtractTypeFromFlags(Flags flags);
+ static inline CacheHolderFlag ExtractCacheHolderFromFlags(Flags flags);
static inline Kind ExtractKindFromFlags(Flags flags);
- static inline InlineCacheHolderFlag ExtractCacheHolderFromFlags(Flags flags);
static inline ExtraICState ExtractExtraICStateFromFlags(Flags flags);
static inline Flags RemoveTypeFromFlags(Flags flags);
+ static inline Flags RemoveTypeAndHolderFromFlags(Flags flags);
// Convert a target address into a code object.
static inline Code* GetCodeFromTargetAddress(Address address);
// Flags layout. BitField<type, shift, size>.
class ICStateField: public BitField<InlineCacheState, 0, 3> {};
class TypeField: public BitField<StubType, 3, 1> {};
- class CacheHolderField: public BitField<InlineCacheHolderFlag, 5, 1> {};
+ class CacheHolderField : public BitField<CacheHolderFlag, 4, 2> {};
class KindField: public BitField<Kind, 6, 4> {};
// TODO(bmeurer): Bit 10 is available for free use. :-)
class ExtraICStateField: public BitField<ExtraICState, 11,
return map->FindFieldOwner(number_);
}
+ bool ReceiverIsHolder(Handle<Object> receiver) {
+ if (*receiver == holder()) return true;
+ if (lookup_type_ == TRANSITION_TYPE) return true;
+ return false;
+ }
+
void Iterate(ObjectVisitor* visitor);
private:
}
-Code* StubCache::Set(Name* name, Map* map, Code* code) {
- // Get the flags from the code.
- Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
+static Code::Flags CommonStubCacheChecks(Name* name, Map* map,
+ Code::Flags flags, Heap* heap) {
+ flags = Code::RemoveTypeAndHolderFromFlags(flags);
// Validate that the name does not move on scavenge, and that we
// can use identity checks instead of structural equality checks.
- ASSERT(!heap()->InNewSpace(name));
+ ASSERT(!heap->InNewSpace(name));
ASSERT(name->IsUniqueName());
// The state bits are not important to the hash function because
ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
- // Make sure that the code type is not included in the hash.
+ // Make sure that the code type and cache holder are not included in the hash.
ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
+ ASSERT(Code::ExtractCacheHolderFromFlags(flags) == 0);
+
+ return flags;
+}
+
+
+Code* StubCache::Set(Name* name, Map* map, Code* code) {
+ Code::Flags flags = CommonStubCacheChecks(name, map, code->flags(), heap());
// Compute the primary entry.
int primary_offset = PrimaryOffset(name, flags, map);
// secondary cache before overwriting it.
if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) {
Map* old_map = primary->map;
- Code::Flags old_flags = Code::RemoveTypeFromFlags(old_code->flags());
+ Code::Flags old_flags =
+ Code::RemoveTypeAndHolderFromFlags(old_code->flags());
int seed = PrimaryOffset(primary->key, old_flags, old_map);
int secondary_offset = SecondaryOffset(primary->key, old_flags, seed);
Entry* secondary = entry(secondary_, secondary_offset);
}
-Handle<Code> StubCache::FindIC(Handle<Name> name,
- Handle<Map> stub_holder,
- Code::Kind kind,
- ExtraICState extra_state,
- InlineCacheHolderFlag cache_holder) {
+Code* StubCache::Get(Name* name, Map* map, Code::Flags flags) {
+ flags = CommonStubCacheChecks(name, map, flags, heap());
+ int primary_offset = PrimaryOffset(name, flags, map);
+ Entry* primary = entry(primary_, primary_offset);
+ if (primary->key == name && primary->map == map) {
+ return primary->value;
+ }
+ int secondary_offset = SecondaryOffset(name, flags, primary_offset);
+ Entry* secondary = entry(secondary_, secondary_offset);
+ if (secondary->key == name && secondary->map == map) {
+ return secondary->value;
+ }
+ return NULL;
+}
+
+
+Handle<Code> StubCache::FindIC(Handle<Name> name, Handle<Map> stub_holder,
+ Code::Kind kind, ExtraICState extra_state,
+ CacheHolderFlag cache_holder) {
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind, extra_state, cache_holder);
Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_);
}
-Handle<Code> StubCache::FindHandler(Handle<Name> name,
- Handle<Map> stub_holder,
+Handle<Code> StubCache::FindHandler(Handle<Name> name, Handle<Map> stub_holder,
Code::Kind kind,
- InlineCacheHolderFlag cache_holder,
+ CacheHolderFlag cache_holder,
Code::StubType type) {
Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder);
Handle<HeapType> type,
Handle<Code> handler,
ExtraICState extra_ic_state) {
- InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type);
+ CacheHolderFlag flag;
+ Handle<Map> stub_holder = IC::GetICCacheHolder(*type, isolate(), &flag);
- Handle<Map> stub_holder;
Handle<Code> ic;
// There are multiple string maps that all use the same prototype. That
// prototype cannot hold multiple handlers, one for each of the string maps,
// for a single name. Hence, turn off caching of the IC.
bool can_be_cached = !type->Is(HeapType::String());
if (can_be_cached) {
- stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate());
ic = FindIC(name, stub_holder, kind, extra_ic_state, flag);
if (!ic.is_null()) return ic;
}
Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
Handle<HeapType> type) {
- InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type);
- Handle<Map> stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate());
+ Handle<Map> receiver_map = IC::TypeToMap(*type, isolate());
+ if (receiver_map->prototype()->IsNull()) {
+ // TODO(jkummerow/verwaest): If there is no prototype and the property
+ // is nonexistent, introduce a builtin to handle this (fast properties
+ // -> return undefined, dictionary properties -> do negative lookup).
+ return Handle<Code>();
+ }
+ CacheHolderFlag flag;
+ Handle<Map> stub_holder_map =
+ IC::GetHandlerCacheHolder(*type, false, isolate(), &flag);
+
// If no dictionary mode objects are present in the prototype chain, the load
// nonexistent IC stub can be shared for all names for a given map and we use
// the empty string for the map cache in that case. If there are dictionary
// mode objects involved, we need to do negative lookups in the stub and
// therefore the stub will be specific to the name.
- Handle<Map> current_map = stub_holder;
- Handle<Name> cache_name = current_map->is_dictionary_map()
- ? name : Handle<Name>::cast(isolate()->factory()->nonexistent_symbol());
- Handle<Object> next(current_map->prototype(), isolate());
- Handle<JSObject> last = Handle<JSObject>::null();
- while (!next->IsNull()) {
- last = Handle<JSObject>::cast(next);
- next = handle(current_map->prototype(), isolate());
- current_map = handle(Handle<HeapObject>::cast(next)->map());
+ Handle<Name> cache_name =
+ receiver_map->is_dictionary_map()
+ ? name
+ : Handle<Name>::cast(isolate()->factory()->nonexistent_symbol());
+ Handle<Map> current_map = stub_holder_map;
+ Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
+ while (true) {
if (current_map->is_dictionary_map()) cache_name = name;
+ if (current_map->prototype()->IsNull()) break;
+ last = handle(JSObject::cast(current_map->prototype()));
+ current_map = handle(last->map());
}
-
// Compile the stub that is either shared for all names or
// name specific if there are global objects involved.
- Handle<Code> handler = FindHandler(
- cache_name, stub_holder, Code::LOAD_IC, flag, Code::FAST);
+ Handle<Code> handler =
+ FindHandler(cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST);
if (!handler.is_null()) {
return handler;
}
LoadStubCompiler compiler(isolate_, kNoExtraICState, flag);
handler = compiler.CompileLoadNonexistent(type, last, cache_name);
- Map::UpdateCodeCache(stub_holder, cache_name, handler);
+ Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
return handler;
}
KeyedAccessStoreMode store_mode) {
ExtraICState extra_state =
KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode);
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::KEYED_STORE_IC, extra_state);
+ Code::Flags flags =
+ Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, extra_state);
ASSERT(store_mode == STANDARD_STORE ||
store_mode == STORE_AND_GROW_NO_TRANSITION ||
Handle<JSObject> StubHolder(Handle<JSObject> receiver,
Handle<JSObject> holder);
- Handle<Code> FindIC(Handle<Name> name,
- Handle<Map> stub_holder_map,
+ Handle<Code> FindIC(Handle<Name> name, Handle<Map> stub_holder_map,
Code::Kind kind,
ExtraICState extra_state = kNoExtraICState,
- InlineCacheHolderFlag cache_holder = OWN_MAP);
+ CacheHolderFlag cache_holder = kCacheOnReceiver);
- Handle<Code> FindHandler(Handle<Name> name,
- Handle<Map> map,
- Code::Kind kind,
- InlineCacheHolderFlag cache_holder,
- Code::StubType type);
+ Handle<Code> FindHandler(Handle<Name> name, Handle<Map> map, Code::Kind kind,
+ CacheHolderFlag cache_holder, Code::StubType type);
Handle<Code> ComputeMonomorphicIC(Code::Kind kind,
Handle<Name> name,
// Update cache for entry hash(name, map).
Code* Set(Name* name, Map* map, Code* code);
+ Code* Get(Name* name, Map* map, Code::Flags flags);
+
// Clear the lookup table (@ mark compact collection).
void Clear();
class BaseLoadStoreStubCompiler: public StubCompiler {
public:
- BaseLoadStoreStubCompiler(Isolate* isolate,
- Code::Kind kind,
+ BaseLoadStoreStubCompiler(Isolate* isolate, Code::Kind kind,
ExtraICState extra_ic_state = kNoExtraICState,
- InlineCacheHolderFlag cache_holder = OWN_MAP)
+ CacheHolderFlag cache_holder = kCacheOnReceiver)
: StubCompiler(isolate, extra_ic_state),
kind_(kind),
cache_holder_(cache_holder) {
bool IncludesNumberType(TypeHandleList* types);
Code::Kind kind_;
- InlineCacheHolderFlag cache_holder_;
+ CacheHolderFlag cache_holder_;
Register* registers_;
};
public:
LoadStubCompiler(Isolate* isolate,
ExtraICState extra_ic_state = kNoExtraICState,
- InlineCacheHolderFlag cache_holder = OWN_MAP,
+ CacheHolderFlag cache_holder = kCacheOnReceiver,
Code::Kind kind = Code::LOAD_IC)
- : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state,
- cache_holder) { }
+ : BaseLoadStoreStubCompiler(isolate, kind, extra_ic_state, cache_holder) {
+ }
virtual ~LoadStubCompiler() { }
Handle<Code> CompileLoadField(Handle<HeapType> type,
public:
KeyedLoadStubCompiler(Isolate* isolate,
ExtraICState extra_ic_state = kNoExtraICState,
- InlineCacheHolderFlag cache_holder = OWN_MAP)
+ CacheHolderFlag cache_holder = kCacheOnReceiver)
: LoadStubCompiler(isolate, extra_ic_state, cache_holder,
- Code::KEYED_LOAD_IC) { }
+ Code::KEYED_LOAD_IC) {}
Handle<Code> CompileLoadElement(Handle<Map> receiver_map);
ASSERT(name.is(rcx));
// Probe the stub cache.
- Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
+ Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+ Code::ComputeHandlerFlags(Code::LOAD_IC));
masm->isolate()->stub_cache()->GenerateProbe(
masm, flags, receiver, name, rbx, rax);
// The return address is on the stack.
// Get the receiver from the stack and probe the stub cache.
- Code::Flags flags = Code::ComputeHandlerFlags(Code::STORE_IC);
+ Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
+ Code::ComputeHandlerFlags(Code::STORE_IC));
masm->isolate()->stub_cache()->GenerateProbe(
masm, flags, ReceiverRegister(), NameRegister(), rbx, no_reg);
__ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
} else {
bool in_new_space = heap()->InNewSpace(*prototype);
- if (in_new_space) {
+ // Two possible reasons for loading the prototype from the map:
+ // (1) Can't store references to new space in code.
+ // (2) Handler is shared for all receivers with the same prototype
+ // map (but not necessarily the same prototype instance).
+ bool load_prototype_from_map = in_new_space || depth == 1;
+ if (load_prototype_from_map) {
// Save the map in scratch1 for later.
__ movp(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
}
}
reg = holder_reg; // From now on the object will be in holder_reg.
- if (in_new_space) {
- // The prototype is in new space; we cannot store a reference to it
- // in the code. Load it from the map.
+ if (load_prototype_from_map) {
__ movp(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
} else {
- // The prototype is in old space; load it directly.
__ Move(reg, prototype);
}
}