void CodeStub::RecordCodeGeneration(Handle<Code> code) {
- IC::RegisterWeakMapDependency(code);
std::ostringstream os;
os << *this;
PROFILE(isolate(),
"report fragmentation for old pointer and data pages")
DEFINE_BOOL(collect_maps, true,
"garbage collect maps from which no objects can be reached")
-DEFINE_BOOL(weak_embedded_maps_in_ic, true,
- "make maps embedded in inline cache stubs")
DEFINE_BOOL(weak_embedded_maps_in_optimized_code, true,
"make maps embedded in optimized code weak")
DEFINE_BOOL(weak_embedded_objects_in_optimized_code, true,
for (HeapObject* obj = code_iterator.Next(); obj != NULL;
obj = code_iterator.Next()) {
Code* code = Code::cast(obj);
- if (!code->is_optimized_code() && !code->is_weak_stub()) continue;
+ if (!code->is_optimized_code()) continue;
if (WillBeDeoptimized(code)) continue;
code->VerifyEmbeddedObjectsDependency();
}
}
-void MarkCompactCollector::ClearDependentICList(Object* head) {
- Object* current = head;
- Object* undefined = heap()->undefined_value();
- while (current != undefined) {
- Code* code = Code::cast(current);
- if (IsMarked(code)) {
- DCHECK(code->is_weak_stub());
- IC::InvalidateMaps(code);
- }
- current = code->next_code_link();
- code->set_next_code_link(undefined);
- }
-}
-
-
void MarkCompactCollector::ClearDependentCode(DependentCode* entries) {
DisallowHeapAllocation no_allocation;
DependentCode::GroupStartIndexes starts(entries);
int number_of_entries = starts.number_of_entries();
if (number_of_entries == 0) return;
- int g = DependentCode::kWeakICGroup;
- if (starts.at(g) != starts.at(g + 1)) {
- int i = starts.at(g);
- DCHECK(i + 1 == starts.at(g + 1));
- Object* head = entries->object_at(i);
- ClearDependentICList(head);
- }
- g = DependentCode::kWeakCodeGroup;
+ int g = DependentCode::kWeakCodeGroup;
for (int i = starts.at(g); i < starts.at(g + 1); i++) {
// If the entry is compilation info then the map must be alive,
// and ClearDependentCode shouldn't be called.
int MarkCompactCollector::ClearNonLiveDependentCodeInGroup(
DependentCode* entries, int group, int start, int end, int new_start) {
int survived = 0;
- if (group == DependentCode::kWeakICGroup) {
- // Dependent weak IC stubs form a linked list and only the head is stored
- // in the dependent code array.
- if (start != end) {
- DCHECK(start + 1 == end);
- Object* old_head = entries->object_at(start);
- MarkCompactWeakObjectRetainer retainer;
- Object* head = VisitWeakList<Code>(heap(), old_head, &retainer);
- entries->set_object_at(new_start, head);
- Object** slot = entries->slot_at(new_start);
- RecordSlot(slot, slot, head);
- // We do not compact this group even if the head is undefined,
- // more dependent ICs are likely to be added later.
- survived = 1;
- }
- } else {
- for (int i = start; i < end; i++) {
- Object* obj = entries->object_at(i);
- DCHECK(obj->IsCode() || IsMarked(obj));
- if (IsMarked(obj) &&
- (!obj->IsCode() || !WillBeDeoptimized(Code::cast(obj)))) {
- if (new_start + survived != i) {
- entries->set_object_at(new_start + survived, obj);
- }
- Object** slot = entries->slot_at(new_start + survived);
- RecordSlot(slot, slot, obj);
- survived++;
+ for (int i = start; i < end; i++) {
+ Object* obj = entries->object_at(i);
+ DCHECK(obj->IsCode() || IsMarked(obj));
+ if (IsMarked(obj) &&
+ (!obj->IsCode() || !WillBeDeoptimized(Code::cast(obj)))) {
+ if (new_start + survived != i) {
+ entries->set_object_at(new_start + survived, obj);
}
+ Object** slot = entries->slot_at(new_start + survived);
+ RecordSlot(slot, slot, obj);
+ survived++;
}
}
entries->set_number_of_entries(
void TrimEnumCache(Map* map, DescriptorArray* descriptors);
void ClearDependentCode(DependentCode* dependent_code);
- void ClearDependentICList(Object* head);
void ClearNonLiveDependentCode(DependentCode* dependent_code);
int ClearNonLiveDependentCodeInGroup(DependentCode* dependent_code, int group,
int start, int end, int new_start);
// to be serialized.
if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub() &&
!target->is_call_stub() &&
- ((heap->flush_monomorphic_ics() && !target->is_weak_stub()) ||
+ ((heap->flush_monomorphic_ics() && !target->embeds_maps_weakly()) ||
heap->isolate()->serializer_enabled() ||
- target->ic_age() != heap->global_ic_age() ||
- target->is_invalidated_weak_stub())) {
+ target->ic_age() != heap->global_ic_age())) {
ICUtility::Clear(heap->isolate(), rinfo->pc(),
rinfo->host()->constant_pool());
target = Code::GetCodeFromTargetAddress(rinfo->target_address());
bool is_weak_object =
(array->get_weak_object_state() ==
ConstantPoolArray::WEAK_OBJECTS_IN_OPTIMIZED_CODE &&
- Code::IsWeakObjectInOptimizedCode(object)) ||
- (array->get_weak_object_state() ==
- ConstantPoolArray::WEAK_OBJECTS_IN_IC &&
- Code::IsWeakObjectInIC(object));
+ Code::IsWeakObjectInOptimizedCode(object));
if (!is_weak_object) {
StaticVisitor::MarkObject(heap, object);
}
Code::Flags flags =
Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder());
Handle<Code> code = GetCodeWithFlags(flags, name);
- IC::RegisterWeakMapDependency(code);
PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
return code;
}
void IC::set_target(Code* code) {
-#ifdef VERIFY_HEAP
- code->VerifyEmbeddedObjectsDependency();
-#endif
SetTargetAtAddress(address(), code, constant_pool());
target_set_ = true;
}
}
-void IC::RegisterWeakMapDependency(Handle<Code> stub) {
- if (FLAG_collect_maps && FLAG_weak_embedded_maps_in_ic &&
- stub->CanBeWeakStub()) {
- DCHECK(!stub->is_weak_stub());
- MapHandleList maps;
- stub->FindAllMaps(&maps);
- if (maps.length() == 1 && stub->IsWeakObjectInIC(*maps.at(0))) {
- Map::AddDependentIC(maps.at(0), stub);
- stub->mark_as_weak_stub();
- if (FLAG_enable_ool_constant_pool) {
- stub->constant_pool()->set_weak_object_state(
- ConstantPoolArray::WEAK_OBJECTS_IN_IC);
- }
- }
- }
-}
-
-
-void IC::InvalidateMaps(Code* stub) {
- DCHECK(stub->is_weak_stub());
- stub->mark_as_invalidated_weak_stub();
- Isolate* isolate = stub->GetIsolate();
- Heap* heap = isolate->heap();
- Object* undefined = heap->undefined_value();
- int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
- for (RelocIterator it(stub, mode_mask); !it.done(); it.next()) {
- RelocInfo::Mode mode = it.rinfo()->rmode();
- if (mode == RelocInfo::EMBEDDED_OBJECT &&
- it.rinfo()->target_object()->IsMap()) {
- it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
- }
- }
- CpuFeatures::FlushICache(stub->instruction_start(), stub->instruction_size());
-}
-
-
void IC::Clear(Isolate* isolate, Address address,
ConstantPoolArray* constant_pool) {
Code* target = GetTargetAtAddress(address, constant_pool);
state_ = PROTOTYPE_FAILURE;
}
- // If the stub contains weak maps then this function adds the stub to
- // the dependent code array of each weak map.
- static void RegisterWeakMapDependency(Handle<Code> stub);
-
- // This function is called when a weak map in the stub is dying,
- // invalidates the stub by setting maps in it to undefined.
- static void InvalidateMaps(Code* stub);
-
// Clear the inline cache to initial state.
static void Clear(Isolate* isolate, Address address,
ConstantPoolArray* constant_pool);
if (IsWeakObject(obj)) {
if (obj->IsMap()) {
Map* map = Map::cast(obj);
- DependentCode::DependencyGroup group = is_optimized_code() ?
- DependentCode::kWeakCodeGroup : DependentCode::kWeakICGroup;
- CHECK(map->dependent_code()->Contains(group, this));
+ CHECK(map->dependent_code()->Contains(DependentCode::kWeakCodeGroup,
+ this));
} else if (obj->IsJSObject()) {
Object* raw_table = GetIsolate()->heap()->weak_object_to_code_table();
WeakHashTable* table = WeakHashTable::cast(raw_table);
}
-bool Code::is_weak_stub() {
- return CanBeWeakStub() && WeakStubField::decode(
- READ_UINT32_FIELD(this, kKindSpecificFlags1Offset));
-}
-
-
-void Code::mark_as_weak_stub() {
- DCHECK(CanBeWeakStub());
- int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset);
- int updated = WeakStubField::update(previous, true);
- WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated);
-}
-
-
-bool Code::is_invalidated_weak_stub() {
- return is_weak_stub() && InvalidatedWeakStubField::decode(
- READ_UINT32_FIELD(this, kKindSpecificFlags1Offset));
-}
-
-
-void Code::mark_as_invalidated_weak_stub() {
- DCHECK(is_inline_cache_stub());
- int previous = READ_UINT32_FIELD(this, kKindSpecificFlags1Offset);
- int updated = InvalidatedWeakStubField::update(previous, true);
- WRITE_UINT32_FIELD(this, kKindSpecificFlags1Offset, updated);
-}
-
-
bool Code::is_inline_cache_stub() {
Kind kind = this->kind();
switch (kind) {
};
-bool Code::IsWeakObjectInIC(Object* object) {
- return object->IsMap() && Map::cast(object)->CanTransition() &&
- FLAG_collect_maps &&
- FLAG_weak_embedded_maps_in_ic;
-}
-
-
Object* Map::prototype() const {
return READ_FIELD(this, kPrototypeOffset);
}
}
-// static
-void Map::AddDependentIC(Handle<Map> map,
- Handle<Code> stub) {
- DCHECK(stub->next_code_link()->IsUndefined());
- int n = map->dependent_code()->number_of_entries(DependentCode::kWeakICGroup);
- if (n == 0) {
- // Slow path: insert the head of the list with possible heap allocation.
- Map::AddDependentCode(map, DependentCode::kWeakICGroup, stub);
- } else {
- // Fast path: link the stub to the existing head of the list without any
- // heap allocation.
- DCHECK(n == 1);
- map->dependent_code()->AddToDependentICList(stub);
- }
-}
-
-
DependentCode::GroupStartIndexes::GroupStartIndexes(DependentCode* entries) {
Recompute(entries);
}
}
-static bool CodeListContains(Object* head, Code* code) {
- while (!head->IsUndefined()) {
- if (head == code) return true;
- head = Code::cast(head)->next_code_link();
- }
- return false;
-}
-
-
bool DependentCode::Contains(DependencyGroup group, Code* code) {
GroupStartIndexes starts(this);
int start = starts.at(group);
int end = starts.at(group + 1);
- if (group == kWeakICGroup) {
- return CodeListContains(object_at(start), code);
- }
for (int i = start; i < end; i++) {
if (object_at(i) == code) return true;
}
}
-void DependentCode::AddToDependentICList(Handle<Code> stub) {
- DisallowHeapAllocation no_heap_allocation;
- GroupStartIndexes starts(this);
- int i = starts.at(kWeakICGroup);
- Object* head = object_at(i);
- // Try to insert the stub after the head of the list to minimize number of
- // writes to the DependentCode array, since a write to the array can make it
- // strong if it was alread marked by incremental marker.
- if (head->IsCode()) {
- stub->set_next_code_link(Code::cast(head)->next_code_link());
- Code::cast(head)->set_next_code_link(*stub);
- } else {
- stub->set_next_code_link(head);
- set_object_at(i, *stub);
- }
-}
-
-
void DependentCode::SetMarkedForDeoptimization(Code* code,
DependencyGroup group) {
code->set_marked_for_deoptimization(true);
const char* DependentCode::DependencyGroupName(DependencyGroup group) {
switch (group) {
- case kWeakICGroup:
- return "weak-ic";
case kWeakCodeGroup:
return "weak-code";
case kTransitionGroup:
//
class ConstantPoolArray: public HeapObject {
public:
- enum WeakObjectState {
- NO_WEAK_OBJECTS,
- WEAK_OBJECTS_IN_OPTIMIZED_CODE,
- WEAK_OBJECTS_IN_IC
- };
+ enum WeakObjectState { NO_WEAK_OBJECTS, WEAK_OBJECTS_IN_OPTIMIZED_CODE };
enum Type {
INT64 = 0,
inline bool is_to_boolean_ic_stub() { return kind() == TO_BOOLEAN_IC; }
inline bool is_keyed_stub();
inline bool is_optimized_code() { return kind() == OPTIMIZED_FUNCTION; }
- inline bool is_weak_stub();
- inline void mark_as_weak_stub();
- inline bool is_invalidated_weak_stub();
- inline void mark_as_invalidated_weak_stub();
-
- inline bool CanBeWeakStub() {
+ inline bool embeds_maps_weakly() {
Kind k = kind();
return (k == LOAD_IC || k == STORE_IC || k == KEYED_LOAD_IC ||
k == KEYED_STORE_IC || k == COMPARE_NIL_IC) &&
void VerifyEmbeddedObjectsInFullCode();
#endif // DEBUG
- inline bool CanContainWeakObjects() {
- return is_optimized_code() || is_weak_stub();
- }
+ inline bool CanContainWeakObjects() { return is_optimized_code(); }
inline bool IsWeakObject(Object* object) {
return (is_optimized_code() && !is_turbofanned() &&
- IsWeakObjectInOptimizedCode(object)) ||
- (is_weak_stub() && IsWeakObjectInIC(object));
+ IsWeakObjectInOptimizedCode(object));
}
static inline bool IsWeakObjectInOptimizedCode(Object* object);
- static inline bool IsWeakObjectInIC(Object* object);
// Max loop nesting marker used to postpose OSR. We don't take loop
// nesting that is deeper than 5 levels into account.
static const int kHasFunctionCacheBit =
kStackSlotsFirstBit + kStackSlotsBitCount;
static const int kMarkedForDeoptimizationBit = kHasFunctionCacheBit + 1;
- static const int kWeakStubBit = kMarkedForDeoptimizationBit + 1;
- static const int kInvalidatedWeakStubBit = kWeakStubBit + 1;
- static const int kIsTurbofannedBit = kInvalidatedWeakStubBit + 1;
+ static const int kIsTurbofannedBit = kMarkedForDeoptimizationBit + 1;
STATIC_ASSERT(kStackSlotsFirstBit + kStackSlotsBitCount <= 32);
STATIC_ASSERT(kIsTurbofannedBit + 1 <= 32);
}; // NOLINT
class MarkedForDeoptimizationField
: public BitField<bool, kMarkedForDeoptimizationBit, 1> {}; // NOLINT
- class WeakStubField : public BitField<bool, kWeakStubBit, 1> {}; // NOLINT
- class InvalidatedWeakStubField
- : public BitField<bool, kInvalidatedWeakStubBit, 1> {}; // NOLINT
class IsTurbofannedField : public BitField<bool, kIsTurbofannedBit, 1> {
}; // NOLINT
class DependentCode: public FixedArray {
public:
enum DependencyGroup {
- // Group of IC stubs that weakly embed this map and depend on being
- // invalidated when the map is garbage collected. Dependent IC stubs form
- // a linked list. This group stores only the head of the list. This means
- // that the number_of_entries(kWeakICGroup) is 0 or 1.
- kWeakICGroup,
// Group of code that weakly embed this map and depend on being
// deoptimized when the map is garbage collected.
kWeakCodeGroup,
bool MarkCodeForDeoptimization(Isolate* isolate,
DependentCode::DependencyGroup group);
- void AddToDependentICList(Handle<Code> stub);
// The following low-level accessors should only be used by this class
// and the mark compact collector.
static void AddDependentCode(Handle<Map> map,
DependentCode::DependencyGroup group,
Handle<Code> code);
- static void AddDependentIC(Handle<Map> map,
- Handle<Code> stub);
bool IsMapInArrayPrototypeChain();