Chromium Code Reviews| Index: src/deoptimizer.cc |
| diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc |
| index fd7c2829adde7dc9ab9799385bfcb11282af0fb2..54b195dddfa2effb08dadb765be7a5d032fe16df 100644 |
| --- a/src/deoptimizer.cc |
| +++ b/src/deoptimizer.cc |
| @@ -331,34 +331,47 @@ void Deoptimizer::VisitAllOptimizedFunctions( |
| // Removes the functions selected by the given filter from the optimized |
| -// function list of the given context and partitions the removed functions |
| -// into one or more lists such that all functions in a list share the same |
| -// code. The head of each list is written in the deoptimizing_functions field |
| -// of the corresponding code object. |
| -// The found code objects are returned in the given zone list. |
| -static void PartitionOptimizedFunctions(Context* context, |
| - OptimizedFunctionFilter* filter, |
| - ZoneList<Code*>* partitions, |
| - Zone* zone, |
| - Object* undefined) { |
| +// function list of the given context and adds their code to the list of |
| +// code objects to be deoptimized. |
| +static void SelectCodeToDeoptimize(Context* context, |
| + OptimizedFunctionFilter* filter, |
| + ZoneList<Code*>* codes, |
| + Zone* zone, |
| + Object* undefined) { |
| DisallowHeapAllocation no_allocation; |
| Object* current = context->get(Context::OPTIMIZED_FUNCTIONS_LIST); |
| Object* remainder_head = undefined; |
| Object* remainder_tail = undefined; |
| - ASSERT_EQ(0, partitions->length()); |
| + |
| + // TODO(titzer): rewrite to not modify unselected functions. |
|
Michael Starzinger
2013/07/24 09:24:57
I am unsure about this TODO, what does this imply?
|
| while (current != undefined) { |
| JSFunction* function = JSFunction::cast(current); |
| current = function->next_function_link(); |
| if (filter->TakeFunction(function)) { |
| + // Extract this function from the context's list and remember the code. |
| Code* code = function->code(); |
| - if (code->deoptimizing_functions() == undefined) { |
| - partitions->Add(code, zone); |
| + ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION); |
| + if (code->marked_for_deoptimization()) { |
| + ASSERT(codes->Contains(code)); |
| } else { |
| - ASSERT(partitions->Contains(code)); |
| + code->set_marked_for_deoptimization(true); |
| + codes->Add(code, zone); |
| + } |
| + SharedFunctionInfo* shared = function->shared(); |
| + // Replace the function's code with the shared code. |
| + function->set_code(shared->code()); |
| + // Evict the code from the optimized code map. |
| + shared->EvictFromOptimizedCodeMap(code, "deoptimized function"); |
| + // Remove the function from the optimized functions list. |
| + function->set_next_function_link(undefined); |
| + |
| + if (FLAG_trace_deopt) { |
| + PrintF("[forced deoptimization: "); |
| + function->PrintName(); |
| + PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function)); |
| } |
| - function->set_next_function_link(code->deoptimizing_functions()); |
| - code->set_deoptimizing_functions(function); |
| } else { |
| + // Don't select this function; link it back into the list. |
| if (remainder_head == undefined) { |
| remainder_head = function; |
| } else { |
| @@ -421,19 +434,11 @@ void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) { |
| void Deoptimizer::DeoptimizeFunction(JSFunction* function) { |
| - if (!function->IsOptimized()) return; |
| Code* code = function->code(); |
| - Context* context = function->context()->native_context(); |
| - Isolate* isolate = context->GetIsolate(); |
| - Object* undefined = isolate->heap()->undefined_value(); |
| - Zone zone(isolate); |
| - ZoneList<Code*> codes(1, &zone); |
| + if (code->kind() != Code::OPTIMIZED_FUNCTION) return; |
| DeoptimizeWithMatchingCodeFilter filter(code); |
| - PartitionOptimizedFunctions(context, &filter, &codes, &zone, undefined); |
| - ASSERT_EQ(1, codes.length()); |
| - DeoptimizeFunctionWithPreparedFunctionList( |
| - JSFunction::cast(codes.at(0)->deoptimizing_functions())); |
| - codes.at(0)->set_deoptimizing_functions(undefined); |
| + DeoptimizeAllFunctionsForContext( |
| + function->context()->native_context(), &filter); |
| } |
| @@ -443,12 +448,10 @@ void Deoptimizer::DeoptimizeAllFunctionsForContext( |
| Isolate* isolate = context->GetIsolate(); |
| Object* undefined = isolate->heap()->undefined_value(); |
| Zone zone(isolate); |
| - ZoneList<Code*> codes(1, &zone); |
| - PartitionOptimizedFunctions(context, filter, &codes, &zone, undefined); |
| - for (int i = 0; i < codes.length(); ++i) { |
| - DeoptimizeFunctionWithPreparedFunctionList( |
| - JSFunction::cast(codes.at(i)->deoptimizing_functions())); |
| - codes.at(i)->set_deoptimizing_functions(undefined); |
| + ZoneList<Code*> codes(4, &zone); |
| + SelectCodeToDeoptimize(context, filter, &codes, &zone, undefined); |
| + for (int i = 0; i < codes.length(); i++) { |
| + DeoptimizeCode(isolate, codes.at(i)); |
| } |
| } |
| @@ -466,6 +469,63 @@ void Deoptimizer::DeoptimizeAllFunctionsWith(Isolate* isolate, |
| } |
| +class DeoptimizeMarkedCodeFilter : public OptimizedFunctionFilter { |
|
Michael Starzinger
2013/07/24 09:24:57
nit: Can we move this up to the other filters so t
|
| + public: |
| + virtual bool TakeFunction(JSFunction* function) { |
| + return function->code()->marked_for_deoptimization(); |
| + } |
| +}; |
| + |
| + |
| +void Deoptimizer::DeoptimizeCodeList(Isolate* isolate, ZoneList<Code*>* codes) { |
| + if (codes->length() == 0) return; // Nothing to do. |
| + |
| + // Mark the code; any functions refering to this code will be selected. |
| + for (int i = 0; i < codes->length(); i++) { |
| + ASSERT(!codes->at(i)->marked_for_deoptimization()); |
| + codes->at(i)->set_marked_for_deoptimization(true); |
| + } |
| + |
| + // For all contexts, remove optimized functions that refer to the selected |
| + // code from the optimized function lists. |
| + Object* undefined = isolate->heap()->undefined_value(); |
| + Zone zone(isolate); |
| + Object* list = isolate->heap()->native_contexts_list(); |
| + DeoptimizeMarkedCodeFilter filter; |
| + while (!list->IsUndefined()) { |
| + Context* context = Context::cast(list); |
| + // Note that selecting code unlinks the functions that refer to it. |
| + SelectCodeToDeoptimize(context, &filter, codes, &zone, undefined); |
| + list = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); |
| + } |
| + |
| + // Now deoptimize all the code. |
| + for (int i = 0; i < codes->length(); i++) { |
| + DeoptimizeCode(isolate, codes->at(i)); |
| + } |
| +} |
| + |
| + |
| +void Deoptimizer::DeoptimizeCode(Isolate* isolate, Code* code) { |
| + HandleScope scope(isolate); |
| + DisallowHeapAllocation nha; |
| + |
| + // Do platform-specific patching of the optimized code. |
| + PatchCodeForDeoptimization(isolate, code); |
| + |
| + // Add the deoptimizing code to the list. |
| + DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code); |
| + DeoptimizerData* data = isolate->deoptimizer_data(); |
| + node->set_next(data->deoptimizing_code_list_); |
| + data->deoptimizing_code_list_ = node; |
| + |
| + // We might be in the middle of incremental marking with compaction. |
| + // Tell collector to treat this code object in a special way and |
| + // ignore all slots that might have been recorded on it. |
| + isolate->heap()->mark_compact_collector()->InvalidateCode(code); |
| +} |
| + |
| + |
| void Deoptimizer::HandleWeakDeoptimizedCode(v8::Isolate* isolate, |
| v8::Persistent<v8::Value>* obj, |
| void* parameter) { |
| @@ -2569,21 +2629,6 @@ void Deoptimizer::EnsureCodeForDeoptimizationEntry(Isolate* isolate, |
| } |
| -void Deoptimizer::ReplaceCodeForRelatedFunctions(JSFunction* function, |
| - Code* code) { |
| - SharedFunctionInfo* shared = function->shared(); |
| - Object* undefined = function->GetHeap()->undefined_value(); |
| - Object* current = function; |
| - |
| - while (current != undefined) { |
| - JSFunction* func = JSFunction::cast(current); |
| - current = func->next_function_link(); |
| - func->set_code(shared->code()); |
| - func->set_next_function_link(undefined); |
| - } |
| -} |
| - |
| - |
| FrameDescription::FrameDescription(uint32_t frame_size, |
| JSFunction* function) |
| : frame_size_(frame_size), |