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 14 matching lines...) Expand all Loading... |
386 public: | 399 public: |
387 explicit DeoptimizeWithMatchingCodeFilter(Code* code) : code_(code) {} | 400 explicit DeoptimizeWithMatchingCodeFilter(Code* code) : code_(code) {} |
388 virtual bool TakeFunction(JSFunction* function) { | 401 virtual bool TakeFunction(JSFunction* function) { |
389 return function->code() == code_; | 402 return function->code() == code_; |
390 } | 403 } |
391 private: | 404 private: |
392 Code* code_; | 405 Code* code_; |
393 }; | 406 }; |
394 | 407 |
395 | 408 |
| 409 class DeoptimizeMarkedCodeFilter : public OptimizedFunctionFilter { |
| 410 public: |
| 411 virtual bool TakeFunction(JSFunction* function) { |
| 412 return function->code()->marked_for_deoptimization(); |
| 413 } |
| 414 }; |
| 415 |
| 416 |
396 void Deoptimizer::DeoptimizeAll(Isolate* isolate) { | 417 void Deoptimizer::DeoptimizeAll(Isolate* isolate) { |
397 DisallowHeapAllocation no_allocation; | 418 DisallowHeapAllocation no_allocation; |
398 | 419 |
399 if (FLAG_trace_deopt) { | 420 if (FLAG_trace_deopt) { |
400 PrintF("[deoptimize all contexts]\n"); | 421 PrintF("[deoptimize all contexts]\n"); |
401 } | 422 } |
402 | 423 |
403 DeoptimizeAllFilter filter; | 424 DeoptimizeAllFilter filter; |
404 DeoptimizeAllFunctionsWith(isolate, &filter); | 425 DeoptimizeAllFunctionsWith(isolate, &filter); |
405 } | 426 } |
406 | 427 |
407 | 428 |
408 void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) { | 429 void Deoptimizer::DeoptimizeGlobalObject(JSObject* object) { |
409 DisallowHeapAllocation no_allocation; | 430 DisallowHeapAllocation no_allocation; |
410 DeoptimizeAllFilter filter; | 431 DeoptimizeAllFilter filter; |
411 if (object->IsJSGlobalProxy()) { | 432 if (object->IsJSGlobalProxy()) { |
412 Object* proto = object->GetPrototype(); | 433 Object* proto = object->GetPrototype(); |
413 ASSERT(proto->IsJSGlobalObject()); | 434 ASSERT(proto->IsJSGlobalObject()); |
414 DeoptimizeAllFunctionsForContext( | 435 DeoptimizeAllFunctionsForContext( |
415 GlobalObject::cast(proto)->native_context(), &filter); | 436 GlobalObject::cast(proto)->native_context(), &filter); |
416 } else if (object->IsGlobalObject()) { | 437 } else if (object->IsGlobalObject()) { |
417 DeoptimizeAllFunctionsForContext( | 438 DeoptimizeAllFunctionsForContext( |
418 GlobalObject::cast(object)->native_context(), &filter); | 439 GlobalObject::cast(object)->native_context(), &filter); |
419 } | 440 } |
420 } | 441 } |
421 | 442 |
422 | 443 |
423 void Deoptimizer::DeoptimizeFunction(JSFunction* function) { | 444 void Deoptimizer::DeoptimizeFunction(JSFunction* function) { |
424 if (!function->IsOptimized()) return; | |
425 Code* code = function->code(); | 445 Code* code = function->code(); |
426 Context* context = function->context()->native_context(); | 446 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); | 447 DeoptimizeWithMatchingCodeFilter filter(code); |
432 PartitionOptimizedFunctions(context, &filter, &codes, &zone, undefined); | 448 DeoptimizeAllFunctionsForContext( |
433 ASSERT_EQ(1, codes.length()); | 449 function->context()->native_context(), &filter); |
434 DeoptimizeFunctionWithPreparedFunctionList( | |
435 JSFunction::cast(codes.at(0)->deoptimizing_functions())); | |
436 codes.at(0)->set_deoptimizing_functions(undefined); | |
437 } | 450 } |
438 | 451 |
439 | 452 |
440 void Deoptimizer::DeoptimizeAllFunctionsForContext( | 453 void Deoptimizer::DeoptimizeAllFunctionsForContext( |
441 Context* context, OptimizedFunctionFilter* filter) { | 454 Context* context, OptimizedFunctionFilter* filter) { |
442 ASSERT(context->IsNativeContext()); | 455 ASSERT(context->IsNativeContext()); |
443 Isolate* isolate = context->GetIsolate(); | 456 Isolate* isolate = context->GetIsolate(); |
444 Object* undefined = isolate->heap()->undefined_value(); | 457 Object* undefined = isolate->heap()->undefined_value(); |
445 Zone zone(isolate); | 458 Zone zone(isolate); |
446 ZoneList<Code*> codes(1, &zone); | 459 ZoneList<Code*> codes(4, &zone); |
447 PartitionOptimizedFunctions(context, filter, &codes, &zone, undefined); | 460 SelectCodeToDeoptimize(context, filter, &codes, &zone, undefined); |
448 for (int i = 0; i < codes.length(); ++i) { | 461 for (int i = 0; i < codes.length(); i++) { |
449 DeoptimizeFunctionWithPreparedFunctionList( | 462 DeoptimizeCode(isolate, codes.at(i)); |
450 JSFunction::cast(codes.at(i)->deoptimizing_functions())); | |
451 codes.at(i)->set_deoptimizing_functions(undefined); | |
452 } | 463 } |
453 } | 464 } |
454 | 465 |
455 | 466 |
456 void Deoptimizer::DeoptimizeAllFunctionsWith(Isolate* isolate, | 467 void Deoptimizer::DeoptimizeAllFunctionsWith(Isolate* isolate, |
457 OptimizedFunctionFilter* filter) { | 468 OptimizedFunctionFilter* filter) { |
458 DisallowHeapAllocation no_allocation; | 469 DisallowHeapAllocation no_allocation; |
459 | 470 |
460 // Run through the list of all native contexts and deoptimize. | 471 // Run through the list of all native contexts and deoptimize. |
461 Object* context = isolate->heap()->native_contexts_list(); | 472 Object* context = isolate->heap()->native_contexts_list(); |
462 while (!context->IsUndefined()) { | 473 while (!context->IsUndefined()) { |
463 DeoptimizeAllFunctionsForContext(Context::cast(context), filter); | 474 DeoptimizeAllFunctionsForContext(Context::cast(context), filter); |
464 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); | 475 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); |
465 } | 476 } |
466 } | 477 } |
467 | 478 |
468 | 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); |
| 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 |