Chromium Code Reviews| 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 |