Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/code_generator.h" | 5 #include "vm/code_generator.h" |
| 6 | 6 |
| 7 #include "vm/assembler_macros.h" | 7 #include "vm/assembler_macros.h" |
| 8 #include "vm/ast.h" | 8 #include "vm/ast.h" |
| 9 #include "vm/code_patcher.h" | 9 #include "vm/code_patcher.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| 11 #include "vm/dart_api_impl.h" | 11 #include "vm/dart_api_impl.h" |
| 12 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
| 13 #include "vm/debugger.h" | 13 #include "vm/debugger.h" |
| 14 #include "vm/exceptions.h" | 14 #include "vm/exceptions.h" |
| 15 #include "vm/intermediate_language.h" | |
| 15 #include "vm/object_store.h" | 16 #include "vm/object_store.h" |
| 16 #include "vm/message.h" | 17 #include "vm/message.h" |
| 17 #include "vm/message_handler.h" | 18 #include "vm/message_handler.h" |
| 18 #include "vm/resolver.h" | 19 #include "vm/resolver.h" |
| 19 #include "vm/runtime_entry.h" | 20 #include "vm/runtime_entry.h" |
| 20 #include "vm/stack_frame.h" | 21 #include "vm/stack_frame.h" |
| 21 #include "vm/symbols.h" | 22 #include "vm/symbols.h" |
| 22 #include "vm/verifier.h" | 23 #include "vm/verifier.h" |
| 23 | 24 |
| 24 namespace dart { | 25 namespace dart { |
| (...skipping 1372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1397 #define DEOPT_REASON_ID_TO_TEXT(name) case k##name: return #name; | 1398 #define DEOPT_REASON_ID_TO_TEXT(name) case k##name: return #name; |
| 1398 DEOPT_REASONS(DEOPT_REASON_ID_TO_TEXT) | 1399 DEOPT_REASONS(DEOPT_REASON_ID_TO_TEXT) |
| 1399 #undef DEOPT_REASON_ID_TO_TEXT | 1400 #undef DEOPT_REASON_ID_TO_TEXT |
| 1400 default: | 1401 default: |
| 1401 UNREACHABLE(); | 1402 UNREACHABLE(); |
| 1402 return ""; | 1403 return ""; |
| 1403 } | 1404 } |
| 1404 } | 1405 } |
| 1405 | 1406 |
| 1406 | 1407 |
| 1407 // The top Dart frame belongs to the optimized method that needs to be | 1408 static intptr_t GetDeoptInfo(const Code& code, uword pc) { |
| 1408 // deoptimized. The pc of the Dart frame points to the deoptimization point. | 1409 const PcDescriptors& descriptors = |
| 1409 // Find the node id of the deoptimization point and find the continuation | 1410 PcDescriptors::Handle(code.pc_descriptors()); |
| 1410 // pc in the unoptimized code. | 1411 ASSERT(!descriptors.IsNull()); |
| 1411 // Since both unoptimized and optimized code have the same layout, we need only | 1412 // Locate deopt id at deoptimization point inside optimized code. |
| 1412 // to patch the pc of the Dart frame and to disable/enable appropriate code. | 1413 for (int i = 0; i < descriptors.Length(); i++) { |
| 1413 DEFINE_RUNTIME_ENTRY(Deoptimize, 1) { | 1414 if (static_cast<uword>(descriptors.PC(i)) == pc) { |
| 1414 ASSERT(arguments.Count() == kDeoptimizeRuntimeEntry.argument_count()); | 1415 return descriptors.NodeId(i); |
| 1415 const Smi& deoptimization_reason_id = Smi::CheckedHandle(arguments.At(0)); | 1416 } |
| 1416 DartFrameIterator iterator; | 1417 } |
| 1418 return Computation::kNoCid; | |
| 1419 } | |
| 1420 | |
| 1421 | |
| 1422 // Copy saved registers and caller's frame into temporary buffers. | |
| 1423 // Access the deopt information for the deoptimziation point. | |
|
siva
2012/07/31 01:59:12
deoptimization
srdjan
2012/07/31 16:21:28
Done.
| |
| 1424 // Return the new stack size (including PC marker and deopt return address, | |
| 1425 // excluding FP). | |
| 1426 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, | |
| 1427 intptr_t deopt_reason, | |
| 1428 intptr_t* saved_registers_address) { | |
| 1429 Isolate* isolate = Isolate::Current(); | |
| 1430 Zone zone(isolate); | |
| 1431 HANDLESCOPE(isolate); | |
| 1432 | |
| 1433 // Copy saved registers. | |
| 1434 intptr_t* registers_copy = new intptr_t[kNumberOfCpuRegisters]; | |
|
siva
2012/07/31 01:59:12
ASSERT(saved_registers_address != NULL);
ASSERT(re
srdjan
2012/07/31 16:21:28
Done.
| |
| 1435 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) { | |
| 1436 registers_copy[i] = *saved_registers_address; | |
| 1437 saved_registers_address++; | |
| 1438 } | |
| 1439 isolate->set_deopt_registers_copy(registers_copy); | |
| 1440 | |
| 1441 DartFrameIterator iterator(reinterpret_cast<uword>(saved_registers_address)); | |
|
siva
2012/07/31 01:59:12
maybe instead of saved_registers_address you could
srdjan
2012/07/31 16:21:28
Done.
| |
| 1442 StackFrame* caller_frame = iterator.NextFrame(); | |
| 1443 ASSERT(caller_frame != NULL); | |
| 1444 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); | |
| 1445 ASSERT(optimized_code.is_optimized()); | |
| 1446 | |
| 1447 const intptr_t deopt_id = GetDeoptInfo(optimized_code, caller_frame->pc()); | |
| 1448 ASSERT(deopt_id != Computation::kNoCid); | |
| 1449 | |
| 1450 // Add incoming arguments. | |
| 1451 const Function& function = Function::Handle(optimized_code.function()); | |
| 1452 // Think of copied arguments. | |
| 1453 const intptr_t num_args = (function.num_optional_parameters() > 0) ? | |
| 1454 0 : function.num_fixed_parameters(); | |
| 1455 // FP, PC marker and return address will all be copied. | |
| 1456 const intptr_t frame_copy_size = | |
| 1457 1 // Deoptimized function's return address: caller_frame->pc(). | |
| 1458 + ((caller_frame->fp() - caller_frame->sp()) / kWordSize) | |
| 1459 + 1 // PC marker. | |
| 1460 + 1 // Caller return address. | |
| 1461 + num_args; | |
| 1462 intptr_t* frame_copy = new intptr_t[frame_copy_size]; | |
| 1463 isolate->SetDeoptFrameCopy(frame_copy, frame_copy_size); | |
|
siva
2012/07/31 01:59:12
for consistency you should probably set frame_copy
srdjan
2012/07/31 16:21:28
Done.
| |
| 1464 // Include the return address of deoptimized code. | |
| 1465 intptr_t* start = reinterpret_cast<intptr_t*>(caller_frame->sp() - kWordSize); | |
| 1466 for (intptr_t i = 0; i < frame_copy_size; i++) { | |
| 1467 frame_copy[i] = *(start + i); | |
| 1468 } | |
| 1469 if (FLAG_trace_deopt) { | |
| 1470 OS::Print("Deoptimizing (reason %d '%s') at pc 0x%x id %d '%s'\n", | |
| 1471 deopt_reason, | |
| 1472 DeoptReasonToText(deopt_reason), | |
| 1473 caller_frame->pc(), | |
| 1474 deopt_id, | |
| 1475 function.ToFullyQualifiedCString()); | |
| 1476 } | |
| 1477 // TODO(srdjan): find deopt info and the size of stack, currently stack size | |
| 1478 // is the same as before. | |
| 1479 const intptr_t stack_size_in_bytes = caller_frame->fp() - caller_frame->sp(); | |
| 1480 // Include the space for return address. | |
| 1481 return stack_size_in_bytes + kWordSize; | |
| 1482 } | |
| 1483 END_LEAF_RUNTIME_ENTRY | |
| 1484 | |
| 1485 | |
| 1486 // The stack has been adjusted to fit all values for unoptimized frame. | |
| 1487 // Fill the unoptimized frame. | |
| 1488 DEFINE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, uword last_fp) { | |
| 1489 Isolate* isolate = Isolate::Current(); | |
| 1490 Zone zone(isolate); | |
| 1491 HANDLESCOPE(isolate); | |
| 1492 | |
| 1493 DartFrameIterator iterator(last_fp); | |
| 1417 StackFrame* caller_frame = iterator.NextFrame(); | 1494 StackFrame* caller_frame = iterator.NextFrame(); |
| 1418 ASSERT(caller_frame != NULL); | 1495 ASSERT(caller_frame != NULL); |
| 1419 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); | 1496 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); |
| 1420 const Function& function = Function::Handle(optimized_code.function()); | 1497 const Function& function = Function::Handle(optimized_code.function()); |
| 1421 ASSERT(!function.IsNull()); | 1498 ASSERT(!function.IsNull()); |
| 1422 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); | 1499 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); |
|
siva
2012/07/31 01:59:12
At this point it is possible that there is no unop
srdjan
2012/07/31 16:21:28
Function always refers to unoptimized code, i.e.,
| |
| 1423 ASSERT(!optimized_code.IsNull() && optimized_code.is_optimized()); | 1500 ASSERT(!optimized_code.IsNull() && optimized_code.is_optimized()); |
| 1424 ASSERT(!unoptimized_code.IsNull() && !unoptimized_code.is_optimized()); | 1501 ASSERT(!unoptimized_code.IsNull() && !unoptimized_code.is_optimized()); |
| 1425 const PcDescriptors& descriptors = | 1502 |
| 1426 PcDescriptors::Handle(optimized_code.pc_descriptors()); | 1503 intptr_t* frame_copy = isolate->deopt_frame_copy(); |
|
siva
2012/07/31 01:59:12
the setter function is named SetDeoptFrameCopy and
srdjan
2012/07/31 16:21:28
SetDeoptFrameCopy sets the size and the buffer, it
| |
| 1427 ASSERT(!descriptors.IsNull()); | 1504 intptr_t* registers_copy = isolate->deopt_registers_copy(); |
|
siva
2012/07/31 01:59:12
Where is registers_copy used in this code?
srdjan
2012/07/31 16:21:28
Current deoptimization stubs already save the regi
| |
| 1428 // Locate node id at deoptimization point inside optimized code. | 1505 |
| 1429 intptr_t deopt_node_id = AstNode::kNoId; | 1506 intptr_t deopt_id = GetDeoptInfo(optimized_code, caller_frame->pc()); |
| 1430 intptr_t deopt_token_index = 0; | 1507 ASSERT(deopt_id != Computation::kNoCid); |
| 1431 for (int i = 0; i < descriptors.Length(); i++) { | 1508 uword continue_at_pc = unoptimized_code.GetDeoptPcAtNodeId(deopt_id); |
| 1432 if (static_cast<uword>(descriptors.PC(i)) == caller_frame->pc()) { | 1509 if (FLAG_trace_deopt) { |
| 1433 deopt_node_id = descriptors.NodeId(i); | 1510 OS::Print(" -> continue at 0x%x\n", continue_at_pc); |
| 1434 deopt_token_index = descriptors.TokenIndex(i); | 1511 // TODO(srdjan): If we could allow GC, we could print the line where |
| 1435 break; | 1512 // deoptimization occured. |
| 1436 } | |
| 1437 } | 1513 } |
| 1438 ASSERT(deopt_node_id != AstNode::kNoId); | 1514 const intptr_t deopt_frame_copy_size = isolate->deopt_frame_copy_size(); |
| 1439 uword continue_at_pc = | 1515 // TODO(srdjan): Use deopt info to copy the values to right place. |
| 1440 unoptimized_code.GetDeoptPcAtNodeId(deopt_node_id); | 1516 const intptr_t pc_marker_index = |
| 1441 ASSERT(continue_at_pc != 0); | 1517 ((caller_frame->fp() - caller_frame->sp()) / kWordSize); |
| 1442 if (FLAG_trace_deopt) { | |
| 1443 OS::Print("Deoptimizing (reason %d '%s') at pc 0x%x id %d '%s' " | |
| 1444 "-> continue at 0x%x \n", | |
| 1445 deoptimization_reason_id.Value(), | |
| 1446 DeoptReasonToText(deoptimization_reason_id.Value()), | |
| 1447 caller_frame->pc(), | |
| 1448 deopt_node_id, | |
| 1449 function.ToFullyQualifiedCString(), | |
| 1450 continue_at_pc); | |
| 1451 const Class& cls = Class::Handle(function.owner()); | |
| 1452 const Script& script = Script::Handle(cls.script()); | |
| 1453 intptr_t line, column; | |
| 1454 script.GetTokenLocation(deopt_token_index, &line, &column); | |
| 1455 OS::Print(" Line: %d Column: %d ", line, column); | |
| 1456 OS::Print(">> %s\n", String::Handle(script.GetLine(line)).ToCString()); | |
| 1457 } | |
| 1458 // Patch the return PC and saved PC marker in frame to point to the | 1518 // Patch the return PC and saved PC marker in frame to point to the |
| 1459 // unoptimized version. | 1519 // unoptimized version. |
| 1460 caller_frame->set_pc(continue_at_pc); | 1520 frame_copy[0] = continue_at_pc; |
| 1461 caller_frame->SetEntrypointMarker( | 1521 frame_copy[pc_marker_index] = unoptimized_code.EntryPoint() + |
| 1462 unoptimized_code.EntryPoint() + | 1522 AssemblerMacros::kOffsetOfSavedPCfromEntrypoint; |
| 1463 AssemblerMacros::kOffsetOfSavedPCfromEntrypoint); | 1523 intptr_t* start = reinterpret_cast<intptr_t*>(caller_frame->sp() - kWordSize); |
| 1524 for (intptr_t i = 0; i < deopt_frame_copy_size; i++) { | |
| 1525 *(start + i) = frame_copy[i]; | |
| 1526 } | |
| 1527 isolate->SetDeoptFrameCopy(NULL, 0); | |
| 1528 isolate->set_deopt_registers_copy(NULL); | |
| 1529 delete[] frame_copy; | |
| 1530 delete[] registers_copy; | |
| 1464 | 1531 |
| 1465 // Clear invocation counter so that the function gets optimized after | 1532 // Clear invocation counter so that the function gets optimized after |
| 1466 // types/classes have been collected. | 1533 // classes have been collected. |
| 1467 function.set_usage_counter(0); | 1534 function.set_usage_counter(0); |
| 1468 function.set_deoptimization_counter(function.deoptimization_counter() + 1); | 1535 function.set_deoptimization_counter(function.deoptimization_counter() + 1); |
| 1469 | 1536 |
| 1470 // We have to skip the following otherwise the compiler will complain | |
| 1471 // when it attempts to install unoptimized code into a function that | |
| 1472 // was already deoptimized. | |
| 1473 if (function.HasOptimizedCode()) { | 1537 if (function.HasOptimizedCode()) { |
| 1474 // Get unoptimized code. Compilation restores (reenables) the entry of | 1538 function.SwitchToUnoptimizedCode(); |
| 1475 // unoptimized code. | |
| 1476 const Error& error = Error::Handle(Compiler::CompileFunction(function)); | |
| 1477 if (!error.IsNull()) { | |
| 1478 Exceptions::PropagateError(error); | |
| 1479 } | |
| 1480 } | |
| 1481 // TODO(srdjan): Handle better complex cases, e.g. when an older optimized | |
| 1482 // code is alive on frame and gets deoptimized after the function was | |
| 1483 // optimized a second time. | |
| 1484 if (FLAG_trace_deopt) { | |
| 1485 OS::Print("After patching ->0x%x:\n", continue_at_pc); | |
| 1486 } | 1539 } |
| 1487 } | 1540 } |
| 1541 END_LEAF_RUNTIME_ENTRY | |
| 1488 | 1542 |
| 1489 | 1543 |
| 1490 // We are entering function name for a valid argument count. | 1544 // We are entering function name for a valid argument count. |
| 1491 void FunctionsCache::EnterFunctionAt(int i, | 1545 void FunctionsCache::EnterFunctionAt(int i, |
| 1492 const Array& cache, | 1546 const Array& cache, |
| 1493 const Function& function, | 1547 const Function& function, |
| 1494 int num_arguments, | 1548 int num_arguments, |
| 1495 int num_named_arguments) { | 1549 int num_named_arguments) { |
| 1496 ASSERT((i % kNumEntries) == 0); | 1550 ASSERT((i % kNumEntries) == 0); |
| 1497 ASSERT(function.AreValidArgumentCounts(num_arguments, | 1551 ASSERT(function.AreValidArgumentCounts(num_arguments, |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1568 } | 1622 } |
| 1569 } | 1623 } |
| 1570 } | 1624 } |
| 1571 // The cache is null terminated, therefore the loop above should never | 1625 // The cache is null terminated, therefore the loop above should never |
| 1572 // terminate by itself. | 1626 // terminate by itself. |
| 1573 UNREACHABLE(); | 1627 UNREACHABLE(); |
| 1574 return Code::null(); | 1628 return Code::null(); |
| 1575 } | 1629 } |
| 1576 | 1630 |
| 1577 } // namespace dart | 1631 } // namespace dart |
| OLD | NEW |