Chromium Code Reviews| Index: src/objects-visiting-inl.h |
| diff --git a/src/objects-visiting-inl.h b/src/objects-visiting-inl.h |
| index ea5f1cadbbb5b2d62ca00ccc31134c3dd281b20c..b0db3bf24a7d14a1f56f3d4e03e5e5d67c57fd7c 100644 |
| --- a/src/objects-visiting-inl.h |
| +++ b/src/objects-visiting-inl.h |
| @@ -138,9 +138,9 @@ void StaticMarkingVisitor<StaticVisitor>::Initialize() { |
| table_.Register(kVisitCode, &VisitCode); |
| - // Registration for kVisitSharedFunctionInfo is done by StaticVisitor. |
| + table_.Register(kVisitSharedFunctionInfo, &VisitSharedFunctionInfo); |
| - // Registration for kVisitJSFunction is done by StaticVisitor. |
| + table_.Register(kVisitJSFunction, &VisitJSFunction); |
| // Registration for kVisitJSRegExp is done by StaticVisitor. |
| @@ -284,6 +284,71 @@ void StaticMarkingVisitor<StaticVisitor>::VisitCode( |
| template<typename StaticVisitor> |
| +void StaticMarkingVisitor<StaticVisitor>::VisitSharedFunctionInfo( |
| + Map* map, HeapObject* object) { |
| + Heap* heap = map->GetHeap(); |
| + SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); |
| + if (shared->ic_age() != heap->global_ic_age()) { |
| + shared->ResetForNewContext(heap->global_ic_age()); |
| + } |
| + MarkCompactCollector* collector = heap->mark_compact_collector(); |
| + if (collector->is_code_flushing_enabled()) { |
| + if (IsFlushable(heap, shared)) { |
| + // This function's code looks flushable. But we have to postpone |
| + // the decision until we see all functions that point to the same |
| + // SharedFunctionInfo because some of them might be optimized. |
| + // That would also make the non-optimized version of the code |
| + // non-flushable, because it is required for bailing out from |
| + // optimized code. |
| + collector->code_flusher()->AddCandidate(shared); |
| + // Treat the reference to the code object weakly. |
| + VisitSharedFunctionInfoWeakCode(heap, object); |
| + return; |
| + } |
| + } |
| + VisitSharedFunctionInfoStrongCode(heap, object); |
| +} |
| + |
| + |
| +template<typename StaticVisitor> |
| +void StaticMarkingVisitor<StaticVisitor>::VisitJSFunction( |
| + Map* map, HeapObject* object) { |
| + Heap* heap = map->GetHeap(); |
| + JSFunction* function = JSFunction::cast(object); |
| + MarkCompactCollector* collector = heap->mark_compact_collector(); |
| + if (collector->is_code_flushing_enabled()) { |
| + if (IsFlushable(heap, function)) { |
| + // This function's code looks flushable. But we have to postpone |
| + // the decision until we see all functions that point to the same |
| + // SharedFunctionInfo because some of them might be optimized. |
| + // That would also make the non-optimized version of the code |
| + // non-flushable, because it is required for bailing out from |
| + // optimized code. |
| + collector->code_flusher()->AddCandidate(function); |
| + // Visit shared function info immediately to avoid double checking |
| + // of its flushability later. This is just an optimization because |
| + // the shared function info would eventually be visited. |
| + SharedFunctionInfo* shared = function->unchecked_shared(); |
| + if (StaticVisitor::MarkObjectWithoutPush(heap, shared)) { |
| + StaticVisitor::MarkObject(heap, shared->map()); |
| + VisitSharedFunctionInfoWeakCode(heap, shared); |
| + } |
| + // Treat the reference to the code object weakly. |
| + VisitJSFunctionWeakCode(heap, object); |
| + return; |
| + } else { |
| + // Visit all unoptimized code objects to prevent flushing them. |
| + StaticVisitor::MarkObject(heap, function->shared()->code()); |
| + if (function->code()->kind() == Code::OPTIMIZED_FUNCTION) { |
| + MarkInlinedFunctionsCode(heap, function->code()); |
| + } |
| + } |
| + } |
| + VisitJSFunctionStrongCode(heap, object); |
| +} |
| + |
| + |
| +template<typename StaticVisitor> |
| void StaticMarkingVisitor<StaticVisitor>::VisitJSRegExp( |
| Map* map, HeapObject* object) { |
| int last_property_offset = |
| @@ -355,6 +420,191 @@ void StaticMarkingVisitor<StaticVisitor>::MarkTransitionArray( |
| } |
| } |
| +template<typename StaticVisitor> |
| +void StaticMarkingVisitor<StaticVisitor>::MarkInlinedFunctionsCode( |
| + Heap* heap, Code* code) { |
| + // For optimized functions we should retain both non-optimized version |
| + // of its code and non-optimized version of all inlined functions. |
| + // This is required to support bailing out from inlined code. |
| + DeoptimizationInputData* data = |
| + DeoptimizationInputData::cast(code->deoptimization_data()); |
| + FixedArray* literals = data->LiteralArray(); |
| + for (int i = 0, count = data->InlinedFunctionCount()->value(); |
| + i < count; |
| + i++) { |
| + JSFunction* inlined = JSFunction::cast(literals->get(i)); |
| + StaticVisitor::MarkObject(heap, inlined->shared()->code()); |
| + } |
| +} |
| + |
| + |
| +inline static bool IsValidNonBuiltinContext(Object* context) { |
| + return context->IsContext() && |
| + !Context::cast(context)->global_object()->IsJSBuiltinsObject(); |
| +} |
| + |
| + |
| +inline static bool HasSourceCode(Heap* heap, SharedFunctionInfo* info) { |
| + Object* undefined = heap->undefined_value(); |
| + return (info->script() != undefined) && |
| + (reinterpret_cast<Script*>(info->script())->source() != undefined); |
| +} |
| + |
| + |
| +template<typename StaticVisitor> |
| +bool StaticMarkingVisitor<StaticVisitor>::IsFlushable( |
| + Heap* heap, JSFunction* function) { |
| + SharedFunctionInfo* shared_info = function->unchecked_shared(); |
| + |
| + // Code is either on stack, in compilation cache or referenced |
| + // by optimized version of function. |
| + MarkBit code_mark = Marking::MarkBitFrom(function->code()); |
| + if (code_mark.Get()) { |
| + if (!Marking::MarkBitFrom(shared_info).Get()) { |
| + shared_info->set_code_age(0); |
| + } |
| + return false; |
| + } |
| + |
| + // The function must have a valid context and not be a builtin. |
| + if (!IsValidNonBuiltinContext(function->unchecked_context())) { |
| + return false; |
| + } |
| + |
| + // We do not flush code for optimized functions. |
| + if (function->code() != shared_info->code()) { |
| + return false; |
| + } |
| + |
| + return IsFlushable(heap, shared_info); |
| +} |
| + |
| + |
| +template<typename StaticVisitor> |
| +bool StaticMarkingVisitor<StaticVisitor>::IsFlushable( |
| + Heap* heap, SharedFunctionInfo* shared_info) { |
| + // Code is either on stack, in compilation cache or referenced |
| + // by optimized version of function. |
| + MarkBit code_mark = Marking::MarkBitFrom(shared_info->code()); |
| + if (code_mark.Get()) { |
| + return false; |
| + } |
| + |
| + // The function must be compiled and have the source code available, |
| + // to be able to recompile it in case we need the function again. |
| + if (!(shared_info->is_compiled() && HasSourceCode(heap, shared_info))) { |
| + return false; |
| + } |
| + |
| + // We never flush code for API functions. |
| + Object* function_data = shared_info->function_data(); |
| + if (function_data->IsFunctionTemplateInfo()) { |
| + return false; |
| + } |
| + |
| + // Only flush code for functions. |
| + if (shared_info->code()->kind() != Code::FUNCTION) { |
| + return false; |
| + } |
| + |
| + // Function must be lazy compilable. |
| + if (!shared_info->allows_lazy_compilation()) { |
| + return false; |
| + } |
| + |
| + // If this is a full script wrapped in a function we do no flush the code. |
| + if (shared_info->is_toplevel()) { |
| + return false; |
| + } |
| + |
| + // TODO(mstarzinger): The following will soon be replaced by a new way of |
| + // aging code, that is based on an aging stub in the function prologue. |
| + |
| + // How many collections newly compiled code object will survive before being |
| + // flushed. |
| + static const int kCodeAgeThreshold = 5; |
| + |
| + // Age this shared function info. |
| + if (shared_info->code_age() < kCodeAgeThreshold) { |
| + shared_info->set_code_age(shared_info->code_age() + 1); |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| + |
| +template<typename StaticVisitor> |
| +void StaticMarkingVisitor<StaticVisitor>::VisitSharedFunctionInfoStrongCode( |
| + Heap* heap, HeapObject* object) { |
| + StaticVisitor::BeforeVisitingSharedFunctionInfo(object); |
| + Object** start_slot = |
| + HeapObject::RawField(object, |
| + SharedFunctionInfo::BodyDescriptor::kStartOffset); |
| + Object** end_slot = |
| + HeapObject::RawField(object, |
| + SharedFunctionInfo::BodyDescriptor::kEndOffset); |
| + StaticVisitor::VisitPointers(heap, start_slot, start_slot, end_slot); |
| +} |
| + |
| + |
| +template<typename StaticVisitor> |
| +void StaticMarkingVisitor<StaticVisitor>::VisitSharedFunctionInfoWeakCode( |
| + Heap* heap, HeapObject* object) { |
| + StaticVisitor::BeforeVisitingSharedFunctionInfo(object); |
| + Object** name_slot = |
| + HeapObject::RawField(object, SharedFunctionInfo::kNameOffset); |
| + StaticVisitor::VisitPointer(heap, name_slot); |
| + |
| + // Skip visiting kCodeOffset as it is treated weakly here. |
|
ulan
2012/10/12 11:48:32
Maybe add static asserts that kNameOffset + kPoint
Michael Starzinger
2012/10/12 12:16:37
Done.
|
| + |
| + Object** start_slot = |
| + HeapObject::RawField(object, |
| + SharedFunctionInfo::kOptimizedCodeMapOffset); |
| + Object** end_slot = |
| + HeapObject::RawField(object, |
| + SharedFunctionInfo::BodyDescriptor::kEndOffset); |
| + StaticVisitor::VisitPointers(heap, start_slot, start_slot, end_slot); |
| +} |
| + |
| + |
| +template<typename StaticVisitor> |
| +void StaticMarkingVisitor<StaticVisitor>::VisitJSFunctionStrongCode( |
| + Heap* heap, HeapObject* object) { |
| + Object** start_slot = |
| + HeapObject::RawField(object, JSFunction::kPropertiesOffset); |
| + Object** end_slot = |
| + HeapObject::RawField(object, JSFunction::kCodeEntryOffset); |
| + StaticVisitor::VisitPointers(heap, start_slot, start_slot, end_slot); |
| + |
| + VisitCodeEntry(heap, object->address() + JSFunction::kCodeEntryOffset); |
|
Michael Starzinger
2012/10/12 12:16:37
As discussed offline, I also added the static asse
|
| + |
| + start_slot = |
| + HeapObject::RawField(object, JSFunction::kPrototypeOrInitialMapOffset); |
| + end_slot = |
| + HeapObject::RawField(object, JSFunction::kNonWeakFieldsEndOffset); |
| + StaticVisitor::VisitPointers(heap, start_slot, start_slot, end_slot); |
| +} |
| + |
| + |
| +template<typename StaticVisitor> |
| +void StaticMarkingVisitor<StaticVisitor>::VisitJSFunctionWeakCode( |
| + Heap* heap, HeapObject* object) { |
| + Object** start_slot = |
| + HeapObject::RawField(object, JSFunction::kPropertiesOffset); |
| + Object** end_slot = |
| + HeapObject::RawField(object, JSFunction::kCodeEntryOffset); |
| + StaticVisitor::VisitPointers(heap, start_slot, start_slot, end_slot); |
| + |
| + // Skip visiting kCodeEntryOffset as it is treated weakly here. |
|
ulan
2012/10/12 11:48:32
Maybe add static asserts as in the comment above?
Michael Starzinger
2012/10/12 12:16:37
Done.
|
| + |
| + start_slot = |
| + HeapObject::RawField(object, JSFunction::kPrototypeOrInitialMapOffset); |
| + end_slot = |
| + HeapObject::RawField(object, JSFunction::kNonWeakFieldsEndOffset); |
| + StaticVisitor::VisitPointers(heap, start_slot, start_slot, end_slot); |
| +} |
| + |
| void Code::CodeIterateBody(ObjectVisitor* v) { |
| int mode_mask = RelocInfo::kCodeTargetMask | |