OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
324 // Run through the list of all native contexts and deoptimize. | 324 // Run through the list of all native contexts and deoptimize. |
325 Object* context = isolate->heap()->native_contexts_list(); | 325 Object* context = isolate->heap()->native_contexts_list(); |
326 while (!context->IsUndefined()) { | 326 while (!context->IsUndefined()) { |
327 VisitAllOptimizedFunctionsForContext(Context::cast(context), visitor); | 327 VisitAllOptimizedFunctionsForContext(Context::cast(context), visitor); |
328 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); | 328 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); |
329 } | 329 } |
330 } | 330 } |
331 | 331 |
332 | 332 |
333 // Removes the functions selected by the given filter from the optimized | 333 // Removes the functions selected by the given filter from the optimized |
334 // function list of the given context and partitions the removed functions | 334 // function list of the given context and adds their code to the list of |
335 // into one or more lists such that all functions in a list share the same | 335 // code objects to be deoptimized. |
336 // code. The head of each list is written in the deoptimizing_functions field | 336 static void SelectCodeToDeoptimize(Context* context, |
337 // of the corresponding code object. | 337 OptimizedFunctionFilter* filter, |
338 // The found code objects are returned in the given zone list. | 338 ZoneList<Code*>* codes, |
339 static void PartitionOptimizedFunctions(Context* context, | 339 Zone* zone, |
340 OptimizedFunctionFilter* filter, | 340 Object* undefined) { |
341 ZoneList<Code*>* partitions, | |
342 Zone* zone, | |
343 Object* undefined) { | |
344 DisallowHeapAllocation no_allocation; | 341 DisallowHeapAllocation no_allocation; |
345 Object* current = context->get(Context::OPTIMIZED_FUNCTIONS_LIST); | 342 Object* current = context->get(Context::OPTIMIZED_FUNCTIONS_LIST); |
346 Object* remainder_head = undefined; | 343 Object* remainder_head = undefined; |
347 Object* remainder_tail = undefined; | 344 Object* remainder_tail = undefined; |
348 ASSERT_EQ(0, partitions->length()); | 345 |
346 // TODO(titzer): rewrite to not modify unselected functions. | |
349 while (current != undefined) { | 347 while (current != undefined) { |
350 JSFunction* function = JSFunction::cast(current); | 348 JSFunction* function = JSFunction::cast(current); |
351 current = function->next_function_link(); | 349 current = function->next_function_link(); |
352 if (filter->TakeFunction(function)) { | 350 if (filter->TakeFunction(function)) { |
351 // Extract this function from the context's list and remember the code. | |
353 Code* code = function->code(); | 352 Code* code = function->code(); |
354 if (code->deoptimizing_functions() == undefined) { | 353 ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION); |
355 partitions->Add(code, zone); | 354 if (code->marked_for_deoptimization()) { |
355 ASSERT(codes->Contains(code)); | |
356 } else { | 356 } else { |
357 ASSERT(partitions->Contains(code)); | 357 code->set_marked_for_deoptimization(true); |
358 codes->Add(code, zone); | |
358 } | 359 } |
359 function->set_next_function_link(code->deoptimizing_functions()); | 360 SharedFunctionInfo* shared = function->shared(); |
360 code->set_deoptimizing_functions(function); | 361 // Replace the function's code with the shared code. |
362 function->set_code(shared->code()); | |
363 // Evict the code from the optimized code map. | |
364 shared->EvictFromOptimizedCodeMap(code, "deoptimized function"); | |
365 // Remove the function from the optimized functions list. | |
366 function->set_next_function_link(undefined); | |
367 | |
368 if (FLAG_trace_deopt) { | |
369 PrintF("[forced deoptimization: "); | |
370 function->PrintName(); | |
371 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function)); | |
372 } | |
361 } else { | 373 } else { |
374 // Don't select this function; link it back into the list. | |
362 if (remainder_head == undefined) { | 375 if (remainder_head == undefined) { |
363 remainder_head = function; | 376 remainder_head = function; |
364 } else { | 377 } else { |
365 JSFunction::cast(remainder_tail)->set_next_function_link(function); | 378 JSFunction::cast(remainder_tail)->set_next_function_link(function); |
366 } | 379 } |
367 remainder_tail = function; | 380 remainder_tail = function; |
368 } | 381 } |
369 } | 382 } |
370 if (remainder_tail != undefined) { | 383 if (remainder_tail != undefined) { |
371 JSFunction::cast(remainder_tail)->set_next_function_link(undefined); | 384 JSFunction::cast(remainder_tail)->set_next_function_link(undefined); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
414 DeoptimizeAllFunctionsForContext( | 427 DeoptimizeAllFunctionsForContext( |
415 GlobalObject::cast(proto)->native_context(), &filter); | 428 GlobalObject::cast(proto)->native_context(), &filter); |
416 } else if (object->IsGlobalObject()) { | 429 } else if (object->IsGlobalObject()) { |
417 DeoptimizeAllFunctionsForContext( | 430 DeoptimizeAllFunctionsForContext( |
418 GlobalObject::cast(object)->native_context(), &filter); | 431 GlobalObject::cast(object)->native_context(), &filter); |
419 } | 432 } |
420 } | 433 } |
421 | 434 |
422 | 435 |
423 void Deoptimizer::DeoptimizeFunction(JSFunction* function) { | 436 void Deoptimizer::DeoptimizeFunction(JSFunction* function) { |
424 if (!function->IsOptimized()) return; | |
425 Code* code = function->code(); | 437 Code* code = function->code(); |
426 Context* context = function->context()->native_context(); | 438 if (code->kind() != Code::OPTIMIZED_FUNCTION) return; |
427 Isolate* isolate = context->GetIsolate(); | |
428 Object* undefined = isolate->heap()->undefined_value(); | |
429 Zone zone(isolate); | |
430 ZoneList<Code*> codes(1, &zone); | |
431 DeoptimizeWithMatchingCodeFilter filter(code); | 439 DeoptimizeWithMatchingCodeFilter filter(code); |
432 PartitionOptimizedFunctions(context, &filter, &codes, &zone, undefined); | 440 DeoptimizeAllFunctionsForContext( |
433 ASSERT_EQ(1, codes.length()); | 441 function->context()->native_context(), &filter); |
434 DeoptimizeFunctionWithPreparedFunctionList( | |
435 JSFunction::cast(codes.at(0)->deoptimizing_functions())); | |
436 codes.at(0)->set_deoptimizing_functions(undefined); | |
437 } | 442 } |
438 | 443 |
439 | 444 |
440 void Deoptimizer::DeoptimizeAllFunctionsForContext( | 445 void Deoptimizer::DeoptimizeAllFunctionsForContext( |
441 Context* context, OptimizedFunctionFilter* filter) { | 446 Context* context, OptimizedFunctionFilter* filter) { |
442 ASSERT(context->IsNativeContext()); | 447 ASSERT(context->IsNativeContext()); |
443 Isolate* isolate = context->GetIsolate(); | 448 Isolate* isolate = context->GetIsolate(); |
444 Object* undefined = isolate->heap()->undefined_value(); | 449 Object* undefined = isolate->heap()->undefined_value(); |
445 Zone zone(isolate); | 450 Zone zone(isolate); |
446 ZoneList<Code*> codes(1, &zone); | 451 ZoneList<Code*> codes(4, &zone); |
447 PartitionOptimizedFunctions(context, filter, &codes, &zone, undefined); | 452 SelectCodeToDeoptimize(context, filter, &codes, &zone, undefined); |
448 for (int i = 0; i < codes.length(); ++i) { | 453 for (int i = 0; i < codes.length(); i++) { |
449 DeoptimizeFunctionWithPreparedFunctionList( | 454 DeoptimizeCode(isolate, codes.at(i)); |
450 JSFunction::cast(codes.at(i)->deoptimizing_functions())); | |
451 codes.at(i)->set_deoptimizing_functions(undefined); | |
452 } | 455 } |
453 } | 456 } |
454 | 457 |
455 | 458 |
456 void Deoptimizer::DeoptimizeAllFunctionsWith(Isolate* isolate, | 459 void Deoptimizer::DeoptimizeAllFunctionsWith(Isolate* isolate, |
457 OptimizedFunctionFilter* filter) { | 460 OptimizedFunctionFilter* filter) { |
458 DisallowHeapAllocation no_allocation; | 461 DisallowHeapAllocation no_allocation; |
459 | 462 |
460 // Run through the list of all native contexts and deoptimize. | 463 // Run through the list of all native contexts and deoptimize. |
461 Object* context = isolate->heap()->native_contexts_list(); | 464 Object* context = isolate->heap()->native_contexts_list(); |
462 while (!context->IsUndefined()) { | 465 while (!context->IsUndefined()) { |
463 DeoptimizeAllFunctionsForContext(Context::cast(context), filter); | 466 DeoptimizeAllFunctionsForContext(Context::cast(context), filter); |
464 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); | 467 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); |
465 } | 468 } |
466 } | 469 } |
467 | 470 |
468 | 471 |
472 class DeoptimizeMarkedCodeFilter : public OptimizedFunctionFilter { | |
473 public: | |
474 virtual bool TakeFunction(JSFunction* function) { | |
475 return function->code()->marked_for_deoptimization(); | |
476 } | |
477 }; | |
478 | |
479 | |
480 void Deoptimizer::DeoptimizeCodeList(Isolate* isolate, ZoneList<Code*>* codes) { | |
481 if (codes->length() == 0) return; // Nothing to do. | |
482 | |
483 // Mark the code; any functions refering to this code will be selected. | |
484 for (int i = 0; i < codes->length(); i++) { | |
485 ASSERT(!codes->at(i)->marked_for_deoptimization()); | |
486 codes->at(i)->set_marked_for_deoptimization(true); | |
ulan
2013/07/22 09:23:08
Maybe move marking for deoptimization to the place
titzer
2013/07/23 12:41:00
I wanted to keep the modification of this flag loc
| |
487 } | |
488 | |
489 // For all contexts, remove optimized functions that refer to the selected | |
490 // code from the optimized function lists. | |
491 Object* undefined = isolate->heap()->undefined_value(); | |
492 Zone zone(isolate); | |
493 Object* list = isolate->heap()->native_contexts_list(); | |
494 DeoptimizeMarkedCodeFilter filter; | |
495 while (!list->IsUndefined()) { | |
496 Context* context = Context::cast(list); | |
497 // Note that selecting code unlinks the functions that refer to it. | |
498 SelectCodeToDeoptimize(context, &filter, codes, &zone, undefined); | |
499 list = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); | |
500 } | |
501 | |
502 // Now deoptimize all the code. | |
503 for (int i = 0; i < codes->length(); i++) { | |
504 DeoptimizeCode(isolate, codes->at(i)); | |
505 } | |
506 } | |
507 | |
508 | |
509 void Deoptimizer::DeoptimizeCode(Isolate* isolate, Code* code) { | |
510 HandleScope scope(isolate); | |
511 DisallowHeapAllocation nha; | |
512 | |
513 // Do platform-specific patching of the optimized code. | |
514 PatchCodeForDeoptimization(isolate, code); | |
515 | |
516 // Add the deoptimizing code to the list. | |
517 DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code); | |
518 DeoptimizerData* data = isolate->deoptimizer_data(); | |
519 node->set_next(data->deoptimizing_code_list_); | |
520 data->deoptimizing_code_list_ = node; | |
521 | |
522 // We might be in the middle of incremental marking with compaction. | |
523 // Tell collector to treat this code object in a special way and | |
524 // ignore all slots that might have been recorded on it. | |
525 isolate->heap()->mark_compact_collector()->InvalidateCode(code); | |
526 } | |
527 | |
528 | |
469 void Deoptimizer::HandleWeakDeoptimizedCode(v8::Isolate* isolate, | 529 void Deoptimizer::HandleWeakDeoptimizedCode(v8::Isolate* isolate, |
470 v8::Persistent<v8::Value>* obj, | 530 v8::Persistent<v8::Value>* obj, |
471 void* parameter) { | 531 void* parameter) { |
472 DeoptimizingCodeListNode* node = | 532 DeoptimizingCodeListNode* node = |
473 reinterpret_cast<DeoptimizingCodeListNode*>(parameter); | 533 reinterpret_cast<DeoptimizingCodeListNode*>(parameter); |
474 DeoptimizerData* data = | 534 DeoptimizerData* data = |
475 reinterpret_cast<Isolate*>(isolate)->deoptimizer_data(); | 535 reinterpret_cast<Isolate*>(isolate)->deoptimizer_data(); |
476 data->RemoveDeoptimizingCode(*node->code()); | 536 data->RemoveDeoptimizingCode(*node->code()); |
477 #ifdef DEBUG | 537 #ifdef DEBUG |
478 for (DeoptimizingCodeListNode* current = data->deoptimizing_code_list_; | 538 for (DeoptimizingCodeListNode* current = data->deoptimizing_code_list_; |
(...skipping 2083 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2562 desc.instr_size); | 2622 desc.instr_size); |
2563 chunk->CommitArea(desc.instr_size); | 2623 chunk->CommitArea(desc.instr_size); |
2564 CopyBytes(chunk->area_start(), desc.buffer, | 2624 CopyBytes(chunk->area_start(), desc.buffer, |
2565 static_cast<size_t>(desc.instr_size)); | 2625 static_cast<size_t>(desc.instr_size)); |
2566 CPU::FlushICache(chunk->area_start(), desc.instr_size); | 2626 CPU::FlushICache(chunk->area_start(), desc.instr_size); |
2567 | 2627 |
2568 data->deopt_entry_code_entries_[type] = entry_count; | 2628 data->deopt_entry_code_entries_[type] = entry_count; |
2569 } | 2629 } |
2570 | 2630 |
2571 | 2631 |
2572 void Deoptimizer::ReplaceCodeForRelatedFunctions(JSFunction* function, | |
2573 Code* code) { | |
2574 SharedFunctionInfo* shared = function->shared(); | |
2575 Object* undefined = function->GetHeap()->undefined_value(); | |
2576 Object* current = function; | |
2577 | |
2578 while (current != undefined) { | |
2579 JSFunction* func = JSFunction::cast(current); | |
2580 current = func->next_function_link(); | |
2581 func->set_code(shared->code()); | |
2582 func->set_next_function_link(undefined); | |
2583 } | |
2584 } | |
2585 | |
2586 | |
2587 FrameDescription::FrameDescription(uint32_t frame_size, | 2632 FrameDescription::FrameDescription(uint32_t frame_size, |
2588 JSFunction* function) | 2633 JSFunction* function) |
2589 : frame_size_(frame_size), | 2634 : frame_size_(frame_size), |
2590 function_(function), | 2635 function_(function), |
2591 top_(kZapUint32), | 2636 top_(kZapUint32), |
2592 pc_(kZapUint32), | 2637 pc_(kZapUint32), |
2593 fp_(kZapUint32), | 2638 fp_(kZapUint32), |
2594 context_(kZapUint32) { | 2639 context_(kZapUint32) { |
2595 // Zap all the registers. | 2640 // Zap all the registers. |
2596 for (int r = 0; r < Register::kNumRegisters; r++) { | 2641 for (int r = 0; r < Register::kNumRegisters; r++) { |
(...skipping 499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3096 | 3141 |
3097 void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) { | 3142 void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) { |
3098 v->VisitPointer(BitCast<Object**>(&function_)); | 3143 v->VisitPointer(BitCast<Object**>(&function_)); |
3099 v->VisitPointers(parameters_, parameters_ + parameters_count_); | 3144 v->VisitPointers(parameters_, parameters_ + parameters_count_); |
3100 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_); | 3145 v->VisitPointers(expression_stack_, expression_stack_ + expression_count_); |
3101 } | 3146 } |
3102 | 3147 |
3103 #endif // ENABLE_DEBUGGER_SUPPORT | 3148 #endif // ENABLE_DEBUGGER_SUPPORT |
3104 | 3149 |
3105 } } // namespace v8::internal | 3150 } } // namespace v8::internal |
OLD | NEW |