Index: src/deoptimizer.cc |
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc |
index fd7c2829adde7dc9ab9799385bfcb11282af0fb2..d0f5bfc9f06267ff051f7fe64c3365b27981ba9f 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. |
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 { |
@@ -393,6 +406,14 @@ class DeoptimizeWithMatchingCodeFilter : public OptimizedFunctionFilter { |
}; |
+class DeoptimizeMarkedCodeFilter : public OptimizedFunctionFilter { |
+ public: |
+ virtual bool TakeFunction(JSFunction* function) { |
+ return function->code()->marked_for_deoptimization(); |
+ } |
+}; |
+ |
+ |
void Deoptimizer::DeoptimizeAll(Isolate* isolate) { |
DisallowHeapAllocation no_allocation; |
@@ -421,19 +442,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 +456,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 +477,55 @@ void Deoptimizer::DeoptimizeAllFunctionsWith(Isolate* isolate, |
} |
+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), |