| Index: src/deoptimizer.cc
|
| diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
|
| index b460f3f5189c06f40fef77434b19cdd927b2864d..05199fcfe159a98af9bd88baabba48dbabbf99a5 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) {
|
| @@ -900,15 +960,15 @@ void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
|
| // input frame. For all subsequent output frames, it can be read from the
|
| // previous one. This frame's pc can be computed from the non-optimized
|
| // function code and AST id of the bailout.
|
| - output_offset -= kPointerSize;
|
| - input_offset -= kPointerSize;
|
| + output_offset -= kPCOnStackSize;
|
| + input_offset -= kPCOnStackSize;
|
| intptr_t value;
|
| if (is_bottommost) {
|
| value = input_->GetFrameSlot(input_offset);
|
| } else {
|
| value = output_[frame_index - 1]->GetPc();
|
| }
|
| - output_frame->SetFrameSlot(output_offset, value);
|
| + output_frame->SetCallerPc(output_offset, value);
|
| if (trace_) {
|
| PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
|
| V8PRIxPTR " ; caller's pc\n",
|
| @@ -919,14 +979,14 @@ void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
|
| // as in the input frame. For all subsequent output frames, it can be
|
| // read from the previous one. Also compute and set this frame's frame
|
| // pointer.
|
| - output_offset -= kPointerSize;
|
| - input_offset -= kPointerSize;
|
| + output_offset -= kFPOnStackSize;
|
| + input_offset -= kFPOnStackSize;
|
| if (is_bottommost) {
|
| value = input_->GetFrameSlot(input_offset);
|
| } else {
|
| value = output_[frame_index - 1]->GetFp();
|
| }
|
| - output_frame->SetFrameSlot(output_offset, value);
|
| + output_frame->SetCallerFp(output_offset, value);
|
| intptr_t fp_value = top_address + output_offset;
|
| ASSERT(!is_bottommost || (input_->GetRegister(fp_reg.code()) +
|
| has_alignment_padding_ * kPointerSize) == fp_value);
|
| @@ -1049,9 +1109,9 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
|
| }
|
|
|
| // Read caller's PC from the previous frame.
|
| - output_offset -= kPointerSize;
|
| + output_offset -= kPCOnStackSize;
|
| intptr_t callers_pc = output_[frame_index - 1]->GetPc();
|
| - output_frame->SetFrameSlot(output_offset, callers_pc);
|
| + output_frame->SetCallerPc(output_offset, callers_pc);
|
| if (trace_) {
|
| PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
|
| V8PRIxPTR " ; caller's pc\n",
|
| @@ -1059,9 +1119,9 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
|
| }
|
|
|
| // Read caller's FP from the previous frame, and set this frame's FP.
|
| - output_offset -= kPointerSize;
|
| + output_offset -= kFPOnStackSize;
|
| intptr_t value = output_[frame_index - 1]->GetFp();
|
| - output_frame->SetFrameSlot(output_offset, value);
|
| + output_frame->SetCallerFp(output_offset, value);
|
| intptr_t fp_value = top_address + output_offset;
|
| output_frame->SetFp(fp_value);
|
| if (trace_) {
|
| @@ -1152,9 +1212,9 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
|
| }
|
|
|
| // Read caller's PC from the previous frame.
|
| - output_offset -= kPointerSize;
|
| + output_offset -= kPCOnStackSize;
|
| intptr_t callers_pc = output_[frame_index - 1]->GetPc();
|
| - output_frame->SetFrameSlot(output_offset, callers_pc);
|
| + output_frame->SetCallerPc(output_offset, callers_pc);
|
| if (trace_) {
|
| PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
|
| V8PRIxPTR " ; caller's pc\n",
|
| @@ -1162,9 +1222,9 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
|
| }
|
|
|
| // Read caller's FP from the previous frame, and set this frame's FP.
|
| - output_offset -= kPointerSize;
|
| + output_offset -= kFPOnStackSize;
|
| intptr_t value = output_[frame_index - 1]->GetFp();
|
| - output_frame->SetFrameSlot(output_offset, value);
|
| + output_frame->SetCallerFp(output_offset, value);
|
| intptr_t fp_value = top_address + output_offset;
|
| output_frame->SetFp(fp_value);
|
| if (trace_) {
|
| @@ -1265,7 +1325,9 @@ void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
|
| // MacroAssembler::EnterFrame). For a setter stub frame we need one additional
|
| // entry for the implicit return value, see
|
| // StoreStubCompiler::CompileStoreViaSetter.
|
| - unsigned fixed_frame_entries = 1 + 4 + (is_setter_stub_frame ? 1 : 0);
|
| + unsigned fixed_frame_entries = (kPCOnStackSize / kPointerSize) +
|
| + (kFPOnStackSize / kPointerSize) + 3 +
|
| + (is_setter_stub_frame ? 1 : 0);
|
| unsigned fixed_frame_size = fixed_frame_entries * kPointerSize;
|
| unsigned output_frame_size = height_in_bytes + fixed_frame_size;
|
|
|
| @@ -1287,9 +1349,9 @@ void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
|
| unsigned output_offset = output_frame_size;
|
|
|
| // Read caller's PC from the previous frame.
|
| - output_offset -= kPointerSize;
|
| + output_offset -= kPCOnStackSize;
|
| intptr_t callers_pc = output_[frame_index - 1]->GetPc();
|
| - output_frame->SetFrameSlot(output_offset, callers_pc);
|
| + output_frame->SetCallerPc(output_offset, callers_pc);
|
| if (trace_) {
|
| PrintF(" 0x%08" V8PRIxPTR ": [top + %u] <- 0x%08" V8PRIxPTR
|
| " ; caller's pc\n",
|
| @@ -1297,9 +1359,9 @@ void Deoptimizer::DoComputeAccessorStubFrame(TranslationIterator* iterator,
|
| }
|
|
|
| // Read caller's FP from the previous frame, and set this frame's FP.
|
| - output_offset -= kPointerSize;
|
| + output_offset -= kFPOnStackSize;
|
| intptr_t value = output_[frame_index - 1]->GetFp();
|
| - output_frame->SetFrameSlot(output_offset, value);
|
| + output_frame->SetCallerFp(output_offset, value);
|
| intptr_t fp_value = top_address + output_offset;
|
| output_frame->SetFp(fp_value);
|
| if (trace_) {
|
| @@ -1435,10 +1497,10 @@ void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
|
| output_frame->SetTop(top_address);
|
|
|
| // Read caller's PC (JSFunction continuation) from the input frame.
|
| - unsigned input_frame_offset = input_frame_size - kPointerSize;
|
| - unsigned output_frame_offset = output_frame_size - kPointerSize;
|
| + unsigned input_frame_offset = input_frame_size - kPCOnStackSize;
|
| + unsigned output_frame_offset = output_frame_size - kFPOnStackSize;
|
| intptr_t value = input_->GetFrameSlot(input_frame_offset);
|
| - output_frame->SetFrameSlot(output_frame_offset, value);
|
| + output_frame->SetCallerPc(output_frame_offset, value);
|
| if (trace_) {
|
| PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
|
| V8PRIxPTR " ; caller's pc\n",
|
| @@ -1446,10 +1508,10 @@ void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
|
| }
|
|
|
| // Read caller's FP from the input frame, and set this frame's FP.
|
| - input_frame_offset -= kPointerSize;
|
| + input_frame_offset -= kFPOnStackSize;
|
| value = input_->GetFrameSlot(input_frame_offset);
|
| - output_frame_offset -= kPointerSize;
|
| - output_frame->SetFrameSlot(output_frame_offset, value);
|
| + output_frame_offset -= kFPOnStackSize;
|
| + output_frame->SetCallerFp(output_frame_offset, value);
|
| intptr_t frame_ptr = input_->GetRegister(fp_reg.code());
|
| output_frame->SetRegister(fp_reg.code(), frame_ptr);
|
| output_frame->SetFp(frame_ptr);
|
| @@ -2569,21 +2631,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),
|
|
|