Register InstanceofStub::right() { return r1; }
+void LoadFieldStub::Generate(MacroAssembler* masm) {
+ StubCompiler::DoGenerateFastPropertyLoad(masm, r0, reg_, inobject_, index_);
+ __ Ret();
+}
+
+
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
// The displacement is the offset of the last parameter (if any)
// relative to the frame pointer.
// -----------------------------------
// Probe the stub cache.
- Code::Flags flags =
- Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
+ Code::Flags flags = Code::ComputeFlags(
+ Code::LOAD_IC, MONOMORPHIC, Code::HANDLER_FRAGMENT);
Isolate::Current()->stub_cache()->GenerateProbe(
masm, flags, r0, r2, r3, r4, r5, r6);
Register src,
Handle<JSObject> holder,
PropertyIndex index) {
- if (index.is_header_index()) {
- int offset = index.header_index() * kPointerSize;
- __ ldr(dst, FieldMemOperand(src, offset));
- } else {
- // Adjust for the number of properties stored in the holder.
- int slot = index.field_index() - holder->map()->inobject_properties();
- if (slot < 0) {
- // Get the property straight out of the holder.
- int offset = holder->map()->instance_size() + (slot * kPointerSize);
- __ ldr(dst, FieldMemOperand(src, offset));
- } else {
- // Calculate the offset into the properties array.
- int offset = slot * kPointerSize + FixedArray::kHeaderSize;
- __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
- __ ldr(dst, FieldMemOperand(dst, offset));
- }
+ DoGenerateFastPropertyLoad(
+ masm, dst, src, index.is_inobject(holder), index.translate(holder));
+}
+
+
+void StubCompiler::DoGenerateFastPropertyLoad(MacroAssembler* masm,
+ Register dst,
+ Register src,
+ bool inobject,
+ int index) {
+ int offset = index * kPointerSize;
+ if (!inobject) {
+ // Calculate the offset into the properties array.
+ offset = offset + FixedArray::kHeaderSize;
+ __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
+ src = dst;
}
+ __ ldr(dst, FieldMemOperand(src, offset));
}
#define __ ACCESS_MASM(masm())
+void StubCompiler::GenerateTailCall(Handle<Code> code) {
+ __ Jump(code, RelocInfo::CODE_TARGET);
+}
+
+
Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
Register scratch2,
Handle<String> name,
int save_at_depth,
- Label* miss) {
+ Label* miss,
+ PrototypeCheckType check) {
+ Handle<JSObject> first = object;
// Make sure there's no overlap between holder and object registers.
ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
reg = holder_reg; // From now on the object will be in holder_reg.
__ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
} else {
- Handle<Map> current_map(current->map());
- __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
- ALLOW_ELEMENT_TRANSITION_MAPS);
+ Register map_reg = scratch1;
+ if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+ Handle<Map> current_map(current->map());
+ // CheckMap implicitly loads the map of |reg| into |map_reg|.
+ __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK,
+ ALLOW_ELEMENT_TRANSITION_MAPS);
+ } else {
+ __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
+ }
// Check access rights to the global object. This has to happen after
// the map check so that we know that the object is actually a global
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.
- __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
+ __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
} else {
// The prototype is in old space; load it directly.
__ mov(reg, Operand(prototype));
// Log the check depth.
LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
- // Check the holder map.
- __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
- DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+ // Check the holder map.
+ __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
+ DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ }
// Perform security check for access to the global object.
ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
Label* miss) {
- __ b(success);
- __ bind(miss);
- GenerateLoadMiss(masm(), kind());
+ if (!miss->is_unused()) {
+ __ b(success);
+ __ bind(miss);
+ GenerateLoadMiss(masm(), kind());
+ }
}
Handle<JSObject> holder,
Handle<String> name,
Label* success,
- FrontendCheckType check,
Handle<ExecutableAccessorInfo> callback) {
Label miss;
- Register reg = HandlerFrontendHeader(
- object, object_reg, holder, name, &miss, check);
+ Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
ASSERT(!reg.is(scratch2()));
Handle<GlobalObject> global) {
Label miss;
- Register reg = HandlerFrontendHeader(
- object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS);
+ Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
__ Ret();
// Return the generated code.
- return GetCode(Code::NONEXISTENT, factory()->empty_string());
+ return GetCode(Code::HANDLER_FRAGMENT, Code::NONEXISTENT, name);
}
bool is_dont_delete) {
Label success, miss;
- HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global),
- name, &miss, PERFORM_INITIAL_CHECKS);
+ __ CheckMap(
+ receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
+ HandlerFrontendHeader(
+ object, receiver(), Handle<JSObject>::cast(global), name, &miss);
// Get the value from the cell.
__ mov(r3, Operand(cell));
__ Ret();
// Return the generated code.
- return GetCode(Code::NORMAL, name);
+ return GetCode(Code::IC_FRAGMENT, Code::NORMAL, name);
}
__ Jump(ic, RelocInfo::CODE_TARGET);
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string());
+ return GetCode(Code::IC_FRAGMENT, Code::NORMAL, factory()->empty_string());
}
-Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
+Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
MapHandleList* receiver_maps,
- CodeHandleList* handler_ics) {
- // ----------- S t a t e -------------
- // -- lr : return address
- // -- r0 : key
- // -- r1 : receiver
- // -----------------------------------
+ CodeHandleList* handlers,
+ Handle<String> name,
+ Code::StubType type,
+ IcCheckType check) {
Label miss;
- __ JumpIfSmi(r1, &miss);
+
+ if (check == PROPERTY) {
+ GenerateNameCheck(name, this->name(), &miss);
+ }
+
+ __ JumpIfSmi(receiver(), &miss);
+ Register map_reg = scratch1();
int receiver_count = receiver_maps->length();
- __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+ __ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
for (int current = 0; current < receiver_count; ++current) {
__ mov(ip, Operand(receiver_maps->at(current)));
- __ cmp(r2, ip);
- __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET, eq);
+ __ cmp(map_reg, ip);
+ __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq);
}
__ bind(&miss);
- Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
- __ Jump(miss_ic, RelocInfo::CODE_TARGET, al);
+ GenerateLoadMiss(masm(), kind());
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
+ InlineCacheState state =
+ receiver_maps->length() > 1 ? POLYMORPHIC : MONOMORPHIC;
+ return GetCode(Code::IC_FRAGMENT, type, name, state);
}
V(LoadIC_PreMonomorphic, LOAD_IC, PREMONOMORPHIC, \
Code::kNoExtraICState) \
V(LoadIC_Normal, LOAD_IC, MONOMORPHIC, \
- Code::kNoExtraICState) \
+ Code::IC_FRAGMENT) \
V(LoadIC_Megamorphic, LOAD_IC, MEGAMORPHIC, \
Code::kNoExtraICState) \
V(LoadIC_Getter_ForDeopt, LOAD_IC, MONOMORPHIC, \
// Copy the generated code into a heap object.
Code::Flags flags = Code::ComputeFlags(
- static_cast<Code::Kind>(GetCodeKind()), GetICState(), GetExtraICState());
+ static_cast<Code::Kind>(GetCodeKind()),
+ GetICState(),
+ GetExtraICState(),
+ GetStubType());
Handle<Code> new_object = factory->NewCode(
desc, flags, masm.CodeObject(), NeedsImmovableCode());
return new_object;
V(TransitionElementsKind) \
V(StoreArrayLiteralElement) \
V(StubFailureTrampoline) \
- V(ProfileEntryHook)
+ V(ProfileEntryHook) \
+ /* IC Handler stubs */ \
+ V(LoadField)
// List of code stubs only used on ARM platforms.
#ifdef V8_TARGET_ARCH_ARM
virtual Code::ExtraICState GetExtraICState() {
return Code::kNoExtraICState;
}
+ virtual Code::StubType GetStubType() {
+ return Code::NORMAL;
+ }
// Returns whether the code generated for this stub needs to be allocated as
// a fixed (non-moveable) code object.
virtual void Generate(MacroAssembler* masm);
private:
+ STATIC_ASSERT(KindBits::kSize == 4);
class WrapperModeBits: public BitField<bool, 4, 1> {};
virtual CodeStub::Major MajorKey() { return StringLength; }
virtual int MinorKey() {
}
private:
+ STATIC_ASSERT(KindBits::kSize == 4);
class StrictModeBits: public BitField<bool, 4, 1> {};
virtual int MinorKey() {
return KindBits::encode(kind()) | StrictModeBits::encode(strict_mode_);
};
+class HandlerStub: public ICStub {
+ public:
+ explicit HandlerStub(Code::Kind kind) : ICStub(kind) { }
+
+ protected:
+ virtual Code::ExtraICState GetExtraICState() {
+ return Code::HANDLER_FRAGMENT;
+ }
+};
+
+
+class LoadFieldStub: public HandlerStub {
+ public:
+ LoadFieldStub(Register reg, bool inobject, int index)
+ : HandlerStub(Code::LOAD_IC),
+ reg_(reg),
+ inobject_(inobject),
+ index_(index) { }
+ virtual void Generate(MacroAssembler* masm);
+
+ protected:
+ virtual Code::StubType GetStubType() { return Code::FIELD; }
+
+ private:
+ STATIC_ASSERT(KindBits::kSize == 4);
+ class RegisterBits: public BitField<int, 4, 6> {};
+ class InobjectBits: public BitField<bool, 10, 1> {};
+ class IndexBits: public BitField<int, 11, 11> {};
+ virtual CodeStub::Major MajorKey() { return LoadField; }
+ virtual int MinorKey() {
+ return KindBits::encode(kind())
+ | RegisterBits::encode(reg_.code())
+ | InobjectBits::encode(inobject_)
+ | IndexBits::encode(index_);
+ }
+
+ Register reg_;
+ bool inobject_;
+ int index_;
+};
+
+
class BinaryOpStub: public PlatformCodeStub {
public:
BinaryOpStub(Token::Value op, OverwriteMode mode)
}
+void LoadFieldStub::Generate(MacroAssembler* masm) {
+ StubCompiler::DoGenerateFastPropertyLoad(masm, eax, reg_, inobject_, index_);
+ __ ret(0);
+}
+
+
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
// The key is in edx and the parameter count is in eax.
// -----------------------------------
// Probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
- Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
- eax);
+ Code::Flags flags = Code::ComputeFlags(
+ Code::LOAD_IC, MONOMORPHIC, Code::HANDLER_FRAGMENT);
+ Isolate::Current()->stub_cache()->GenerateProbe(
+ masm, flags, edx, ecx, ebx, eax);
// Cache miss: Jump to runtime.
GenerateMiss(masm);
Register src,
Handle<JSObject> holder,
PropertyIndex index) {
- if (index.is_header_index()) {
- int offset = index.header_index() * kPointerSize;
- __ mov(dst, FieldOperand(src, offset));
- } else {
- // Adjust for the number of properties stored in the holder.
- int slot = index.field_index() - holder->map()->inobject_properties();
- if (slot < 0) {
- // Get the property straight out of the holder.
- int offset = holder->map()->instance_size() + (slot * kPointerSize);
- __ mov(dst, FieldOperand(src, offset));
- } else {
- // Calculate the offset into the properties array.
- int offset = slot * kPointerSize + FixedArray::kHeaderSize;
- __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
- __ mov(dst, FieldOperand(dst, offset));
- }
+ DoGenerateFastPropertyLoad(
+ masm, dst, src, index.is_inobject(holder), index.translate(holder));
+}
+
+
+void StubCompiler::DoGenerateFastPropertyLoad(MacroAssembler* masm,
+ Register dst,
+ Register src,
+ bool inobject,
+ int index) {
+ int offset = index * kPointerSize;
+ if (!inobject) {
+ // Calculate the offset into the properties array.
+ offset = offset + FixedArray::kHeaderSize;
+ __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
+ src = dst;
}
+ __ mov(dst, FieldOperand(src, offset));
}
#define __ ACCESS_MASM(masm())
+void StubCompiler::GenerateTailCall(Handle<Code> code) {
+ __ jmp(code, RelocInfo::CODE_TARGET);
+}
+
+
Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
Register scratch2,
Handle<String> name,
int save_at_depth,
- Label* miss) {
+ Label* miss,
+ PrototypeCheckType check) {
+ Handle<JSObject> first = object;
// Make sure there's no overlap between holder and object registers.
ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
// Save the map in scratch1 for later.
__ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
}
- __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
- ALLOW_ELEMENT_TRANSITION_MAPS);
+ if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+ __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
+ ALLOW_ELEMENT_TRANSITION_MAPS);
+ }
// Check access rights to the global object. This has to happen after
// the map check so that we know that the object is actually a global
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- // Check the holder map.
- __ CheckMap(reg, Handle<Map>(holder->map()),
- miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+ // Check the holder map.
+ __ CheckMap(reg, Handle<Map>(holder->map()),
+ miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ }
// Perform security check for access to the global object.
ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
Label* miss) {
- __ jmp(success);
- __ bind(miss);
- GenerateLoadMiss(masm(), kind());
+ if (!miss->is_unused()) {
+ __ jmp(success);
+ __ bind(miss);
+ GenerateLoadMiss(masm(), kind());
+ }
}
Handle<JSObject> holder,
Handle<String> name,
Label* success,
- FrontendCheckType check,
Handle<ExecutableAccessorInfo> callback) {
Label miss;
- Register reg = HandlerFrontendHeader(
- object, object_reg, holder, name, &miss, check);
+ Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
ASSERT(!reg.is(scratch2()));
Handle<GlobalObject> global) {
Label miss;
- Register reg = HandlerFrontendHeader(
- object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS);
+ Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
__ mov(scratch2(), esp);
ASSERT(!scratch2().is(reg));
__ push(reg); // holder
- // Push data from AccessorInfo.
+ // Push data from ExecutableAccessorInfo.
if (isolate()->heap()->InNewSpace(callback->data())) {
__ mov(scratch1(), Immediate(callback));
__ push(FieldOperand(scratch1(), ExecutableAccessorInfo::kDataOffset));
}
__ push(Immediate(reinterpret_cast<int>(isolate())));
- // Save a pointer to where we pushed the arguments pointer.
- // This will be passed as the const AccessorInfo& to the C++ callback.
+ // Save a pointer to where we pushed the arguments pointer. This will be
+ // passed as the const ExecutableAccessorInfo& to the C++ callback.
__ push(scratch2());
__ push(name()); // name
__ ret(0);
// Return the generated code.
- return GetCode(Code::NONEXISTENT, factory()->empty_string());
+ return GetCode(Code::HANDLER_FRAGMENT, Code::NONEXISTENT, name);
}
bool is_dont_delete) {
Label success, miss;
- HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global),
- name, &miss, PERFORM_INITIAL_CHECKS);
+ __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
+ HandlerFrontendHeader(
+ object, receiver(), Handle<JSObject>::cast(global), name, &miss);
// Get the value from the cell.
if (Serializer::enabled()) {
__ mov(eax, Immediate(cell));
__ ret(0);
// Return the generated code.
- return GetCode(Code::NORMAL, name);
+ return GetCode(Code::IC_FRAGMENT, Code::NORMAL, name);
}
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string());
+ return GetCode(Code::IC_FRAGMENT, Code::NORMAL, factory()->empty_string());
}
-Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
+Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
MapHandleList* receiver_maps,
- CodeHandleList* handler_ics) {
- // ----------- S t a t e -------------
- // -- ecx : key
- // -- edx : receiver
- // -- esp[0] : return address
- // -----------------------------------
+ CodeHandleList* handlers,
+ Handle<String> name,
+ Code::StubType type,
+ IcCheckType check) {
Label miss;
- __ JumpIfSmi(edx, &miss);
- Register map_reg = ebx;
- __ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset));
+ if (check == PROPERTY) {
+ GenerateNameCheck(name, this->name(), &miss);
+ }
+
+ __ JumpIfSmi(receiver(), &miss);
+ Register map_reg = scratch1();
+ __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
int receiver_count = receiver_maps->length();
for (int current = 0; current < receiver_count; ++current) {
__ cmp(map_reg, receiver_maps->at(current));
- __ j(equal, handler_ics->at(current));
+ __ j(equal, handlers->at(current));
}
__ bind(&miss);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+ GenerateLoadMiss(masm(), kind());
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
+ InlineCacheState state =
+ receiver_maps->length() > 1 ? POLYMORPHIC : MONOMORPHIC;
+ return GetCode(Code::IC_FRAGMENT, type, name, state);
}
}
+static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
+ Handle<Map> new_receiver_map) {
+ ASSERT(!new_receiver_map.is_null());
+ for (int current = 0; current < receiver_maps->length(); ++current) {
+ if (!receiver_maps->at(current).is_null() &&
+ receiver_maps->at(current).is_identical_to(new_receiver_map)) {
+ return false;
+ }
+ }
+ receiver_maps->Add(new_receiver_map);
+ return true;
+}
+
+
+bool IC::UpdatePolymorphicIC(State state,
+ StrictModeFlag strict_mode,
+ Handle<JSObject> receiver,
+ Handle<String> name,
+ Handle<Code> code) {
+ if (code->type() == Code::NORMAL) return false;
+ if (target()->ic_state() == MONOMORPHIC &&
+ target()->type() == Code::NORMAL) {
+ return false;
+ }
+ MapHandleList receiver_maps;
+ CodeHandleList handlers;
+ target()->FindAllMaps(&receiver_maps);
+ int number_of_maps = receiver_maps.length();
+ if (number_of_maps == 0 || number_of_maps >= 4) return false;
+
+ target()->FindAllCode(&handlers, receiver_maps.length());
+
+ if (!AddOneReceiverMapIfMissing(&receiver_maps,
+ Handle<Map>(receiver->map()))) {
+ return false;
+ }
+
+ handlers.Add(code);
+ Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
+ &receiver_maps, &handlers, name);
+ set_target(*ic);
+ return true;
+}
+
+
+void LoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name) {
+ if (handler->type() == Code::NORMAL) return set_target(*handler);
+ Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
+ receiver, handler, name);
+ set_target(*ic);
+}
+
+
+void KeyedLoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name) {
+ if (handler->type() == Code::NORMAL) return set_target(*handler);
+ Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedMonomorphicIC(
+ receiver, handler, name);
+ set_target(*ic);
+}
+
+
void IC::PatchCache(State state,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
case UNINITIALIZED:
case PREMONOMORPHIC:
case MONOMORPHIC_PROTOTYPE_FAILURE:
- set_target(*code);
+ UpdateMonomorphicIC(receiver, code, name);
break;
case MONOMORPHIC:
// Only move to megamorphic if the target changes.
if (target() != *code) {
- // We are transitioning from monomorphic to megamorphic case.
- // Place the current monomorphic stub and stub compiled for
- // the receiver into stub cache.
+ if (target()->is_load_stub()) {
+ if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) {
+ break;
+ }
+ }
+ // We are transitioning from monomorphic to megamorphic case. Place the
+ // stub compiled for the receiver into stub cache.
Map* map = target()->FindFirstMap();
if (map != NULL) {
UpdateMegamorphicCache(map, *name, target());
UpdateMegamorphicCache(receiver->map(), *name, *code);
break;
case POLYMORPHIC:
- // When trying to patch a polymorphic stub with anything other than
- // another polymorphic stub, go generic.
- // TODO(verwaest): Currently we always go generic since no polymorphic
- // stubs enter this code path. Replace with proper updating once named
- // load/store can also be polymorphic.
- set_target((strict_mode == kStrictMode)
- ? *generic_stub_strict()
- : *generic_stub());
+ if (target()->is_load_stub()) {
+ if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) {
+ break;
+ }
+ MapHandleList receiver_maps;
+ CodeHandleList handlers;
+ target()->FindAllMaps(&receiver_maps);
+ target()->FindAllCode(&handlers, receiver_maps.length());
+ for (int i = 0; i < receiver_maps.length(); i++) {
+ UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i));
+ }
+ UpdateMegamorphicCache(receiver->map(), *name, *code);
+ set_target(*megamorphic_stub());
+ } else {
+ // When trying to patch a polymorphic keyed load/store element stub
+ // with anything other than another polymorphic stub, go generic.
+ set_target((strict_mode == kStrictMode)
+ ? *generic_stub_strict()
+ : *generic_stub());
+ }
break;
case DEBUG_STUB:
break;
}
+static void GetReceiverMapsForStub(Handle<Code> stub,
+ MapHandleList* result) {
+ ASSERT(stub->is_inline_cache_stub());
+ switch (stub->ic_state()) {
+ case MONOMORPHIC: {
+ Map* map = stub->FindFirstMap();
+ if (map != NULL) {
+ result->Add(Handle<Map>(map));
+ }
+ break;
+ }
+ case POLYMORPHIC: {
+ AssertNoAllocation no_allocation;
+ int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+ for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
+ RelocInfo* info = it.rinfo();
+ Handle<Object> object(info->target_object(), stub->GetIsolate());
+ if (object->IsString()) break;
+ ASSERT(object->IsMap());
+ AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
+ }
+ break;
+ }
+ case MEGAMORPHIC:
+ break;
+ case UNINITIALIZED:
+ case PREMONOMORPHIC:
+ case MONOMORPHIC_PROTOTYPE_FAILURE:
+ case GENERIC:
+ case DEBUG_STUB:
+ UNREACHABLE();
+ break;
+ }
+}
+
+
void LoadIC::UpdateCaches(LookupResult* lookup,
State state,
Handle<Object> object,
// setting the monomorphic state.
code = pre_monomorphic_stub();
} else {
- code = ComputeLoadMonomorphic(lookup, receiver, name);
+ code = ComputeLoadHandler(lookup, receiver, name);
if (code.is_null()) return;
}
}
-Handle<Code> LoadIC::ComputeLoadMonomorphic(LookupResult* lookup,
- Handle<JSObject> receiver,
- Handle<String> name) {
+Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
+ Handle<JSObject> receiver,
+ Handle<String> name) {
if (!lookup->IsProperty()) {
// Nonexistent property. The result is undefined.
return isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver);
// property must be found in the receiver for the stub to be
// applicable.
if (!holder.is_identical_to(receiver)) break;
- return isolate()->stub_cache()->ComputeLoadNormal();
+ return isolate()->stub_cache()->ComputeLoadNormal(name, receiver);
case CALLBACKS: {
Handle<Object> callback(lookup->GetCallbackObject(), isolate());
if (callback->IsExecutableAccessorInfo()) {
}
-static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
- Handle<Map> new_receiver_map) {
- ASSERT(!new_receiver_map.is_null());
- for (int current = 0; current < receiver_maps->length(); ++current) {
- if (!receiver_maps->at(current).is_null() &&
- receiver_maps->at(current).is_identical_to(new_receiver_map)) {
- return false;
- }
- }
- receiver_maps->Add(new_receiver_map);
- return true;
-}
-
-
-static void GetReceiverMapsForStub(Handle<Code> stub,
- MapHandleList* result) {
- ASSERT(stub->is_inline_cache_stub());
- ASSERT(stub->is_keyed_load_stub() || stub->is_keyed_store_stub());
- switch (stub->ic_state()) {
- case MONOMORPHIC: {
- Map* map = stub->FindFirstMap();
- if (map != NULL) {
- result->Add(Handle<Map>(map));
- }
- break;
- }
- case POLYMORPHIC: {
- AssertNoAllocation no_allocation;
- int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- Handle<Object> object(info->target_object(), stub->GetIsolate());
- ASSERT(object->IsMap());
- AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
- }
- break;
- }
- case MEGAMORPHIC:
- break;
- case UNINITIALIZED:
- case PREMONOMORPHIC:
- case MONOMORPHIC_PROTOTYPE_FAILURE:
- case GENERIC:
- case DEBUG_STUB:
- UNREACHABLE();
- break;
- }
-}
-
-
Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
State ic_state = target()->ic_state();
}
-Handle<Code> KeyedLoadIC::ComputeLoadMonomorphic(LookupResult* lookup,
- Handle<JSObject> receiver,
- Handle<String> name) {
+Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup,
+ Handle<JSObject> receiver,
+ Handle<String> name) {
// Bail out if we didn't find a result.
if (!lookup->IsProperty()) return Handle<Code>::null();
static inline void SetTargetAtAddress(Address address, Code* target);
static void PostPatching(Address address, Code* target, Code* old_target);
+ virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name) {
+ set_target(*handler);
+ }
+ bool UpdatePolymorphicIC(State state,
+ StrictModeFlag strict_mode,
+ Handle<JSObject> receiver,
+ Handle<String> name,
+ Handle<Code> code);
void PatchCache(State state,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
State state,
Handle<Object> object,
Handle<String> name);
- virtual Handle<Code> ComputeLoadMonomorphic(LookupResult* lookup,
- Handle<JSObject> receiver,
- Handle<String> name);
+ virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name);
+ virtual Handle<Code> ComputeLoadHandler(LookupResult* lookup,
+ Handle<JSObject> receiver,
+ Handle<String> name);
private:
// Stub accessors.
}
// Update the inline cache.
- virtual Handle<Code> ComputeLoadMonomorphic(LookupResult* lookup,
- Handle<JSObject> receiver,
- Handle<String> name);
+ virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name);
+ virtual Handle<Code> ComputeLoadHandler(LookupResult* lookup,
+ Handle<JSObject> receiver,
+ Handle<String> name);
virtual void UpdateMegamorphicCache(Map* map, String* name, Code* code) { }
private:
V(KEYED_EXTERNAL_ARRAY_STORE_IC_TAG, "KeyedExternalArrayStoreIC") \
V(LAZY_COMPILE_TAG, "LazyCompile") \
V(LOAD_IC_TAG, "LoadIC") \
+ V(LOAD_POLYMORPHIC_IC_TAG, "LoadPolymorphicIC") \
V(REG_EXP_TAG, "RegExp") \
V(SCRIPT_TAG, "Script") \
V(STORE_IC_TAG, "StoreIC") \
}
-Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
+Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
MapHandleList* receiver_maps,
- CodeHandleList* handler_ics) {
+ CodeHandleList* handlers) {
// ----------- S t a t e -------------
// -- ra : return address
// -- a0 : key
int receiver_count = receiver_maps->length();
__ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
for (int current = 0; current < receiver_count; ++current) {
- __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
+ __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
eq, a2, Operand(receiver_maps->at(current)));
}
__ bind(&miss);
- Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
- __ Jump(miss_ic, RelocInfo::CODE_TARGET);
+ GenerateLoadMiss(masm(), kind());
// Return the generated code.
return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
StubType type,
int argc,
InlineCacheHolderFlag holder) {
- // Extra IC state is only allowed for call IC stubs or for store IC
- // stubs.
- ASSERT(extra_ic_state == kNoExtraICState ||
- kind == CALL_IC ||
- kind == STORE_IC ||
- kind == KEYED_STORE_IC);
// Compute the bit mask.
int bits = KindField::encode(kind)
| ICStateField::encode(ic_state)
}
+void Code::FindAllMaps(MapHandleList* maps) {
+ ASSERT(is_inline_cache_stub());
+ AssertNoAllocation no_allocation;
+ int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+ for (RelocIterator it(this, mask); !it.done(); it.next()) {
+ RelocInfo* info = it.rinfo();
+ Object* object = info->target_object();
+ if (object->IsMap()) maps->Add(Handle<Map>(Map::cast(object)));
+ }
+}
+
+
+Code* Code::FindFirstCode() {
+ ASSERT(is_inline_cache_stub());
+ AssertNoAllocation no_allocation;
+ int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
+ for (RelocIterator it(this, mask); !it.done(); it.next()) {
+ RelocInfo* info = it.rinfo();
+ return Code::GetCodeFromTargetAddress(info->target_address());
+ }
+ return NULL;
+}
+
+
+void Code::FindAllCode(CodeHandleList* code_list, int length) {
+ ASSERT(is_inline_cache_stub());
+ AssertNoAllocation no_allocation;
+ int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
+ int i = 0;
+ for (RelocIterator it(this, mask); !it.done(); it.next()) {
+ if (i++ == length) return;
+ RelocInfo* info = it.rinfo();
+ Code* code = Code::GetCodeFromTargetAddress(info->target_address());
+ ASSERT(code->is_load_stub());
+ code_list->Add(Handle<Code>(code));
+ }
+ UNREACHABLE();
+}
+
+
void Code::ClearInlineCaches() {
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
NONEXISTENT
};
+ enum IcFragment {
+ IC_FRAGMENT,
+ HANDLER_FRAGMENT
+ };
+
enum {
NUMBER_OF_KINDS = LAST_IC_KIND + 1
};
// Find the first map in an IC stub.
Map* FindFirstMap();
+ void FindAllMaps(MapHandleList* maps);
+
+ // Find the first code in an IC stub.
+ Code* FindFirstCode();
+ void FindAllCode(CodeHandleList* code_list, int length);
class ExtraICStateStrictMode: public BitField<StrictModeFlag, 0, 1> {};
class ExtraICStateKeyedAccessGrowMode:
return value();
}
+ bool is_inobject(Handle<JSObject> holder) {
+ if (is_header_index()) return true;
+ return field_index() < holder->map()->inobject_properties();
+ }
+
+ int translate(Handle<JSObject> holder) {
+ if (is_header_index()) return header_index();
+ int index = field_index() - holder->map()->inobject_properties();
+ if (index >= 0) return index;
+ return index + holder->map()->instance_size() / kPointerSize;
+ }
+
private:
static const int kHeaderIndexBit = 1 << 31;
static const int kIndexMask = ~kHeaderIndexBit;
}
+Handle<JSObject> StubCache::StubHolder(Handle<JSObject> receiver,
+ Handle<JSObject> holder) {
+ InlineCacheHolderFlag cache_holder =
+ IC::GetCodeCacheForObject(*receiver, *holder);
+ return Handle<JSObject>(IC::GetCodeCacheHolder(
+ isolate_, *receiver, cache_holder));
+}
+
+
+Handle<Code> StubCache::FindStub(Handle<String> name,
+ Handle<JSObject> stub_holder,
+ Code::Kind kind,
+ Code::StubType type,
+ Code::IcFragment fragment) {
+ Code::Flags flags = Code::ComputeMonomorphicFlags(kind, fragment, type);
+ Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
+ isolate_);
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+ return Handle<Code>::null();
+}
+
+
+Handle<Code> StubCache::FindHandler(Handle<String> name,
+ Handle<JSObject> handler_holder,
+ Code::Kind kind,
+ Code::StubType type) {
+ return FindStub(name, handler_holder, kind, type, Code::HANDLER_FRAGMENT);
+}
+
+
+Handle<Code> StubCache::ComputeMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name) {
+ Handle<Code> ic = FindStub(name, receiver, Code::LOAD_IC,
+ handler->type(), Code::IC_FRAGMENT);
+ if (!ic.is_null()) return ic;
+
+ LoadStubCompiler ic_compiler(isolate());
+ ic = ic_compiler.CompileMonomorphicIC(
+ Handle<Map>(receiver->map()), handler, name);
+
+ JSObject::UpdateMapCodeCache(receiver, name, ic);
+ return ic;
+}
+
+
+Handle<Code> StubCache::ComputeKeyedMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name) {
+ Handle<Code> ic = FindStub(name, receiver, Code::KEYED_LOAD_IC,
+ handler->type(), Code::IC_FRAGMENT);
+ if (!ic.is_null()) return ic;
+
+ KeyedLoadStubCompiler ic_compiler(isolate());
+ ic = ic_compiler.CompileMonomorphicIC(
+ Handle<Map>(receiver->map()), handler, name);
+
+ JSObject::UpdateMapCodeCache(receiver, name, ic);
+ return ic;
+}
+
+
Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
Handle<JSObject> receiver) {
// If no global objects are present in the prototype chain, the load
// Compile the stub that is either shared for all names or
// name specific if there are global objects involved.
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::LOAD_IC, Code::kNoExtraICState, Code::NONEXISTENT);
- Handle<Object> probe(receiver->map()->FindInCodeCache(*cache_name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<Code> handler = FindHandler(
+ cache_name, receiver, Code::LOAD_IC, Code::NONEXISTENT);
+ if (!handler.is_null()) return handler;
LoadStubCompiler compiler(isolate_);
- Handle<Code> code =
+ handler =
compiler.CompileLoadNonexistent(receiver, current, cache_name, global);
- PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *cache_name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *cache_name, *code));
- JSObject::UpdateMapCodeCache(receiver, cache_name, code);
- return code;
+ JSObject::UpdateMapCodeCache(receiver, cache_name, handler);
+ return handler;
}
Handle<JSObject> receiver,
Handle<JSObject> holder,
PropertyIndex field) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::LOAD_IC, Code::kNoExtraICState, Code::FIELD);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ if (receiver.is_identical_to(holder)) {
+ LoadFieldStub stub(LoadStubCompiler::receiver(),
+ field.is_inobject(holder),
+ field.translate(holder));
+ return stub.GetCode(isolate());
+ }
+
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindHandler(
+ name, stub_holder, Code::LOAD_IC, Code::FIELD);
+ if (!stub.is_null()) return stub;
LoadStubCompiler compiler(isolate_);
- Handle<Code> code = compiler.CompileLoadField(receiver, holder, name, field);
- PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ Handle<Code> handler =
+ compiler.CompileLoadField(receiver, holder, name, field);
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
Handle<JSObject> holder,
Handle<ExecutableAccessorInfo> callback) {
ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::LOAD_IC, Code::kNoExtraICState, Code::CALLBACKS);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindHandler(
+ name, stub_holder, Code::LOAD_IC, Code::CALLBACKS);
+ if (!stub.is_null()) return stub;
LoadStubCompiler compiler(isolate_);
- Handle<Code> code =
+ Handle<Code> handler =
compiler.CompileLoadCallback(receiver, holder, name, callback);
- PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<JSFunction> getter) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::LOAD_IC, Code::kNoExtraICState, Code::CALLBACKS);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindHandler(
+ name, stub_holder, Code::LOAD_IC, Code::CALLBACKS);
+ if (!stub.is_null()) return stub;
LoadStubCompiler compiler(isolate_);
- Handle<Code> code =
+ Handle<Code> handler =
compiler.CompileLoadViaGetter(receiver, holder, name, getter);
- PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<JSFunction> value) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::LOAD_IC, Code::kNoExtraICState, Code::CONSTANT_FUNCTION);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> handler = FindHandler(
+ name, stub_holder, Code::LOAD_IC, Code::CONSTANT_FUNCTION);
+ if (!handler.is_null()) return handler;
LoadStubCompiler compiler(isolate_);
- Handle<Code> code =
- compiler.CompileLoadConstant(receiver, holder, name, value);
- PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ handler = compiler.CompileLoadConstant(receiver, holder, name, value);
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+
+ return handler;
}
Handle<Code> StubCache::ComputeLoadInterceptor(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::LOAD_IC, Code::kNoExtraICState, Code::INTERCEPTOR);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindHandler(
+ name, stub_holder, Code::LOAD_IC, Code::INTERCEPTOR);
+ if (!stub.is_null()) return stub;
LoadStubCompiler compiler(isolate_);
- Handle<Code> code =
+ Handle<Code> handler =
compiler.CompileLoadInterceptor(receiver, holder, name);
- PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
-Handle<Code> StubCache::ComputeLoadNormal() {
+Handle<Code> StubCache::ComputeLoadNormal(Handle<String> name,
+ Handle<JSObject> receiver) {
return isolate_->builtins()->LoadIC_Normal();
}
Handle<GlobalObject> holder,
Handle<JSGlobalPropertyCell> cell,
bool is_dont_delete) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindStub(
+ name, stub_holder, Code::LOAD_IC, Code::NORMAL, Code::IC_FRAGMENT);
+ if (!stub.is_null()) return stub;
LoadStubCompiler compiler(isolate_);
- Handle<Code> code =
+ Handle<Code> ic =
compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete);
- PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ JSObject::UpdateMapCodeCache(stub_holder, name, ic);
+ return ic;
}
Handle<JSObject> receiver,
Handle<JSObject> holder,
PropertyIndex field) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::KEYED_LOAD_IC, Code::kNoExtraICState, Code::FIELD);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ if (receiver.is_identical_to(holder)) {
+ LoadFieldStub stub(KeyedLoadStubCompiler::receiver(),
+ field.is_inobject(holder),
+ field.translate(holder));
+ return stub.GetCode(isolate());
+ }
+
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindHandler(
+ name, stub_holder, Code::KEYED_LOAD_IC, Code::FIELD);
+ if (!stub.is_null()) return stub;
KeyedLoadStubCompiler compiler(isolate_);
- Handle<Code> code = compiler.CompileLoadField(receiver, holder, name, field);
- PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ Handle<Code> handler =
+ compiler.CompileLoadField(receiver, holder, name, field);
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<JSFunction> value) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::KEYED_LOAD_IC, Code::kNoExtraICState, Code::CONSTANT_FUNCTION);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> handler = FindHandler(
+ name, stub_holder, Code::KEYED_LOAD_IC, Code::CONSTANT_FUNCTION);
+ if (!handler.is_null()) return handler;
KeyedLoadStubCompiler compiler(isolate_);
- Handle<Code> code =
- compiler.CompileLoadConstant(receiver, holder, name, value);
- PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ handler = compiler.CompileLoadConstant(receiver, holder, name, value);
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::KEYED_LOAD_IC, Code::kNoExtraICState, Code::INTERCEPTOR);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindHandler(
+ name, stub_holder, Code::KEYED_LOAD_IC, Code::INTERCEPTOR);
+ if (!stub.is_null()) return stub;
KeyedLoadStubCompiler compiler(isolate_);
- Handle<Code> code = compiler.CompileLoadInterceptor(receiver, holder, name);
- PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ Handle<Code> handler =
+ compiler.CompileLoadInterceptor(receiver, holder, name);
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<ExecutableAccessorInfo> callback) {
- InlineCacheHolderFlag cache_holder =
- IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
- isolate_, *receiver, cache_holder));
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::KEYED_LOAD_IC, Code::kNoExtraICState, Code::CALLBACKS);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
- isolate_);
- if (probe->IsCode()) return Handle<Code>::cast(probe);
+ Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+ Handle<Code> stub = FindHandler(
+ name, stub_holder, Code::KEYED_LOAD_IC, Code::CALLBACKS);
+ if (!stub.is_null()) return stub;
KeyedLoadStubCompiler compiler(isolate_);
- Handle<Code> code =
+ Handle<Code> handler =
compiler.CompileLoadCallback(receiver, holder, name, callback);
- PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
- return code;
+ JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ return handler;
}
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> code =
compiler.CompileStoreField(receiver, field_index, transition, name);
- PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
KeyedLoadStubCompiler compiler(isolate());
Handle<Code> code = compiler.CompileLoadElement(receiver_map);
- PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, 0));
Map::UpdateCodeCache(receiver_map, name, code);
return code;
}
KeyedStoreStubCompiler compiler(isolate(), strict_mode, grow_mode);
Handle<Code> code = compiler.CompileStoreElement(receiver_map);
- PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, 0));
Map::UpdateCodeCache(receiver_map, name, code);
return code;
}
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> code = compiler.CompileStoreGlobal(receiver, cell, name);
- PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> code =
compiler.CompileStoreCallback(name, receiver, holder, callback);
- PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> code =
compiler.CompileStoreViaSetter(name, receiver, holder, setter);
- PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> code = compiler.CompileStoreInterceptor(receiver, name);
- PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
DO_NOT_ALLOW_JSARRAY_GROWTH);
Handle<Code> code =
compiler.CompileStoreField(receiver, field_index, transition, name);
- PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
// Compute the check type and the map.
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*object, *holder);
- Handle<JSObject> map_holder(
- IC::GetCodeCacheHolder(isolate_, *object, cache_holder));
+ Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
+ isolate_, *object, cache_holder));
// Compute check type based on receiver/holder.
CheckType check = RECEIVER_MAP_CHECK;
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind, extra_state, Code::CONSTANT_FUNCTION, argc, cache_holder);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
+ Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
PROFILE(isolate_,
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
+ JSObject::UpdateMapCodeCache(stub_holder, name, code);
return code;
}
// Compute the check type and the map.
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*object, *holder);
- Handle<JSObject> map_holder(
- IC::GetCodeCacheHolder(isolate_, *object, cache_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
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind, extra_state, Code::FIELD, argc, cache_holder);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
+ Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
PROFILE(isolate_,
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
+ JSObject::UpdateMapCodeCache(stub_holder, name, code);
return code;
}
// Compute the check type and the map.
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*object, *holder);
- Handle<JSObject> map_holder(
- IC::GetCodeCacheHolder(isolate_, *object, cache_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
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind, extra_state, Code::INTERCEPTOR, argc, cache_holder);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
+ Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
PROFILE(isolate(),
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
+ JSObject::UpdateMapCodeCache(stub_holder, name, code);
return code;
}
Handle<JSFunction> function) {
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*receiver, *holder);
- Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
+ Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
isolate_, *receiver, cache_holder));
Code::Flags flags = Code::ComputeMonomorphicFlags(
kind, extra_state, Code::NORMAL, argc, cache_holder);
- Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
+ Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
PROFILE(isolate(),
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
- JSObject::UpdateMapCodeCache(map_holder, name, code);
+ JSObject::UpdateMapCodeCache(stub_holder, name, code);
return code;
}
Handle<Object> probe = cache->Lookup(receiver_maps, flags);
if (probe->IsCode()) return Handle<Code>::cast(probe);
+ CodeHandleList handlers(receiver_maps->length());
KeyedLoadStubCompiler compiler(isolate_);
- Handle<Code> code = compiler.CompileLoadElementPolymorphic(receiver_maps);
+ compiler.CompileElementHandlers(receiver_maps, &handlers);
+ Handle<Code> code = compiler.CompilePolymorphicIC(
+ receiver_maps, &handlers, factory()->empty_string(),
+ Code::NORMAL, ELEMENT);
+
+ isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
+
PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
return code;
}
+Handle<Code> StubCache::ComputePolymorphicIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ Handle<String> name) {
+ LoadStubCompiler ic_compiler(isolate_);
+ Handle<Code> ic = ic_compiler.CompilePolymorphicIC(
+ receiver_maps, handlers, name, Code::NORMAL, PROPERTY);
+ return ic;
+}
+
+
Handle<Code> StubCache::ComputeStoreElementPolymorphic(
MapHandleList* receiver_maps,
KeyedAccessGrowMode grow_mode,
Register object_reg,
Handle<JSObject> holder,
Handle<String> name,
- Label* miss,
- FrontendCheckType check) {
- if (check == PERFORM_INITIAL_CHECKS) {
- GenerateNameCheck(name, this->name(), miss);
- // Check that the receiver isn't a smi.
- __ JumpIfSmi(object_reg, miss);
- }
-
+ Label* miss) {
// Check the prototype chain.
return CheckPrototypes(object, object_reg, holder,
scratch1(), scratch2(), scratch3(),
- name, miss);
+ name, miss, SKIP_RECEIVER);
}
Register object_reg,
Handle<JSObject> holder,
Handle<String> name,
- Label* success,
- FrontendCheckType check) {
+ Label* success) {
Label miss;
- Register reg = HandlerFrontendHeader(
- object, object_reg, holder, name, &miss, check);
+ Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
HandlerFrontendFooter(success, &miss);
return reg;
Handle<Code> BaseLoadStubCompiler::CompileLoadField(Handle<JSObject> object,
Handle<JSObject> holder,
Handle<String> name,
- PropertyIndex index) {
- Label success;
- Register reg = HandlerFrontend(object, receiver(), holder, name,
- &success, PERFORM_INITIAL_CHECKS);
- __ bind(&success);
- GenerateLoadField(reg, holder, index);
+ PropertyIndex field) {
+ Label miss;
+
+ Register reg = HandlerFrontendHeader(object, receiver(), holder, name, &miss);
+
+ LoadFieldStub stub(reg, field.is_inobject(holder), field.translate(holder));
+ GenerateTailCall(stub.GetCode(isolate()));
+
+ __ bind(&miss);
+ GenerateLoadMiss(masm(), kind());
// Return the generated code.
- return GetCode(Code::FIELD, name);
+ return GetCode(Code::HANDLER_FRAGMENT, Code::FIELD, name);
}
Handle<String> name,
Handle<JSFunction> value) {
Label success;
- HandlerFrontend(object, receiver(), holder, name,
- &success, PERFORM_INITIAL_CHECKS);
+ HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
GenerateLoadConstant(value);
// Return the generated code.
- return GetCode(Code::CONSTANT_FUNCTION, name);
+ return GetCode(Code::HANDLER_FRAGMENT, Code::CONSTANT_FUNCTION, name);
}
Label success;
Register reg = CallbackHandlerFrontend(
- object, receiver(), holder, name, &success,
- PERFORM_INITIAL_CHECKS, callback);
+ object, receiver(), holder, name, &success, callback);
__ bind(&success);
GenerateLoadCallback(reg, callback);
// Return the generated code.
- return GetCode(Code::CALLBACKS, name);
+ return GetCode(Code::HANDLER_FRAGMENT, Code::CALLBACKS, name);
}
LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
- Register reg = HandlerFrontend(object, receiver(), holder, name,
- &success, PERFORM_INITIAL_CHECKS);
+ Register reg = HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
// TODO(368): Compile in the whole chain: all the interceptors in
// prototypes and ultimate answer.
GenerateLoadInterceptor(reg, object, holder, &lookup, name);
// Return the generated code.
- return GetCode(Code::INTERCEPTOR, name);
+ return GetCode(Code::HANDLER_FRAGMENT, Code::INTERCEPTOR, name);
}
Label success;
Handle<JSObject> holder(lookup->holder());
if (lookup->IsField()) {
- // 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, SKIP_INITIAL_CHECKS);
- __ bind(&success);
- GenerateLoadField(reg, holder, lookup->GetFieldIndex());
+ PropertyIndex field = lookup->GetFieldIndex();
+ if (interceptor_holder.is_identical_to(holder)) {
+ LoadFieldStub stub(interceptor_reg,
+ field.is_inobject(holder),
+ field.translate(holder));
+ GenerateTailCall(stub.GetCode(isolate()));
+ } else {
+ // 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);
+ GenerateLoadField(reg, holder, field);
+ }
} else {
// We found CALLBACKS property in prototype chain of interceptor's
// holder.
ASSERT(callback->getter() != NULL);
Register reg = CallbackHandlerFrontend(
- interceptor_holder, interceptor_reg, holder,
- name, &success, SKIP_INITIAL_CHECKS, callback);
+ interceptor_holder, interceptor_reg, holder, name, &success, callback);
__ bind(&success);
GenerateLoadCallback(reg, callback);
}
}
+Handle<Code> BaseLoadStubCompiler::CompileMonomorphicIC(
+ Handle<Map> receiver_map,
+ Handle<Code> handler,
+ Handle<String> name) {
+ MapHandleList receiver_maps(1);
+ receiver_maps.Add(receiver_map);
+ CodeHandleList handlers(1);
+ handlers.Add(handler);
+ Code::StubType type = handler->type();
+ return CompilePolymorphicIC(&receiver_maps, &handlers, name, type, PROPERTY);
+}
+
+
Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
Handle<JSObject> object,
Handle<JSObject> holder,
Handle<String> name,
Handle<JSFunction> getter) {
Label success;
- HandlerFrontend(object, receiver(), holder, name,
- &success, PERFORM_INITIAL_CHECKS);
+ HandlerFrontend(object, receiver(), holder, name, &success);
__ bind(&success);
GenerateLoadViaGetter(masm(), getter);
// Return the generated code.
- return GetCode(Code::CALLBACKS, name);
+ return GetCode(Code::HANDLER_FRAGMENT, Code::CALLBACKS, name);
}
#undef __
-Handle<Code> LoadStubCompiler::GetCode(Code::StubType type,
- Handle<String> name,
- InlineCacheState state) {
- Code::Flags flags = Code::ComputeMonomorphicFlags(
- Code::LOAD_IC, Code::kNoExtraICState, type);
- Handle<Code> code = GetCodeWithFlags(flags, name);
- PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
+void LoadStubCompiler::JitEvent(Handle<String> name, Handle<Code> code) {
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
- return code;
}
-Handle<Code> KeyedLoadStubCompiler::GetCode(Code::StubType type,
- Handle<String> name,
- InlineCacheState state) {
- Code::Flags flags = Code::ComputeFlags(
- Code::KEYED_LOAD_IC, state, Code::kNoExtraICState, type);
+void KeyedLoadStubCompiler::JitEvent(Handle<String> name, Handle<Code> code) {
+ GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
+}
+
+
+Handle<Code> BaseLoadStubCompiler::GetCode(Code::IcFragment fragment,
+ Code::StubType type,
+ Handle<String> name,
+ InlineCacheState state) {
+ Code::Flags flags = Code::ComputeFlags(kind(), state, fragment, type);
Handle<Code> code = GetCodeWithFlags(flags, name);
- PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
- GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
+ PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
+ JitEvent(name, code);
return code;
}
-Handle<Code> KeyedLoadStubCompiler::CompileLoadElementPolymorphic(
- MapHandleList* receiver_maps) {
- CodeHandleList handler_ics(receiver_maps->length());
+void KeyedLoadStubCompiler::CompileElementHandlers(MapHandleList* receiver_maps,
+ CodeHandleList* handlers) {
for (int i = 0; i < receiver_maps->length(); ++i) {
Handle<Map> receiver_map = receiver_maps->at(i);
Handle<Code> cached_stub;
}
}
- handler_ics.Add(cached_stub);
+ handlers->Add(cached_stub);
}
- Handle<Code> code = CompileLoadPolymorphic(receiver_maps, &handler_ics);
- isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
- PROFILE(isolate(),
- CodeCreateEvent(Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG, *code, 0));
- return code;
}
-
Handle<Code> StoreStubCompiler::GetCode(Code::StubType type,
Handle<String> name) {
Code::Flags flags = Code::ComputeMonomorphicFlags(
Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
MapHandleList* receiver_maps) {
// Collect MONOMORPHIC stubs for all |receiver_maps|.
- CodeHandleList handler_ics(receiver_maps->length());
+ CodeHandleList handlers(receiver_maps->length());
MapHandleList transitioned_maps(receiver_maps->length());
for (int i = 0; i < receiver_maps->length(); ++i) {
Handle<Map> receiver_map(receiver_maps->at(i));
grow_mode_).GetCode(isolate());
}
ASSERT(!cached_stub.is_null());
- handler_ics.Add(cached_stub);
+ handlers.Add(cached_stub);
transitioned_maps.Add(transitioned_map);
}
Handle<Code> code =
- CompileStorePolymorphic(receiver_maps, &handler_ics, &transitioned_maps);
+ CompileStorePolymorphic(receiver_maps, &handlers, &transitioned_maps);
isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
PROFILE(isolate(),
CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0));
void Initialize();
+ Handle<JSObject> StubHolder(Handle<JSObject> receiver,
+ Handle<JSObject> holder);
+
+ Handle<Code> FindStub(Handle<String> name,
+ Handle<JSObject> stub_holder,
+ Code::Kind kind,
+ Code::StubType type,
+ Code::IcFragment fragment);
+
+ Handle<Code> FindHandler(Handle<String> name,
+ Handle<JSObject> stub_holder,
+ Code::Kind kind,
+ Code::StubType type);
+
+ Handle<Code> ComputeMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name);
+ Handle<Code> ComputeKeyedMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name);
// Computes the right stub matching. Inserts the result in the
// cache before returning. This might compile a stub if needed.
Handle<JSObject> object,
Handle<JSObject> holder);
- Handle<Code> ComputeLoadNormal();
+ Handle<Code> ComputeLoadNormal(Handle<String> name,
+ Handle<JSObject> object);
Handle<Code> ComputeLoadGlobal(Handle<String> name,
Handle<JSObject> object,
KeyedAccessGrowMode grow_mode,
StrictModeFlag strict_mode);
+ Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ Handle<String> name);
+
// Finds the Code object stored in the Heap::non_monomorphic_cache().
Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor);
+enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER };
+enum IcCheckType { ELEMENT, PROPERTY };
+
+
// The stub compilers compile stubs for the stub cache.
class StubCompiler BASE_EMBEDDED {
public:
Register src,
Handle<JSObject> holder,
PropertyIndex index);
+ static void DoGenerateFastPropertyLoad(MacroAssembler* masm,
+ Register dst,
+ Register src,
+ bool inobject,
+ int index);
static void GenerateLoadArrayLength(MacroAssembler* masm,
Register receiver,
Register scratch1,
Register scratch2,
Handle<String> name,
- Label* miss) {
+ Label* miss,
+ PrototypeCheckType check = CHECK_ALL_MAPS) {
return CheckPrototypes(object, object_reg, holder, holder_reg, scratch1,
- scratch2, name, kInvalidProtoDepth, miss);
+ scratch2, name, kInvalidProtoDepth, miss, check);
}
Register CheckPrototypes(Handle<JSObject> object,
Register scratch2,
Handle<String> name,
int save_at_depth,
- Label* miss);
+ Label* miss,
+ PrototypeCheckType check = CHECK_ALL_MAPS);
protected:
Heap* heap() { return isolate()->heap(); }
Factory* factory() { return isolate()->factory(); }
+ void GenerateTailCall(Handle<Code> code);
+
private:
Isolate* isolate_;
MacroAssembler masm_;
Handle<JSObject> holder,
Handle<String> name);
+ Handle<Code> CompileMonomorphicIC(Handle<Map> receiver_map,
+ Handle<Code> handler,
+ Handle<String> name);
+ Handle<Code> CompilePolymorphicIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ Handle<String> name,
+ Code::StubType type,
+ IcCheckType check);
+
protected:
Register HandlerFrontendHeader(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
Handle<String> name,
- Label* success,
- FrontendCheckType check);
+ Label* success);
void HandlerFrontendFooter(Label* success, Label* miss);
Register HandlerFrontend(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
Handle<String> name,
- Label* success,
- FrontendCheckType check);
+ Label* success);
Register CallbackHandlerFrontend(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
Handle<String> name,
Label* success,
- FrontendCheckType check,
Handle<ExecutableAccessorInfo> callback);
void NonexistentHandlerFrontend(Handle<JSObject> object,
Handle<JSObject> last,
Handle<String> name,
LookupResult* lookup);
+ Handle<Code> GetCode(Code::IcFragment fragment,
+ Code::StubType type,
+ Handle<String> name,
+ InlineCacheState state = MONOMORPHIC);
Register receiver() { return registers_[0]; }
Register name() { return registers_[1]; }
private:
virtual Code::Kind kind() = 0;
+ virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) = 0;
+ virtual void JitEvent(Handle<String> name, Handle<Code> code) = 0;
virtual void GenerateNameCheck(Handle<String> name,
Register name_reg,
Label* miss) { }
- virtual Handle<Code> GetCode(Code::StubType type,
- Handle<String> name,
- InlineCacheState state = MONOMORPHIC) = 0;
Register* registers_;
};
Handle<String> name,
bool is_dont_delete);
+ static Register receiver() { return registers()[0]; }
+
private:
- Register* registers();
+ static Register* registers();
virtual Code::Kind kind() { return Code::LOAD_IC; }
- virtual Handle<Code> GetCode(Code::StubType type,
- Handle<String> name,
- InlineCacheState state = MONOMORPHIC);
+ virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) {
+ return code->ic_state() == MONOMORPHIC
+ ? Logger::LOAD_IC_TAG : Logger::LOAD_POLYMORPHIC_IC_TAG;
+ }
+ virtual void JitEvent(Handle<String> name, Handle<Code> code);
};
Handle<Code> CompileLoadElement(Handle<Map> receiver_map);
- Handle<Code> CompileLoadPolymorphic(MapHandleList* receiver_maps,
- CodeHandleList* handler_ics);
+ void CompileElementHandlers(MapHandleList* receiver_maps,
+ CodeHandleList* handlers);
Handle<Code> CompileLoadElementPolymorphic(MapHandleList* receiver_maps);
static void GenerateLoadDictionaryElement(MacroAssembler* masm);
+ static Register receiver() { return registers()[0]; }
+
private:
- Register* registers();
+ static Register* registers();
virtual Code::Kind kind() { return Code::KEYED_LOAD_IC; }
- virtual Handle<Code> GetCode(Code::StubType type,
- Handle<String> name,
- InlineCacheState state = MONOMORPHIC);
+ virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) {
+ return code->ic_state() == MONOMORPHIC
+ ? Logger::KEYED_LOAD_IC_TAG : Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG;
+ }
+ virtual void JitEvent(Handle<String> name, Handle<Code> code);
virtual void GenerateNameCheck(Handle<String> name,
Register name_reg,
Label* miss);
if (!object->IsCode()) return false;
Handle<Code> code = Handle<Code>::cast(object);
if (!code->is_load_stub()) return false;
+ if (code->ic_state() != MONOMORPHIC) return false;
return stub->Describes(*code);
}
}
+static void AddMapIfMissing(Handle<Map> map, SmallMapList* list,
+ Zone* zone) {
+ for (int i = 0; i < list->length(); ++i) {
+ if (list->at(i).is_identical_to(map)) return;
+ }
+ list->Add(map, zone);
+}
+
+
+void TypeFeedbackOracle::CollectPolymorphicMaps(Handle<Code> code,
+ SmallMapList* types) {
+ MapHandleList maps;
+ code->FindAllMaps(&maps);
+ types->Reserve(maps.length(), zone());
+ for (int i = 0; i < maps.length(); i++) {
+ Handle<Map> map(maps.at(i));
+ if (!CanRetainOtherContext(*map, *native_context_)) {
+ AddMapIfMissing(map, types, zone());
+ }
+ }
+}
+
+
void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id,
Handle<String> name,
Code::Flags flags,
ASSERT(Handle<Code>::cast(object)->ic_state() == GENERIC);
} else if (object->IsMap()) {
types->Add(Handle<Map>::cast(object), zone());
+ } else if (Handle<Code>::cast(object)->ic_state() == POLYMORPHIC) {
+ CollectPolymorphicMaps(Handle<Code>::cast(object), types);
} else if (FLAG_collect_megamorphic_maps_from_stub_cache &&
Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) {
types->Reserve(4, zone());
}
-static void AddMapIfMissing(Handle<Map> map, SmallMapList* list,
- Zone* zone) {
- for (int i = 0; i < list->length(); ++i) {
- if (list->at(i).is_identical_to(map)) return;
- }
- list->Add(map, zone);
-}
-
-
void TypeFeedbackOracle::CollectKeyedReceiverTypes(TypeFeedbackId ast_id,
SmallMapList* types) {
Handle<Object> object = GetInfo(ast_id);
Handle<Code> code = Handle<Code>::cast(object);
if (code->kind() == Code::KEYED_LOAD_IC ||
code->kind() == Code::KEYED_STORE_IC) {
- AssertNoAllocation no_allocation;
- int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- for (RelocIterator it(*code, mask); !it.done(); it.next()) {
- RelocInfo* info = it.rinfo();
- Object* object = info->target_object();
- if (object->IsMap()) {
- Map* map = Map::cast(object);
- if (!CanRetainOtherContext(map, *native_context_)) {
- AddMapIfMissing(Handle<Map>(map), types, zone());
- }
- }
- }
+ CollectPolymorphicMaps(code, types);
}
}
static bool CanRetainOtherContext(JSFunction* function,
Context* native_context);
+ void CollectPolymorphicMaps(Handle<Code> code, SmallMapList* types);
+
CheckType GetCallCheckType(Call* expr);
Handle<JSObject> GetPrototypeForPrimitiveCheck(CheckType check);
// using a shift count of 32.
static const uint32_t kMask = ((1U << shift) << size) - (1U << shift);
static const uint32_t kShift = shift;
+ static const uint32_t kSize = size;
// Value for the field with all bits set.
static const T kMax = static_cast<T>((1U << size) - 1);
}
+void LoadFieldStub::Generate(MacroAssembler* masm) {
+ StubCompiler::DoGenerateFastPropertyLoad(masm, rax, reg_, inobject_, index_);
+ __ ret(0);
+}
+
+
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
// The key is in rdx and the parameter count is in rax.
// -----------------------------------
// Probe the stub cache.
- Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
- Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rax, rcx, rbx,
- rdx);
+ Code::Flags flags = Code::ComputeFlags(
+ Code::LOAD_IC, MONOMORPHIC, Code::HANDLER_FRAGMENT);
+ Isolate::Current()->stub_cache()->GenerateProbe(
+ masm, flags, rax, rcx, rbx, rdx);
// Cache miss: Jump to runtime.
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
Register src,
Handle<JSObject> holder,
PropertyIndex index) {
- if (index.is_header_index()) {
- int offset = index.header_index() * kPointerSize;
- __ movq(dst, FieldOperand(src, offset));
- } else {
- // Adjust for the number of properties stored in the holder.
- int slot = index.field_index() - holder->map()->inobject_properties();
- if (slot < 0) {
- // Get the property straight out of the holder.
- int offset = holder->map()->instance_size() + (slot * kPointerSize);
- __ movq(dst, FieldOperand(src, offset));
- } else {
- // Calculate the offset into the properties array.
- int offset = slot * kPointerSize + FixedArray::kHeaderSize;
- __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
- __ movq(dst, FieldOperand(dst, offset));
- }
+ DoGenerateFastPropertyLoad(
+ masm, dst, src, index.is_inobject(holder), index.translate(holder));
+}
+
+
+void StubCompiler::DoGenerateFastPropertyLoad(MacroAssembler* masm,
+ Register dst,
+ Register src,
+ bool inobject,
+ int index) {
+ int offset = index * kPointerSize;
+ if (!inobject) {
+ // Calculate the offset into the properties array.
+ offset = offset + FixedArray::kHeaderSize;
+ __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
+ src = dst;
}
+ __ movq(dst, FieldOperand(src, offset));
}
#define __ ACCESS_MASM((masm()))
+void StubCompiler::GenerateTailCall(Handle<Code> code) {
+ __ jmp(code, RelocInfo::CODE_TARGET);
+}
+
+
Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
Register scratch2,
Handle<String> name,
int save_at_depth,
- Label* miss) {
+ Label* miss,
+ PrototypeCheckType check) {
+ Handle<JSObject> first = object;
// Make sure there's no overlap between holder and object registers.
ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
// Save the map in scratch1 for later.
__ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
}
- __ CheckMap(reg, Handle<Map>(current_map),
- miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+ __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
+ ALLOW_ELEMENT_TRANSITION_MAPS);
+ }
// Check access rights to the global object. This has to happen after
// the map check so that we know that the object is actually a global
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- // Check the holder map.
- __ CheckMap(reg, Handle<Map>(holder->map()),
- miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+ // Check the holder map.
+ __ CheckMap(reg, Handle<Map>(holder->map()),
+ miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+ }
// Perform security check for access to the global object.
ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
Label* miss) {
- __ jmp(success);
- __ bind(miss);
- GenerateLoadMiss(masm(), kind());
+ if (!miss->is_unused()) {
+ __ jmp(success);
+ __ bind(miss);
+ GenerateLoadMiss(masm(), kind());
+ }
}
Handle<JSObject> holder,
Handle<String> name,
Label* success,
- FrontendCheckType check,
Handle<ExecutableAccessorInfo> callback) {
Label miss;
- Register reg = HandlerFrontendHeader(
- object, object_reg, holder, name, &miss, check);
+ Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
ASSERT(!reg.is(scratch2()));
Handle<GlobalObject> global) {
Label miss;
- Register reg = HandlerFrontendHeader(
- object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS);
+ Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
}
__ PushAddress(ExternalReference::isolate_address()); // isolate
__ push(name()); // name
- // Save a pointer to where we pushed the arguments pointer.
- // This will be passed as the const AccessorInfo& to the C++ callback.
+ // Save a pointer to where we pushed the arguments pointer. This will be
+ // passed as the const ExecutableAccessorInfo& to the C++ callback.
#if defined(__MINGW64__)
Register accessor_info_arg = rdx;
__ ret(0);
// Return the generated code.
- return GetCode(Code::NONEXISTENT, factory()->empty_string());
+ return GetCode(Code::HANDLER_FRAGMENT, Code::NONEXISTENT, name);
}
// rax is used as receiver(), which we would otherwise clobber before a
// potential miss.
- HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global),
- name, &miss, PERFORM_INITIAL_CHECKS);
+ __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
+ HandlerFrontendHeader(
+ object, receiver(), Handle<JSObject>::cast(global), name, &miss);
// Get the value from the cell.
__ Move(rbx, cell);
__ ret(0);
// Return the generated code.
- return GetCode(Code::NORMAL, name);
+ return GetCode(Code::IC_FRAGMENT, Code::NORMAL, name);
}
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string());
+ return GetCode(Code::IC_FRAGMENT, Code::NORMAL, factory()->empty_string());
}
-Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
+Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
MapHandleList* receiver_maps,
- CodeHandleList* handler_ics) {
- // ----------- S t a t e -------------
- // -- rax : key
- // -- rdx : receiver
- // -- rsp[0] : return address
- // -----------------------------------
+ CodeHandleList* handlers,
+ Handle<String> name,
+ Code::StubType type,
+ IcCheckType check) {
Label miss;
- __ JumpIfSmi(rdx, &miss);
- Register map_reg = rbx;
- __ movq(map_reg, FieldOperand(rdx, HeapObject::kMapOffset));
+ if (check == PROPERTY) {
+ GenerateNameCheck(name, this->name(), &miss);
+ }
+
+ __ JumpIfSmi(receiver(), &miss);
+ Register map_reg = scratch1();
+ __ movq(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
int receiver_count = receiver_maps->length();
for (int current = 0; current < receiver_count; ++current) {
// Check map and tail call if there's a match
__ Cmp(map_reg, receiver_maps->at(current));
- __ j(equal, handler_ics->at(current), RelocInfo::CODE_TARGET);
+ __ j(equal, handlers->at(current), RelocInfo::CODE_TARGET);
}
__ bind(&miss);
- GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+ GenerateLoadMiss(masm(), kind());
// Return the generated code.
- return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
+ InlineCacheState state =
+ receiver_maps->length() > 1 ? POLYMORPHIC : MONOMORPHIC;
+ return GetCode(Code::IC_FRAGMENT, type, name, state);
}
v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
- CHECK(ic_before->ic_state() == MEGAMORPHIC);
+ CHECK(ic_before->ic_state() == POLYMORPHIC);
// Fire context dispose notification.
v8::V8::ContextDisposedNotification();