OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/inspector/v8-debugger.h" | 5 #include "src/inspector/v8-debugger.h" |
6 | 6 |
7 #include "src/inspector/debugger-script.h" | 7 #include "src/inspector/debugger-script.h" |
8 #include "src/inspector/inspected-context.h" | 8 #include "src/inspector/inspected-context.h" |
9 #include "src/inspector/protocol/Protocol.h" | 9 #include "src/inspector/protocol/Protocol.h" |
10 #include "src/inspector/script-breakpoint.h" | 10 #include "src/inspector/script-breakpoint.h" |
(...skipping 24 matching lines...) Expand all Loading... |
35 v8::Local<v8::Value> contextData; | 35 v8::Local<v8::Value> contextData; |
36 if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) { | 36 if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) { |
37 return nullptr; | 37 return nullptr; |
38 } | 38 } |
39 int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value()); | 39 int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value()); |
40 int contextGroupId = inspector->contextGroupId(contextId); | 40 int contextGroupId = inspector->contextGroupId(contextId); |
41 if (!contextGroupId) return nullptr; | 41 if (!contextGroupId) return nullptr; |
42 return inspector->enabledDebuggerAgentForGroup(contextGroupId); | 42 return inspector->enabledDebuggerAgentForGroup(contextGroupId); |
43 } | 43 } |
44 | 44 |
| 45 v8::MaybeLocal<v8::Array> collectionsEntries(v8::Local<v8::Context> context, |
| 46 v8::Local<v8::Value> value) { |
| 47 v8::Isolate* isolate = context->GetIsolate(); |
| 48 v8::Local<v8::Array> entries; |
| 49 bool isKeyValue = false; |
| 50 if (!v8::debug::EntriesPreview(isolate, value, &isKeyValue).ToLocal(&entries)) |
| 51 return v8::MaybeLocal<v8::Array>(); |
| 52 |
| 53 v8::Local<v8::Array> wrappedEntries = v8::Array::New(isolate); |
| 54 CHECK(!isKeyValue || wrappedEntries->Length() % 2 == 0); |
| 55 if (!wrappedEntries->SetPrototype(context, v8::Null(isolate)) |
| 56 .FromMaybe(false)) |
| 57 return v8::MaybeLocal<v8::Array>(); |
| 58 for (uint32_t i = 0; i < entries->Length(); i += isKeyValue ? 2 : 1) { |
| 59 v8::Local<v8::Value> item; |
| 60 if (!entries->Get(context, i).ToLocal(&item)) continue; |
| 61 v8::Local<v8::Value> value; |
| 62 if (isKeyValue && !entries->Get(context, i + 1).ToLocal(&value)) continue; |
| 63 v8::Local<v8::Object> wrapper = v8::Object::New(isolate); |
| 64 if (!wrapper->SetPrototype(context, v8::Null(isolate)).FromMaybe(false)) |
| 65 continue; |
| 66 createDataProperty( |
| 67 context, wrapper, |
| 68 toV8StringInternalized(isolate, isKeyValue ? "key" : "value"), item); |
| 69 if (isKeyValue) { |
| 70 createDataProperty(context, wrapper, |
| 71 toV8StringInternalized(isolate, "value"), value); |
| 72 } |
| 73 createDataProperty(context, wrappedEntries, wrappedEntries->Length(), |
| 74 wrapper); |
| 75 } |
| 76 if (!markArrayEntriesAsInternal(context, wrappedEntries, |
| 77 V8InternalValueType::kEntry)) { |
| 78 return v8::MaybeLocal<v8::Array>(); |
| 79 } |
| 80 return wrappedEntries; |
| 81 } |
| 82 |
45 } // namespace | 83 } // namespace |
46 | 84 |
47 static bool inLiveEditScope = false; | 85 static bool inLiveEditScope = false; |
48 | 86 |
49 v8::MaybeLocal<v8::Value> V8Debugger::callDebuggerMethod( | 87 v8::MaybeLocal<v8::Value> V8Debugger::callDebuggerMethod( |
50 const char* functionName, int argc, v8::Local<v8::Value> argv[], | 88 const char* functionName, int argc, v8::Local<v8::Value> argv[], |
51 bool catchExceptions) { | 89 bool catchExceptions) { |
52 v8::MicrotasksScope microtasks(m_isolate, | 90 v8::MicrotasksScope microtasks(m_isolate, |
53 v8::MicrotasksScope::kDoNotRunMicrotasks); | 91 v8::MicrotasksScope::kDoNotRunMicrotasks); |
54 DCHECK(m_isolate->InContext()); | 92 DCHECK(m_isolate->InContext()); |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 else | 297 else |
260 v8::debug::CancelDebugBreak(m_isolate); | 298 v8::debug::CancelDebugBreak(m_isolate); |
261 } | 299 } |
262 | 300 |
263 bool V8Debugger::canBreakProgram() { | 301 bool V8Debugger::canBreakProgram() { |
264 if (!m_breakpointsActivated) return false; | 302 if (!m_breakpointsActivated) return false; |
265 return v8::debug::HasNonBlackboxedFrameOnStack(m_isolate); | 303 return v8::debug::HasNonBlackboxedFrameOnStack(m_isolate); |
266 } | 304 } |
267 | 305 |
268 void V8Debugger::breakProgram() { | 306 void V8Debugger::breakProgram() { |
269 if (isPaused()) { | 307 // Don't allow nested breaks. |
270 DCHECK(!m_runningNestedMessageLoop); | 308 if (isPaused()) return; |
271 v8::Local<v8::Value> exception; | |
272 v8::Local<v8::Array> hitBreakpoints; | |
273 handleProgramBreak(m_pausedContext, m_executionState, exception, | |
274 hitBreakpoints); | |
275 return; | |
276 } | |
277 | |
278 if (!canBreakProgram()) return; | 309 if (!canBreakProgram()) return; |
279 | 310 |
280 v8::HandleScope scope(m_isolate); | 311 v8::HandleScope scope(m_isolate); |
281 v8::Local<v8::Function> breakFunction; | 312 v8::Local<v8::Function> breakFunction; |
282 if (!v8::Function::New(m_isolate->GetCurrentContext(), | 313 if (!v8::Function::New(m_isolate->GetCurrentContext(), |
283 &V8Debugger::breakProgramCallback, | 314 &V8Debugger::breakProgramCallback, |
284 v8::External::New(m_isolate, this), 0, | 315 v8::External::New(m_isolate, this), 0, |
285 v8::ConstructorBehavior::kThrow) | 316 v8::ConstructorBehavior::kThrow) |
286 .ToLocal(&breakFunction)) | 317 .ToLocal(&breakFunction)) |
287 return; | 318 return; |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 1) | 437 1) |
407 .build(); | 438 .build(); |
408 *compileError = true; | 439 *compileError = true; |
409 return Response::OK(); | 440 return Response::OK(); |
410 } | 441 } |
411 } | 442 } |
412 return Response::InternalError(); | 443 return Response::InternalError(); |
413 } | 444 } |
414 | 445 |
415 JavaScriptCallFrames V8Debugger::currentCallFrames(int limit) { | 446 JavaScriptCallFrames V8Debugger::currentCallFrames(int limit) { |
416 if (!m_isolate->InContext()) return JavaScriptCallFrames(); | 447 if (!isPaused()) return JavaScriptCallFrames(); |
417 v8::Local<v8::Value> currentCallFramesV8; | 448 v8::Local<v8::Value> currentCallFramesV8; |
418 if (m_executionState.IsEmpty()) { | 449 v8::Local<v8::Value> argv[] = {m_executionState, |
419 v8::Local<v8::Function> currentCallFramesFunction = | 450 v8::Integer::New(m_isolate, limit)}; |
420 v8::Local<v8::Function>::Cast( | 451 if (!callDebuggerMethod("currentCallFrames", arraysize(argv), argv, true) |
421 m_debuggerScript.Get(m_isolate) | 452 .ToLocal(¤tCallFramesV8)) { |
422 ->Get(debuggerContext(), | 453 return JavaScriptCallFrames(); |
423 toV8StringInternalized(m_isolate, "currentCallFrames")) | |
424 .ToLocalChecked()); | |
425 if (!v8::debug::Call(debuggerContext(), currentCallFramesFunction, | |
426 v8::Integer::New(m_isolate, limit)) | |
427 .ToLocal(¤tCallFramesV8)) | |
428 return JavaScriptCallFrames(); | |
429 } else { | |
430 v8::Local<v8::Value> argv[] = {m_executionState, | |
431 v8::Integer::New(m_isolate, limit)}; | |
432 if (!callDebuggerMethod("currentCallFrames", arraysize(argv), argv, true) | |
433 .ToLocal(¤tCallFramesV8)) | |
434 return JavaScriptCallFrames(); | |
435 } | 454 } |
436 DCHECK(!currentCallFramesV8.IsEmpty()); | |
437 if (!currentCallFramesV8->IsArray()) return JavaScriptCallFrames(); | 455 if (!currentCallFramesV8->IsArray()) return JavaScriptCallFrames(); |
438 v8::Local<v8::Array> callFramesArray = currentCallFramesV8.As<v8::Array>(); | 456 v8::Local<v8::Array> callFramesArray = currentCallFramesV8.As<v8::Array>(); |
439 JavaScriptCallFrames callFrames; | 457 JavaScriptCallFrames callFrames; |
440 for (uint32_t i = 0; i < callFramesArray->Length(); ++i) { | 458 for (uint32_t i = 0; i < callFramesArray->Length(); ++i) { |
441 v8::Local<v8::Value> callFrameValue; | 459 v8::Local<v8::Value> callFrameValue; |
442 if (!callFramesArray->Get(debuggerContext(), i).ToLocal(&callFrameValue)) | 460 if (!callFramesArray->Get(debuggerContext(), i).ToLocal(&callFrameValue)) |
443 return JavaScriptCallFrames(); | 461 return JavaScriptCallFrames(); |
444 if (!callFrameValue->IsObject()) return JavaScriptCallFrames(); | 462 if (!callFrameValue->IsObject()) return JavaScriptCallFrames(); |
445 v8::Local<v8::Object> callFrameObject = callFrameValue.As<v8::Object>(); | 463 v8::Local<v8::Object> callFrameObject = callFrameValue.As<v8::Object>(); |
446 callFrames.push_back(JavaScriptCallFrame::create( | 464 callFrames.push_back(JavaScriptCallFrame::create( |
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
696 toV8StringInternalized(m_isolate, "[[FunctionLocation]]")); | 714 toV8StringInternalized(m_isolate, "[[FunctionLocation]]")); |
697 createDataProperty(context, properties, properties->Length(), location); | 715 createDataProperty(context, properties, properties->Length(), location); |
698 } | 716 } |
699 if (function->IsGeneratorFunction()) { | 717 if (function->IsGeneratorFunction()) { |
700 createDataProperty(context, properties, properties->Length(), | 718 createDataProperty(context, properties, properties->Length(), |
701 toV8StringInternalized(m_isolate, "[[IsGenerator]]")); | 719 toV8StringInternalized(m_isolate, "[[IsGenerator]]")); |
702 createDataProperty(context, properties, properties->Length(), | 720 createDataProperty(context, properties, properties->Length(), |
703 v8::True(m_isolate)); | 721 v8::True(m_isolate)); |
704 } | 722 } |
705 } | 723 } |
| 724 v8::Local<v8::Array> entries; |
| 725 if (collectionsEntries(context, value).ToLocal(&entries)) { |
| 726 createDataProperty(context, properties, properties->Length(), |
| 727 toV8StringInternalized(m_isolate, "[[Entries]]")); |
| 728 createDataProperty(context, properties, properties->Length(), entries); |
| 729 } |
706 if (!enabled()) return properties; | 730 if (!enabled()) return properties; |
707 if (value->IsMap() || value->IsWeakMap() || value->IsSet() || | |
708 value->IsWeakSet() || value->IsSetIterator() || value->IsMapIterator()) { | |
709 v8::Local<v8::Value> entries = | |
710 collectionEntries(context, v8::Local<v8::Object>::Cast(value)); | |
711 if (entries->IsArray()) { | |
712 createDataProperty(context, properties, properties->Length(), | |
713 toV8StringInternalized(m_isolate, "[[Entries]]")); | |
714 createDataProperty(context, properties, properties->Length(), entries); | |
715 } | |
716 } | |
717 if (value->IsGeneratorObject()) { | 731 if (value->IsGeneratorObject()) { |
718 v8::Local<v8::Value> location = | 732 v8::Local<v8::Value> location = |
719 generatorObjectLocation(context, v8::Local<v8::Object>::Cast(value)); | 733 generatorObjectLocation(context, v8::Local<v8::Object>::Cast(value)); |
720 if (location->IsObject()) { | 734 if (location->IsObject()) { |
721 createDataProperty( | 735 createDataProperty( |
722 context, properties, properties->Length(), | 736 context, properties, properties->Length(), |
723 toV8StringInternalized(m_isolate, "[[GeneratorLocation]]")); | 737 toV8StringInternalized(m_isolate, "[[GeneratorLocation]]")); |
724 createDataProperty(context, properties, properties->Length(), location); | 738 createDataProperty(context, properties, properties->Length(), location); |
725 } | 739 } |
726 v8::Local<v8::Value> scopes; | 740 v8::Local<v8::Value> scopes; |
(...skipping 10 matching lines...) Expand all Loading... |
737 if (boundFunction->IsUndefined() && | 751 if (boundFunction->IsUndefined() && |
738 functionScopes(context, function).ToLocal(&scopes)) { | 752 functionScopes(context, function).ToLocal(&scopes)) { |
739 createDataProperty(context, properties, properties->Length(), | 753 createDataProperty(context, properties, properties->Length(), |
740 toV8StringInternalized(m_isolate, "[[Scopes]]")); | 754 toV8StringInternalized(m_isolate, "[[Scopes]]")); |
741 createDataProperty(context, properties, properties->Length(), scopes); | 755 createDataProperty(context, properties, properties->Length(), scopes); |
742 } | 756 } |
743 } | 757 } |
744 return properties; | 758 return properties; |
745 } | 759 } |
746 | 760 |
747 v8::Local<v8::Value> V8Debugger::collectionEntries( | |
748 v8::Local<v8::Context> context, v8::Local<v8::Object> object) { | |
749 if (!enabled()) { | |
750 UNREACHABLE(); | |
751 return v8::Undefined(m_isolate); | |
752 } | |
753 v8::Local<v8::Value> argv[] = {object}; | |
754 v8::Local<v8::Value> entriesValue; | |
755 if (!callDebuggerMethod("getCollectionEntries", 1, argv, true) | |
756 .ToLocal(&entriesValue) || | |
757 !entriesValue->IsArray()) | |
758 return v8::Undefined(m_isolate); | |
759 | |
760 v8::Local<v8::Array> entries = entriesValue.As<v8::Array>(); | |
761 v8::Local<v8::Array> copiedArray = | |
762 v8::Array::New(m_isolate, entries->Length()); | |
763 if (!copiedArray->SetPrototype(context, v8::Null(m_isolate)).FromMaybe(false)) | |
764 return v8::Undefined(m_isolate); | |
765 for (uint32_t i = 0; i < entries->Length(); ++i) { | |
766 v8::Local<v8::Value> item; | |
767 if (!entries->Get(debuggerContext(), i).ToLocal(&item)) | |
768 return v8::Undefined(m_isolate); | |
769 v8::Local<v8::Value> copied; | |
770 if (!copyValueFromDebuggerContext(m_isolate, debuggerContext(), context, | |
771 item) | |
772 .ToLocal(&copied)) | |
773 return v8::Undefined(m_isolate); | |
774 if (!createDataProperty(context, copiedArray, i, copied).FromMaybe(false)) | |
775 return v8::Undefined(m_isolate); | |
776 } | |
777 if (!markArrayEntriesAsInternal(context, | |
778 v8::Local<v8::Array>::Cast(copiedArray), | |
779 V8InternalValueType::kEntry)) | |
780 return v8::Undefined(m_isolate); | |
781 return copiedArray; | |
782 } | |
783 | |
784 v8::Local<v8::Value> V8Debugger::generatorObjectLocation( | 761 v8::Local<v8::Value> V8Debugger::generatorObjectLocation( |
785 v8::Local<v8::Context> context, v8::Local<v8::Object> object) { | 762 v8::Local<v8::Context> context, v8::Local<v8::Object> object) { |
786 if (!enabled()) { | 763 if (!enabled()) { |
787 UNREACHABLE(); | 764 UNREACHABLE(); |
788 return v8::Null(m_isolate); | 765 return v8::Null(m_isolate); |
789 } | 766 } |
790 v8::Local<v8::Value> argv[] = {object}; | 767 v8::Local<v8::Value> argv[] = {object}; |
791 v8::Local<v8::Value> location; | 768 v8::Local<v8::Value> location; |
792 v8::Local<v8::Value> copied; | 769 v8::Local<v8::Value> copied; |
793 if (!callDebuggerMethod("getGeneratorObjectLocation", 1, argv, true) | 770 if (!callDebuggerMethod("getGeneratorObjectLocation", 1, argv, true) |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
995 | 972 |
996 size_t stackSize = | 973 size_t stackSize = |
997 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; | 974 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; |
998 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) | 975 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) |
999 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 976 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
1000 | 977 |
1001 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 978 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); |
1002 } | 979 } |
1003 | 980 |
1004 } // namespace v8_inspector | 981 } // namespace v8_inspector |
OLD | NEW |