| 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 |