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/deopt_instructions.h" | |
14 #include "vm/exceptions.h" | 15 #include "vm/exceptions.h" |
15 #include "vm/intermediate_language.h" | 16 #include "vm/intermediate_language.h" |
16 #include "vm/object_store.h" | 17 #include "vm/object_store.h" |
17 #include "vm/message.h" | 18 #include "vm/message.h" |
18 #include "vm/message_handler.h" | 19 #include "vm/message_handler.h" |
20 #include "vm/parser.h" | |
19 #include "vm/resolver.h" | 21 #include "vm/resolver.h" |
20 #include "vm/runtime_entry.h" | 22 #include "vm/runtime_entry.h" |
21 #include "vm/stack_frame.h" | 23 #include "vm/stack_frame.h" |
22 #include "vm/symbols.h" | 24 #include "vm/symbols.h" |
23 #include "vm/verifier.h" | 25 #include "vm/verifier.h" |
24 | 26 |
25 namespace dart { | 27 namespace dart { |
26 | 28 |
27 DEFINE_FLAG(bool, inline_cache, true, "Enable inline caches"); | 29 DEFINE_FLAG(bool, inline_cache, true, "Enable inline caches"); |
28 DEFINE_FLAG(bool, trace_deopt, false, "Trace deoptimization"); | 30 DEFINE_FLAG(bool, trace_deopt, false, "Trace deoptimization"); |
(...skipping 1352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1381 #define DEOPT_REASON_ID_TO_TEXT(name) case k##name: return #name; | 1383 #define DEOPT_REASON_ID_TO_TEXT(name) case k##name: return #name; |
1382 DEOPT_REASONS(DEOPT_REASON_ID_TO_TEXT) | 1384 DEOPT_REASONS(DEOPT_REASON_ID_TO_TEXT) |
1383 #undef DEOPT_REASON_ID_TO_TEXT | 1385 #undef DEOPT_REASON_ID_TO_TEXT |
1384 default: | 1386 default: |
1385 UNREACHABLE(); | 1387 UNREACHABLE(); |
1386 return ""; | 1388 return ""; |
1387 } | 1389 } |
1388 } | 1390 } |
1389 | 1391 |
1390 | 1392 |
1391 static void GetDeoptInfo(const Code& code, | 1393 static void GetDeoptIxDescrAtPc(const Code& code, |
1392 uword pc, | 1394 uword pc, |
1393 intptr_t* deopt_id, | 1395 intptr_t* deopt_id, |
1394 intptr_t* deopt_reason) { | 1396 intptr_t* deopt_reason, |
1397 intptr_t* deopt_index) { | |
1395 const PcDescriptors& descriptors = | 1398 const PcDescriptors& descriptors = |
1396 PcDescriptors::Handle(code.pc_descriptors()); | 1399 PcDescriptors::Handle(code.pc_descriptors()); |
1397 ASSERT(!descriptors.IsNull()); | 1400 ASSERT(!descriptors.IsNull()); |
1398 // Locate deopt id at deoptimization point inside optimized code. | 1401 // Locate deopt id at deoptimization point inside optimized code. |
1399 for (int i = 0; i < descriptors.Length(); i++) { | 1402 for (int i = 0; i < descriptors.Length(); i++) { |
1400 if ((static_cast<uword>(descriptors.PC(i)) == pc) && | 1403 if ((static_cast<uword>(descriptors.PC(i)) == pc) && |
1401 (descriptors.DescriptorKind(i) == PcDescriptors::kDeoptIndex)) { | 1404 (descriptors.DescriptorKind(i) == PcDescriptors::kDeoptIndex)) { |
1402 *deopt_id = descriptors.DeoptId(i); | 1405 *deopt_id = descriptors.DeoptId(i); |
1403 *deopt_reason = descriptors.DeoptReason(i); | 1406 *deopt_reason = descriptors.DeoptReason(i); |
1407 *deopt_index = descriptors.DeoptIndex(i); | |
1404 return; | 1408 return; |
1405 } | 1409 } |
1406 } | 1410 } |
1407 *deopt_id = Isolate::kNoDeoptId; | 1411 *deopt_id = Isolate::kNoDeoptId; |
1408 *deopt_reason = kDeoptUnknown; | 1412 *deopt_reason = kDeoptUnknown; |
1413 *deopt_index = -1; | |
1409 } | 1414 } |
1410 | 1415 |
1411 | 1416 |
1412 // Copy saved registers and caller's frame into temporary buffers. | |
1413 // Access the deopt information for the deoptimization point. | |
1414 // Return the new stack size (including PC marker and deopt return address, | |
1415 // excluding FP). | |
1416 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, | |
1417 intptr_t* saved_registers_address) { | |
1418 Isolate* isolate = Isolate::Current(); | |
1419 Zone zone(isolate); | |
1420 HANDLESCOPE(isolate); | |
1421 | 1417 |
1422 const uword last_fp = | 1418 // Copy saved registers into the isolate buffer. |
1423 reinterpret_cast<uword>(saved_registers_address + kNumberOfCpuRegisters); | 1419 static void CopySavedRegisters(intptr_t* saved_registers_address) { |
1424 // Copy saved registers. | |
1425 intptr_t* registers_copy = new intptr_t[kNumberOfCpuRegisters]; | 1420 intptr_t* registers_copy = new intptr_t[kNumberOfCpuRegisters]; |
siva
2012/08/09 21:38:19
Why did you choose to make the register copy an al
srdjan
2012/08/09 23:28:30
I did not want to always allocate one per Isolate.
| |
1426 ASSERT(registers_copy != NULL); | 1421 ASSERT(registers_copy != NULL); |
1427 ASSERT(saved_registers_address != NULL); | 1422 ASSERT(saved_registers_address != NULL); |
1428 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) { | 1423 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) { |
1429 registers_copy[i] = *saved_registers_address; | 1424 registers_copy[i] = *saved_registers_address; |
1430 saved_registers_address++; | 1425 saved_registers_address++; |
1431 } | 1426 } |
1432 isolate->set_deopt_registers_copy(registers_copy); | 1427 Isolate::Current()->set_deopt_registers_copy(registers_copy); |
siva
2012/08/09 21:38:19
We should add an assert in set_deopt_registers_cop
srdjan
2012/08/09 23:28:30
And prevents memory leak ... good idea, done.
| |
1433 ASSERT(reinterpret_cast<uword>(saved_registers_address) == last_fp); | 1428 } |
1429 | |
1430 | |
1431 // Copy optimized frame into the isolate buffer. | |
1432 // The first incoming argument is stored at the last entry in the | |
1433 // copied frame buffer. | |
1434 static void CopyFrame(const Code& optimized_code, const StackFrame& frame) { | |
1435 const Function& function = Function::Handle(optimized_code.function()); | |
1436 // Do not copy incoming arguments if there are optional arguments (they | |
1437 // are copied into local space at method entry). | |
1438 const intptr_t num_args = (function.num_optional_parameters() > 0) ? | |
1439 0 : function.num_fixed_parameters(); | |
1440 // FP, PC-marker and return-address will be copied as well. | |
1441 const intptr_t frame_copy_size = | |
1442 1 // Deoptimized function's return address: caller_frame->pc(). | |
1443 + ((frame.fp() - frame.sp()) / kWordSize) | |
1444 + 1 // PC marker. | |
1445 + 1 // Caller return address. | |
1446 + num_args; | |
1447 intptr_t* frame_copy = new intptr_t[frame_copy_size]; | |
1448 ASSERT(frame_copy != NULL); | |
1449 // Include the return address of optimized code. | |
1450 intptr_t* start = reinterpret_cast<intptr_t*>(frame.sp() - kWordSize); | |
1451 for (intptr_t i = 0; i < frame_copy_size; i++) { | |
1452 frame_copy[i] = *(start + i); | |
1453 } | |
1454 Isolate::Current()->SetDeoptFrameCopy(frame_copy, frame_copy_size); | |
siva
2012/08/09 21:38:19
Similarly assert
ASSERT(deopt_frame_copy_ == NULL)
srdjan
2012/08/09 23:28:30
Done.
| |
1455 } | |
1456 | |
1457 | |
1458 // Copies saved registers and caller's frame into temporary buffers. | |
1459 // Returns the stack size of unoptimzied frame. | |
1460 DEFINE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, | |
1461 intptr_t* saved_registers_address) { | |
1462 Isolate* isolate = Isolate::Current(); | |
1463 Zone zone(isolate); | |
1464 HANDLESCOPE(isolate); | |
1465 | |
1466 // All registers have been saved below last-fp. | |
1467 const uword last_fp = | |
1468 reinterpret_cast<uword>(saved_registers_address + kNumberOfCpuRegisters); | |
1469 CopySavedRegisters(saved_registers_address); | |
1470 | |
1471 // Get optimized code and frame that need to be deoptimized. | |
1434 DartFrameIterator iterator(last_fp); | 1472 DartFrameIterator iterator(last_fp); |
1435 StackFrame* caller_frame = iterator.NextFrame(); | 1473 StackFrame* caller_frame = iterator.NextFrame(); |
1436 ASSERT(caller_frame != NULL); | 1474 ASSERT(caller_frame != NULL); |
1437 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); | 1475 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); |
1438 ASSERT(optimized_code.is_optimized()); | 1476 ASSERT(optimized_code.is_optimized()); |
1439 | 1477 |
1440 intptr_t deopt_id, deopt_reason; | 1478 intptr_t deopt_id, deopt_reason, deopt_index; |
1441 GetDeoptInfo(optimized_code, caller_frame->pc(), &deopt_id, &deopt_reason); | 1479 GetDeoptIxDescrAtPc(optimized_code, caller_frame->pc(), |
1480 &deopt_id, &deopt_reason, &deopt_index); | |
1442 ASSERT(deopt_id != Isolate::kNoDeoptId); | 1481 ASSERT(deopt_id != Isolate::kNoDeoptId); |
1443 | 1482 |
1444 // Add incoming arguments. | 1483 CopyFrame(optimized_code, *caller_frame); |
1445 const Function& function = Function::Handle(optimized_code.function()); | |
1446 // Think of copied arguments. | |
1447 const intptr_t num_args = (function.num_optional_parameters() > 0) ? | |
1448 0 : function.num_fixed_parameters(); | |
1449 // FP, PC marker and return address will all be copied. | |
1450 const intptr_t frame_copy_size = | |
1451 1 // Deoptimized function's return address: caller_frame->pc(). | |
1452 + ((caller_frame->fp() - caller_frame->sp()) / kWordSize) | |
1453 + 1 // PC marker. | |
1454 + 1 // Caller return address. | |
1455 + num_args; | |
1456 intptr_t* frame_copy = new intptr_t[frame_copy_size]; | |
1457 ASSERT(frame_copy != NULL); | |
1458 // Include the return address of deoptimized code. | |
1459 intptr_t* start = reinterpret_cast<intptr_t*>(caller_frame->sp() - kWordSize); | |
1460 for (intptr_t i = 0; i < frame_copy_size; i++) { | |
1461 frame_copy[i] = *(start + i); | |
1462 } | |
1463 isolate->SetDeoptFrameCopy(frame_copy, frame_copy_size); | |
1464 if (FLAG_trace_deopt) { | 1484 if (FLAG_trace_deopt) { |
1485 intptr_t deopt_id, deopt_reason, deopt_index; | |
1486 GetDeoptIxDescrAtPc(optimized_code, caller_frame->pc(), | |
1487 &deopt_id, &deopt_reason, &deopt_index); | |
1465 OS::Print("Deoptimizing (reason %d '%s') at pc 0x%x id %d '%s'\n", | 1488 OS::Print("Deoptimizing (reason %d '%s') at pc 0x%x id %d '%s'\n", |
1466 deopt_reason, | 1489 deopt_reason, |
1467 DeoptReasonToText(deopt_reason), | 1490 DeoptReasonToText(deopt_reason), |
1468 caller_frame->pc(), | 1491 caller_frame->pc(), |
1469 deopt_id, | 1492 deopt_id, |
1470 function.ToFullyQualifiedCString()); | 1493 Function::Handle(optimized_code.function()).ToFullyQualifiedCString()); |
1471 } | 1494 } |
1472 // TODO(srdjan): find deopt info and the size of stack, currently stack size | 1495 |
1473 // is the same as before. | 1496 // Compute the stack size of unoptimized frame |
1474 const intptr_t stack_size_in_bytes = caller_frame->fp() - caller_frame->sp(); | 1497 const Array& deopt_info_array = |
1475 // Include the space for return address. | 1498 Array::Handle(optimized_code.deopt_info_array()); |
1476 return stack_size_in_bytes + kWordSize; | 1499 ASSERT(!deopt_info_array.IsNull()); |
1500 DeoptInfo& deopt_info = DeoptInfo::Handle(); | |
1501 deopt_info ^= deopt_info_array.At(deopt_index); | |
1502 if (deopt_info.IsNull()) { | |
1503 // TODO(srdjan): Deprecate. | |
1504 // Include the space for return address. | |
1505 intptr_t stack_size_in_bytes = caller_frame->fp() - caller_frame->sp(); | |
1506 return stack_size_in_bytes + kWordSize; | |
1507 } else { | |
1508 // For functions with optional argument deoptimization info does not | |
1509 // describe incoming arguments. | |
1510 const Function& function = Function::Handle(optimized_code.function()); | |
1511 const intptr_t num_args = (function.num_optional_parameters() > 0) ? | |
1512 0 : function.num_fixed_parameters(); | |
1513 intptr_t unoptimized_stack_size = | |
1514 + deopt_info.Length() - num_args | |
1515 - 2; // Subtract caller FP and PC. | |
1516 return unoptimized_stack_size * kWordSize; | |
1517 } | |
1477 } | 1518 } |
1478 END_LEAF_RUNTIME_ENTRY | 1519 END_LEAF_RUNTIME_ENTRY |
1479 | 1520 |
1480 | 1521 |
1522 | |
1523 static void DeoptimizeWithDeoptInfo(const Code& code, | |
1524 const DeoptInfo& deopt_info, | |
1525 const StackFrame& caller_frame) { | |
1526 const intptr_t len = deopt_info.Length(); | |
1527 GrowableArray<DeoptInstr*> deopt_instructions(len); | |
1528 for (intptr_t i = 0; i < len; i++) { | |
1529 deopt_instructions.Add(DeoptInstr::Create(deopt_info.Instruction(i), | |
1530 deopt_info.FromIndex(i))); | |
1531 } | |
1532 | |
1533 intptr_t* start = reinterpret_cast<intptr_t*>(caller_frame.sp() - kWordSize); | |
1534 const Function& function = Function::Handle(code.function()); | |
1535 const intptr_t num_args = (function.num_optional_parameters() > 0) ? | |
1536 0 : function.num_fixed_parameters(); | |
1537 DeoptimizationContext deopt_context(start, | |
1538 Array::Handle(code.object_table()), | |
1539 num_args); | |
1540 for (intptr_t to_index = 0; to_index < len; to_index++) { | |
1541 deopt_instructions[to_index]->Execute(&deopt_context, to_index); | |
1542 } | |
1543 if (FLAG_trace_deopt) { | |
1544 for (intptr_t i = 0; i < len; i++) { | |
1545 OS::Print("*%d. 0x%x [%s]\n", | |
1546 i, start[i], deopt_instructions[i]->ToCString()); | |
1547 } | |
1548 } | |
1549 } | |
1550 | |
1551 | |
1481 // The stack has been adjusted to fit all values for unoptimized frame. | 1552 // The stack has been adjusted to fit all values for unoptimized frame. |
1482 // Fill the unoptimized frame. | 1553 // Fill the unoptimized frame. |
1483 DEFINE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, uword last_fp) { | 1554 DEFINE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, uword last_fp) { |
1484 Isolate* isolate = Isolate::Current(); | 1555 Isolate* isolate = Isolate::Current(); |
1485 Zone zone(isolate); | 1556 Zone zone(isolate); |
1486 HANDLESCOPE(isolate); | 1557 HANDLESCOPE(isolate); |
1487 | 1558 |
1488 DartFrameIterator iterator(last_fp); | 1559 DartFrameIterator iterator(last_fp); |
1489 StackFrame* caller_frame = iterator.NextFrame(); | 1560 StackFrame* caller_frame = iterator.NextFrame(); |
1490 ASSERT(caller_frame != NULL); | 1561 ASSERT(caller_frame != NULL); |
1491 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); | 1562 const Code& optimized_code = Code::Handle(caller_frame->LookupDartCode()); |
1492 const Function& function = Function::Handle(optimized_code.function()); | 1563 const Function& function = Function::Handle(optimized_code.function()); |
1493 ASSERT(!function.IsNull()); | 1564 ASSERT(!function.IsNull()); |
1494 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); | 1565 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); |
1495 ASSERT(!optimized_code.IsNull() && optimized_code.is_optimized()); | 1566 ASSERT(!optimized_code.IsNull() && optimized_code.is_optimized()); |
1496 ASSERT(!unoptimized_code.IsNull() && !unoptimized_code.is_optimized()); | 1567 ASSERT(!unoptimized_code.IsNull() && !unoptimized_code.is_optimized()); |
1497 | 1568 |
1498 intptr_t* frame_copy = isolate->deopt_frame_copy(); | 1569 intptr_t* frame_copy = isolate->deopt_frame_copy(); |
1499 intptr_t* registers_copy = isolate->deopt_registers_copy(); | 1570 intptr_t* registers_copy = isolate->deopt_registers_copy(); |
1500 | 1571 |
1501 intptr_t deopt_id, deopt_reason; | 1572 intptr_t deopt_id, deopt_reason, deopt_index; |
1502 GetDeoptInfo(optimized_code, caller_frame->pc(), &deopt_id, &deopt_reason); | 1573 GetDeoptIxDescrAtPc(optimized_code, caller_frame->pc(), |
1574 &deopt_id, &deopt_reason, &deopt_index); | |
1503 ASSERT(deopt_id != Isolate::kNoDeoptId); | 1575 ASSERT(deopt_id != Isolate::kNoDeoptId); |
1504 uword continue_at_pc = unoptimized_code.GetDeoptPcAtDeoptId(deopt_id); | 1576 uword continue_at_pc = unoptimized_code.GetDeoptPcAtDeoptId(deopt_id); |
1505 if (FLAG_trace_deopt) { | 1577 if (FLAG_trace_deopt) { |
1506 OS::Print(" -> continue at 0x%x\n", continue_at_pc); | 1578 OS::Print(" -> continue at 0x%x\n", continue_at_pc); |
1507 // TODO(srdjan): If we could allow GC, we could print the line where | 1579 // TODO(srdjan): If we could allow GC, we could print the line where |
1508 // deoptimization occured. | 1580 // deoptimization occured. |
1509 } | 1581 } |
1510 const intptr_t deopt_frame_copy_size = isolate->deopt_frame_copy_size(); | 1582 const Array& deopt_info_array = |
1511 // TODO(srdjan): Use deopt info to copy the values to right place. | 1583 Array::Handle(optimized_code.deopt_info_array()); |
1512 const intptr_t pc_marker_index = | 1584 ASSERT(!deopt_info_array.IsNull()); |
1513 ((caller_frame->fp() - caller_frame->sp()) / kWordSize); | 1585 DeoptInfo& deopt_info = DeoptInfo::Handle(); |
1514 // Patch the return PC and saved PC marker in frame to point to the | 1586 deopt_info ^= deopt_info_array.At(deopt_index); |
1515 // unoptimized version. | 1587 if (deopt_info.IsNull()) { |
1516 frame_copy[0] = continue_at_pc; | 1588 // TODO(srdjan): Deprecate. |
1517 frame_copy[pc_marker_index] = unoptimized_code.EntryPoint() + | 1589 const intptr_t deopt_frame_copy_size = isolate->deopt_frame_copy_size(); |
1518 AssemblerMacros::kOffsetOfSavedPCfromEntrypoint; | 1590 const intptr_t pc_marker_index = |
1519 intptr_t* start = reinterpret_cast<intptr_t*>(caller_frame->sp() - kWordSize); | 1591 ((caller_frame->fp() - caller_frame->sp()) / kWordSize); |
1520 for (intptr_t i = 0; i < deopt_frame_copy_size; i++) { | 1592 // Patch the return PC and saved PC marker in frame to point to the |
1521 *(start + i) = frame_copy[i]; | 1593 // unoptimized version. |
1594 frame_copy[0] = continue_at_pc; | |
1595 frame_copy[pc_marker_index] = | |
1596 unoptimized_code.EntryPoint() + | |
1597 AssemblerMacros::kOffsetOfSavedPCfromEntrypoint; | |
1598 intptr_t* start = | |
1599 reinterpret_cast<intptr_t*>(caller_frame->sp() - kWordSize); | |
1600 for (intptr_t i = 0; i < deopt_frame_copy_size; i++) { | |
1601 if (FLAG_trace_deopt) { | |
1602 OS::Print("%d. 0x%x\n", i, frame_copy[i]); | |
1603 } | |
1604 *(start + i) = frame_copy[i]; | |
1605 } | |
1606 } else { | |
1607 DeoptimizeWithDeoptInfo(optimized_code, deopt_info, *caller_frame); | |
1522 } | 1608 } |
1609 | |
1523 isolate->SetDeoptFrameCopy(NULL, 0); | 1610 isolate->SetDeoptFrameCopy(NULL, 0); |
1524 isolate->set_deopt_registers_copy(NULL); | 1611 isolate->set_deopt_registers_copy(NULL); |
1525 delete[] frame_copy; | 1612 delete[] frame_copy; |
1526 delete[] registers_copy; | 1613 delete[] registers_copy; |
1527 | 1614 |
1528 // Clear invocation counter so that the function gets optimized after | 1615 // Clear invocation counter so that the function gets optimized after |
1529 // classes have been collected. | 1616 // classes have been collected. |
1530 function.set_usage_counter(0); | 1617 function.set_usage_counter(0); |
1531 function.set_deoptimization_counter(function.deoptimization_counter() + 1); | 1618 function.set_deoptimization_counter(function.deoptimization_counter() + 1); |
1532 | 1619 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1618 } | 1705 } |
1619 } | 1706 } |
1620 } | 1707 } |
1621 // The cache is null terminated, therefore the loop above should never | 1708 // The cache is null terminated, therefore the loop above should never |
1622 // terminate by itself. | 1709 // terminate by itself. |
1623 UNREACHABLE(); | 1710 UNREACHABLE(); |
1624 return Code::null(); | 1711 return Code::null(); |
1625 } | 1712 } |
1626 | 1713 |
1627 } // namespace dart | 1714 } // namespace dart |
OLD | NEW |