Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(273)

Side by Side Diff: src/debug/liveedit.cc

Issue 2636913002: [liveedit] reimplement frame restarting. (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698