OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/debug/liveedit.h" | 5 #include "src/debug/liveedit.h" |
6 | 6 |
7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
9 #include "src/compilation-cache.h" | 9 #include "src/compilation-cache.h" |
10 #include "src/compiler.h" | 10 #include "src/compiler.h" |
(...skipping 635 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
646 | 646 |
647 Handle<SharedFunctionInfo> SharedInfoWrapper::GetInfo() { | 647 Handle<SharedFunctionInfo> SharedInfoWrapper::GetInfo() { |
648 Handle<Object> element = this->GetField(kSharedInfoOffset_); | 648 Handle<Object> element = this->GetField(kSharedInfoOffset_); |
649 Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element); | 649 Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element); |
650 return UnwrapSharedFunctionInfoFromJSValue(value_wrapper); | 650 return UnwrapSharedFunctionInfoFromJSValue(value_wrapper); |
651 } | 651 } |
652 | 652 |
653 | 653 |
654 void LiveEdit::InitializeThreadLocal(Debug* debug) { | 654 void LiveEdit::InitializeThreadLocal(Debug* debug) { |
655 debug->thread_local_.frame_drop_mode_ = LIVE_EDIT_FRAMES_UNTOUCHED; | 655 debug->thread_local_.frame_drop_mode_ = LIVE_EDIT_FRAMES_UNTOUCHED; |
656 debug->thread_local_.new_fp_ = 0; | |
656 } | 657 } |
657 | 658 |
658 | 659 |
659 bool LiveEdit::SetAfterBreakTarget(Debug* debug) { | |
660 Code* code = NULL; | |
661 Isolate* isolate = debug->isolate_; | |
662 switch (debug->thread_local_.frame_drop_mode_) { | |
663 case LIVE_EDIT_FRAMES_UNTOUCHED: | |
664 return false; | |
665 case LIVE_EDIT_FRAME_DROPPED_IN_DEBUG_SLOT_CALL: | |
666 // Debug break slot stub does not return normally, instead it manually | |
667 // cleans the stack and jumps. We should patch the jump address. | |
668 code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit); | |
669 break; | |
670 case LIVE_EDIT_FRAME_DROPPED_IN_DIRECT_CALL: | |
671 // Nothing to do, after_break_target is not used here. | |
672 return true; | |
673 case LIVE_EDIT_FRAME_DROPPED_IN_RETURN_CALL: | |
674 code = isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit); | |
675 break; | |
676 case LIVE_EDIT_CURRENTLY_SET_MODE: | |
677 UNREACHABLE(); | |
678 break; | |
679 } | |
680 debug->after_break_target_ = code->entry(); | |
681 return true; | |
682 } | |
683 | |
684 | |
685 MaybeHandle<JSArray> LiveEdit::GatherCompileInfo(Handle<Script> script, | 660 MaybeHandle<JSArray> LiveEdit::GatherCompileInfo(Handle<Script> script, |
686 Handle<String> source) { | 661 Handle<String> source) { |
687 Isolate* isolate = script->GetIsolate(); | 662 Isolate* isolate = script->GetIsolate(); |
688 | 663 |
689 MaybeHandle<JSArray> infos; | 664 MaybeHandle<JSArray> infos; |
690 Handle<Object> original_source = | 665 Handle<Object> original_source = |
691 Handle<Object>(script->source(), isolate); | 666 Handle<Object>(script->source(), isolate); |
692 script->set_source(*source); | 667 script->set_source(*source); |
693 | 668 |
694 { | 669 { |
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1314 UnwrapSharedFunctionInfoFromJSValue(jsvalue); | 1289 UnwrapSharedFunctionInfoFromJSValue(jsvalue); |
1315 | 1290 |
1316 if (function->Inlines(*shared)) { | 1291 if (function->Inlines(*shared)) { |
1317 SetElementSloppy(result, i, Handle<Smi>(Smi::FromInt(status), isolate)); | 1292 SetElementSloppy(result, i, Handle<Smi>(Smi::FromInt(status), isolate)); |
1318 return true; | 1293 return true; |
1319 } | 1294 } |
1320 } | 1295 } |
1321 return false; | 1296 return false; |
1322 } | 1297 } |
1323 | 1298 |
1324 | |
1325 // Iterates over handler chain and removes all elements that are inside | |
1326 // frames being dropped. | |
1327 static bool FixTryCatchHandler(StackFrame* top_frame, | |
1328 StackFrame* bottom_frame) { | |
1329 Address* pointer_address = | |
1330 &Memory::Address_at(top_frame->isolate()->get_address_from_id( | |
1331 Isolate::kHandlerAddress)); | |
1332 | |
1333 while (*pointer_address < top_frame->sp()) { | |
1334 pointer_address = &Memory::Address_at(*pointer_address); | |
1335 } | |
1336 Address* above_frame_address = pointer_address; | |
1337 while (*pointer_address < bottom_frame->fp()) { | |
1338 pointer_address = &Memory::Address_at(*pointer_address); | |
1339 } | |
1340 bool change = *above_frame_address != *pointer_address; | |
1341 *above_frame_address = *pointer_address; | |
1342 return change; | |
1343 } | |
1344 | |
1345 | |
1346 // Initializes an artificial stack frame. The data it contains is used for: | |
1347 // a. successful work of frame dropper code which eventually gets control, | |
1348 // b. being compatible with a typed frame structure for various stack | |
1349 // iterators. | |
1350 // Frame structure (conforms to InternalFrame structure): | |
1351 // -- function | |
1352 // -- code | |
1353 // -- SMI marker | |
1354 // -- frame base | |
1355 static void SetUpFrameDropperFrame(StackFrame* bottom_js_frame, | |
1356 Handle<Code> code) { | |
1357 DCHECK(bottom_js_frame->is_java_script()); | |
1358 Address fp = bottom_js_frame->fp(); | |
1359 Memory::Object_at(fp + FrameDropperFrameConstants::kFunctionOffset) = | |
1360 Memory::Object_at(fp + StandardFrameConstants::kFunctionOffset); | |
1361 Memory::Object_at(fp + FrameDropperFrameConstants::kFrameTypeOffset) = | |
1362 Smi::FromInt(StackFrame::INTERNAL); | |
1363 Memory::Object_at(fp + FrameDropperFrameConstants::kCodeOffset) = *code; | |
1364 } | |
1365 | |
1366 | |
1367 // Removes specified range of frames from stack. There may be 1 or more | 1299 // Removes specified range of frames from stack. There may be 1 or more |
1368 // frames in range. Anyway the bottom frame is restarted rather than dropped, | 1300 // frames in range. Anyway the bottom frame is restarted rather than dropped, |
1369 // and therefore has to be a JavaScript frame. | 1301 // and therefore has to be a JavaScript frame. |
jgruber
2017/01/17 13:29:58
What about a DCHECK(bottom_frame->type() == JAVA_S
Yang
2017/01/18 07:49:08
Done.
| |
1370 // Returns error message or NULL. | 1302 // Returns error message or NULL. |
1371 static const char* DropFrames(Vector<StackFrame*> frames, int top_frame_index, | 1303 static const char* DropFrames(Vector<StackFrame*> frames, int top_frame_index, |
1372 int bottom_js_frame_index, | 1304 int bottom_js_frame_index, |
1373 LiveEditFrameDropMode* mode) { | 1305 LiveEditFrameDropMode* mode) { |
1374 if (!LiveEdit::kFrameDropperSupported) { | 1306 if (!LiveEdit::kFrameDropperSupported) { |
1375 return "Stack manipulations are not supported in this architecture."; | 1307 return "Stack manipulations are not supported in this architecture."; |
1376 } | 1308 } |
1377 | 1309 |
1378 StackFrame* pre_top_frame = frames[top_frame_index - 1]; | |
1379 StackFrame* top_frame = frames[top_frame_index]; | 1310 StackFrame* top_frame = frames[top_frame_index]; |
1380 StackFrame* bottom_js_frame = frames[bottom_js_frame_index]; | 1311 StackFrame* bottom_frame = frames[bottom_js_frame_index]; |
jgruber
2017/01/17 13:29:58
Nit: We could rename bottom_js_frame_index paramet
Yang
2017/01/18 07:49:08
Folded all of this into a new function "ScheduleFr
| |
1381 | 1312 |
1382 DCHECK(bottom_js_frame->is_java_script()); | 1313 Isolate* isolate = top_frame->isolate(); |
1383 | 1314 isolate->debug()->DropToFP(bottom_frame->fp()); |
1384 // Check the nature of the top frame. | |
1385 Isolate* isolate = bottom_js_frame->isolate(); | |
1386 Code* pre_top_frame_code = pre_top_frame->LookupCode(); | |
1387 bool frame_has_padding = true; | |
1388 if (pre_top_frame_code == | |
1389 isolate->builtins()->builtin(Builtins::kSlot_DebugBreak)) { | |
1390 // OK, we can drop debug break slot. | |
1391 *mode = LIVE_EDIT_FRAME_DROPPED_IN_DEBUG_SLOT_CALL; | |
1392 } else if (pre_top_frame_code == | |
1393 isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit)) { | |
1394 // OK, we can drop our own code. | |
1395 pre_top_frame = frames[top_frame_index - 2]; | |
1396 top_frame = frames[top_frame_index - 1]; | |
1397 *mode = LIVE_EDIT_CURRENTLY_SET_MODE; | |
1398 frame_has_padding = false; | |
1399 } else if (pre_top_frame_code == | |
1400 isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) { | |
1401 *mode = LIVE_EDIT_FRAME_DROPPED_IN_RETURN_CALL; | |
1402 } else if (pre_top_frame_code->kind() == Code::STUB && | |
1403 CodeStub::GetMajorKey(pre_top_frame_code) == CodeStub::CEntry) { | |
1404 // Entry from our unit tests on 'debugger' statement. | |
1405 // It's fine, we support this case. | |
1406 *mode = LIVE_EDIT_FRAME_DROPPED_IN_DIRECT_CALL; | |
1407 // We don't have a padding from 'debugger' statement call. | |
1408 // Here the stub is CEntry, it's not debug-only and can't be padded. | |
1409 // If anyone would complain, a proxy padded stub could be added. | |
1410 frame_has_padding = false; | |
1411 } else if (pre_top_frame->type() == StackFrame::ARGUMENTS_ADAPTOR) { | |
1412 // This must be adaptor that remain from the frame dropping that | |
1413 // is still on stack. A frame dropper frame must be above it. | |
1414 DCHECK(frames[top_frame_index - 2]->LookupCode() == | |
1415 isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit)); | |
1416 pre_top_frame = frames[top_frame_index - 3]; | |
1417 top_frame = frames[top_frame_index - 2]; | |
1418 *mode = LIVE_EDIT_CURRENTLY_SET_MODE; | |
1419 frame_has_padding = false; | |
1420 } else if (pre_top_frame_code->kind() == Code::BYTECODE_HANDLER) { | |
1421 // Interpreted bytecode takes up two stack frames, one for the bytecode | |
1422 // handler and one for the interpreter entry trampoline. Therefore we shift | |
1423 // up by one frame. | |
1424 *mode = LIVE_EDIT_FRAME_DROPPED_IN_DIRECT_CALL; | |
1425 pre_top_frame = frames[top_frame_index - 2]; | |
1426 top_frame = frames[top_frame_index - 1]; | |
1427 } else { | |
1428 return "Unknown structure of stack above changing function"; | |
1429 } | |
1430 | |
1431 Address unused_stack_top = top_frame->sp(); | |
1432 Address unused_stack_bottom = | |
1433 bottom_js_frame->fp() - FrameDropperFrameConstants::kFixedFrameSize + | |
1434 2 * kPointerSize; // Bigger address end is exclusive. | |
1435 | |
1436 Address* top_frame_pc_address = top_frame->pc_address(); | |
1437 | |
1438 // top_frame may be damaged below this point. Do not used it. | |
1439 DCHECK(!(top_frame = NULL)); | |
1440 | |
1441 if (unused_stack_top > unused_stack_bottom) { | |
1442 if (frame_has_padding) { | |
1443 int shortage_bytes = | |
1444 static_cast<int>(unused_stack_top - unused_stack_bottom); | |
1445 | |
1446 Address padding_start = | |
1447 pre_top_frame->fp() - | |
1448 (FrameDropperFrameConstants::kFixedFrameSize - kPointerSize); | |
1449 | |
1450 Address padding_pointer = padding_start; | |
1451 Smi* padding_object = Smi::FromInt(LiveEdit::kFramePaddingValue); | |
1452 while (Memory::Object_at(padding_pointer) == padding_object) { | |
1453 padding_pointer -= kPointerSize; | |
1454 } | |
1455 int padding_counter = | |
1456 Smi::cast(Memory::Object_at(padding_pointer))->value(); | |
1457 if (padding_counter * kPointerSize < shortage_bytes) { | |
1458 return "Not enough space for frame dropper frame " | |
1459 "(even with padding frame)"; | |
1460 } | |
1461 Memory::Object_at(padding_pointer) = | |
1462 Smi::FromInt(padding_counter - shortage_bytes / kPointerSize); | |
1463 | |
1464 StackFrame* pre_pre_frame = frames[top_frame_index - 2]; | |
1465 | |
1466 MemMove(padding_start + kPointerSize - shortage_bytes, | |
1467 padding_start + kPointerSize, | |
1468 FrameDropperFrameConstants::kFixedFrameSize - kPointerSize); | |
1469 | |
1470 pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes); | |
1471 pre_pre_frame->SetCallerFp(pre_top_frame->fp()); | |
1472 unused_stack_top -= shortage_bytes; | |
1473 | |
1474 STATIC_ASSERT(sizeof(Address) == kPointerSize); | |
1475 top_frame_pc_address -= shortage_bytes / kPointerSize; | |
1476 } else { | |
1477 return "Not enough space for frame dropper frame"; | |
1478 } | |
1479 } | |
1480 | |
1481 // Committing now. After this point we should return only NULL value. | |
1482 | |
1483 FixTryCatchHandler(pre_top_frame, bottom_js_frame); | |
1484 // Make sure FixTryCatchHandler is idempotent. | |
1485 DCHECK(!FixTryCatchHandler(pre_top_frame, bottom_js_frame)); | |
1486 | |
1487 Handle<Code> code = isolate->builtins()->FrameDropper_LiveEdit(); | |
1488 *top_frame_pc_address = code->entry(); | |
1489 pre_top_frame->SetCallerFp(bottom_js_frame->fp()); | |
1490 | |
1491 SetUpFrameDropperFrame(bottom_js_frame, code); | |
1492 | |
1493 for (Address a = unused_stack_top; | |
1494 a < unused_stack_bottom; | |
1495 a += kPointerSize) { | |
1496 Memory::Object_at(a) = Smi::kZero; | |
1497 } | |
1498 | |
1499 return NULL; | 1315 return NULL; |
1500 } | 1316 } |
1501 | 1317 |
1502 | 1318 |
1503 // Describes a set of call frames that execute any of listed functions. | 1319 // Describes a set of call frames that execute any of listed functions. |
1504 // Finding no such frames does not mean error. | 1320 // Finding no such frames does not mean error. |
1505 class MultipleFunctionTarget { | 1321 class MultipleFunctionTarget { |
1506 public: | 1322 public: |
1507 MultipleFunctionTarget(Handle<JSArray> old_shared_array, | 1323 MultipleFunctionTarget(Handle<JSArray> old_shared_array, |
1508 Handle<JSArray> new_shared_array, | 1324 Handle<JSArray> new_shared_array, |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1673 } | 1489 } |
1674 | 1490 |
1675 LiveEditFrameDropMode drop_mode = LIVE_EDIT_FRAMES_UNTOUCHED; | 1491 LiveEditFrameDropMode drop_mode = LIVE_EDIT_FRAMES_UNTOUCHED; |
1676 const char* error_message = | 1492 const char* error_message = |
1677 DropFrames(frames, top_frame_index, bottom_js_frame_index, &drop_mode); | 1493 DropFrames(frames, top_frame_index, bottom_js_frame_index, &drop_mode); |
1678 | 1494 |
1679 if (error_message != NULL) { | 1495 if (error_message != NULL) { |
1680 return error_message; | 1496 return error_message; |
1681 } | 1497 } |
1682 | 1498 |
1683 // Adjust break_frame after some frames has been dropped. | 1499 debug->UpdateBreakFrameId(); |
1684 StackFrame::Id new_id = StackFrame::NO_ID; | |
1685 for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) { | |
1686 if (frames[i]->type() == StackFrame::JAVA_SCRIPT || | |
1687 frames[i]->type() == StackFrame::INTERPRETED) { | |
1688 new_id = frames[i]->id(); | |
1689 break; | |
1690 } | |
1691 } | |
1692 debug->FramesHaveBeenDropped(new_id, drop_mode); | |
1693 return NULL; | 1500 return NULL; |
1694 } | 1501 } |
1695 | 1502 |
1696 | 1503 |
1697 // Fills result array with statuses of functions. Modifies the stack | 1504 // Fills result array with statuses of functions. Modifies the stack |
1698 // removing all listed function if possible and if do_drop is true. | 1505 // removing all listed function if possible and if do_drop is true. |
1699 static const char* DropActivationsInActiveThread( | 1506 static const char* DropActivationsInActiveThread( |
1700 Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array, | 1507 Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array, |
1701 Handle<JSArray> result, bool do_drop) { | 1508 Handle<JSArray> result, bool do_drop) { |
1702 MultipleFunctionTarget target(old_shared_array, new_shared_array, result); | 1509 MultipleFunctionTarget target(old_shared_array, new_shared_array, result); |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1979 scope_info_length++; | 1786 scope_info_length++; |
1980 | 1787 |
1981 current_scope = current_scope->outer_scope(); | 1788 current_scope = current_scope->outer_scope(); |
1982 } | 1789 } |
1983 | 1790 |
1984 return scope_info_list; | 1791 return scope_info_list; |
1985 } | 1792 } |
1986 | 1793 |
1987 } // namespace internal | 1794 } // namespace internal |
1988 } // namespace v8 | 1795 } // namespace v8 |
OLD | NEW |