Index: src/deoptimizer.cc |
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc |
index 8f1711144e65c9a121a233b08a44d507ea893332..c4dae93b62fe111ab3f6dbfb7b3da6ff1d8479a4 100644 |
--- a/src/deoptimizer.cc |
+++ b/src/deoptimizer.cc |
@@ -247,45 +247,6 @@ void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm, |
} |
-class DeoptimizingVisitor : public OptimizedFunctionVisitor { |
- public: |
- virtual void EnterContext(Context* context) { |
- if (FLAG_trace_deopt) { |
- PrintF("[deoptimize context: %" V8PRIxPTR "]\n", |
- reinterpret_cast<intptr_t>(context)); |
- } |
- } |
- |
- virtual void VisitFunction(JSFunction* function) { |
- Deoptimizer::DeoptimizeFunction(function); |
- } |
- |
- virtual void LeaveContext(Context* context) { |
- context->ClearOptimizedFunctions(); |
- } |
-}; |
- |
- |
-void Deoptimizer::DeoptimizeAll() { |
- AssertNoAllocation no_allocation; |
- |
- if (FLAG_trace_deopt) { |
- PrintF("[deoptimize all contexts]\n"); |
- } |
- |
- DeoptimizingVisitor visitor; |
- VisitAllOptimizedFunctions(&visitor); |
-} |
- |
- |
-void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) { |
- AssertNoAllocation no_allocation; |
- |
- DeoptimizingVisitor visitor; |
- VisitAllOptimizedFunctionsForGlobalObject(object, &visitor); |
-} |
- |
- |
void Deoptimizer::VisitAllOptimizedFunctionsForContext( |
Context* context, OptimizedFunctionVisitor* visitor) { |
Isolate* isolate = context->GetIsolate(); |
@@ -315,36 +276,151 @@ void Deoptimizer::VisitAllOptimizedFunctionsForContext( |
} |
-void Deoptimizer::VisitAllOptimizedFunctionsForGlobalObject( |
- JSObject* object, OptimizedFunctionVisitor* visitor) { |
+void Deoptimizer::VisitAllOptimizedFunctions( |
+ OptimizedFunctionVisitor* visitor) { |
+ AssertNoAllocation no_allocation; |
+ |
+ // Run through the list of all native contexts and deoptimize. |
+ Object* context = Isolate::Current()->heap()->native_contexts_list(); |
+ while (!context->IsUndefined()) { |
+ VisitAllOptimizedFunctionsForContext(Context::cast(context), visitor); |
+ context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); |
+ } |
+} |
+ |
+ |
+// 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) { |
+ AssertNoAllocation no_allocation; |
+ Object* current = context->get(Context::OPTIMIZED_FUNCTIONS_LIST); |
+ Object* remainder_head = undefined; |
+ Object* remainder_tail = undefined; |
+ ASSERT_EQ(0, partitions->length()); |
+ while (current != undefined) { |
+ JSFunction* function = JSFunction::cast(current); |
+ current = function->next_function_link(); |
+ if (filter->TakeFunction(function)) { |
+ Code* code = function->code(); |
+ if (code->deoptimizing_functions() == undefined) { |
+ partitions->Add(code, zone); |
+ } else { |
+ ASSERT(partitions->Contains(code)); |
+ } |
+ function->set_next_function_link(code->deoptimizing_functions()); |
+ code->set_deoptimizing_functions(function); |
+ } else { |
+ if (remainder_head == undefined) { |
+ remainder_head = function; |
+ } else { |
+ JSFunction::cast(remainder_tail)->set_next_function_link(function); |
+ } |
+ remainder_tail = function; |
+ } |
+ } |
+ if (remainder_tail != undefined) { |
+ JSFunction::cast(remainder_tail)->set_next_function_link(undefined); |
+ } |
+ context->set(Context::OPTIMIZED_FUNCTIONS_LIST, remainder_head); |
+} |
+ |
+ |
+class DeoptimizeAllFilter : public OptimizedFunctionFilter { |
+ public: |
+ virtual bool TakeFunction(JSFunction* function) { |
+ return true; |
+ } |
+}; |
+ |
+ |
+class DeoptimizeWithMatchingCodeFilter : public OptimizedFunctionFilter { |
+ public: |
+ explicit DeoptimizeWithMatchingCodeFilter(Code* code) : code_(code) {} |
+ virtual bool TakeFunction(JSFunction* function) { |
+ return function->code() == code_; |
+ } |
+ private: |
+ Code* code_; |
+}; |
+ |
+ |
+void Deoptimizer::DeoptimizeAll() { |
AssertNoAllocation no_allocation; |
+ if (FLAG_trace_deopt) { |
+ PrintF("[deoptimize all contexts]\n"); |
+ } |
+ |
+ DeoptimizeAllFilter filter; |
+ DeoptimizeAllFunctionsWith(&filter); |
+} |
+ |
+ |
+void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) { |
+ AssertNoAllocation no_allocation; |
+ DeoptimizeAllFilter filter; |
if (object->IsJSGlobalProxy()) { |
Object* proto = object->GetPrototype(); |
ASSERT(proto->IsJSGlobalObject()); |
- VisitAllOptimizedFunctionsForContext( |
- GlobalObject::cast(proto)->native_context(), visitor); |
+ DeoptimizeAllFunctionsForContext( |
+ GlobalObject::cast(proto)->native_context(), &filter); |
} else if (object->IsGlobalObject()) { |
- VisitAllOptimizedFunctionsForContext( |
- GlobalObject::cast(object)->native_context(), visitor); |
+ DeoptimizeAllFunctionsForContext( |
+ GlobalObject::cast(object)->native_context(), &filter); |
} |
} |
-void Deoptimizer::VisitAllOptimizedFunctions( |
- OptimizedFunctionVisitor* visitor) { |
+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->runtime_zone(); |
+ ZoneScope zone_scope(zone, DELETE_ON_EXIT); |
+ ZoneList<Code*> codes(1, zone); |
+ 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); |
+} |
+ |
+ |
+void Deoptimizer::DeoptimizeAllFunctionsForContext( |
+ Context* context, OptimizedFunctionFilter* filter) { |
+ ASSERT(context->IsNativeContext()); |
+ Isolate* isolate = context->GetIsolate(); |
+ Object* undefined = isolate->heap()->undefined_value(); |
+ Zone* zone = isolate->runtime_zone(); |
+ ZoneScope zone_scope(zone, DELETE_ON_EXIT); |
+ 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); |
+ } |
+} |
+ |
+ |
+void Deoptimizer::DeoptimizeAllFunctionsWith(OptimizedFunctionFilter* filter) { |
AssertNoAllocation no_allocation; |
// Run through the list of all native contexts and deoptimize. |
Object* context = Isolate::Current()->heap()->native_contexts_list(); |
while (!context->IsUndefined()) { |
- // GC can happen when the context is not fully initialized, |
- // so the global field of the context can be undefined. |
- Object* global = Context::cast(context)->get(Context::GLOBAL_OBJECT_INDEX); |
- if (!global->IsUndefined()) { |
- VisitAllOptimizedFunctionsForGlobalObject(JSObject::cast(global), |
- visitor); |
- } |
+ DeoptimizeAllFunctionsForContext(Context::cast(context), filter); |
context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); |
} |
} |
@@ -1476,44 +1552,11 @@ void Deoptimizer::RemoveDeoptimizingCode(Code* code) { |
} |
-static Object* CutOutRelatedFunctionsList(Context* context, |
- Code* code, |
- Object* undefined) { |
- Object* result_list_head = undefined; |
- Object* head; |
- Object* current; |
- current = head = context->get(Context::OPTIMIZED_FUNCTIONS_LIST); |
- JSFunction* prev = NULL; |
- while (current != undefined) { |
- JSFunction* func = JSFunction::cast(current); |
- current = func->next_function_link(); |
- if (func->code() == code) { |
- func->set_next_function_link(result_list_head); |
- result_list_head = func; |
- if (prev) { |
- prev->set_next_function_link(current); |
- } else { |
- head = current; |
- } |
- } else { |
- prev = func; |
- } |
- } |
- if (head != context->get(Context::OPTIMIZED_FUNCTIONS_LIST)) { |
- context->set(Context::OPTIMIZED_FUNCTIONS_LIST, head); |
- } |
- return result_list_head; |
-} |
- |
- |
void Deoptimizer::ReplaceCodeForRelatedFunctions(JSFunction* function, |
Code* code) { |
- Context* context = function->context()->native_context(); |
- |
SharedFunctionInfo* shared = function->shared(); |
- |
Object* undefined = Isolate::Current()->heap()->undefined_value(); |
- Object* current = CutOutRelatedFunctionsList(context, code, undefined); |
+ Object* current = function; |
while (current != undefined) { |
JSFunction* func = JSFunction::cast(current); |