| 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),
|
|
|