diff options
Diffstat (limited to 'deps/v8/src/inspector')
49 files changed, 1439 insertions, 758 deletions
diff --git a/deps/v8/src/inspector/BUILD.gn b/deps/v8/src/inspector/BUILD.gn index 6ebb91ccbc..e6742c09f7 100644 --- a/deps/v8/src/inspector/BUILD.gn +++ b/deps/v8/src/inspector/BUILD.gn @@ -140,7 +140,6 @@ v8_source_set("inspector") { "inspected-context.h", "java-script-call-frame.cc", "java-script-call-frame.h", - "protocol-platform.h", "remote-object-id.cc", "remote-object-id.h", "script-breakpoint.h", @@ -150,6 +149,8 @@ v8_source_set("inspector") { "string-16.h", "string-util.cc", "string-util.h", + "test-interface.cc", + "test-interface.h", "v8-console-agent-impl.cc", "v8-console-agent-impl.h", "v8-console-message.cc", @@ -186,5 +187,7 @@ v8_source_set("inspector") { "v8-stack-trace-impl.h", "v8-value-copier.cc", "v8-value-copier.h", + "wasm-translation.cc", + "wasm-translation.h", ] } diff --git a/deps/v8/src/inspector/DEPS b/deps/v8/src/inspector/DEPS index d49c6a6254..748a7c12d9 100644 --- a/deps/v8/src/inspector/DEPS +++ b/deps/v8/src/inspector/DEPS @@ -4,6 +4,7 @@ include_rules = [ "+src/base/macros.h", "+src/base/logging.h", "+src/base/platform/platform.h", + "+src/conversions.h", "+src/inspector", "+src/tracing", "-include/v8-debug.h", diff --git a/deps/v8/src/inspector/debugger-script.js b/deps/v8/src/inspector/debugger-script.js index 1614566ffa..7843dc9d67 100644 --- a/deps/v8/src/inspector/debugger-script.js +++ b/deps/v8/src/inspector/debugger-script.js @@ -33,17 +33,6 @@ var DebuggerScript = {}; -/** - * @param {?CompileEvent} eventData - */ -DebuggerScript.getAfterCompileScript = function(eventData) -{ - var script = eventData.script().value(); - if (!script.is_debugger_script) - return script; - return null; -} - /** @type {!Map<!ScopeType, string>} */ DebuggerScript._scopeTypeNames = new Map(); DebuggerScript._scopeTypeNames.set(ScopeType.Global, "global"); @@ -53,6 +42,8 @@ DebuggerScript._scopeTypeNames.set(ScopeType.Closure, "closure"); DebuggerScript._scopeTypeNames.set(ScopeType.Catch, "catch"); DebuggerScript._scopeTypeNames.set(ScopeType.Block, "block"); DebuggerScript._scopeTypeNames.set(ScopeType.Script, "script"); +DebuggerScript._scopeTypeNames.set(ScopeType.Eval, "eval"); +DebuggerScript._scopeTypeNames.set(ScopeType.Module, "module"); /** * @param {function()} fun @@ -83,6 +74,34 @@ DebuggerScript.getFunctionScopes = function(fun) } /** + * @param {Object} gen + * @return {?Array<!Scope>} + */ +DebuggerScript.getGeneratorScopes = function(gen) +{ + var mirror = MakeMirror(gen); + if (!mirror.isGenerator()) + return null; + var generatorMirror = /** @type {!GeneratorMirror} */(mirror); + var count = generatorMirror.scopeCount(); + if (count == 0) + return null; + var result = []; + for (var i = 0; i < count; i++) { + var scopeDetails = generatorMirror.scope(i).details(); + var scopeObject = DebuggerScript._buildScopeObject(scopeDetails.type(), scopeDetails.object()); + if (!scopeObject) + continue; + result.push({ + type: /** @type {string} */(DebuggerScript._scopeTypeNames.get(scopeDetails.type())), + object: scopeObject, + name: scopeDetails.name() || "" + }); + } + return result; +} + +/** * @param {Object} object * @return {?RawLocation} */ @@ -126,20 +145,6 @@ DebuggerScript.getCollectionEntries = function(object) } /** - * @param {string|undefined} contextData - * @return {number} - */ -DebuggerScript._executionContextId = function(contextData) -{ - if (!contextData) - return 0; - var match = contextData.match(/^[^,]*,([^,]*),.*$/); - if (!match) - return 0; - return parseInt(match[1], 10) || 0; -} - -/** * @param {!ExecutionState} execState * @param {!BreakpointInfo} info * @return {string|undefined} @@ -467,12 +472,9 @@ DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror) function contextId() { var mirror = ensureFuncMirror(); - // Old V8 do not have context() function on these objects - if (!mirror.context) - return DebuggerScript._executionContextId(mirror.script().value().context_data); var context = mirror.context(); - if (context) - return DebuggerScript._executionContextId(context.data()); + if (context && context.data()) + return Number(context.data()); return 0; } @@ -491,7 +493,7 @@ DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror) */ function evaluate(expression) { - return frameMirror.evaluate(expression, false).value(); + return frameMirror.evaluate(expression).value(); } /** @return {undefined} */ @@ -541,15 +543,21 @@ DebuggerScript._buildScopeObject = function(scopeType, scopeObject) case ScopeType.Catch: case ScopeType.Block: case ScopeType.Script: + case ScopeType.Eval: + case ScopeType.Module: // For transient objects we create a "persistent" copy that contains // the same properties. // Reset scope object prototype to null so that the proto properties // don't appear in the local scope section. var properties = /** @type {!ObjectMirror} */(MakeMirror(scopeObject, true /* transient */)).properties(); // Almost always Script scope will be empty, so just filter out that noise. - // Also drop empty Block scopes, should we get any. - if (!properties.length && (scopeType === ScopeType.Script || scopeType === ScopeType.Block)) + // Also drop empty Block, Eval and Script scopes, should we get any. + if (!properties.length && (scopeType === ScopeType.Script || + scopeType === ScopeType.Block || + scopeType === ScopeType.Eval || + scopeType === ScopeType.Module)) { break; + } result = { __proto__: null }; for (var j = 0; j < properties.length; j++) { var name = properties[j].name(); diff --git a/deps/v8/src/inspector/debugger_script_externs.js b/deps/v8/src/inspector/debugger_script_externs.js index cc152d5537..4fa3a0fbe3 100644 --- a/deps/v8/src/inspector/debugger_script_externs.js +++ b/deps/v8/src/inspector/debugger_script_externs.js @@ -19,21 +19,6 @@ var Scope; var RawLocation; /** @typedef {{ - id: number, - name: string, - sourceURL: (string|undefined), - sourceMappingURL: (string|undefined), - source: string, - startLine: number, - endLine: number, - startColumn: number, - endColumn: number, - executionContextId: number, - executionContextAuxData: string - }} */ -var FormattedScript; - -/** @typedef {{ functionName: string, location: !RawLocation, this: !Object, @@ -47,6 +32,7 @@ var JavaScriptCallFrameDetails; sourceID: function():(number), line: function():number, column: function():number, + contextId: function():number, thisObject: !Object, evaluate: function(string):*, restart: function():undefined, @@ -174,13 +160,6 @@ BreakPoint.prototype.number = function() {} /** @interface */ -function CompileEvent() {} - -/** @return {!ScriptMirror} */ -CompileEvent.prototype.script = function() {} - - -/** @interface */ function BreakEvent() {} /** @return {!Array<!BreakPoint>|undefined} */ @@ -192,10 +171,8 @@ function ExecutionState() {} /** * @param {string} source - * @param {boolean} disableBreak - * @param {*=} additionalContext */ -ExecutionState.prototype.evaluateGlobal = function(source, disableBreak, additionalContext) {} +ExecutionState.prototype.evaluateGlobal = function(source) {} /** @return {number} */ ExecutionState.prototype.frameCount = function() {} @@ -220,7 +197,9 @@ var ScopeType = { Global: 0, Closure: 3, Catch: 4, Block: 5, - Script: 6 }; + Script: 6, + Eval: 7, + Module: 8}; /** @typedef {{ @@ -237,14 +216,6 @@ var SourceLocation; /** @typedef{{ * id: number, * context_data: (string|undefined), - * source_url: (string|undefined), - * source_mapping_url: (string|undefined), - * is_debugger_script: boolean, - * source: string, - * line_offset: number, - * column_offset: number, - * nameOrSourceURL: function():string, - * compilationType: function():!ScriptCompilationType, * }} */ var Script; @@ -421,6 +392,15 @@ GeneratorMirror.prototype.sourceLocation = function() {} /** @return {!FunctionMirror} */ GeneratorMirror.prototype.func = function() {} +/** @return {number} */ +GeneratorMirror.prototype.scopeCount = function() {} + +/** + * @param {number} index + * @return {!ScopeMirror|undefined} + */ +GeneratorMirror.prototype.scope = function(index) {} + /** * @interface @@ -457,9 +437,8 @@ FrameMirror.prototype.script = function() {} /** * @param {string} source - * @param {boolean} disableBreak */ -FrameMirror.prototype.evaluate = function(source, disableBreak) {} +FrameMirror.prototype.evaluate = function(source) {} FrameMirror.prototype.restart = function() {} diff --git a/deps/v8/src/inspector/injected-script-native.cc b/deps/v8/src/inspector/injected-script-native.cc index fcf2ead94b..5d0136b3b6 100644 --- a/deps/v8/src/inspector/injected-script-native.cc +++ b/deps/v8/src/inspector/injected-script-native.cc @@ -44,8 +44,8 @@ int InjectedScriptNative::bind(v8::Local<v8::Value> value, const String16& groupName) { if (m_lastBoundObjectId <= 0) m_lastBoundObjectId = 1; int id = m_lastBoundObjectId++; - m_idToWrappedObject[id] = - wrapUnique(new v8::Global<v8::Value>(m_isolate, value)); + m_idToWrappedObject.insert( + std::make_pair(id, v8::Global<v8::Value>(m_isolate, value))); addObjectToGroup(id, groupName); return id; } @@ -57,7 +57,7 @@ void InjectedScriptNative::unbind(int id) { v8::Local<v8::Value> InjectedScriptNative::objectForId(int id) { auto iter = m_idToWrappedObject.find(id); - return iter != m_idToWrappedObject.end() ? iter->second->Get(m_isolate) + return iter != m_idToWrappedObject.end() ? iter->second.Get(m_isolate) : v8::Local<v8::Value>(); } diff --git a/deps/v8/src/inspector/injected-script-native.h b/deps/v8/src/inspector/injected-script-native.h index 3bdf24709d..c0b93013fe 100644 --- a/deps/v8/src/inspector/injected-script-native.h +++ b/deps/v8/src/inspector/injected-script-native.h @@ -34,8 +34,7 @@ class InjectedScriptNative final { int m_lastBoundObjectId; v8::Isolate* m_isolate; - protocol::HashMap<int, std::unique_ptr<v8::Global<v8::Value>>> - m_idToWrappedObject; + protocol::HashMap<int, v8::Global<v8::Value>> m_idToWrappedObject; typedef protocol::HashMap<int, String16> IdToObjectGroupName; IdToObjectGroupName m_idToObjectGroupName; typedef protocol::HashMap<String16, std::vector<int>> NameToObjectGroup; diff --git a/deps/v8/src/inspector/injected-script-source.js b/deps/v8/src/inspector/injected-script-source.js index f3c8d6b96e..b52277a8eb 100644 --- a/deps/v8/src/inspector/injected-script-source.js +++ b/deps/v8/src/inspector/injected-script-source.js @@ -211,6 +211,8 @@ InjectedScript.closureTypes["block"] = "Block"; InjectedScript.closureTypes["script"] = "Script"; InjectedScript.closureTypes["with"] = "With Block"; InjectedScript.closureTypes["global"] = "Global"; +InjectedScript.closureTypes["eval"] = "Eval"; +InjectedScript.closureTypes["module"] = "Module"; InjectedScript.prototype = { /** @@ -617,7 +619,13 @@ InjectedScript.prototype = { var className = InjectedScriptHost.internalConstructorName(obj); if (subtype === "array" || subtype === "typedarray") { if (typeof obj.length === "number") - className += "[" + obj.length + "]"; + return className + "(" + obj.length + ")"; + return className; + } + + if (subtype === "map" || subtype === "set") { + if (typeof obj.size === "number") + return className + "(" + obj.size + ")"; return className; } @@ -929,17 +937,16 @@ InjectedScript.RemoteObject.prototype = { if (!descriptor.isOwn) continue; - // Ignore computed properties. - if (!("value" in descriptor)) + // Ignore computed properties unless they have getters. + if (!("value" in descriptor)) { + if (descriptor.get) + this._appendPropertyPreview(preview, { name: name, type: "accessor", __proto__: null }, propertiesThreshold); continue; + } var value = descriptor.value; var type = typeof value; - // Never render functions in object preview. - if (type === "function" && (this.subtype !== "array" || !isUInt32(name))) - continue; - // Special-case HTMLAll. if (type === "undefined" && injectedScript._isHTMLAllCollection(value)) type = "object"; diff --git a/deps/v8/src/inspector/injected-script.cc b/deps/v8/src/inspector/injected-script.cc index d605227222..9d9c3270c2 100644 --- a/deps/v8/src/inspector/injected-script.cc +++ b/deps/v8/src/inspector/injected-script.cc @@ -105,9 +105,9 @@ std::unique_ptr<InjectedScript> InjectedScript::create( if (inspector->getContext(contextGroupId, contextId) != inspectedContext) return nullptr; if (!injectedScriptValue->IsObject()) return nullptr; - return wrapUnique(new InjectedScript(inspectedContext, - injectedScriptValue.As<v8::Object>(), - std::move(injectedScriptNative))); + return std::unique_ptr<InjectedScript>( + new InjectedScript(inspectedContext, injectedScriptValue.As<v8::Object>(), + std::move(injectedScriptNative))); } InjectedScript::InjectedScript( @@ -150,7 +150,7 @@ Response InjectedScript::getProperties( if (!response.isSuccess()) return response; protocol::ErrorSupport errors; std::unique_ptr<Array<PropertyDescriptor>> result = - Array<PropertyDescriptor>::parse(protocolValue.get(), &errors); + Array<PropertyDescriptor>::fromValue(protocolValue.get(), &errors); if (errors.hasErrors()) return Response::Error(errors.errors()); *properties = std::move(result); return Response::OK(); @@ -158,7 +158,7 @@ Response InjectedScript::getProperties( void InjectedScript::releaseObject(const String16& objectId) { std::unique_ptr<protocol::Value> parsedObjectId = - protocol::parseJSON(objectId); + protocol::StringUtil::parseJSON(objectId); if (!parsedObjectId) return; protocol::DictionaryValue* object = protocol::DictionaryValue::cast(parsedObjectId.get()); @@ -184,7 +184,7 @@ Response InjectedScript::wrapObject( if (!response.isSuccess()) return response; *result = - protocol::Runtime::RemoteObject::parse(protocolValue.get(), &errors); + protocol::Runtime::RemoteObject::fromValue(protocolValue.get(), &errors); if (!result->get()) return Response::Error(errors.errors()); return Response::OK(); } @@ -260,7 +260,8 @@ std::unique_ptr<protocol::Runtime::RemoteObject> InjectedScript::wrapTable( Response response = toProtocolValue(context, r, &protocolValue); if (!response.isSuccess()) return nullptr; protocol::ErrorSupport errors; - return protocol::Runtime::RemoteObject::parse(protocolValue.get(), &errors); + return protocol::Runtime::RemoteObject::fromValue(protocolValue.get(), + &errors); } Response InjectedScript::findObject(const RemoteObjectId& objectId, @@ -317,7 +318,7 @@ Response InjectedScript::resolveCallArgument( if (callArgument->hasValue() || callArgument->hasUnserializableValue()) { String16 value = callArgument->hasValue() - ? callArgument->getValue(nullptr)->toJSONString() + ? callArgument->getValue(nullptr)->serialize() : "Number(\"" + callArgument->getUnserializableValue("") + "\")"; if (!m_context->inspector() ->compileAndRunInternalScript( @@ -418,7 +419,7 @@ InjectedScript::Scope::Scope(V8InspectorImpl* inspector, int contextGroupId) m_handleScope(inspector->isolate()), m_tryCatch(inspector->isolate()), m_ignoreExceptionsAndMuteConsole(false), - m_previousPauseOnExceptionsState(v8::DebugInterface::NoBreakOnException), + m_previousPauseOnExceptionsState(v8::debug::NoBreakOnException), m_userGesture(false) {} Response InjectedScript::Scope::initialize() { @@ -448,14 +449,13 @@ void InjectedScript::Scope::ignoreExceptionsAndMuteConsole() { m_inspector->client()->muteMetrics(m_contextGroupId); m_inspector->muteExceptions(m_contextGroupId); m_previousPauseOnExceptionsState = - setPauseOnExceptionsState(v8::DebugInterface::NoBreakOnException); + setPauseOnExceptionsState(v8::debug::NoBreakOnException); } -v8::DebugInterface::ExceptionBreakState -InjectedScript::Scope::setPauseOnExceptionsState( - v8::DebugInterface::ExceptionBreakState newState) { +v8::debug::ExceptionBreakState InjectedScript::Scope::setPauseOnExceptionsState( + v8::debug::ExceptionBreakState newState) { if (!m_inspector->debugger()->enabled()) return newState; - v8::DebugInterface::ExceptionBreakState presentState = + v8::debug::ExceptionBreakState presentState = m_inspector->debugger()->getPauseOnExceptionsState(); if (presentState != newState) m_inspector->debugger()->setPauseOnExceptionsState(newState); diff --git a/deps/v8/src/inspector/injected-script.h b/deps/v8/src/inspector/injected-script.h index 6500f4dbb7..9e6680a7e3 100644 --- a/deps/v8/src/inspector/injected-script.h +++ b/deps/v8/src/inspector/injected-script.h @@ -120,15 +120,15 @@ class InjectedScript final { private: void cleanup(); - v8::DebugInterface::ExceptionBreakState setPauseOnExceptionsState( - v8::DebugInterface::ExceptionBreakState); + v8::debug::ExceptionBreakState setPauseOnExceptionsState( + v8::debug::ExceptionBreakState); v8::HandleScope m_handleScope; v8::TryCatch m_tryCatch; v8::Local<v8::Context> m_context; std::unique_ptr<V8Console::CommandLineAPIScope> m_commandLineAPIScope; bool m_ignoreExceptionsAndMuteConsole; - v8::DebugInterface::ExceptionBreakState m_previousPauseOnExceptionsState; + v8::debug::ExceptionBreakState m_previousPauseOnExceptionsState; bool m_userGesture; }; diff --git a/deps/v8/src/inspector/inspected-context.cc b/deps/v8/src/inspector/inspected-context.cc index dab3bba050..6d9f51ed3f 100644 --- a/deps/v8/src/inspector/inspected-context.cc +++ b/deps/v8/src/inspector/inspected-context.cc @@ -41,10 +41,12 @@ InspectedContext::InspectedContext(V8InspectorImpl* inspector, m_humanReadableName(toString16(info.humanReadableName)), m_auxData(toString16(info.auxData)), m_reported(false) { + v8::Isolate* isolate = m_inspector->isolate(); + info.context->SetEmbedderData(static_cast<int>(v8::Context::kDebugIdIndex), + v8::Int32::New(isolate, contextId)); m_context.SetWeak(&m_context, &clearContext, v8::WeakCallbackType::kParameter); - v8::Isolate* isolate = m_inspector->isolate(); v8::Local<v8::Object> global = info.context->Global(); v8::Local<v8::Object> console = V8Console::createConsole(this, info.hasMemoryOnConsole); @@ -65,6 +67,14 @@ InspectedContext::~InspectedContext() { } } +// static +int InspectedContext::contextId(v8::Local<v8::Context> context) { + v8::Local<v8::Value> data = + context->GetEmbedderData(static_cast<int>(v8::Context::kDebugIdIndex)); + if (data.IsEmpty() || !data->IsInt32()) return 0; + return static_cast<int>(data.As<v8::Int32>()->Value()); +} + v8::Local<v8::Context> InspectedContext::context() const { return m_context.Get(isolate()); } diff --git a/deps/v8/src/inspector/inspected-context.h b/deps/v8/src/inspector/inspected-context.h index f31eb76419..f8d97e9b94 100644 --- a/deps/v8/src/inspector/inspected-context.h +++ b/deps/v8/src/inspector/inspected-context.h @@ -21,6 +21,8 @@ class InspectedContext { public: ~InspectedContext(); + static int contextId(v8::Local<v8::Context>); + v8::Local<v8::Context> context() const; int contextId() const { return m_contextId; } int contextGroupId() const { return m_contextGroupId; } diff --git a/deps/v8/src/inspector/inspector.gyp b/deps/v8/src/inspector/inspector.gyp index 91507bd579..c70722f852 100644 --- a/deps/v8/src/inspector/inspector.gyp +++ b/deps/v8/src/inspector/inspector.gyp @@ -13,13 +13,6 @@ 'targets': [ { 'target_name': 'inspector_injected_script', 'type': 'none', - 'conditions': [ - ['want_separate_host_toolset==1', { - 'toolsets': ['host', 'target'], - }, { - 'toolsets': ['target'], - }] - ], 'actions': [ { 'action_name': 'convert_js_to_cpp_char_array', @@ -44,13 +37,6 @@ }, { 'target_name': 'inspector_debugger_script', 'type': 'none', - 'conditions': [ - ['want_separate_host_toolset==1', { - 'toolsets': ['host', 'target'], - }, { - 'toolsets': ['target'], - }] - ], 'actions': [ { 'action_name': 'convert_js_to_cpp_char_array', @@ -75,13 +61,6 @@ }, { 'target_name': 'protocol_compatibility', 'type': 'none', - 'conditions': [ - ['want_separate_host_toolset==1', { - 'toolsets': ['host', 'target'], - }, { - 'toolsets': ['target'], - }] - ], 'actions': [ { 'action_name': 'protocol_compatibility', @@ -104,13 +83,6 @@ { 'target_name': 'protocol_generated_sources', 'type': 'none', 'dependencies': [ 'protocol_compatibility' ], - 'conditions': [ - ['want_separate_host_toolset==1', { - 'toolsets': ['host', 'target'], - }, { - 'toolsets': ['target'], - }] - ], 'actions': [ { 'action_name': 'protocol_generated_sources', diff --git a/deps/v8/src/inspector/inspector.gypi b/deps/v8/src/inspector/inspector.gypi index 863c038d6a..8aff49d0ea 100644 --- a/deps/v8/src/inspector/inspector.gypi +++ b/deps/v8/src/inspector/inspector.gypi @@ -44,7 +44,6 @@ 'inspector/inspected-context.h', 'inspector/java-script-call-frame.cc', 'inspector/java-script-call-frame.h', - 'inspector/protocol-platform.h', 'inspector/remote-object-id.cc', 'inspector/remote-object-id.h', 'inspector/script-breakpoint.h', @@ -54,6 +53,8 @@ 'inspector/string-16.h', 'inspector/string-util.cc', 'inspector/string-util.h', + 'inspector/test-interface.cc', + 'inspector/test-interface.h', 'inspector/v8-console.cc', 'inspector/v8-console.h', 'inspector/v8-console-agent-impl.cc', @@ -90,6 +91,8 @@ 'inspector/v8-stack-trace-impl.h', 'inspector/v8-value-copier.cc', 'inspector/v8-value-copier.h', + 'inspector/wasm-translation.cc', + 'inspector/wasm-translation.h', ] } } diff --git a/deps/v8/src/inspector/inspector_protocol_config.json b/deps/v8/src/inspector/inspector_protocol_config.json index cb9e6698d1..22e2cf5636 100644 --- a/deps/v8/src/inspector/inspector_protocol_config.json +++ b/deps/v8/src/inspector/inspector_protocol_config.json @@ -3,7 +3,31 @@ "path": "js_protocol.json", "package": "src/inspector/protocol", "output": "protocol", - "namespace": ["v8_inspector", "protocol"] + "namespace": ["v8_inspector", "protocol"], + "options": [ + { + "domain": "Schema", + "exported": ["Domain"] + }, + { + "domain": "Runtime", + "async": ["evaluate", "awaitPromise", "callFunctionOn", "runScript"], + "exported": ["StackTrace", "RemoteObject"] + }, + { + "domain": "Debugger", + "exported": ["SearchMatch", "paused.reason"] + }, + { + "domain": "Console" + }, + { + "domain": "Profiler" + }, + { + "domain": "HeapProfiler" + } + ] }, "exported": { @@ -19,7 +43,6 @@ "lib": { "package": "src/inspector/protocol", "output": "protocol", - "string_header": "src/inspector/string-util.h", - "platform_header": "src/inspector/protocol-platform.h" + "string_header": "src/inspector/string-util.h" } } diff --git a/deps/v8/src/inspector/java-script-call-frame.cc b/deps/v8/src/inspector/java-script-call-frame.cc index 2da4f04249..f9d0585a8e 100644 --- a/deps/v8/src/inspector/java-script-call-frame.cc +++ b/deps/v8/src/inspector/java-script-call-frame.cc @@ -91,7 +91,7 @@ bool JavaScriptCallFrame::isAtReturn() const { return result.As<v8::Boolean>()->BooleanValue(context).FromMaybe(false); } -v8::Local<v8::Object> JavaScriptCallFrame::details() const { +v8::MaybeLocal<v8::Object> JavaScriptCallFrame::details() const { v8::MicrotasksScope microtasks(m_isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); v8::Local<v8::Context> context = @@ -101,8 +101,12 @@ v8::Local<v8::Object> JavaScriptCallFrame::details() const { v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast( callFrame->Get(context, toV8StringInternalized(m_isolate, "details")) .ToLocalChecked()); - return v8::Local<v8::Object>::Cast( - func->Call(context, callFrame, 0, nullptr).ToLocalChecked()); + v8::TryCatch try_catch(m_isolate); + v8::Local<v8::Value> details; + if (func->Call(context, callFrame, 0, nullptr).ToLocal(&details)) { + return v8::Local<v8::Object>::Cast(details); + } + return v8::MaybeLocal<v8::Object>(); } v8::MaybeLocal<v8::Value> JavaScriptCallFrame::evaluate( @@ -129,10 +133,11 @@ v8::MaybeLocal<v8::Value> JavaScriptCallFrame::restart() { v8::Local<v8::Function> restartFunction = v8::Local<v8::Function>::Cast( callFrame->Get(context, toV8StringInternalized(m_isolate, "restart")) .ToLocalChecked()); - v8::DebugInterface::SetLiveEditEnabled(m_isolate, true); + v8::TryCatch try_catch(m_isolate); + v8::debug::SetLiveEditEnabled(m_isolate, true); v8::MaybeLocal<v8::Value> result = restartFunction->Call( m_debuggerContext.Get(m_isolate), callFrame, 0, nullptr); - v8::DebugInterface::SetLiveEditEnabled(m_isolate, false); + v8::debug::SetLiveEditEnabled(m_isolate, false); return result; } @@ -154,6 +159,7 @@ v8::MaybeLocal<v8::Value> JavaScriptCallFrame::setVariableValue( v8::Local<v8::Value> argv[] = { v8::Local<v8::Value>(v8::Integer::New(m_isolate, scopeNumber)), variableName, newValue}; + v8::TryCatch try_catch(m_isolate); return setVariableValueFunction->Call(context, callFrame, arraysize(argv), argv); } diff --git a/deps/v8/src/inspector/java-script-call-frame.h b/deps/v8/src/inspector/java-script-call-frame.h index 5a4ce19cc2..6b73abf0ad 100644 --- a/deps/v8/src/inspector/java-script-call-frame.h +++ b/deps/v8/src/inspector/java-script-call-frame.h @@ -31,10 +31,10 @@ #ifndef V8_INSPECTOR_JAVASCRIPTCALLFRAME_H_ #define V8_INSPECTOR_JAVASCRIPTCALLFRAME_H_ +#include <memory> #include <vector> #include "src/base/macros.h" -#include "src/inspector/protocol-platform.h" #include "include/v8.h" @@ -44,7 +44,8 @@ class JavaScriptCallFrame { public: static std::unique_ptr<JavaScriptCallFrame> create( v8::Local<v8::Context> debuggerContext, v8::Local<v8::Object> callFrame) { - return wrapUnique(new JavaScriptCallFrame(debuggerContext, callFrame)); + return std::unique_ptr<JavaScriptCallFrame>( + new JavaScriptCallFrame(debuggerContext, callFrame)); } ~JavaScriptCallFrame(); @@ -54,7 +55,7 @@ class JavaScriptCallFrame { int contextId() const; bool isAtReturn() const; - v8::Local<v8::Object> details() const; + v8::MaybeLocal<v8::Object> details() const; v8::MaybeLocal<v8::Value> evaluate(v8::Local<v8::Value> expression); v8::MaybeLocal<v8::Value> restart(); diff --git a/deps/v8/src/inspector/js_protocol.json b/deps/v8/src/inspector/js_protocol.json index c1ac585ed1..d0af43ded5 100644 --- a/deps/v8/src/inspector/js_protocol.json +++ b/deps/v8/src/inspector/js_protocol.json @@ -9,7 +9,6 @@ "id": "Domain", "type": "object", "description": "Description of the protocol domain.", - "exported": true, "properties": [ { "name": "name", "type": "string", "description": "Domain name." }, { "name": "version", "type": "string", "description": "Domain version." } @@ -51,7 +50,6 @@ "id": "RemoteObject", "type": "object", "description": "Mirror object referencing original JavaScript object.", - "exported": true, "properties": [ { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." }, { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "map", "set", "iterator", "generator", "error", "proxy", "promise", "typedarray"], "description": "Object subtype hint. Specified for <code>object</code> type values only." }, @@ -200,7 +198,6 @@ "id": "StackTrace", "type": "object", "description": "Call frames for assertions or error messages.", - "exported": true, "properties": [ { "name": "description", "type": "string", "optional": true, "description": "String label of this stack trace. For async traces this may be a name of the function that initiated the async call." }, { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "JavaScript function name." }, @@ -211,7 +208,6 @@ "commands": [ { "name": "evaluate", - "async": true, "parameters": [ { "name": "expression", "type": "string", "description": "Expression to evaluate." }, { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." }, @@ -231,7 +227,6 @@ }, { "name": "awaitPromise", - "async": true, "parameters": [ { "name": "promiseObjectId", "$ref": "RemoteObjectId", "description": "Identifier of the promise." }, { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object that should be sent by value." }, @@ -245,7 +240,6 @@ }, { "name": "callFunctionOn", - "async": true, "parameters": [ { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to call function on." }, { "name": "functionDeclaration", "type": "string", "description": "Declaration of the function to call." }, @@ -333,7 +327,6 @@ }, { "name": "runScript", - "async": true, "parameters": [ { "name": "scriptId", "$ref": "ScriptId", "description": "Id of the script to run." }, { "name": "executionContextId", "$ref": "ExecutionContextId", "optional": true, "description": "Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page." }, @@ -460,7 +453,7 @@ "id": "Scope", "type": "object", "properties": [ - { "name": "type", "type": "string", "enum": ["global", "local", "with", "closure", "catch", "block", "script"], "description": "Scope type." }, + { "name": "type", "type": "string", "enum": ["global", "local", "with", "closure", "catch", "block", "script", "eval", "module"], "description": "Scope type." }, { "name": "object", "$ref": "Runtime.RemoteObject", "description": "Object representing the scope. For <code>global</code> and <code>with</code> scopes it represents the actual object; for the rest of the scopes, it is artificial transient object enumerating scope variables as its properties." }, { "name": "name", "type": "string", "optional": true }, { "name": "startLocation", "$ref": "Location", "optional": true, "description": "Location in the source code where scope starts" }, @@ -472,7 +465,6 @@ "id": "SearchMatch", "type": "object", "description": "Search match for resource.", - "exported": true, "properties": [ { "name": "lineNumber", "type": "number", "description": "Line number in resource content." }, { "name": "lineContent", "type": "string", "description": "Line with match content." } @@ -733,7 +725,7 @@ "name": "paused", "parameters": [ { "name": "callFrames", "type": "array", "items": { "$ref": "CallFrame" }, "description": "Call stack the virtual machine stopped on." }, - { "name": "reason", "type": "string", "enum": [ "XHR", "DOM", "EventListener", "exception", "assert", "debugCommand", "promiseRejection", "other" ], "description": "Pause reason.", "exported": true }, + { "name": "reason", "type": "string", "enum": [ "XHR", "DOM", "EventListener", "exception", "assert", "debugCommand", "promiseRejection", "other" ], "description": "Pause reason." }, { "name": "data", "type": "object", "optional": true, "description": "Object containing break-specific auxiliary properties." }, { "name": "hitBreakpoints", "type": "array", "optional": true, "items": { "type": "string" }, "description": "Hit breakpoints IDs" }, { "name": "asyncStackTrace", "$ref": "Runtime.StackTrace", "optional": true, "description": "Async stack trace, if any." } diff --git a/deps/v8/src/inspector/protocol-platform.h b/deps/v8/src/inspector/protocol-platform.h deleted file mode 100644 index c7723932b4..0000000000 --- a/deps/v8/src/inspector/protocol-platform.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_INSPECTOR_PROTOCOLPLATFORM_H_ -#define V8_INSPECTOR_PROTOCOLPLATFORM_H_ - -#include <memory> - -#include "src/base/logging.h" - -namespace v8_inspector { - -template <typename T> -std::unique_ptr<T> wrapUnique(T* ptr) { - return std::unique_ptr<T>(ptr); -} - -} // namespace v8_inspector - -#endif // V8_INSPECTOR_PROTOCOLPLATFORM_H_ diff --git a/deps/v8/src/inspector/remote-object-id.cc b/deps/v8/src/inspector/remote-object-id.cc index aac6724498..2f5f051816 100644 --- a/deps/v8/src/inspector/remote-object-id.cc +++ b/deps/v8/src/inspector/remote-object-id.cc @@ -13,7 +13,8 @@ RemoteObjectIdBase::RemoteObjectIdBase() : m_injectedScriptId(0) {} std::unique_ptr<protocol::DictionaryValue> RemoteObjectIdBase::parseInjectedScriptId(const String16& objectId) { - std::unique_ptr<protocol::Value> parsedValue = protocol::parseJSON(objectId); + std::unique_ptr<protocol::Value> parsedValue = + protocol::StringUtil::parseJSON(objectId); if (!parsedValue || parsedValue->type() != protocol::Value::TypeObject) return nullptr; diff --git a/deps/v8/src/inspector/script-breakpoint.h b/deps/v8/src/inspector/script-breakpoint.h index 025233dd19..a981b1626c 100644 --- a/deps/v8/src/inspector/script-breakpoint.h +++ b/deps/v8/src/inspector/script-breakpoint.h @@ -35,15 +35,18 @@ namespace v8_inspector { struct ScriptBreakpoint { - ScriptBreakpoint() : ScriptBreakpoint(0, 0, String16()) {} - - ScriptBreakpoint(int lineNumber, int columnNumber, const String16& condition) - : lineNumber(lineNumber), - columnNumber(columnNumber), - condition(condition) {} - - int lineNumber; - int columnNumber; + ScriptBreakpoint() {} + + ScriptBreakpoint(String16 script_id, int line_number, int column_number, + String16 condition) + : script_id(std::move(script_id)), + line_number(line_number), + column_number(column_number), + condition(std::move(condition)) {} + + String16 script_id; + int line_number = 0; + int column_number = 0; String16 condition; }; diff --git a/deps/v8/src/inspector/search-util.cc b/deps/v8/src/inspector/search-util.cc index a6fba06c11..b05d7a07ec 100644 --- a/deps/v8/src/inspector/search-util.cc +++ b/deps/v8/src/inspector/search-util.cc @@ -132,7 +132,8 @@ std::unique_ptr<V8Regex> createSearchRegex(V8InspectorImpl* inspector, const String16& query, bool caseSensitive, bool isRegex) { String16 regexSource = isRegex ? query : createSearchRegexSource(query); - return wrapUnique(new V8Regex(inspector, regexSource, caseSensitive)); + return std::unique_ptr<V8Regex>( + new V8Regex(inspector, regexSource, caseSensitive)); } } // namespace diff --git a/deps/v8/src/inspector/string-16.cc b/deps/v8/src/inspector/string-16.cc index 09909a911b..6544646d71 100644 --- a/deps/v8/src/inspector/string-16.cc +++ b/deps/v8/src/inspector/string-16.cc @@ -8,14 +8,11 @@ #include <cctype> #include <cstdlib> #include <cstring> -#include <iomanip> #include <limits> -#include <locale> -#include <sstream> #include <string> #include "src/base/platform/platform.h" -#include "src/inspector/protocol-platform.h" +#include "src/conversions.h" namespace v8_inspector { @@ -367,10 +364,9 @@ static inline void putUTF8Triple(char*& buffer, UChar ch) { // static String16 String16::fromInteger(int number) { - const size_t kBufferSize = 50; - char buffer[kBufferSize]; - v8::base::OS::SNPrintF(buffer, kBufferSize, "%d", number); - return String16(buffer); + char arr[50]; + v8::internal::Vector<char> buffer(arr, arraysize(arr)); + return String16(IntToCString(number, buffer)); } // static @@ -387,19 +383,16 @@ String16 String16::fromInteger(size_t number) { // static String16 String16::fromDouble(double number) { - std::ostringstream s; - s.imbue(std::locale("C")); - s << std::fixed << std::setprecision(std::numeric_limits<double>::digits10) - << number; - return String16(s.str().c_str()); + char arr[50]; + v8::internal::Vector<char> buffer(arr, arraysize(arr)); + return String16(DoubleToCString(number, buffer)); } // static String16 String16::fromDouble(double number, int precision) { - std::ostringstream s; - s.imbue(std::locale("C")); - s << std::fixed << std::setprecision(precision) << number; - return String16(s.str().c_str()); + std::unique_ptr<char[]> str( + v8::internal::DoubleToPrecisionCString(number, precision)); + return String16(str.get()); } int String16::toInteger(bool* ok) const { diff --git a/deps/v8/src/inspector/string-16.h b/deps/v8/src/inspector/string-16.h index 360ec93864..0270f5117a 100644 --- a/deps/v8/src/inspector/string-16.h +++ b/deps/v8/src/inspector/string-16.h @@ -23,7 +23,7 @@ class String16 { String16() {} String16(const String16& other) : m_impl(other.m_impl), hash_code(other.hash_code) {} - String16(const String16&& other) + String16(String16&& other) : m_impl(std::move(other.m_impl)), hash_code(other.hash_code) {} String16(const UChar* characters, size_t size) : m_impl(characters, size) {} String16(const UChar* characters) // NOLINT(runtime/explicit) diff --git a/deps/v8/src/inspector/string-util.cc b/deps/v8/src/inspector/string-util.cc index e6ad5d0c5b..31b2db572d 100644 --- a/deps/v8/src/inspector/string-util.cc +++ b/deps/v8/src/inspector/string-util.cc @@ -50,8 +50,7 @@ v8::Local<v8::String> toV8String(v8::Isolate* isolate, } String16 toProtocolString(v8::Local<v8::String> value) { - if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) - return String16(); + if (value.IsEmpty() || value->IsNullOrUndefined()) return String16(); std::unique_ptr<UChar[]> buffer(new UChar[value->Length()]); value->Write(reinterpret_cast<uint16_t*>(buffer.get()), 0, value->Length()); return String16(buffer.get(), value->Length()); @@ -93,19 +92,20 @@ bool stringViewStartsWith(const StringView& string, const char* prefix) { namespace protocol { -std::unique_ptr<protocol::Value> parseJSON(const StringView& string) { +std::unique_ptr<protocol::Value> StringUtil::parseJSON( + const StringView& string) { if (!string.length()) return nullptr; if (string.is8Bit()) { - return protocol::parseJSON(string.characters8(), + return parseJSONCharacters(string.characters8(), static_cast<int>(string.length())); } - return protocol::parseJSON(string.characters16(), + return parseJSONCharacters(string.characters16(), static_cast<int>(string.length())); } -std::unique_ptr<protocol::Value> parseJSON(const String16& string) { +std::unique_ptr<protocol::Value> StringUtil::parseJSON(const String16& string) { if (!string.length()) return nullptr; - return protocol::parseJSON(string.characters16(), + return parseJSONCharacters(string.characters16(), static_cast<int>(string.length())); } @@ -119,7 +119,7 @@ std::unique_ptr<StringBuffer> StringBuffer::create(const StringView& string) { // static std::unique_ptr<StringBufferImpl> StringBufferImpl::adopt(String16& string) { - return wrapUnique(new StringBufferImpl(string)); + return std::unique_ptr<StringBufferImpl>(new StringBufferImpl(string)); } StringBufferImpl::StringBufferImpl(String16& string) { diff --git a/deps/v8/src/inspector/string-util.h b/deps/v8/src/inspector/string-util.h index e1a69e8906..c484aab2ed 100644 --- a/deps/v8/src/inspector/string-util.h +++ b/deps/v8/src/inspector/string-util.h @@ -5,6 +5,9 @@ #ifndef V8_INSPECTOR_STRINGUTIL_H_ #define V8_INSPECTOR_STRINGUTIL_H_ +#include <memory> + +#include "src/base/logging.h" #include "src/base/macros.h" #include "src/inspector/string-16.h" @@ -33,11 +36,10 @@ class StringUtil { static void builderReserve(StringBuilder& builder, size_t capacity) { builder.reserveCapacity(capacity); } + static std::unique_ptr<protocol::Value> parseJSON(const String16& json); + static std::unique_ptr<protocol::Value> parseJSON(const StringView& json); }; -std::unique_ptr<protocol::Value> parseJSON(const StringView& json); -std::unique_ptr<protocol::Value> parseJSON(const String16& json); - } // namespace protocol v8::Local<v8::String> toV8String(v8::Isolate*, const String16&); diff --git a/deps/v8/src/inspector/test-interface.cc b/deps/v8/src/inspector/test-interface.cc new file mode 100644 index 0000000000..ead1dc3b81 --- /dev/null +++ b/deps/v8/src/inspector/test-interface.cc @@ -0,0 +1,18 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/inspector/test-interface.h" + +#include "src/inspector/v8-debugger.h" +#include "src/inspector/v8-inspector-impl.h" + +namespace v8_inspector { + +void SetMaxAsyncTaskStacksForTest(V8Inspector* inspector, int limit) { + static_cast<V8InspectorImpl*>(inspector) + ->debugger() + ->setMaxAsyncTaskStacksForTest(limit); +} + +} // v8_inspector diff --git a/deps/v8/src/inspector/test-interface.h b/deps/v8/src/inspector/test-interface.h new file mode 100644 index 0000000000..98bedc2786 --- /dev/null +++ b/deps/v8/src/inspector/test-interface.h @@ -0,0 +1,18 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_INSPECTOR_TEST_INTERFACE_H_ +#define V8_INSPECTOR_TEST_INTERFACE_H_ + +#include "include/v8.h" + +namespace v8_inspector { + +class V8Inspector; + +V8_EXPORT void SetMaxAsyncTaskStacksForTest(V8Inspector* inspector, int limit); + +} // v8_inspector + +#endif // V8_INSPECTOR_TEST_INTERFACE_H_ diff --git a/deps/v8/src/inspector/v8-console-message.cc b/deps/v8/src/inspector/v8-console-message.cc index 63f1d49faf..281a0b1d90 100644 --- a/deps/v8/src/inspector/v8-console-message.cc +++ b/deps/v8/src/inspector/v8-console-message.cc @@ -4,6 +4,7 @@ #include "src/inspector/v8-console-message.h" +#include "src/debug/debug-interface.h" #include "src/inspector/inspected-context.h" #include "src/inspector/protocol/Protocol.h" #include "src/inspector/string-util.h" @@ -58,6 +59,7 @@ String16 consoleAPITypeValue(ConsoleAPIType type) { } const unsigned maxConsoleMessageCount = 1000; +const int maxConsoleMessageV8Size = 10 * 1024 * 1024; const unsigned maxArrayItemsLimit = 10000; const unsigned maxStackDepthLimit = 32; @@ -361,7 +363,7 @@ std::unique_ptr<V8ConsoleMessage> V8ConsoleMessage::createForConsoleAPI( V8InspectorImpl* inspector = inspectedContext->inspector(); v8::Local<v8::Context> context = inspectedContext->context(); - std::unique_ptr<V8ConsoleMessage> message = wrapUnique( + std::unique_ptr<V8ConsoleMessage> message( new V8ConsoleMessage(V8MessageOrigin::kConsole, timestamp, String16())); if (stackTrace && !stackTrace->isEmpty()) { message->m_url = toString16(stackTrace->topSourceURL()); @@ -371,9 +373,12 @@ std::unique_ptr<V8ConsoleMessage> V8ConsoleMessage::createForConsoleAPI( message->m_stackTrace = std::move(stackTrace); message->m_type = type; message->m_contextId = contextId; - for (size_t i = 0; i < arguments.size(); ++i) - message->m_arguments.push_back( - wrapUnique(new v8::Global<v8::Value>(isolate, arguments.at(i)))); + for (size_t i = 0; i < arguments.size(); ++i) { + message->m_arguments.push_back(std::unique_ptr<v8::Global<v8::Value>>( + new v8::Global<v8::Value>(isolate, arguments.at(i)))); + message->m_v8Size += + v8::debug::EstimatedValueSize(isolate, arguments.at(i)); + } if (arguments.size()) message->m_message = V8ValueStringBuilder::toString(arguments[0], context); @@ -404,7 +409,7 @@ std::unique_ptr<V8ConsoleMessage> V8ConsoleMessage::createForException( std::unique_ptr<V8StackTraceImpl> stackTrace, int scriptId, v8::Isolate* isolate, const String16& message, int contextId, v8::Local<v8::Value> exception, unsigned exceptionId) { - std::unique_ptr<V8ConsoleMessage> consoleMessage = wrapUnique( + std::unique_ptr<V8ConsoleMessage> consoleMessage( new V8ConsoleMessage(V8MessageOrigin::kException, timestamp, message)); consoleMessage->setLocation(url, lineNumber, columnNumber, std::move(stackTrace), scriptId); @@ -413,7 +418,10 @@ std::unique_ptr<V8ConsoleMessage> V8ConsoleMessage::createForException( if (contextId && !exception.IsEmpty()) { consoleMessage->m_contextId = contextId; consoleMessage->m_arguments.push_back( - wrapUnique(new v8::Global<v8::Value>(isolate, exception))); + std::unique_ptr<v8::Global<v8::Value>>( + new v8::Global<v8::Value>(isolate, exception))); + consoleMessage->m_v8Size += + v8::debug::EstimatedValueSize(isolate, exception); } return consoleMessage; } @@ -422,7 +430,7 @@ std::unique_ptr<V8ConsoleMessage> V8ConsoleMessage::createForException( std::unique_ptr<V8ConsoleMessage> V8ConsoleMessage::createForRevokedException( double timestamp, const String16& messageText, unsigned revokedExceptionId) { - std::unique_ptr<V8ConsoleMessage> message = wrapUnique(new V8ConsoleMessage( + std::unique_ptr<V8ConsoleMessage> message(new V8ConsoleMessage( V8MessageOrigin::kRevokedException, timestamp, messageText)); message->m_revokedExceptionId = revokedExceptionId; return message; @@ -434,15 +442,14 @@ void V8ConsoleMessage::contextDestroyed(int contextId) { if (m_message.isEmpty()) m_message = "<message collected>"; Arguments empty; m_arguments.swap(empty); + m_v8Size = 0; } // ------------------------ V8ConsoleMessageStorage ---------------------------- V8ConsoleMessageStorage::V8ConsoleMessageStorage(V8InspectorImpl* inspector, int contextGroupId) - : m_inspector(inspector), - m_contextGroupId(contextGroupId), - m_expiredCount(0) {} + : m_inspector(inspector), m_contextGroupId(contextGroupId) {} V8ConsoleMessageStorage::~V8ConsoleMessageStorage() { clear(); } @@ -463,23 +470,33 @@ void V8ConsoleMessageStorage::addMessage( DCHECK(m_messages.size() <= maxConsoleMessageCount); if (m_messages.size() == maxConsoleMessageCount) { - ++m_expiredCount; + m_estimatedSize -= m_messages.front()->estimatedSize(); + m_messages.pop_front(); + } + while (m_estimatedSize + message->estimatedSize() > maxConsoleMessageV8Size && + !m_messages.empty()) { + m_estimatedSize -= m_messages.front()->estimatedSize(); m_messages.pop_front(); } + m_messages.push_back(std::move(message)); + m_estimatedSize += m_messages.back()->estimatedSize(); } void V8ConsoleMessageStorage::clear() { m_messages.clear(); - m_expiredCount = 0; + m_estimatedSize = 0; if (V8InspectorSessionImpl* session = m_inspector->sessionForContextGroup(m_contextGroupId)) session->releaseObjectGroup("console"); } void V8ConsoleMessageStorage::contextDestroyed(int contextId) { - for (size_t i = 0; i < m_messages.size(); ++i) + m_estimatedSize = 0; + for (size_t i = 0; i < m_messages.size(); ++i) { m_messages[i]->contextDestroyed(contextId); + m_estimatedSize += m_messages[i]->estimatedSize(); + } } } // namespace v8_inspector diff --git a/deps/v8/src/inspector/v8-console-message.h b/deps/v8/src/inspector/v8-console-message.h index a6e9eafe2d..8ab81f4dcb 100644 --- a/deps/v8/src/inspector/v8-console-message.h +++ b/deps/v8/src/inspector/v8-console-message.h @@ -65,6 +65,10 @@ class V8ConsoleMessage { ConsoleAPIType type() const; void contextDestroyed(int contextId); + int estimatedSize() const { + return m_v8Size + static_cast<int>(m_message.length() * sizeof(UChar)); + } + private: V8ConsoleMessage(V8MessageOrigin, double timestamp, const String16& message); @@ -89,6 +93,7 @@ class V8ConsoleMessage { ConsoleAPIType m_type; unsigned m_exceptionId; unsigned m_revokedExceptionId; + int m_v8Size = 0; Arguments m_arguments; String16 m_detailedMessage; }; @@ -99,7 +104,6 @@ class V8ConsoleMessageStorage { ~V8ConsoleMessageStorage(); int contextGroupId() { return m_contextGroupId; } - int expiredCount() { return m_expiredCount; } const std::deque<std::unique_ptr<V8ConsoleMessage>>& messages() const { return m_messages; } @@ -111,7 +115,7 @@ class V8ConsoleMessageStorage { private: V8InspectorImpl* m_inspector; int m_contextGroupId; - int m_expiredCount; + int m_estimatedSize = 0; std::deque<std::unique_ptr<V8ConsoleMessage>> m_messages; }; diff --git a/deps/v8/src/inspector/v8-console.cc b/deps/v8/src/inspector/v8-console.cc index fee61177e7..3b47d2f6b4 100644 --- a/deps/v8/src/inspector/v8-console.cc +++ b/deps/v8/src/inspector/v8-console.cc @@ -714,6 +714,29 @@ v8::Local<v8::Object> V8Console::createConsole( createBoundFunctionProperty(context, console, "timeStamp", V8Console::timeStampCallback); + const char* jsConsoleAssert = + "(function(){\n" + " var originAssert = this.assert;\n" + " originAssert.apply = Function.prototype.apply;\n" + " this.assert = assertWrapper;\n" + " assertWrapper.toString = () => originAssert.toString();\n" + " function assertWrapper(){\n" + " if (!!arguments[0]) return;\n" + " originAssert.apply(null, arguments);\n" + " }\n" + "})"; + + v8::Local<v8::String> assertSource = toV8String(isolate, jsConsoleAssert); + V8InspectorImpl* inspector = inspectedContext->inspector(); + v8::Local<v8::Value> setupFunction; + if (inspector->compileAndRunInternalScript(context, assertSource) + .ToLocal(&setupFunction) && + setupFunction->IsFunction()) { + inspector->callInternalFunction( + v8::Local<v8::Function>::Cast(setupFunction), context, console, 0, + nullptr); + } + if (hasMemoryAttribute) console->SetAccessorProperty( toV8StringInternalized(isolate, "memory"), diff --git a/deps/v8/src/inspector/v8-debugger-agent-impl.cc b/deps/v8/src/inspector/v8-debugger-agent-impl.cc index 224ae282c4..b287d1c082 100644 --- a/deps/v8/src/inspector/v8-debugger-agent-impl.cc +++ b/deps/v8/src/inspector/v8-debugger-agent-impl.cc @@ -60,8 +60,28 @@ static const char kDebuggerNotEnabled[] = "Debugger agent is not enabled"; static const char kDebuggerNotPaused[] = "Can only perform operation while paused."; -static String16 breakpointIdSuffix( - V8DebuggerAgentImpl::BreakpointSource source) { +namespace { + +void TranslateWasmStackTraceLocations(Array<CallFrame>* stackTrace, + WasmTranslation* wasmTranslation) { + for (size_t i = 0, e = stackTrace->length(); i != e; ++i) { + protocol::Debugger::Location* location = stackTrace->get(i)->getLocation(); + String16 scriptId = location->getScriptId(); + int lineNumber = location->getLineNumber(); + int columnNumber = location->getColumnNumber(-1); + + if (!wasmTranslation->TranslateWasmScriptLocationToProtocolLocation( + &scriptId, &lineNumber, &columnNumber)) { + continue; + } + + location->setScriptId(std::move(scriptId)); + location->setLineNumber(lineNumber); + location->setColumnNumber(columnNumber); + } +} + +String16 breakpointIdSuffix(V8DebuggerAgentImpl::BreakpointSource source) { switch (source) { case V8DebuggerAgentImpl::UserBreakpointSource: break; @@ -73,26 +93,25 @@ static String16 breakpointIdSuffix( return String16(); } -static String16 generateBreakpointId( - const String16& scriptId, int lineNumber, int columnNumber, - V8DebuggerAgentImpl::BreakpointSource source) { +String16 generateBreakpointId(const ScriptBreakpoint& breakpoint, + V8DebuggerAgentImpl::BreakpointSource source) { String16Builder builder; - builder.append(scriptId); + builder.append(breakpoint.script_id); builder.append(':'); - builder.appendNumber(lineNumber); + builder.appendNumber(breakpoint.line_number); builder.append(':'); - builder.appendNumber(columnNumber); + builder.appendNumber(breakpoint.column_number); builder.append(breakpointIdSuffix(source)); return builder.toString(); } -static bool positionComparator(const std::pair<int, int>& a, - const std::pair<int, int>& b) { +bool positionComparator(const std::pair<int, int>& a, + const std::pair<int, int>& b) { if (a.first != b.first) return a.first < b.first; return a.second < b.second; } -static std::unique_ptr<protocol::Debugger::Location> buildProtocolLocation( +std::unique_ptr<protocol::Debugger::Location> buildProtocolLocation( const String16& scriptId, int lineNumber, int columnNumber) { return protocol::Debugger::Location::create() .setScriptId(scriptId) @@ -101,6 +120,8 @@ static std::unique_ptr<protocol::Debugger::Location> buildProtocolLocation( .build(); } +} // namespace + V8DebuggerAgentImpl::V8DebuggerAgentImpl( V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, protocol::DictionaryValue* state) @@ -161,7 +182,7 @@ Response V8DebuggerAgentImpl::disable() { m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, protocol::DictionaryValue::create()); m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, - v8::DebugInterface::NoBreakOnException); + v8::debug::NoBreakOnException); m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, 0); if (!m_pausedContext.IsEmpty()) m_debugger->continueProgram(); @@ -199,7 +220,7 @@ void V8DebuggerAgentImpl::restore() { enableImpl(); - int pauseState = v8::DebugInterface::NoBreakOnException; + int pauseState = v8::debug::NoBreakOnException; m_state->getInteger(DebuggerAgentState::pauseOnExceptionsState, &pauseState); setPauseOnExceptionsImpl(pauseState); @@ -291,12 +312,13 @@ Response V8DebuggerAgentImpl::setBreakpointByUrl( breakpointId, buildObjectForBreakpointCookie( url, lineNumber, columnNumber, condition, isRegex)); - ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); + ScriptBreakpoint breakpoint(String16(), lineNumber, columnNumber, condition); for (const auto& script : m_scripts) { if (!matches(m_inspector, script.second->sourceURL(), url, isRegex)) continue; - std::unique_ptr<protocol::Debugger::Location> location = resolveBreakpoint( - breakpointId, script.first, breakpoint, UserBreakpointSource); + breakpoint.script_id = script.first; + std::unique_ptr<protocol::Debugger::Location> location = + resolveBreakpoint(breakpointId, breakpoint, UserBreakpointSource); if (location) (*locations)->addItem(std::move(location)); } @@ -308,21 +330,18 @@ Response V8DebuggerAgentImpl::setBreakpoint( std::unique_ptr<protocol::Debugger::Location> location, Maybe<String16> optionalCondition, String16* outBreakpointId, std::unique_ptr<protocol::Debugger::Location>* actualLocation) { - String16 scriptId = location->getScriptId(); - int lineNumber = location->getLineNumber(); - int columnNumber = location->getColumnNumber(0); - - String16 condition = optionalCondition.fromMaybe(""); + ScriptBreakpoint breakpoint( + location->getScriptId(), location->getLineNumber(), + location->getColumnNumber(0), optionalCondition.fromMaybe(String16())); - String16 breakpointId = generateBreakpointId( - scriptId, lineNumber, columnNumber, UserBreakpointSource); + String16 breakpointId = + generateBreakpointId(breakpoint, UserBreakpointSource); if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) != m_breakpointIdToDebuggerBreakpointIds.end()) { return Response::Error("Breakpoint at specified location already exists."); } - ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); - *actualLocation = resolveBreakpoint(breakpointId, scriptId, breakpoint, - UserBreakpointSource); + *actualLocation = + resolveBreakpoint(breakpointId, breakpoint, UserBreakpointSource); if (!*actualLocation) return Response::Error("Could not resolve breakpoint"); *outBreakpointId = breakpointId; return Response::OK(); @@ -365,9 +384,9 @@ Response V8DebuggerAgentImpl::getPossibleBreakpoints( return Response::Error( "start.lineNumber and start.columnNumber should be >= 0"); - v8::DebugInterface::Location v8Start(start->getLineNumber(), - start->getColumnNumber(0)); - v8::DebugInterface::Location v8End; + v8::debug::Location v8Start(start->getLineNumber(), + start->getColumnNumber(0)); + v8::debug::Location v8End; if (end.isJust()) { if (end.fromJust()->getScriptId() != scriptId) return Response::Error("Locations should contain the same scriptId"); @@ -376,12 +395,12 @@ Response V8DebuggerAgentImpl::getPossibleBreakpoints( if (line < 0 || column < 0) return Response::Error( "end.lineNumber and end.columnNumber should be >= 0"); - v8End = v8::DebugInterface::Location(line, column); + v8End = v8::debug::Location(line, column); } auto it = m_scripts.find(scriptId); if (it == m_scripts.end()) return Response::Error("Script not found"); - std::vector<v8::DebugInterface::Location> v8Locations; + std::vector<v8::debug::Location> v8Locations; if (!it->second->getPossibleBreakpoints(v8Start, v8End, &v8Locations)) return Response::InternalError(); @@ -405,13 +424,13 @@ Response V8DebuggerAgentImpl::continueToLocation( m_continueToLocationBreakpointId = ""; } - String16 scriptId = location->getScriptId(); - int lineNumber = location->getLineNumber(); - int columnNumber = location->getColumnNumber(0); + ScriptBreakpoint breakpoint(location->getScriptId(), + location->getLineNumber(), + location->getColumnNumber(0), String16()); - ScriptBreakpoint breakpoint(lineNumber, columnNumber, ""); m_continueToLocationBreakpointId = m_debugger->setBreakpoint( - scriptId, breakpoint, &lineNumber, &columnNumber); + breakpoint, &breakpoint.line_number, &breakpoint.column_number); + // TODO(kozyatinskiy): Return actual line and column number. return resume(); } @@ -493,23 +512,28 @@ V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::shouldSkipStepPause( std::unique_ptr<protocol::Debugger::Location> V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId, - const String16& scriptId, const ScriptBreakpoint& breakpoint, BreakpointSource source) { + v8::HandleScope handles(m_isolate); DCHECK(enabled()); // FIXME: remove these checks once crbug.com/520702 is resolved. CHECK(!breakpointId.isEmpty()); - CHECK(!scriptId.isEmpty()); - ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId); + CHECK(!breakpoint.script_id.isEmpty()); + ScriptsMap::iterator scriptIterator = m_scripts.find(breakpoint.script_id); if (scriptIterator == m_scripts.end()) return nullptr; - if (breakpoint.lineNumber < scriptIterator->second->startLine() || - scriptIterator->second->endLine() < breakpoint.lineNumber) + if (breakpoint.line_number < scriptIterator->second->startLine() || + scriptIterator->second->endLine() < breakpoint.line_number) return nullptr; + ScriptBreakpoint translatedBreakpoint = breakpoint; + m_debugger->wasmTranslation()->TranslateProtocolLocationToWasmScriptLocation( + &translatedBreakpoint.script_id, &translatedBreakpoint.line_number, + &translatedBreakpoint.column_number); + int actualLineNumber; int actualColumnNumber; String16 debuggerBreakpointId = m_debugger->setBreakpoint( - scriptId, breakpoint, &actualLineNumber, &actualColumnNumber); + translatedBreakpoint, &actualLineNumber, &actualColumnNumber); if (debuggerBreakpointId.isEmpty()) return nullptr; m_serverBreakpoints[debuggerBreakpointId] = @@ -518,7 +542,8 @@ V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId, m_breakpointIdToDebuggerBreakpointIds[breakpointId].push_back( debuggerBreakpointId); - return buildProtocolLocation(scriptId, actualLineNumber, actualColumnNumber); + return buildProtocolLocation(translatedBreakpoint.script_id, actualLineNumber, + actualColumnNumber); } Response V8DebuggerAgentImpl::searchInContent( @@ -531,9 +556,8 @@ Response V8DebuggerAgentImpl::searchInContent( return Response::Error("No script for id: " + scriptId); std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches = - searchInTextByLinesImpl(m_session, - toProtocolString(it->second->source(m_isolate)), - query, optionalCaseSensitive.fromMaybe(false), + searchInTextByLinesImpl(m_session, it->second->source(m_isolate), query, + optionalCaseSensitive.fromMaybe(false), optionalIsRegex.fromMaybe(false)); *results = protocol::Array<protocol::Debugger::SearchMatch>::create(); for (size_t i = 0; i < matches.size(); ++i) @@ -604,7 +628,7 @@ Response V8DebuggerAgentImpl::getScriptSource(const String16& scriptId, if (it == m_scripts.end()) return Response::Error("No script for id: " + scriptId); v8::HandleScope handles(m_isolate); - *scriptSource = toProtocolString(it->second->source(m_isolate)); + *scriptSource = it->second->source(m_isolate); return Response::OK(); } @@ -699,13 +723,13 @@ Response V8DebuggerAgentImpl::stepOut() { Response V8DebuggerAgentImpl::setPauseOnExceptions( const String16& stringPauseState) { if (!enabled()) return Response::Error(kDebuggerNotEnabled); - v8::DebugInterface::ExceptionBreakState pauseState; + v8::debug::ExceptionBreakState pauseState; if (stringPauseState == "none") { - pauseState = v8::DebugInterface::NoBreakOnException; + pauseState = v8::debug::NoBreakOnException; } else if (stringPauseState == "all") { - pauseState = v8::DebugInterface::BreakOnAnyException; + pauseState = v8::debug::BreakOnAnyException; } else if (stringPauseState == "uncaught") { - pauseState = v8::DebugInterface::BreakOnUncaughtException; + pauseState = v8::debug::BreakOnUncaughtException; } else { return Response::Error("Unknown pause on exceptions mode: " + stringPauseState); @@ -716,7 +740,7 @@ Response V8DebuggerAgentImpl::setPauseOnExceptions( void V8DebuggerAgentImpl::setPauseOnExceptionsImpl(int pauseState) { m_debugger->setPauseOnExceptionsState( - static_cast<v8::DebugInterface::ExceptionBreakState>(pauseState)); + static_cast<v8::debug::ExceptionBreakState>(pauseState)); m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, pauseState); } @@ -910,7 +934,7 @@ Response V8DebuggerAgentImpl::currentCallFrames( } v8::HandleScope handles(m_isolate); v8::Local<v8::Context> debuggerContext = - v8::DebugInterface::GetDebugContext(m_isolate); + v8::debug::GetDebugContext(m_isolate); v8::Context::Scope contextScope(debuggerContext); v8::Local<v8::Array> objects = v8::Array::New(m_isolate); @@ -920,8 +944,9 @@ Response V8DebuggerAgentImpl::currentCallFrames( const std::unique_ptr<JavaScriptCallFrame>& currentCallFrame = m_pausedCallFrames[frameOrdinal]; - v8::Local<v8::Object> details = currentCallFrame->details(); - if (details.IsEmpty()) return Response::InternalError(); + v8::Local<v8::Object> details; + if (!currentCallFrame->details().ToLocal(&details)) + return Response::InternalError(); int contextId = currentCallFrame->contextId(); @@ -1004,8 +1029,10 @@ Response V8DebuggerAgentImpl::currentCallFrames( Response response = toProtocolValue(debuggerContext, objects, &protocolValue); if (!response.isSuccess()) return response; protocol::ErrorSupport errorSupport; - *result = Array<CallFrame>::parse(protocolValue.get(), &errorSupport); + *result = Array<CallFrame>::fromValue(protocolValue.get(), &errorSupport); if (!*result) return Response::Error(errorSupport.errors()); + TranslateWasmStackTraceLocations(result->get(), + m_debugger->wasmTranslation()); return Response::OK(); } @@ -1019,40 +1046,51 @@ std::unique_ptr<StackTrace> V8DebuggerAgentImpl::currentAsyncStackTrace() { void V8DebuggerAgentImpl::didParseSource( std::unique_ptr<V8DebuggerScript> script, bool success) { v8::HandleScope handles(m_isolate); - String16 scriptSource = toProtocolString(script->source(m_isolate)); + String16 scriptSource = script->source(m_isolate); if (!success) script->setSourceURL(findSourceURL(scriptSource, false)); if (!success) script->setSourceMappingURL(findSourceMapURL(scriptSource, false)); + int contextId = script->executionContextId(); + int contextGroupId = m_inspector->contextGroupId(contextId); + InspectedContext* inspected = + m_inspector->getContext(contextGroupId, contextId); std::unique_ptr<protocol::DictionaryValue> executionContextAuxData; - if (!script->executionContextAuxData().isEmpty()) + if (inspected) { + // Script reused between different groups/sessions can have a stale + // execution context id. executionContextAuxData = protocol::DictionaryValue::cast( - protocol::parseJSON(script->executionContextAuxData())); + protocol::StringUtil::parseJSON(inspected->auxData())); + } bool isLiveEdit = script->isLiveEdit(); bool hasSourceURL = script->hasSourceURL(); String16 scriptId = script->scriptId(); String16 scriptURL = script->sourceURL(); - Maybe<String16> sourceMapURLParam = script->sourceMappingURL(); + m_scripts[scriptId] = std::move(script); + + ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId); + DCHECK(scriptIterator != m_scripts.end()); + V8DebuggerScript* scriptRef = scriptIterator->second.get(); + + Maybe<String16> sourceMapURLParam = scriptRef->sourceMappingURL(); Maybe<protocol::DictionaryValue> executionContextAuxDataParam( std::move(executionContextAuxData)); const bool* isLiveEditParam = isLiveEdit ? &isLiveEdit : nullptr; const bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : nullptr; if (success) m_frontend.scriptParsed( - scriptId, scriptURL, script->startLine(), script->startColumn(), - script->endLine(), script->endColumn(), script->executionContextId(), - script->hash(), std::move(executionContextAuxDataParam), + scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(), + scriptRef->endLine(), scriptRef->endColumn(), contextId, + scriptRef->hash(m_isolate), std::move(executionContextAuxDataParam), isLiveEditParam, std::move(sourceMapURLParam), hasSourceURLParam); else m_frontend.scriptFailedToParse( - scriptId, scriptURL, script->startLine(), script->startColumn(), - script->endLine(), script->endColumn(), script->executionContextId(), - script->hash(), std::move(executionContextAuxDataParam), + scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(), + scriptRef->endLine(), scriptRef->endColumn(), contextId, + scriptRef->hash(m_isolate), std::move(executionContextAuxDataParam), std::move(sourceMapURLParam), hasSourceURLParam); - m_scripts[scriptId] = std::move(script); - if (scriptURL.isEmpty() || !success) return; protocol::DictionaryValue* breakpointsCookie = @@ -1069,14 +1107,15 @@ void V8DebuggerAgentImpl::didParseSource( breakpointObject->getString(DebuggerAgentState::url, &url); if (!matches(m_inspector, scriptURL, url, isRegex)) continue; ScriptBreakpoint breakpoint; + breakpoint.script_id = scriptId; breakpointObject->getInteger(DebuggerAgentState::lineNumber, - &breakpoint.lineNumber); + &breakpoint.line_number); breakpointObject->getInteger(DebuggerAgentState::columnNumber, - &breakpoint.columnNumber); + &breakpoint.column_number); breakpointObject->getString(DebuggerAgentState::condition, &breakpoint.condition); - std::unique_ptr<protocol::Debugger::Location> location = resolveBreakpoint( - cookie.first, scriptId, breakpoint, UserBreakpointSource); + std::unique_ptr<protocol::Debugger::Location> location = + resolveBreakpoint(cookie.first, breakpoint, UserBreakpointSource); if (location) m_frontend.breakpointResolved(cookie.first, std::move(location)); } @@ -1117,7 +1156,7 @@ V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause( if (!exception.IsEmpty()) { InjectedScript* injectedScript = nullptr; - m_session->findInjectedScript(V8Debugger::contextId(context), + m_session->findInjectedScript(InspectedContext::contextId(context), injectedScript); if (injectedScript) { m_breakReason = @@ -1128,7 +1167,7 @@ V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause( injectedScript->wrapObject(exception, kBacktraceObjectGroup, false, false, &obj); if (obj) { - m_breakAuxData = obj->serialize(); + m_breakAuxData = obj->toValue(); m_breakAuxData->setBoolean("uncaught", isUncaught); } else { m_breakAuxData = nullptr; @@ -1200,8 +1239,7 @@ void V8DebuggerAgentImpl::breakProgramOnException( const String16& breakReason, std::unique_ptr<protocol::DictionaryValue> data) { if (!enabled() || - m_debugger->getPauseOnExceptionsState() == - v8::DebugInterface::NoBreakOnException) + m_debugger->getPauseOnExceptionsState() == v8::debug::NoBreakOnException) return; breakProgram(breakReason, std::move(data)); } @@ -1215,17 +1253,17 @@ void V8DebuggerAgentImpl::setBreakpointAt(const String16& scriptId, int lineNumber, int columnNumber, BreakpointSource source, const String16& condition) { - String16 breakpointId = - generateBreakpointId(scriptId, lineNumber, columnNumber, source); - ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); - resolveBreakpoint(breakpointId, scriptId, breakpoint, source); + ScriptBreakpoint breakpoint(scriptId, lineNumber, columnNumber, condition); + String16 breakpointId = generateBreakpointId(breakpoint, source); + resolveBreakpoint(breakpointId, breakpoint, source); } void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId, int lineNumber, int columnNumber, BreakpointSource source) { - removeBreakpointImpl( - generateBreakpointId(scriptId, lineNumber, columnNumber, source)); + removeBreakpointImpl(generateBreakpointId( + ScriptBreakpoint(scriptId, lineNumber, columnNumber, String16()), + source)); } void V8DebuggerAgentImpl::reset() { diff --git a/deps/v8/src/inspector/v8-debugger-agent-impl.h b/deps/v8/src/inspector/v8-debugger-agent-impl.h index e5285f4cc3..4e8e336545 100644 --- a/deps/v8/src/inspector/v8-debugger-agent-impl.h +++ b/deps/v8/src/inspector/v8-debugger-agent-impl.h @@ -162,8 +162,7 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { void setPauseOnExceptionsImpl(int); std::unique_ptr<protocol::Debugger::Location> resolveBreakpoint( - const String16& breakpointId, const String16& scriptId, - const ScriptBreakpoint&, BreakpointSource); + const String16& breakpointId, const ScriptBreakpoint&, BreakpointSource); void removeBreakpointImpl(const String16& breakpointId); void clearBreakDetails(); diff --git a/deps/v8/src/inspector/v8-debugger-script.cc b/deps/v8/src/inspector/v8-debugger-script.cc index ed0c0d63de..d6d15e5ae6 100644 --- a/deps/v8/src/inspector/v8-debugger-script.cc +++ b/deps/v8/src/inspector/v8-debugger-script.cc @@ -4,14 +4,16 @@ #include "src/inspector/v8-debugger-script.h" -#include "src/inspector/protocol-platform.h" +#include "src/inspector/inspected-context.h" #include "src/inspector/string-util.h" namespace v8_inspector { -static const char hexDigits[17] = "0123456789ABCDEF"; +namespace { -static void appendUnsignedAsHex(uint64_t number, String16Builder* destination) { +const char hexDigits[17] = "0123456789ABCDEF"; + +void appendUnsignedAsHex(uint64_t number, String16Builder* destination) { for (size_t i = 0; i < 8; ++i) { UChar c = hexDigits[number & 0xF]; destination->append(c); @@ -23,7 +25,7 @@ static void appendUnsignedAsHex(uint64_t number, String16Builder* destination) { // Multiplikation in // eingeschränkten Branchingprogrammmodellen" by Woelfe. // http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000 -static String16 calculateHash(const String16& str) { +String16 calculateHash(const String16& str) { static uint64_t prime[] = {0x3FB75161, 0xAB1F4E4F, 0x82675BC5, 0xCD924D35, 0x81ABE279}; static uint64_t random[] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, @@ -67,98 +69,178 @@ static String16 calculateHash(const String16& str) { return hash.toString(); } -V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate, - v8::Local<v8::DebugInterface::Script> script, - bool isLiveEdit) { - m_isolate = script->GetIsolate(); - m_id = String16::fromInteger(script->Id()); - v8::Local<v8::String> tmp; - if (script->Name().ToLocal(&tmp)) m_url = toProtocolString(tmp); - if (script->SourceURL().ToLocal(&tmp)) { - m_sourceURL = toProtocolString(tmp); - if (m_url.isEmpty()) m_url = toProtocolString(tmp); - } - if (script->SourceMappingURL().ToLocal(&tmp)) - m_sourceMappingURL = toProtocolString(tmp); - m_startLine = script->LineOffset(); - m_startColumn = script->ColumnOffset(); - std::vector<int> lineEnds = script->LineEnds(); - CHECK(lineEnds.size()); - int source_length = lineEnds[lineEnds.size() - 1]; - if (lineEnds.size()) { - m_endLine = static_cast<int>(lineEnds.size()) + m_startLine - 1; - if (lineEnds.size() > 1) { - m_endColumn = source_length - lineEnds[lineEnds.size() - 2] - 1; +class ActualScript : public V8DebuggerScript { + friend class V8DebuggerScript; + + public: + ActualScript(v8::Isolate* isolate, v8::Local<v8::debug::Script> script, + bool isLiveEdit) + : V8DebuggerScript(isolate, String16::fromInteger(script->Id()), + GetNameOrSourceUrl(script)), + m_isLiveEdit(isLiveEdit) { + v8::Local<v8::String> tmp; + if (script->SourceURL().ToLocal(&tmp)) m_sourceURL = toProtocolString(tmp); + if (script->SourceMappingURL().ToLocal(&tmp)) + m_sourceMappingURL = toProtocolString(tmp); + m_startLine = script->LineOffset(); + m_startColumn = script->ColumnOffset(); + std::vector<int> lineEnds = script->LineEnds(); + CHECK(lineEnds.size()); + int source_length = lineEnds[lineEnds.size() - 1]; + if (lineEnds.size()) { + m_endLine = static_cast<int>(lineEnds.size()) + m_startLine - 1; + if (lineEnds.size() > 1) { + m_endColumn = source_length - lineEnds[lineEnds.size() - 2] - 1; + } else { + m_endColumn = source_length + m_startColumn; + } } else { - m_endColumn = source_length + m_startColumn; + m_endLine = m_startLine; + m_endColumn = m_startColumn; + } + + v8::Local<v8::Value> contextData; + if (script->ContextData().ToLocal(&contextData) && contextData->IsInt32()) { + m_executionContextId = + static_cast<int>(contextData.As<v8::Int32>()->Value()); } - } else { - m_endLine = m_startLine; - m_endColumn = m_startColumn; - } - if (script->ContextData().ToLocal(&tmp)) { - String16 contextData = toProtocolString(tmp); - size_t firstComma = contextData.find(",", 0); - size_t secondComma = firstComma != String16::kNotFound - ? contextData.find(",", firstComma + 1) - : String16::kNotFound; - if (secondComma != String16::kNotFound) { - String16 executionContextId = - contextData.substring(firstComma + 1, secondComma - firstComma - 1); - bool isOk = false; - m_executionContextId = executionContextId.toInteger(&isOk); - if (!isOk) m_executionContextId = 0; - m_executionContextAuxData = contextData.substring(secondComma + 1); + if (script->Source().ToLocal(&tmp)) { + m_sourceObj.Reset(m_isolate, tmp); + String16 source = toProtocolString(tmp); + // V8 will not count last line if script source ends with \n. + if (source.length() > 1 && source[source.length() - 1] == '\n') { + m_endLine++; + m_endColumn = 0; + } } + + m_script.Reset(m_isolate, script); } - m_isLiveEdit = isLiveEdit; + bool isLiveEdit() const override { return m_isLiveEdit; } + + const String16& sourceMappingURL() const override { + return m_sourceMappingURL; + } - if (script->Source().ToLocal(&tmp)) { - m_source.Reset(m_isolate, tmp); - String16 source = toProtocolString(tmp); - m_hash = calculateHash(source); - // V8 will not count last line if script source ends with \n. - if (source.length() > 1 && source[source.length() - 1] == '\n') { - m_endLine++; - m_endColumn = 0; + String16 source(v8::Isolate* isolate) const override { + if (!m_sourceObj.IsEmpty()) + return toProtocolString(m_sourceObj.Get(isolate)); + return V8DebuggerScript::source(isolate); + } + + void setSourceMappingURL(const String16& sourceMappingURL) override { + m_sourceMappingURL = sourceMappingURL; + } + + void setSource(v8::Local<v8::String> source) override { + m_source = String16(); + m_sourceObj.Reset(m_isolate, source); + m_hash = String16(); + } + + bool getPossibleBreakpoints( + const v8::debug::Location& start, const v8::debug::Location& end, + std::vector<v8::debug::Location>* locations) override { + v8::HandleScope scope(m_isolate); + v8::Local<v8::debug::Script> script = m_script.Get(m_isolate); + return script->GetPossibleBreakpoints(start, end, locations); + } + + private: + String16 GetNameOrSourceUrl(v8::Local<v8::debug::Script> script) { + v8::Local<v8::String> name; + if (script->Name().ToLocal(&name) || script->SourceURL().ToLocal(&name)) + return toProtocolString(name); + return String16(); + } + + String16 m_sourceMappingURL; + v8::Global<v8::String> m_sourceObj; + bool m_isLiveEdit = false; + v8::Global<v8::debug::Script> m_script; +}; + +class WasmVirtualScript : public V8DebuggerScript { + friend class V8DebuggerScript; + + public: + WasmVirtualScript(v8::Isolate* isolate, + v8::Local<v8::debug::WasmScript> script, String16 id, + String16 url, String16 source) + : V8DebuggerScript(isolate, std::move(id), std::move(url)), + m_script(isolate, script) { + int num_lines = 0; + int last_newline = -1; + size_t next_newline = source.find('\n', last_newline + 1); + while (next_newline != String16::kNotFound) { + last_newline = static_cast<int>(next_newline); + next_newline = source.find('\n', last_newline + 1); + ++num_lines; } + m_endLine = num_lines; + m_endColumn = static_cast<int>(source.length()) - last_newline - 1; + m_source = std::move(source); + } + + const String16& sourceMappingURL() const override { return emptyString(); } + bool isLiveEdit() const override { return false; } + void setSourceMappingURL(const String16&) override {} + + bool getPossibleBreakpoints( + const v8::debug::Location& start, const v8::debug::Location& end, + std::vector<v8::debug::Location>* locations) override { + // TODO(clemensh): Returning false produces the protocol error "Internal + // error". Implement and fix expected output of + // wasm-get-breakable-locations.js. + return false; + } + + private: + static const String16& emptyString() { + static const String16 singleEmptyString; + return singleEmptyString; } - m_script.Reset(m_isolate, script); + v8::Global<v8::debug::WasmScript> m_script; +}; + +} // namespace + +std::unique_ptr<V8DebuggerScript> V8DebuggerScript::Create( + v8::Isolate* isolate, v8::Local<v8::debug::Script> scriptObj, + bool isLiveEdit) { + return std::unique_ptr<ActualScript>( + new ActualScript(isolate, scriptObj, isLiveEdit)); +} + +std::unique_ptr<V8DebuggerScript> V8DebuggerScript::CreateWasm( + v8::Isolate* isolate, v8::Local<v8::debug::WasmScript> underlyingScript, + String16 id, String16 url, String16 source) { + return std::unique_ptr<WasmVirtualScript>( + new WasmVirtualScript(isolate, underlyingScript, std::move(id), + std::move(url), std::move(source))); } +V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate, String16 id, + String16 url) + : m_id(std::move(id)), m_url(std::move(url)), m_isolate(isolate) {} + V8DebuggerScript::~V8DebuggerScript() {} const String16& V8DebuggerScript::sourceURL() const { return m_sourceURL.isEmpty() ? m_url : m_sourceURL; } -v8::Local<v8::String> V8DebuggerScript::source(v8::Isolate* isolate) const { - return m_source.Get(isolate); +const String16& V8DebuggerScript::hash(v8::Isolate* isolate) const { + if (m_hash.isEmpty()) m_hash = calculateHash(source(isolate)); + DCHECK(!m_hash.isEmpty()); + return m_hash; } void V8DebuggerScript::setSourceURL(const String16& sourceURL) { m_sourceURL = sourceURL; } -void V8DebuggerScript::setSourceMappingURL(const String16& sourceMappingURL) { - m_sourceMappingURL = sourceMappingURL; -} - -void V8DebuggerScript::setSource(v8::Local<v8::String> source) { - m_source.Reset(m_isolate, source); - m_hash = calculateHash(toProtocolString(source)); -} - -bool V8DebuggerScript::getPossibleBreakpoints( - const v8::DebugInterface::Location& start, - const v8::DebugInterface::Location& end, - std::vector<v8::DebugInterface::Location>* locations) { - v8::HandleScope scope(m_isolate); - v8::Local<v8::DebugInterface::Script> script = m_script.Get(m_isolate); - return script->GetPossibleBreakpoints(start, end, locations); -} - } // namespace v8_inspector diff --git a/deps/v8/src/inspector/v8-debugger-script.h b/deps/v8/src/inspector/v8-debugger-script.h index 97b5ba9e51..58beefe5ec 100644 --- a/deps/v8/src/inspector/v8-debugger-script.h +++ b/deps/v8/src/inspector/v8-debugger-script.h @@ -32,6 +32,7 @@ #include "src/base/macros.h" #include "src/inspector/string-16.h" +#include "src/inspector/string-util.h" #include "include/v8.h" #include "src/debug/debug-interface.h" @@ -40,55 +41,56 @@ namespace v8_inspector { class V8DebuggerScript { public: - V8DebuggerScript(v8::Isolate* isolate, - v8::Local<v8::DebugInterface::Script> script, - bool isLiveEdit); - ~V8DebuggerScript(); + static std::unique_ptr<V8DebuggerScript> Create( + v8::Isolate* isolate, v8::Local<v8::debug::Script> script, + bool isLiveEdit); + static std::unique_ptr<V8DebuggerScript> CreateWasm( + v8::Isolate* isolate, v8::Local<v8::debug::WasmScript> underlyingScript, + String16 id, String16 url, String16 source); + + virtual ~V8DebuggerScript(); const String16& scriptId() const { return m_id; } const String16& url() const { return m_url; } bool hasSourceURL() const { return !m_sourceURL.isEmpty(); } const String16& sourceURL() const; - const String16& sourceMappingURL() const { return m_sourceMappingURL; } - v8::Local<v8::String> source(v8::Isolate*) const; - const String16& hash() const { return m_hash; } + virtual const String16& sourceMappingURL() const = 0; + virtual String16 source(v8::Isolate*) const { return m_source; } + const String16& hash(v8::Isolate*) const; int startLine() const { return m_startLine; } int startColumn() const { return m_startColumn; } int endLine() const { return m_endLine; } int endColumn() const { return m_endColumn; } int executionContextId() const { return m_executionContextId; } - const String16& executionContextAuxData() const { - return m_executionContextAuxData; - } - bool isLiveEdit() const { return m_isLiveEdit; } + virtual bool isLiveEdit() const = 0; void setSourceURL(const String16&); - void setSourceMappingURL(const String16&); - void setSource(v8::Local<v8::String>); + virtual void setSourceMappingURL(const String16&) = 0; + virtual void setSource(v8::Local<v8::String> source) { + m_source = toProtocolString(source); + } - bool getPossibleBreakpoints( - const v8::DebugInterface::Location& start, - const v8::DebugInterface::Location& end, - std::vector<v8::DebugInterface::Location>* locations); + virtual bool getPossibleBreakpoints( + const v8::debug::Location& start, const v8::debug::Location& end, + std::vector<v8::debug::Location>* locations) = 0; + + protected: + V8DebuggerScript(v8::Isolate*, String16 id, String16 url); - private: String16 m_id; String16 m_url; String16 m_sourceURL; - String16 m_sourceMappingURL; - v8::Global<v8::String> m_source; - String16 m_hash; - int m_startLine; - int m_startColumn; - int m_endLine; - int m_endColumn; - int m_executionContextId; - String16 m_executionContextAuxData; - bool m_isLiveEdit; + String16 m_source; + mutable String16 m_hash; + int m_startLine = 0; + int m_startColumn = 0; + int m_endLine = 0; + int m_endColumn = 0; + int m_executionContextId = 0; v8::Isolate* m_isolate; - v8::Global<v8::DebugInterface::Script> m_script; + private: DISALLOW_COPY_AND_ASSIGN(V8DebuggerScript); }; diff --git a/deps/v8/src/inspector/v8-debugger.cc b/deps/v8/src/inspector/v8-debugger.cc index b3657e577c..2563f4f36c 100644 --- a/deps/v8/src/inspector/v8-debugger.cc +++ b/deps/v8/src/inspector/v8-debugger.cc @@ -5,6 +5,7 @@ #include "src/inspector/v8-debugger.h" #include "src/inspector/debugger-script.h" +#include "src/inspector/inspected-context.h" #include "src/inspector/protocol/Protocol.h" #include "src/inspector/script-breakpoint.h" #include "src/inspector/string-util.h" @@ -19,11 +20,11 @@ namespace v8_inspector { namespace { -static const char v8AsyncTaskEventEnqueue[] = "enqueue"; -static const char v8AsyncTaskEventEnqueueRecurring[] = "enqueueRecurring"; -static const char v8AsyncTaskEventWillHandle[] = "willHandle"; -static const char v8AsyncTaskEventDidHandle[] = "didHandle"; -static const char v8AsyncTaskEventCancel[] = "cancel"; + +// Based on DevTools frontend measurement, with asyncCallStackDepth = 4, +// average async call stack tail requires ~1 Kb. Let's reserve ~ 128 Mb +// for async stacks. +static const int kMaxAsyncTaskStacks = 128 * 1024; inline v8::Local<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) { return value ? v8::True(isolate) : v8::False(isolate); @@ -34,7 +35,8 @@ inline v8::Local<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) { static bool inLiveEditScope = false; v8::MaybeLocal<v8::Value> V8Debugger::callDebuggerMethod( - const char* functionName, int argc, v8::Local<v8::Value> argv[]) { + const char* functionName, int argc, v8::Local<v8::Value> argv[], + bool catchExceptions) { v8::MicrotasksScope microtasks(m_isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); DCHECK(m_isolate->InContext()); @@ -44,19 +46,25 @@ v8::MaybeLocal<v8::Value> V8Debugger::callDebuggerMethod( debuggerScript ->Get(context, toV8StringInternalized(m_isolate, functionName)) .ToLocalChecked()); + if (catchExceptions) { + v8::TryCatch try_catch(m_isolate); + return function->Call(context, debuggerScript, argc, argv); + } return function->Call(context, debuggerScript, argc, argv); } V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector) : m_isolate(isolate), m_inspector(inspector), - m_lastContextId(0), m_enableCount(0), m_breakpointsActivated(true), m_runningNestedMessageLoop(false), m_ignoreScriptParsedEventsCounter(0), + m_maxAsyncCallStacks(kMaxAsyncTaskStacks), + m_lastTaskId(0), m_maxAsyncCallStackDepth(0), - m_pauseOnExceptionsState(v8::DebugInterface::NoBreakOnException) {} + m_pauseOnExceptionsState(v8::debug::NoBreakOnException), + m_wasmTranslation(isolate) {} V8Debugger::~V8Debugger() {} @@ -64,14 +72,13 @@ void V8Debugger::enable() { if (m_enableCount++) return; DCHECK(!enabled()); v8::HandleScope scope(m_isolate); - v8::DebugInterface::SetDebugEventListener(m_isolate, - &V8Debugger::v8DebugEventCallback, - v8::External::New(m_isolate, this)); - m_debuggerContext.Reset(m_isolate, - v8::DebugInterface::GetDebugContext(m_isolate)); - v8::DebugInterface::ChangeBreakOnException( - m_isolate, v8::DebugInterface::NoBreakOnException); - m_pauseOnExceptionsState = v8::DebugInterface::NoBreakOnException; + v8::debug::SetDebugEventListener(m_isolate, &V8Debugger::v8DebugEventCallback, + v8::External::New(m_isolate, this)); + v8::debug::SetAsyncTaskListener(m_isolate, &V8Debugger::v8AsyncTaskListener, + this); + m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate)); + v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException); + m_pauseOnExceptionsState = v8::debug::NoBreakOnException; compileDebuggerScript(); } @@ -82,61 +89,32 @@ void V8Debugger::disable() { m_debuggerScript.Reset(); m_debuggerContext.Reset(); allAsyncTasksCanceled(); - v8::DebugInterface::SetDebugEventListener(m_isolate, nullptr); + m_wasmTranslation.Clear(); + v8::debug::SetDebugEventListener(m_isolate, nullptr); + v8::debug::SetAsyncTaskListener(m_isolate, nullptr, nullptr); } bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } -// static -int V8Debugger::contextId(v8::Local<v8::Context> context) { - v8::Local<v8::Value> data = - context->GetEmbedderData(static_cast<int>(v8::Context::kDebugIdIndex)); - if (data.IsEmpty() || !data->IsString()) return 0; - String16 dataString = toProtocolString(data.As<v8::String>()); - if (dataString.isEmpty()) return 0; - size_t commaPos = dataString.find(","); - if (commaPos == String16::kNotFound) return 0; - size_t commaPos2 = dataString.find(",", commaPos + 1); - if (commaPos2 == String16::kNotFound) return 0; - return dataString.substring(commaPos + 1, commaPos2 - commaPos - 1) - .toInteger(); -} - -// static -int V8Debugger::getGroupId(v8::Local<v8::Context> context) { - v8::Local<v8::Value> data = - context->GetEmbedderData(static_cast<int>(v8::Context::kDebugIdIndex)); - if (data.IsEmpty() || !data->IsString()) return 0; - String16 dataString = toProtocolString(data.As<v8::String>()); - if (dataString.isEmpty()) return 0; - size_t commaPos = dataString.find(","); - if (commaPos == String16::kNotFound) return 0; - return dataString.substring(0, commaPos).toInteger(); -} - void V8Debugger::getCompiledScripts( int contextGroupId, std::vector<std::unique_ptr<V8DebuggerScript>>& result) { v8::HandleScope scope(m_isolate); - v8::PersistentValueVector<v8::DebugInterface::Script> scripts(m_isolate); - v8::DebugInterface::GetLoadedScripts(m_isolate, scripts); - String16 contextPrefix = String16::fromInteger(contextGroupId) + ","; + v8::PersistentValueVector<v8::debug::Script> scripts(m_isolate); + v8::debug::GetLoadedScripts(m_isolate, scripts); for (size_t i = 0; i < scripts.Size(); ++i) { - v8::Local<v8::DebugInterface::Script> script = scripts.Get(i); + v8::Local<v8::debug::Script> script = scripts.Get(i); if (!script->WasCompiled()) continue; - v8::ScriptOriginOptions origin = script->OriginOptions(); - if (origin.IsEmbedderDebugScript()) continue; - v8::Local<v8::String> v8ContextData; - if (!script->ContextData().ToLocal(&v8ContextData)) continue; - String16 contextData = toProtocolString(v8ContextData); - if (contextData.find(contextPrefix) != 0) continue; - result.push_back( - wrapUnique(new V8DebuggerScript(m_isolate, script, false))); + v8::Local<v8::Value> contextData; + if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) + continue; + int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value()); + if (m_inspector->contextGroupId(contextId) != contextGroupId) continue; + result.push_back(V8DebuggerScript::Create(m_isolate, script, false)); } } -String16 V8Debugger::setBreakpoint(const String16& sourceID, - const ScriptBreakpoint& scriptBreakpoint, +String16 V8Debugger::setBreakpoint(const ScriptBreakpoint& breakpoint, int* actualLineNumber, int* actualColumnNumber) { v8::HandleScope scope(m_isolate); @@ -146,20 +124,20 @@ String16 V8Debugger::setBreakpoint(const String16& sourceID, v8::Local<v8::Object> info = v8::Object::New(m_isolate); bool success = false; success = info->Set(context, toV8StringInternalized(m_isolate, "sourceID"), - toV8String(m_isolate, sourceID)) + toV8String(m_isolate, breakpoint.script_id)) .FromMaybe(false); DCHECK(success); success = info->Set(context, toV8StringInternalized(m_isolate, "lineNumber"), - v8::Integer::New(m_isolate, scriptBreakpoint.lineNumber)) + v8::Integer::New(m_isolate, breakpoint.line_number)) .FromMaybe(false); DCHECK(success); success = info->Set(context, toV8StringInternalized(m_isolate, "columnNumber"), - v8::Integer::New(m_isolate, scriptBreakpoint.columnNumber)) + v8::Integer::New(m_isolate, breakpoint.column_number)) .FromMaybe(false); DCHECK(success); success = info->Set(context, toV8StringInternalized(m_isolate, "condition"), - toV8String(m_isolate, scriptBreakpoint.condition)) + toV8String(m_isolate, breakpoint.condition)) .FromMaybe(false); DCHECK(success); @@ -168,7 +146,7 @@ String16 V8Debugger::setBreakpoint(const String16& sourceID, ->Get(context, toV8StringInternalized(m_isolate, "setBreakpoint")) .ToLocalChecked()); v8::Local<v8::Value> breakpointId = - v8::DebugInterface::Call(debuggerContext(), setBreakpointFunction, info) + v8::debug::Call(debuggerContext(), setBreakpointFunction, info) .ToLocalChecked(); if (!breakpointId->IsString()) return ""; *actualLineNumber = @@ -203,7 +181,7 @@ void V8Debugger::removeBreakpoint(const String16& breakpointId) { ->Get(context, toV8StringInternalized(m_isolate, "removeBreakpoint")) .ToLocalChecked()); - v8::DebugInterface::Call(debuggerContext(), removeBreakpointFunction, info) + v8::debug::Call(debuggerContext(), removeBreakpointFunction, info) .ToLocalChecked(); } @@ -216,8 +194,7 @@ void V8Debugger::clearBreakpoints() { m_debuggerScript.Get(m_isolate) ->Get(context, toV8StringInternalized(m_isolate, "clearBreakpoints")) .ToLocalChecked()); - v8::DebugInterface::Call(debuggerContext(), clearBreakpoints) - .ToLocalChecked(); + v8::debug::Call(debuggerContext(), clearBreakpoints).ToLocalChecked(); } void V8Debugger::setBreakpointsActivated(bool activated) { @@ -241,32 +218,31 @@ void V8Debugger::setBreakpointsActivated(bool activated) { ->Get(context, toV8StringInternalized(m_isolate, "setBreakpointsActivated")) .ToLocalChecked()); - v8::DebugInterface::Call(debuggerContext(), setBreakpointsActivated, info) + v8::debug::Call(debuggerContext(), setBreakpointsActivated, info) .ToLocalChecked(); m_breakpointsActivated = activated; } -v8::DebugInterface::ExceptionBreakState -V8Debugger::getPauseOnExceptionsState() { +v8::debug::ExceptionBreakState V8Debugger::getPauseOnExceptionsState() { DCHECK(enabled()); return m_pauseOnExceptionsState; } void V8Debugger::setPauseOnExceptionsState( - v8::DebugInterface::ExceptionBreakState pauseOnExceptionsState) { + v8::debug::ExceptionBreakState pauseOnExceptionsState) { DCHECK(enabled()); if (m_pauseOnExceptionsState == pauseOnExceptionsState) return; - v8::DebugInterface::ChangeBreakOnException(m_isolate, pauseOnExceptionsState); + v8::debug::ChangeBreakOnException(m_isolate, pauseOnExceptionsState); m_pauseOnExceptionsState = pauseOnExceptionsState; } void V8Debugger::setPauseOnNextStatement(bool pause) { if (m_runningNestedMessageLoop) return; if (pause) - v8::DebugInterface::DebugBreak(m_isolate); + v8::debug::DebugBreak(m_isolate); else - v8::DebugInterface::CancelDebugBreak(m_isolate); + v8::debug::CancelDebugBreak(m_isolate); } bool V8Debugger::canBreakProgram() { @@ -294,7 +270,7 @@ void V8Debugger::breakProgram() { v8::ConstructorBehavior::kThrow) .ToLocal(&breakFunction)) return; - v8::DebugInterface::Call(debuggerContext(), breakFunction).ToLocalChecked(); + v8::debug::Call(debuggerContext(), breakFunction).ToLocalChecked(); } void V8Debugger::continueProgram() { @@ -306,27 +282,27 @@ void V8Debugger::continueProgram() { void V8Debugger::stepIntoStatement() { DCHECK(isPaused()); DCHECK(!m_executionState.IsEmpty()); - v8::DebugInterface::PrepareStep(m_isolate, v8::DebugInterface::StepIn); + v8::debug::PrepareStep(m_isolate, v8::debug::StepIn); continueProgram(); } void V8Debugger::stepOverStatement() { DCHECK(isPaused()); DCHECK(!m_executionState.IsEmpty()); - v8::DebugInterface::PrepareStep(m_isolate, v8::DebugInterface::StepNext); + v8::debug::PrepareStep(m_isolate, v8::debug::StepNext); continueProgram(); } void V8Debugger::stepOutOfFunction() { DCHECK(isPaused()); DCHECK(!m_executionState.IsEmpty()); - v8::DebugInterface::PrepareStep(m_isolate, v8::DebugInterface::StepOut); + v8::debug::PrepareStep(m_isolate, v8::debug::StepOut); continueProgram(); } void V8Debugger::clearStepping() { DCHECK(enabled()); - v8::DebugInterface::ClearStepping(m_isolate); + v8::debug::ClearStepping(m_isolate); } Response V8Debugger::setScriptSource( @@ -337,11 +313,11 @@ Response V8Debugger::setScriptSource( class EnableLiveEditScope { public: explicit EnableLiveEditScope(v8::Isolate* isolate) : m_isolate(isolate) { - v8::DebugInterface::SetLiveEditEnabled(m_isolate, true); + v8::debug::SetLiveEditEnabled(m_isolate, true); inLiveEditScope = true; } ~EnableLiveEditScope() { - v8::DebugInterface::SetLiveEditEnabled(m_isolate, false); + v8::debug::SetLiveEditEnabled(m_isolate, false); inLiveEditScope = false; } @@ -355,7 +331,7 @@ Response V8Debugger::setScriptSource( std::unique_ptr<v8::Context::Scope> contextScope; if (!isPaused()) - contextScope = wrapUnique(new v8::Context::Scope(debuggerContext())); + contextScope.reset(new v8::Context::Scope(debuggerContext())); v8::Local<v8::Value> argv[] = {toV8String(m_isolate, sourceID), newSource, v8Boolean(dryRun, m_isolate)}; @@ -366,7 +342,7 @@ Response V8Debugger::setScriptSource( v8::TryCatch tryCatch(m_isolate); tryCatch.SetVerbose(false); v8::MaybeLocal<v8::Value> maybeResult = - callDebuggerMethod("liveEditScriptSource", 3, argv); + callDebuggerMethod("liveEditScriptSource", 3, argv, false); if (tryCatch.HasCaught()) { v8::Local<v8::Message> message = tryCatch.Message(); if (!message.IsEmpty()) @@ -436,16 +412,16 @@ JavaScriptCallFrames V8Debugger::currentCallFrames(int limit) { ->Get(debuggerContext(), toV8StringInternalized(m_isolate, "currentCallFrames")) .ToLocalChecked()); - currentCallFramesV8 = - v8::DebugInterface::Call(debuggerContext(), currentCallFramesFunction, - v8::Integer::New(m_isolate, limit)) - .ToLocalChecked(); + if (!v8::debug::Call(debuggerContext(), currentCallFramesFunction, + v8::Integer::New(m_isolate, limit)) + .ToLocal(¤tCallFramesV8)) + return JavaScriptCallFrames(); } else { v8::Local<v8::Value> argv[] = {m_executionState, v8::Integer::New(m_isolate, limit)}; - currentCallFramesV8 = - callDebuggerMethod("currentCallFrames", arraysize(argv), argv) - .ToLocalChecked(); + if (!callDebuggerMethod("currentCallFrames", arraysize(argv), argv, true) + .ToLocal(¤tCallFramesV8)) + return JavaScriptCallFrames(); } DCHECK(!currentCallFramesV8.IsEmpty()); if (!currentCallFramesV8->IsArray()) return JavaScriptCallFrames(); @@ -490,8 +466,8 @@ void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext, // Don't allow nested breaks. if (m_runningNestedMessageLoop) return; - V8DebuggerAgentImpl* agent = - m_inspector->enabledDebuggerAgentForGroup(getGroupId(pausedContext)); + V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup( + m_inspector->contextGroupId(pausedContext)); if (!agent) return; std::vector<String16> breakpointIds; @@ -512,12 +488,16 @@ void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext, pausedContext, exception, breakpointIds, isPromiseRejection, isUncaught); if (result == V8DebuggerAgentImpl::RequestNoSkip) { m_runningNestedMessageLoop = true; - int groupId = getGroupId(pausedContext); + int groupId = m_inspector->contextGroupId(pausedContext); DCHECK(groupId); + v8::Context::Scope scope(pausedContext); + v8::Local<v8::Context> context = m_isolate->GetCurrentContext(); + CHECK(!context.IsEmpty() && + context != v8::debug::GetDebugContext(m_isolate)); m_inspector->client()->runMessageLoopOnPause(groupId); // The agent may have been removed in the nested loop. - agent = - m_inspector->enabledDebuggerAgentForGroup(getGroupId(pausedContext)); + agent = m_inspector->enabledDebuggerAgentForGroup( + m_inspector->contextGroupId(pausedContext)); if (agent) agent->didContinue(); m_runningNestedMessageLoop = false; } @@ -525,16 +505,16 @@ void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext, m_executionState.Clear(); if (result == V8DebuggerAgentImpl::RequestStepFrame) { - v8::DebugInterface::PrepareStep(m_isolate, v8::DebugInterface::StepFrame); + v8::debug::PrepareStep(m_isolate, v8::debug::StepFrame); } else if (result == V8DebuggerAgentImpl::RequestStepInto) { - v8::DebugInterface::PrepareStep(m_isolate, v8::DebugInterface::StepIn); + v8::debug::PrepareStep(m_isolate, v8::debug::StepIn); } else if (result == V8DebuggerAgentImpl::RequestStepOut) { - v8::DebugInterface::PrepareStep(m_isolate, v8::DebugInterface::StepOut); + v8::debug::PrepareStep(m_isolate, v8::debug::StepOut); } } void V8Debugger::v8DebugEventCallback( - const v8::DebugInterface::EventDetails& eventDetails) { + const v8::debug::EventDetails& eventDetails) { V8Debugger* thisPtr = toV8Debugger(eventDetails.GetCallbackData()); thisPtr->handleV8DebugEvent(eventDetails); } @@ -555,100 +535,99 @@ v8::Local<v8::Value> V8Debugger::callInternalGetterFunction( } void V8Debugger::handleV8DebugEvent( - const v8::DebugInterface::EventDetails& eventDetails) { + const v8::debug::EventDetails& eventDetails) { if (!enabled()) return; + v8::HandleScope scope(m_isolate); + v8::DebugEvent event = eventDetails.GetEvent(); - if (event != v8::AsyncTaskEvent && event != v8::Break && - event != v8::Exception && event != v8::AfterCompile && - event != v8::BeforeCompile && event != v8::CompileError) + if (event != v8::Break && event != v8::Exception && + event != v8::AfterCompile && event != v8::CompileError) return; v8::Local<v8::Context> eventContext = eventDetails.GetEventContext(); DCHECK(!eventContext.IsEmpty()); + V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup( + m_inspector->contextGroupId(eventContext)); + if (!agent) return; - if (event == v8::AsyncTaskEvent) { - v8::HandleScope scope(m_isolate); - handleV8AsyncTaskEvent(eventContext, eventDetails.GetExecutionState(), - eventDetails.GetEventData()); - return; - } - - V8DebuggerAgentImpl* agent = - m_inspector->enabledDebuggerAgentForGroup(getGroupId(eventContext)); - if (agent) { - v8::HandleScope scope(m_isolate); - if (m_ignoreScriptParsedEventsCounter == 0 && - (event == v8::AfterCompile || event == v8::CompileError)) { - v8::Local<v8::Context> context = debuggerContext(); - v8::Context::Scope contextScope(context); - v8::Local<v8::Value> argv[] = {eventDetails.GetEventData()}; - v8::Local<v8::Value> value = - callDebuggerMethod("getAfterCompileScript", 1, argv).ToLocalChecked(); - if (value->IsNull()) return; - DCHECK(value->IsObject()); - v8::Local<v8::Object> scriptObject = v8::Local<v8::Object>::Cast(value); - v8::Local<v8::DebugInterface::Script> script; - if (!v8::DebugInterface::Script::Wrap(m_isolate, scriptObject) - .ToLocal(&script)) - return; + if (event == v8::AfterCompile || event == v8::CompileError) { + v8::Context::Scope contextScope(debuggerContext()); + // Determine if the script is a wasm script. + v8::Local<v8::Value> scriptMirror = + callInternalGetterFunction(eventDetails.GetEventData(), "script"); + DCHECK(scriptMirror->IsObject()); + v8::Local<v8::Value> scriptWrapper = + callInternalGetterFunction(scriptMirror.As<v8::Object>(), "value"); + DCHECK(scriptWrapper->IsObject()); + v8::Local<v8::debug::Script> script; + if (!v8::debug::Script::Wrap(m_isolate, scriptWrapper.As<v8::Object>()) + .ToLocal(&script)) { + return; + } + if (script->IsWasm()) { + m_wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), agent); + } else if (m_ignoreScriptParsedEventsCounter == 0) { agent->didParseSource( - wrapUnique(new V8DebuggerScript(m_isolate, script, inLiveEditScope)), + V8DebuggerScript::Create(m_isolate, script, inLiveEditScope), event == v8::AfterCompile); - } else if (event == v8::Exception) { - v8::Local<v8::Context> context = debuggerContext(); - v8::Local<v8::Object> eventData = eventDetails.GetEventData(); - v8::Local<v8::Value> exception = - callInternalGetterFunction(eventData, "exception"); - v8::Local<v8::Value> promise = - callInternalGetterFunction(eventData, "promise"); - bool isPromiseRejection = !promise.IsEmpty() && promise->IsObject(); - v8::Local<v8::Value> uncaught = - callInternalGetterFunction(eventData, "uncaught"); - bool isUncaught = uncaught->BooleanValue(context).FromJust(); - handleProgramBreak(eventContext, eventDetails.GetExecutionState(), - exception, v8::Local<v8::Array>(), isPromiseRejection, - isUncaught); - } else if (event == v8::Break) { - v8::Local<v8::Value> argv[] = {eventDetails.GetEventData()}; - v8::Local<v8::Value> hitBreakpoints = - callDebuggerMethod("getBreakpointNumbers", 1, argv).ToLocalChecked(); - DCHECK(hitBreakpoints->IsArray()); - handleProgramBreak(eventContext, eventDetails.GetExecutionState(), - v8::Local<v8::Value>(), - hitBreakpoints.As<v8::Array>()); } + } else if (event == v8::Exception) { + v8::Local<v8::Context> context = debuggerContext(); + v8::Local<v8::Object> eventData = eventDetails.GetEventData(); + v8::Local<v8::Value> exception = + callInternalGetterFunction(eventData, "exception"); + v8::Local<v8::Value> promise = + callInternalGetterFunction(eventData, "promise"); + bool isPromiseRejection = !promise.IsEmpty() && promise->IsObject(); + v8::Local<v8::Value> uncaught = + callInternalGetterFunction(eventData, "uncaught"); + bool isUncaught = uncaught->BooleanValue(context).FromJust(); + handleProgramBreak(eventContext, eventDetails.GetExecutionState(), + exception, v8::Local<v8::Array>(), isPromiseRejection, + isUncaught); + } else if (event == v8::Break) { + v8::Local<v8::Value> argv[] = {eventDetails.GetEventData()}; + v8::Local<v8::Value> hitBreakpoints; + if (!callDebuggerMethod("getBreakpointNumbers", 1, argv, true) + .ToLocal(&hitBreakpoints)) + return; + DCHECK(hitBreakpoints->IsArray()); + handleProgramBreak(eventContext, eventDetails.GetExecutionState(), + v8::Local<v8::Value>(), hitBreakpoints.As<v8::Array>()); } } -void V8Debugger::handleV8AsyncTaskEvent(v8::Local<v8::Context> context, - v8::Local<v8::Object> executionState, - v8::Local<v8::Object> eventData) { - if (!m_maxAsyncCallStackDepth) return; - - String16 type = toProtocolStringWithTypeCheck( - callInternalGetterFunction(eventData, "type")); - String16 name = toProtocolStringWithTypeCheck( - callInternalGetterFunction(eventData, "name")); - int id = static_cast<int>(callInternalGetterFunction(eventData, "id") - ->ToInteger(context) - .ToLocalChecked() - ->Value()); +void V8Debugger::v8AsyncTaskListener(v8::debug::PromiseDebugActionType type, + int id, void* data) { + V8Debugger* debugger = static_cast<V8Debugger*>(data); + if (!debugger->m_maxAsyncCallStackDepth) return; // Async task events from Promises are given misaligned pointers to prevent // from overlapping with other Blink task identifiers. There is a single // namespace of such ids, managed by src/js/promise.js. void* ptr = reinterpret_cast<void*>(id * 2 + 1); - if (type == v8AsyncTaskEventEnqueue) - asyncTaskScheduled(name, ptr, false); - else if (type == v8AsyncTaskEventEnqueueRecurring) - asyncTaskScheduled(name, ptr, true); - else if (type == v8AsyncTaskEventWillHandle) - asyncTaskStarted(ptr); - else if (type == v8AsyncTaskEventDidHandle) - asyncTaskFinished(ptr); - else if (type == v8AsyncTaskEventCancel) - asyncTaskCanceled(ptr); - else - UNREACHABLE(); + switch (type) { + case v8::debug::kDebugEnqueueAsyncFunction: + debugger->asyncTaskScheduled("async function", ptr, true); + break; + case v8::debug::kDebugEnqueuePromiseResolve: + debugger->asyncTaskScheduled("Promise.resolve", ptr, true); + break; + case v8::debug::kDebugEnqueuePromiseReject: + debugger->asyncTaskScheduled("Promise.reject", ptr, true); + break; + case v8::debug::kDebugEnqueuePromiseResolveThenableJob: + debugger->asyncTaskScheduled("PromiseResolveThenableJob", ptr, true); + break; + case v8::debug::kDebugPromiseCollected: + debugger->asyncTaskCanceled(ptr); + break; + case v8::debug::kDebugWillHandle: + debugger->asyncTaskStarted(ptr); + break; + case v8::debug::kDebugDidHandle: + debugger->asyncTaskFinished(ptr); + break; + } } V8StackTraceImpl* V8Debugger::currentAsyncCallChain() { @@ -685,15 +664,27 @@ v8::Local<v8::Context> V8Debugger::debuggerContext() const { return m_debuggerContext.Get(m_isolate); } -v8::MaybeLocal<v8::Value> V8Debugger::functionScopes( - v8::Local<v8::Context> context, v8::Local<v8::Function> function) { +v8::MaybeLocal<v8::Value> V8Debugger::getTargetScopes( + v8::Local<v8::Context> context, v8::Local<v8::Value> value, + ScopeTargetKind kind) { if (!enabled()) { UNREACHABLE(); return v8::Local<v8::Value>::New(m_isolate, v8::Undefined(m_isolate)); } - v8::Local<v8::Value> argv[] = {function}; + v8::Local<v8::Value> argv[] = {value}; v8::Local<v8::Value> scopesValue; - if (!callDebuggerMethod("getFunctionScopes", 1, argv).ToLocal(&scopesValue)) + + const char* debuggerMethod = nullptr; + switch (kind) { + case FUNCTION: + debuggerMethod = "getFunctionScopes"; + break; + case GENERATOR: + debuggerMethod = "getGeneratorScopes"; + break; + } + + if (!callDebuggerMethod(debuggerMethod, 1, argv, true).ToLocal(&scopesValue)) return v8::MaybeLocal<v8::Value>(); v8::Local<v8::Value> copied; if (!copyValueFromDebuggerContext(m_isolate, debuggerContext(), context, @@ -710,11 +701,20 @@ v8::MaybeLocal<v8::Value> V8Debugger::functionScopes( return copied; } +v8::MaybeLocal<v8::Value> V8Debugger::functionScopes( + v8::Local<v8::Context> context, v8::Local<v8::Function> function) { + return getTargetScopes(context, function, FUNCTION); +} + +v8::MaybeLocal<v8::Value> V8Debugger::generatorScopes( + v8::Local<v8::Context> context, v8::Local<v8::Value> generator) { + return getTargetScopes(context, generator, GENERATOR); +} + v8::MaybeLocal<v8::Array> V8Debugger::internalProperties( v8::Local<v8::Context> context, v8::Local<v8::Value> value) { v8::Local<v8::Array> properties; - if (!v8::DebugInterface::GetInternalProperties(m_isolate, value) - .ToLocal(&properties)) + if (!v8::debug::GetInternalProperties(m_isolate, value).ToLocal(&properties)) return v8::MaybeLocal<v8::Array>(); if (value->IsFunction()) { v8::Local<v8::Function> function = value.As<v8::Function>(); @@ -752,6 +752,12 @@ v8::MaybeLocal<v8::Array> V8Debugger::internalProperties( toV8StringInternalized(m_isolate, "[[GeneratorLocation]]")); createDataProperty(context, properties, properties->Length(), location); } + v8::Local<v8::Value> scopes; + if (generatorScopes(context, value).ToLocal(&scopes)) { + createDataProperty(context, properties, properties->Length(), + toV8StringInternalized(m_isolate, "[[Scopes]]")); + createDataProperty(context, properties, properties->Length(), scopes); + } } if (value->IsFunction()) { v8::Local<v8::Function> function = value.As<v8::Function>(); @@ -774,9 +780,11 @@ v8::Local<v8::Value> V8Debugger::collectionEntries( return v8::Undefined(m_isolate); } v8::Local<v8::Value> argv[] = {object}; - v8::Local<v8::Value> entriesValue = - callDebuggerMethod("getCollectionEntries", 1, argv).ToLocalChecked(); - if (!entriesValue->IsArray()) return v8::Undefined(m_isolate); + v8::Local<v8::Value> entriesValue; + if (!callDebuggerMethod("getCollectionEntries", 1, argv, true) + .ToLocal(&entriesValue) || + !entriesValue->IsArray()) + return v8::Undefined(m_isolate); v8::Local<v8::Array> entries = entriesValue.As<v8::Array>(); v8::Local<v8::Array> copiedArray = @@ -809,11 +817,11 @@ v8::Local<v8::Value> V8Debugger::generatorObjectLocation( return v8::Null(m_isolate); } v8::Local<v8::Value> argv[] = {object}; - v8::Local<v8::Value> location = - callDebuggerMethod("getGeneratorObjectLocation", 1, argv) - .ToLocalChecked(); + v8::Local<v8::Value> location; v8::Local<v8::Value> copied; - if (!copyValueFromDebuggerContext(m_isolate, debuggerContext(), context, + if (!callDebuggerMethod("getGeneratorObjectLocation", 1, argv, true) + .ToLocal(&location) || + !copyValueFromDebuggerContext(m_isolate, debuggerContext(), context, location) .ToLocal(&copied) || !copied->IsObject()) @@ -861,23 +869,13 @@ bool V8Debugger::isPaused() { return !m_pausedContext.IsEmpty(); } std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace( v8::Local<v8::StackTrace> stackTrace) { int contextGroupId = - m_isolate->InContext() ? getGroupId(m_isolate->GetCurrentContext()) : 0; + m_isolate->InContext() + ? m_inspector->contextGroupId(m_isolate->GetCurrentContext()) + : 0; return V8StackTraceImpl::create(this, contextGroupId, stackTrace, V8StackTraceImpl::maxCallStackSizeToCapture); } -int V8Debugger::markContext(const V8ContextInfo& info) { - DCHECK(info.context->GetIsolate() == m_isolate); - int contextId = ++m_lastContextId; - String16 debugData = String16::fromInteger(info.contextGroupId) + "," + - String16::fromInteger(contextId) + "," + - toString16(info.auxData); - v8::Context::Scope contextScope(info.context); - info.context->SetEmbedderData(static_cast<int>(v8::Context::kDebugIdIndex), - toV8String(m_isolate, debugData)); - return contextId; -} - void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) { if (depth <= 0) m_maxAsyncCallStackDepthMap.erase(agent); @@ -906,13 +904,22 @@ void V8Debugger::asyncTaskScheduled(const String16& taskName, void* task, if (!m_maxAsyncCallStackDepth) return; v8::HandleScope scope(m_isolate); int contextGroupId = - m_isolate->InContext() ? getGroupId(m_isolate->GetCurrentContext()) : 0; + m_isolate->InContext() + ? m_inspector->contextGroupId(m_isolate->GetCurrentContext()) + : 0; std::unique_ptr<V8StackTraceImpl> chain = V8StackTraceImpl::capture( this, contextGroupId, V8StackTraceImpl::maxCallStackSizeToCapture, taskName); if (chain) { m_asyncTaskStacks[task] = std::move(chain); if (recurring) m_recurringTasks.insert(task); + int id = ++m_lastTaskId; + m_taskToId[task] = id; + m_idToTask[id] = task; + if (static_cast<int>(m_idToTask.size()) > m_maxAsyncCallStacks) { + void* taskToRemove = m_idToTask.begin()->second; + asyncTaskCanceled(taskToRemove); + } } } @@ -920,6 +927,10 @@ void V8Debugger::asyncTaskCanceled(void* task) { if (!m_maxAsyncCallStackDepth) return; m_asyncTaskStacks.erase(task); m_recurringTasks.erase(task); + auto it = m_taskToId.find(task); + if (it == m_taskToId.end()) return; + m_idToTask.erase(it->second); + m_taskToId.erase(it); } void V8Debugger::asyncTaskStarted(void* task) { @@ -948,8 +959,13 @@ void V8Debugger::asyncTaskFinished(void* task) { m_currentTasks.pop_back(); m_currentStacks.pop_back(); - if (m_recurringTasks.find(task) == m_recurringTasks.end()) + if (m_recurringTasks.find(task) == m_recurringTasks.end()) { m_asyncTaskStacks.erase(task); + auto it = m_taskToId.find(task); + if (it == m_taskToId.end()) return; + m_idToTask.erase(it->second); + m_taskToId.erase(it); + } } void V8Debugger::allAsyncTasksCanceled() { @@ -957,6 +973,9 @@ void V8Debugger::allAsyncTasksCanceled() { m_recurringTasks.clear(); m_currentStacks.clear(); m_currentTasks.clear(); + m_idToTask.clear(); + m_taskToId.clear(); + m_lastTaskId = 0; } void V8Debugger::muteScriptParsedEvents() { @@ -973,7 +992,8 @@ std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( if (!m_isolate->InContext()) return nullptr; v8::HandleScope handles(m_isolate); - int contextGroupId = getGroupId(m_isolate->GetCurrentContext()); + int contextGroupId = + m_inspector->contextGroupId(m_isolate->GetCurrentContext()); if (!contextGroupId) return nullptr; size_t stackSize = diff --git a/deps/v8/src/inspector/v8-debugger.h b/deps/v8/src/inspector/v8-debugger.h index 4c7477899a..68fba6eaa8 100644 --- a/deps/v8/src/inspector/v8-debugger.h +++ b/deps/v8/src/inspector/v8-debugger.h @@ -13,6 +13,7 @@ #include "src/inspector/protocol/Forward.h" #include "src/inspector/protocol/Runtime.h" #include "src/inspector/v8-debugger-script.h" +#include "src/inspector/wasm-translation.h" #include "include/v8-inspector.h" @@ -30,20 +31,16 @@ class V8Debugger { V8Debugger(v8::Isolate*, V8InspectorImpl*); ~V8Debugger(); - static int contextId(v8::Local<v8::Context>); - static int getGroupId(v8::Local<v8::Context>); - int markContext(const V8ContextInfo&); - bool enabled() const; - String16 setBreakpoint(const String16& sourceID, const ScriptBreakpoint&, - int* actualLineNumber, int* actualColumnNumber); + String16 setBreakpoint(const ScriptBreakpoint&, int* actualLineNumber, + int* actualColumnNumber); void removeBreakpoint(const String16& breakpointId); void setBreakpointsActivated(bool); bool breakpointsActivated() const { return m_breakpointsActivated; } - v8::DebugInterface::ExceptionBreakState getPauseOnExceptionsState(); - void setPauseOnExceptionsState(v8::DebugInterface::ExceptionBreakState); + v8::debug::ExceptionBreakState getPauseOnExceptionsState(); + void setPauseOnExceptionsState(v8::debug::ExceptionBreakState); void setPauseOnNextStatement(bool); bool canBreakProgram(); void breakProgram(); @@ -94,11 +91,16 @@ class V8Debugger { V8InspectorImpl* inspector() { return m_inspector; } + WasmTranslation* wasmTranslation() { return &m_wasmTranslation; } + + void setMaxAsyncTaskStacksForTest(int limit) { m_maxAsyncCallStacks = limit; } + private: void compileDebuggerScript(); v8::MaybeLocal<v8::Value> callDebuggerMethod(const char* functionName, int argc, - v8::Local<v8::Value> argv[]); + v8::Local<v8::Value> argv[], + bool catchExceptions); v8::Local<v8::Context> debuggerContext() const; void clearBreakpoints(); @@ -109,13 +111,12 @@ class V8Debugger { v8::Local<v8::Array> hitBreakpoints, bool isPromiseRejection = false, bool isUncaught = false); - static void v8DebugEventCallback(const v8::DebugInterface::EventDetails&); + static void v8DebugEventCallback(const v8::debug::EventDetails&); v8::Local<v8::Value> callInternalGetterFunction(v8::Local<v8::Object>, const char* functionName); - void handleV8DebugEvent(const v8::DebugInterface::EventDetails&); - void handleV8AsyncTaskEvent(v8::Local<v8::Context>, - v8::Local<v8::Object> executionState, - v8::Local<v8::Object> eventData); + void handleV8DebugEvent(const v8::debug::EventDetails&); + static void v8AsyncTaskListener(v8::debug::PromiseDebugActionType type, + int id, void* data); v8::Local<v8::Value> collectionEntries(v8::Local<v8::Context>, v8::Local<v8::Object>); @@ -123,12 +124,22 @@ class V8Debugger { v8::Local<v8::Object>); v8::Local<v8::Value> functionLocation(v8::Local<v8::Context>, v8::Local<v8::Function>); + + enum ScopeTargetKind { + FUNCTION, + GENERATOR, + }; + v8::MaybeLocal<v8::Value> getTargetScopes(v8::Local<v8::Context>, + v8::Local<v8::Value>, + ScopeTargetKind); + v8::MaybeLocal<v8::Value> functionScopes(v8::Local<v8::Context>, v8::Local<v8::Function>); + v8::MaybeLocal<v8::Value> generatorScopes(v8::Local<v8::Context>, + v8::Local<v8::Value>); v8::Isolate* m_isolate; V8InspectorImpl* m_inspector; - int m_lastContextId; int m_enableCount; bool m_breakpointsActivated; v8::Global<v8::Object> m_debuggerScript; @@ -141,13 +152,19 @@ class V8Debugger { using AsyncTaskToStackTrace = protocol::HashMap<void*, std::unique_ptr<V8StackTraceImpl>>; AsyncTaskToStackTrace m_asyncTaskStacks; + int m_maxAsyncCallStacks; + std::map<int, void*> m_idToTask; + std::unordered_map<void*, int> m_taskToId; + int m_lastTaskId; protocol::HashSet<void*> m_recurringTasks; int m_maxAsyncCallStackDepth; std::vector<void*> m_currentTasks; std::vector<std::unique_ptr<V8StackTraceImpl>> m_currentStacks; protocol::HashMap<V8DebuggerAgentImpl*, int> m_maxAsyncCallStackDepthMap; - v8::DebugInterface::ExceptionBreakState m_pauseOnExceptionsState; + v8::debug::ExceptionBreakState m_pauseOnExceptionsState; + + WasmTranslation m_wasmTranslation; DISALLOW_COPY_AND_ASSIGN(V8Debugger); }; diff --git a/deps/v8/src/inspector/v8-function-call.cc b/deps/v8/src/inspector/v8-function-call.cc index 3880e3100e..b8c86d3da0 100644 --- a/deps/v8/src/inspector/v8-function-call.cc +++ b/deps/v8/src/inspector/v8-function-call.cc @@ -30,6 +30,7 @@ #include "src/inspector/v8-function-call.h" +#include "src/inspector/inspected-context.h" #include "src/inspector/string-util.h" #include "src/inspector/v8-debugger.h" #include "src/inspector/v8-inspector-impl.h" @@ -89,7 +90,7 @@ v8::Local<v8::Value> V8FunctionCall::callWithoutExceptionHandling() { DCHECK(!info[i].IsEmpty()); } - int contextGroupId = V8Debugger::getGroupId(m_context); + int contextGroupId = m_inspector->contextGroupId(m_context); if (contextGroupId) { m_inspector->client()->muteMetrics(contextGroupId); m_inspector->muteExceptions(contextGroupId); diff --git a/deps/v8/src/inspector/v8-heap-profiler-agent-impl.cc b/deps/v8/src/inspector/v8-heap-profiler-agent-impl.cc index 0ff04e75b9..b3e3d11f51 100644 --- a/deps/v8/src/inspector/v8-heap-profiler-agent-impl.cc +++ b/deps/v8/src/inspector/v8-heap-profiler-agent-impl.cc @@ -5,6 +5,7 @@ #include "src/inspector/v8-heap-profiler-agent-impl.h" #include "src/inspector/injected-script.h" +#include "src/inspector/inspected-context.h" #include "src/inspector/protocol/Protocol.h" #include "src/inspector/string-util.h" #include "src/inspector/v8-debugger.h" @@ -55,7 +56,7 @@ class GlobalObjectNameResolver final const char* GetName(v8::Local<v8::Object> object) override { InspectedContext* context = m_session->inspector()->getContext( m_session->contextGroupId(), - V8Debugger::contextId(object->CreationContext())); + InspectedContext::contextId(object->CreationContext())); if (!context) return ""; String16 name = context->origin(); size_t length = name.length(); @@ -216,7 +217,7 @@ Response V8HeapProfilerAgentImpl::takeHeapSnapshot(Maybe<bool> reportProgress) { if (!profiler) return Response::Error("Cannot access v8 heap profiler"); std::unique_ptr<HeapSnapshotProgress> progress; if (reportProgress.fromMaybe(false)) - progress = wrapUnique(new HeapSnapshotProgress(&m_frontend)); + progress.reset(new HeapSnapshotProgress(&m_frontend)); GlobalObjectNameResolver resolver(m_session); const v8::HeapSnapshot* snapshot = @@ -244,7 +245,7 @@ Response V8HeapProfilerAgentImpl::getObjectByHeapObjectId( *result = m_session->wrapObject(heapObject->CreationContext(), heapObject, objectGroup.fromMaybe(""), false); - if (!result) return Response::Error("Object is not available"); + if (!*result) return Response::Error("Object is not available"); return Response::OK(); } @@ -260,7 +261,8 @@ Response V8HeapProfilerAgentImpl::addInspectedHeapObject( if (!m_session->inspector()->client()->isInspectableHeapObject(heapObject)) return Response::Error("Object is not available"); - m_session->addInspectedObject(wrapUnique(new InspectableHeapObject(id))); + m_session->addInspectedObject( + std::unique_ptr<InspectableHeapObject>(new InspectableHeapObject(id))); return Response::OK(); } diff --git a/deps/v8/src/inspector/v8-inspector-impl.cc b/deps/v8/src/inspector/v8-inspector-impl.cc index bd68548fbf..34e41208ac 100644 --- a/deps/v8/src/inspector/v8-inspector-impl.cc +++ b/deps/v8/src/inspector/v8-inspector-impl.cc @@ -45,7 +45,7 @@ namespace v8_inspector { std::unique_ptr<V8Inspector> V8Inspector::create(v8::Isolate* isolate, V8InspectorClient* client) { - return wrapUnique(new V8InspectorImpl(isolate, client)); + return std::unique_ptr<V8Inspector>(new V8InspectorImpl(isolate, client)); } V8InspectorImpl::V8InspectorImpl(v8::Isolate* isolate, @@ -54,10 +54,21 @@ V8InspectorImpl::V8InspectorImpl(v8::Isolate* isolate, m_client(client), m_debugger(new V8Debugger(isolate, this)), m_capturingStackTracesCount(0), - m_lastExceptionId(0) {} + m_lastExceptionId(0), + m_lastContextId(0) {} V8InspectorImpl::~V8InspectorImpl() {} +int V8InspectorImpl::contextGroupId(v8::Local<v8::Context> context) { + return contextGroupId(InspectedContext::contextId(context)); +} + +int V8InspectorImpl::contextGroupId(int contextId) { + protocol::HashMap<int, int>::iterator it = + m_contextIdToGroupIdMap.find(contextId); + return it != m_contextIdToGroupIdMap.end() ? it->second : 0; +} + V8DebuggerAgentImpl* V8InspectorImpl::enabledDebuggerAgentForGroup( int contextGroupId) { V8InspectorSessionImpl* session = sessionForContextGroup(contextGroupId); @@ -83,7 +94,7 @@ v8::MaybeLocal<v8::Value> V8InspectorImpl::runCompiledScript( v8::Local<v8::Context> context, v8::Local<v8::Script> script) { v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kRunMicrotasks); - int groupId = V8Debugger::getGroupId(context); + int groupId = contextGroupId(context); if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId)) agent->willExecuteScript(script->GetUnboundScript()->GetId()); v8::MaybeLocal<v8::Value> result = script->Run(context); @@ -97,9 +108,23 @@ v8::MaybeLocal<v8::Value> V8InspectorImpl::runCompiledScript( v8::MaybeLocal<v8::Value> V8InspectorImpl::callFunction( v8::Local<v8::Function> function, v8::Local<v8::Context> context, v8::Local<v8::Value> receiver, int argc, v8::Local<v8::Value> info[]) { - v8::MicrotasksScope microtasksScope(m_isolate, - v8::MicrotasksScope::kRunMicrotasks); - int groupId = V8Debugger::getGroupId(context); + return callFunction(function, context, receiver, argc, info, + v8::MicrotasksScope::kRunMicrotasks); +} + +v8::MaybeLocal<v8::Value> V8InspectorImpl::callInternalFunction( + v8::Local<v8::Function> function, v8::Local<v8::Context> context, + v8::Local<v8::Value> receiver, int argc, v8::Local<v8::Value> info[]) { + return callFunction(function, context, receiver, argc, info, + v8::MicrotasksScope::kDoNotRunMicrotasks); +} + +v8::MaybeLocal<v8::Value> V8InspectorImpl::callFunction( + v8::Local<v8::Function> function, v8::Local<v8::Context> context, + v8::Local<v8::Value> receiver, int argc, v8::Local<v8::Value> info[], + v8::MicrotasksScope::Type runMicrotasks) { + v8::MicrotasksScope microtasksScope(m_isolate, runMicrotasks); + int groupId = contextGroupId(context); if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId)) agent->willExecuteScript(function->ScriptId()); v8::MaybeLocal<v8::Value> result = @@ -113,32 +138,28 @@ v8::MaybeLocal<v8::Value> V8InspectorImpl::callFunction( v8::MaybeLocal<v8::Value> V8InspectorImpl::compileAndRunInternalScript( v8::Local<v8::Context> context, v8::Local<v8::String> source) { - v8::Local<v8::Script> script = - compileScript(context, source, String16(), true); - if (script.IsEmpty()) return v8::MaybeLocal<v8::Value>(); + v8::Local<v8::UnboundScript> unboundScript; + if (!v8::debug::CompileInspectorScript(m_isolate, source) + .ToLocal(&unboundScript)) + return v8::MaybeLocal<v8::Value>(); v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kDoNotRunMicrotasks); - return script->Run(context); + v8::Context::Scope contextScope(context); + return unboundScript->BindToCurrentContext()->Run(context); } -v8::Local<v8::Script> V8InspectorImpl::compileScript( - v8::Local<v8::Context> context, v8::Local<v8::String> code, - const String16& fileName, bool markAsInternal) { +v8::MaybeLocal<v8::Script> V8InspectorImpl::compileScript( + v8::Local<v8::Context> context, const String16& code, + const String16& fileName) { v8::ScriptOrigin origin( toV8String(m_isolate, fileName), v8::Integer::New(m_isolate, 0), v8::Integer::New(m_isolate, 0), - v8::False(m_isolate), // sharable - v8::Local<v8::Integer>(), - v8::Boolean::New(m_isolate, markAsInternal), // internal - toV8String(m_isolate, String16()), // sourceMap - v8::True(m_isolate)); // opaqueresource - v8::ScriptCompiler::Source source(code, origin); - v8::Local<v8::Script> script; - if (!v8::ScriptCompiler::Compile(context, &source, - v8::ScriptCompiler::kNoCompileOptions) - .ToLocal(&script)) - return v8::Local<v8::Script>(); - return script; + v8::False(m_isolate), // sharable + v8::Local<v8::Integer>(), toV8String(m_isolate, String16()), // sourceMap + v8::True(m_isolate)); // opaqueresource + v8::ScriptCompiler::Source source(toV8String(m_isolate, code), origin); + return v8::ScriptCompiler::Compile(context, &source, + v8::ScriptCompiler::kNoCompileOptions); } void V8InspectorImpl::enableStackCapturingIfNeeded() { @@ -167,12 +188,12 @@ V8ConsoleMessageStorage* V8InspectorImpl::ensureConsoleMessageStorage( ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(contextGroupId); if (storageIt == m_consoleStorageMap.end()) - storageIt = - m_consoleStorageMap - .insert(std::make_pair( - contextGroupId, - wrapUnique(new V8ConsoleMessageStorage(this, contextGroupId)))) - .first; + storageIt = m_consoleStorageMap + .insert(std::make_pair( + contextGroupId, + std::unique_ptr<V8ConsoleMessageStorage>( + new V8ConsoleMessageStorage(this, contextGroupId)))) + .first; return storageIt->second.get(); } @@ -216,42 +237,43 @@ InspectedContext* V8InspectorImpl::getContext(int groupId, } void V8InspectorImpl::contextCreated(const V8ContextInfo& info) { - int contextId = m_debugger->markContext(info); + int contextId = ++m_lastContextId; + InspectedContext* context = new InspectedContext(this, info, contextId); + m_contextIdToGroupIdMap[contextId] = info.contextGroupId; ContextsByGroupMap::iterator contextIt = m_contexts.find(info.contextGroupId); if (contextIt == m_contexts.end()) contextIt = m_contexts - .insert(std::make_pair(info.contextGroupId, - wrapUnique(new ContextByIdMap()))) + .insert(std::make_pair( + info.contextGroupId, + std::unique_ptr<ContextByIdMap>(new ContextByIdMap()))) .first; - const auto& contextById = contextIt->second; DCHECK(contextById->find(contextId) == contextById->cend()); - InspectedContext* context = new InspectedContext(this, info, contextId); - (*contextById)[contextId] = wrapUnique(context); + (*contextById)[contextId].reset(context); SessionMap::iterator sessionIt = m_sessions.find(info.contextGroupId); if (sessionIt != m_sessions.end()) sessionIt->second->runtimeAgent()->reportExecutionContextCreated(context); } void V8InspectorImpl::contextDestroyed(v8::Local<v8::Context> context) { - int contextId = V8Debugger::contextId(context); - int contextGroupId = V8Debugger::getGroupId(context); + int contextId = InspectedContext::contextId(context); + int groupId = contextGroupId(context); + m_contextIdToGroupIdMap.erase(contextId); - ConsoleStorageMap::iterator storageIt = - m_consoleStorageMap.find(contextGroupId); + ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(groupId); if (storageIt != m_consoleStorageMap.end()) storageIt->second->contextDestroyed(contextId); - InspectedContext* inspectedContext = getContext(contextGroupId, contextId); + InspectedContext* inspectedContext = getContext(groupId, contextId); if (!inspectedContext) return; - SessionMap::iterator iter = m_sessions.find(contextGroupId); + SessionMap::iterator iter = m_sessions.find(groupId); if (iter != m_sessions.end()) iter->second->runtimeAgent()->reportExecutionContextDestroyed( inspectedContext); - discardInspectedContext(contextGroupId, contextId); + discardInspectedContext(groupId, contextId); } void V8InspectorImpl::resetContextGroup(int contextGroupId) { @@ -260,19 +282,22 @@ void V8InspectorImpl::resetContextGroup(int contextGroupId) { SessionMap::iterator session = m_sessions.find(contextGroupId); if (session != m_sessions.end()) session->second->reset(); m_contexts.erase(contextGroupId); + m_debugger->wasmTranslation()->Clear(); } void V8InspectorImpl::willExecuteScript(v8::Local<v8::Context> context, int scriptId) { if (V8DebuggerAgentImpl* agent = - enabledDebuggerAgentForGroup(V8Debugger::getGroupId(context))) + enabledDebuggerAgentForGroup(contextGroupId(context))) { agent->willExecuteScript(scriptId); + } } void V8InspectorImpl::didExecuteScript(v8::Local<v8::Context> context) { if (V8DebuggerAgentImpl* agent = - enabledDebuggerAgentForGroup(V8Debugger::getGroupId(context))) + enabledDebuggerAgentForGroup(contextGroupId(context))) { agent->didExecuteScript(); + } } void V8InspectorImpl::idleStarted() { @@ -292,33 +317,31 @@ unsigned V8InspectorImpl::exceptionThrown( v8::Local<v8::Value> exception, const StringView& detailedMessage, const StringView& url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr<V8StackTrace> stackTrace, int scriptId) { - int contextGroupId = V8Debugger::getGroupId(context); - if (!contextGroupId || m_muteExceptionsMap[contextGroupId]) return 0; - std::unique_ptr<V8StackTraceImpl> stackTraceImpl = - wrapUnique(static_cast<V8StackTraceImpl*>(stackTrace.release())); + int groupId = contextGroupId(context); + if (!groupId || m_muteExceptionsMap[groupId]) return 0; + std::unique_ptr<V8StackTraceImpl> stackTraceImpl( + static_cast<V8StackTraceImpl*>(stackTrace.release())); unsigned exceptionId = nextExceptionId(); std::unique_ptr<V8ConsoleMessage> consoleMessage = V8ConsoleMessage::createForException( m_client->currentTimeMS(), toString16(detailedMessage), toString16(url), lineNumber, columnNumber, std::move(stackTraceImpl), scriptId, m_isolate, toString16(message), - V8Debugger::contextId(context), exception, exceptionId); - ensureConsoleMessageStorage(contextGroupId) - ->addMessage(std::move(consoleMessage)); + InspectedContext::contextId(context), exception, exceptionId); + ensureConsoleMessageStorage(groupId)->addMessage(std::move(consoleMessage)); return exceptionId; } void V8InspectorImpl::exceptionRevoked(v8::Local<v8::Context> context, unsigned exceptionId, const StringView& message) { - int contextGroupId = V8Debugger::getGroupId(context); - if (!contextGroupId) return; + int groupId = contextGroupId(context); + if (!groupId) return; std::unique_ptr<V8ConsoleMessage> consoleMessage = V8ConsoleMessage::createForRevokedException( m_client->currentTimeMS(), toString16(message), exceptionId); - ensureConsoleMessageStorage(contextGroupId) - ->addMessage(std::move(consoleMessage)); + ensureConsoleMessageStorage(groupId)->addMessage(std::move(consoleMessage)); } std::unique_ptr<V8StackTrace> V8InspectorImpl::captureStackTrace( diff --git a/deps/v8/src/inspector/v8-inspector-impl.h b/deps/v8/src/inspector/v8-inspector-impl.h index 0ca1a6a729..f98747543b 100644 --- a/deps/v8/src/inspector/v8-inspector-impl.h +++ b/deps/v8/src/inspector/v8-inspector-impl.h @@ -58,6 +58,8 @@ class V8InspectorImpl : public V8Inspector { v8::Isolate* isolate() const { return m_isolate; } V8InspectorClient* client() { return m_client; } V8Debugger* debugger() { return m_debugger.get(); } + int contextGroupId(v8::Local<v8::Context>); + int contextGroupId(int contextId); v8::MaybeLocal<v8::Value> runCompiledScript(v8::Local<v8::Context>, v8::Local<v8::Script>); @@ -67,10 +69,14 @@ class V8InspectorImpl : public V8Inspector { int argc, v8::Local<v8::Value> info[]); v8::MaybeLocal<v8::Value> compileAndRunInternalScript(v8::Local<v8::Context>, v8::Local<v8::String>); - v8::Local<v8::Script> compileScript(v8::Local<v8::Context>, - v8::Local<v8::String>, - const String16& fileName, - bool markAsInternal); + v8::MaybeLocal<v8::Value> callInternalFunction(v8::Local<v8::Function>, + v8::Local<v8::Context>, + v8::Local<v8::Value> receiver, + int argc, + v8::Local<v8::Value> info[]); + v8::MaybeLocal<v8::Script> compileScript(v8::Local<v8::Context>, + const String16& code, + const String16& fileName); v8::Local<v8::Context> regexContext(); // V8Inspector implementation. @@ -121,12 +127,18 @@ class V8InspectorImpl : public V8Inspector { V8ProfilerAgentImpl* enabledProfilerAgentForGroup(int contextGroupId); private: + v8::MaybeLocal<v8::Value> callFunction( + v8::Local<v8::Function>, v8::Local<v8::Context>, + v8::Local<v8::Value> receiver, int argc, v8::Local<v8::Value> info[], + v8::MicrotasksScope::Type runMicrotasks); + v8::Isolate* m_isolate; V8InspectorClient* m_client; std::unique_ptr<V8Debugger> m_debugger; v8::Global<v8::Context> m_regexContext; int m_capturingStackTracesCount; unsigned m_lastExceptionId; + int m_lastContextId; using MuteExceptionsMap = protocol::HashMap<int, int>; MuteExceptionsMap m_muteExceptionsMap; @@ -142,6 +154,8 @@ class V8InspectorImpl : public V8Inspector { protocol::HashMap<int, std::unique_ptr<V8ConsoleMessageStorage>>; ConsoleStorageMap m_consoleStorageMap; + protocol::HashMap<int, int> m_contextIdToGroupIdMap; + DISALLOW_COPY_AND_ASSIGN(V8InspectorImpl); }; diff --git a/deps/v8/src/inspector/v8-inspector-session-impl.cc b/deps/v8/src/inspector/v8-inspector-session-impl.cc index e415575304..3a5b59c28d 100644 --- a/deps/v8/src/inspector/v8-inspector-session-impl.cc +++ b/deps/v8/src/inspector/v8-inspector-session-impl.cc @@ -40,7 +40,7 @@ bool V8InspectorSession::canDispatchMethod(const StringView& method) { std::unique_ptr<V8InspectorSessionImpl> V8InspectorSessionImpl::create( V8InspectorImpl* inspector, int contextGroupId, V8Inspector::Channel* channel, const StringView& state) { - return wrapUnique( + return std::unique_ptr<V8InspectorSessionImpl>( new V8InspectorSessionImpl(inspector, contextGroupId, channel, state)); } @@ -62,35 +62,35 @@ V8InspectorSessionImpl::V8InspectorSessionImpl(V8InspectorImpl* inspector, m_schemaAgent(nullptr) { if (savedState.length()) { std::unique_ptr<protocol::Value> state = - protocol::parseJSON(toString16(savedState)); + protocol::StringUtil::parseJSON(toString16(savedState)); if (state) m_state = protocol::DictionaryValue::cast(std::move(state)); if (!m_state) m_state = protocol::DictionaryValue::create(); } else { m_state = protocol::DictionaryValue::create(); } - m_runtimeAgent = wrapUnique(new V8RuntimeAgentImpl( + m_runtimeAgent.reset(new V8RuntimeAgentImpl( this, this, agentState(protocol::Runtime::Metainfo::domainName))); protocol::Runtime::Dispatcher::wire(&m_dispatcher, m_runtimeAgent.get()); - m_debuggerAgent = wrapUnique(new V8DebuggerAgentImpl( + m_debuggerAgent.reset(new V8DebuggerAgentImpl( this, this, agentState(protocol::Debugger::Metainfo::domainName))); protocol::Debugger::Dispatcher::wire(&m_dispatcher, m_debuggerAgent.get()); - m_profilerAgent = wrapUnique(new V8ProfilerAgentImpl( + m_profilerAgent.reset(new V8ProfilerAgentImpl( this, this, agentState(protocol::Profiler::Metainfo::domainName))); protocol::Profiler::Dispatcher::wire(&m_dispatcher, m_profilerAgent.get()); - m_heapProfilerAgent = wrapUnique(new V8HeapProfilerAgentImpl( + m_heapProfilerAgent.reset(new V8HeapProfilerAgentImpl( this, this, agentState(protocol::HeapProfiler::Metainfo::domainName))); protocol::HeapProfiler::Dispatcher::wire(&m_dispatcher, m_heapProfilerAgent.get()); - m_consoleAgent = wrapUnique(new V8ConsoleAgentImpl( + m_consoleAgent.reset(new V8ConsoleAgentImpl( this, this, agentState(protocol::Console::Metainfo::domainName))); protocol::Console::Dispatcher::wire(&m_dispatcher, m_consoleAgent.get()); - m_schemaAgent = wrapUnique(new V8SchemaAgentImpl( + m_schemaAgent.reset(new V8SchemaAgentImpl( this, this, agentState(protocol::Schema::Metainfo::domainName))); protocol::Schema::Dispatcher::wire(&m_dispatcher, m_schemaAgent.get()); @@ -126,13 +126,42 @@ protocol::DictionaryValue* V8InspectorSessionImpl::agentState( return state; } -void V8InspectorSessionImpl::sendProtocolResponse(int callId, - const String16& message) { - m_channel->sendProtocolResponse(callId, toStringView(message)); +namespace { + +class MessageBuffer : public StringBuffer { + public: + static std::unique_ptr<MessageBuffer> create( + std::unique_ptr<protocol::Serializable> message) { + return std::unique_ptr<MessageBuffer>( + new MessageBuffer(std::move(message))); + } + + const StringView& string() override { + if (!m_serialized) { + m_serialized = StringBuffer::create(toStringView(m_message->serialize())); + m_message.reset(nullptr); + } + return m_serialized->string(); + } + + private: + explicit MessageBuffer(std::unique_ptr<protocol::Serializable> message) + : m_message(std::move(message)) {} + + std::unique_ptr<protocol::Serializable> m_message; + std::unique_ptr<StringBuffer> m_serialized; +}; + +} // namespace + +void V8InspectorSessionImpl::sendProtocolResponse( + int callId, std::unique_ptr<protocol::Serializable> message) { + m_channel->sendResponse(callId, MessageBuffer::create(std::move(message))); } -void V8InspectorSessionImpl::sendProtocolNotification(const String16& message) { - m_channel->sendProtocolNotification(toStringView(message)); +void V8InspectorSessionImpl::sendProtocolNotification( + std::unique_ptr<protocol::Serializable> message) { + m_channel->sendNotification(MessageBuffer::create(std::move(message))); } void V8InspectorSessionImpl::flushProtocolNotifications() { @@ -266,7 +295,7 @@ V8InspectorSessionImpl::wrapObject(v8::Local<v8::Context> context, const String16& groupName, bool generatePreview) { InjectedScript* injectedScript = nullptr; - findInjectedScript(V8Debugger::contextId(context), injectedScript); + findInjectedScript(InspectedContext::contextId(context), injectedScript); if (!injectedScript) return nullptr; std::unique_ptr<protocol::Runtime::RemoteObject> result; injectedScript->wrapObject(value, groupName, false, generatePreview, &result); @@ -278,7 +307,7 @@ V8InspectorSessionImpl::wrapTable(v8::Local<v8::Context> context, v8::Local<v8::Value> table, v8::Local<v8::Value> columns) { InjectedScript* injectedScript = nullptr; - findInjectedScript(V8Debugger::contextId(context), injectedScript); + findInjectedScript(InspectedContext::contextId(context), injectedScript); if (!injectedScript) return nullptr; return injectedScript->wrapTable(table, columns); } @@ -305,11 +334,11 @@ void V8InspectorSessionImpl::reportAllContexts(V8RuntimeAgentImpl* agent) { void V8InspectorSessionImpl::dispatchProtocolMessage( const StringView& message) { - m_dispatcher.dispatch(protocol::parseJSON(message)); + m_dispatcher.dispatch(protocol::StringUtil::parseJSON(message)); } std::unique_ptr<StringBuffer> V8InspectorSessionImpl::stateJSON() { - String16 json = m_state->toJSONString(); + String16 json = m_state->serialize(); return StringBufferImpl::adopt(json); } @@ -366,7 +395,8 @@ void V8InspectorSessionImpl::schedulePauseOnNextStatement( const StringView& breakReason, const StringView& breakDetails) { m_debuggerAgent->schedulePauseOnNextStatement( toString16(breakReason), - protocol::DictionaryValue::cast(protocol::parseJSON(breakDetails))); + protocol::DictionaryValue::cast( + protocol::StringUtil::parseJSON(breakDetails))); } void V8InspectorSessionImpl::cancelPauseOnNextStatement() { @@ -377,7 +407,8 @@ void V8InspectorSessionImpl::breakProgram(const StringView& breakReason, const StringView& breakDetails) { m_debuggerAgent->breakProgram( toString16(breakReason), - protocol::DictionaryValue::cast(protocol::parseJSON(breakDetails))); + protocol::DictionaryValue::cast( + protocol::StringUtil::parseJSON(breakDetails))); } void V8InspectorSessionImpl::setSkipAllPauses(bool skip) { diff --git a/deps/v8/src/inspector/v8-inspector-session-impl.h b/deps/v8/src/inspector/v8-inspector-session-impl.h index af65aa3c93..7a59e1cead 100644 --- a/deps/v8/src/inspector/v8-inspector-session-impl.h +++ b/deps/v8/src/inspector/v8-inspector-session-impl.h @@ -96,8 +96,10 @@ class V8InspectorSessionImpl : public V8InspectorSession, protocol::DictionaryValue* agentState(const String16& name); // protocol::FrontendChannel implementation. - void sendProtocolResponse(int callId, const String16& message) override; - void sendProtocolNotification(const String16& message) override; + void sendProtocolResponse( + int callId, std::unique_ptr<protocol::Serializable> message) override; + void sendProtocolNotification( + std::unique_ptr<protocol::Serializable> message) override; void flushProtocolNotifications() override; int m_contextGroupId; diff --git a/deps/v8/src/inspector/v8-internal-value-type.cc b/deps/v8/src/inspector/v8-internal-value-type.cc index cde8bc9f7f..46f5dac1ac 100644 --- a/deps/v8/src/inspector/v8-internal-value-type.cc +++ b/deps/v8/src/inspector/v8-internal-value-type.cc @@ -4,7 +4,6 @@ #include "src/inspector/v8-internal-value-type.h" -#include "src/inspector/protocol-platform.h" #include "src/inspector/string-util.h" namespace v8_inspector { diff --git a/deps/v8/src/inspector/v8-profiler-agent-impl.cc b/deps/v8/src/inspector/v8-profiler-agent-impl.cc index 8b888a066b..16c4777e84 100644 --- a/deps/v8/src/inspector/v8-profiler-agent-impl.cc +++ b/deps/v8/src/inspector/v8-profiler-agent-impl.cc @@ -309,8 +309,4 @@ bool V8ProfilerAgentImpl::idleFinished() { return m_profiler; } -void V8ProfilerAgentImpl::collectSample() { - if (m_profiler) m_profiler->CollectSample(); -} - } // namespace v8_inspector diff --git a/deps/v8/src/inspector/v8-profiler-agent-impl.h b/deps/v8/src/inspector/v8-profiler-agent-impl.h index a634ff3cd9..a8441174e0 100644 --- a/deps/v8/src/inspector/v8-profiler-agent-impl.h +++ b/deps/v8/src/inspector/v8-profiler-agent-impl.h @@ -43,8 +43,6 @@ class V8ProfilerAgentImpl : public protocol::Profiler::Backend { bool idleStarted(); bool idleFinished(); - void collectSample(); - private: String16 nextProfileId(); diff --git a/deps/v8/src/inspector/v8-runtime-agent-impl.cc b/deps/v8/src/inspector/v8-runtime-agent-impl.cc index 4dbe60f8f3..b40f08ed06 100644 --- a/deps/v8/src/inspector/v8-runtime-agent-impl.cc +++ b/deps/v8/src/inspector/v8-runtime-agent-impl.cc @@ -241,7 +241,7 @@ Response ensureContext(V8InspectorImpl* inspector, int contextGroupId, inspector->client()->ensureDefaultContextInGroup(contextGroupId); if (defaultContext.IsEmpty()) return Response::Error("Cannot find default execution context"); - *contextId = V8Debugger::contextId(defaultContext); + *contextId = InspectedContext::contextId(defaultContext); } return Response::OK(); } @@ -293,11 +293,11 @@ void V8RuntimeAgentImpl::evaluate( if (evalIsDisabled) scope.context()->AllowCodeGenerationFromStrings(true); v8::MaybeLocal<v8::Value> maybeResultValue; - v8::Local<v8::Script> script = m_inspector->compileScript( - scope.context(), toV8String(m_inspector->isolate(), expression), - String16(), false); - if (!script.IsEmpty()) + v8::Local<v8::Script> script; + if (m_inspector->compileScript(scope.context(), expression, String16()) + .ToLocal(&script)) { maybeResultValue = m_inspector->runCompiledScript(scope.context(), script); + } if (evalIsDisabled) scope.context()->AllowCodeGenerationFromStrings(false); @@ -379,10 +379,14 @@ void V8RuntimeAgentImpl::callFunctionOn( if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole(); if (userGesture.fromMaybe(false)) scope.pretendUserGesture(); - v8::MaybeLocal<v8::Value> maybeFunctionValue = - m_inspector->compileAndRunInternalScript( - scope.context(), - toV8String(m_inspector->isolate(), "(" + expression + ")")); + v8::MaybeLocal<v8::Value> maybeFunctionValue; + v8::Local<v8::Script> functionScript; + if (m_inspector + ->compileScript(scope.context(), "(" + expression + ")", String16()) + .ToLocal(&functionScript)) { + maybeFunctionValue = + m_inspector->runCompiledScript(scope.context(), functionScript); + } // Re-initialize after running client's code, as it could have destroyed // context or session. response = scope.initialize(); @@ -543,11 +547,11 @@ Response V8RuntimeAgentImpl::compileScript( if (!response.isSuccess()) return response; if (!persistScript) m_inspector->debugger()->muteScriptParsedEvents(); - v8::Local<v8::Script> script = m_inspector->compileScript( - scope.context(), toV8String(m_inspector->isolate(), expression), - sourceURL, false); + v8::Local<v8::Script> script; + bool isOk = m_inspector->compileScript(scope.context(), expression, sourceURL) + .ToLocal(&script); if (!persistScript) m_inspector->debugger()->unmuteScriptParsedEvents(); - if (script.IsEmpty()) { + if (!isOk) { if (scope.tryCatch().HasCaught()) { response = scope.injectedScript()->createExceptionDetails( scope.tryCatch(), String16(), false, exceptionDetails); @@ -702,7 +706,7 @@ void V8RuntimeAgentImpl::reportExecutionContextCreated( .build(); if (!context->auxData().isEmpty()) description->setAuxData(protocol::DictionaryValue::cast( - protocol::parseJSON(context->auxData()))); + protocol::StringUtil::parseJSON(context->auxData()))); m_frontend.executionContextCreated(std::move(description)); } diff --git a/deps/v8/src/inspector/v8-stack-trace-impl.cc b/deps/v8/src/inspector/v8-stack-trace-impl.cc index 1a38c6dd82..962a00a773 100644 --- a/deps/v8/src/inspector/v8-stack-trace-impl.cc +++ b/deps/v8/src/inspector/v8-stack-trace-impl.cc @@ -5,12 +5,11 @@ #include "src/inspector/v8-stack-trace-impl.h" #include "src/inspector/string-util.h" +#include "src/inspector/v8-debugger-agent-impl.h" #include "src/inspector/v8-debugger.h" #include "src/inspector/v8-inspector-impl.h" -#include "src/inspector/v8-profiler-agent-impl.h" #include "include/v8-debug.h" -#include "include/v8-profiler.h" #include "include/v8-version.h" namespace v8_inspector { @@ -23,7 +22,9 @@ static const v8::StackTrace::StackTraceOptions stackTraceOptions = v8::StackTrace::kScriptId | v8::StackTrace::kScriptNameOrSourceURL | v8::StackTrace::kFunctionName); -V8StackTraceImpl::Frame toFrame(v8::Local<v8::StackFrame> frame) { +V8StackTraceImpl::Frame toFrame(v8::Local<v8::StackFrame> frame, + WasmTranslation* wasmTranslation, + int contextGroupId) { String16 scriptId = String16::fromInteger(frame->GetScriptId()); String16 sourceName; v8::Local<v8::String> sourceNameValue(frame->GetScriptNameOrSourceURL()); @@ -35,22 +36,30 @@ V8StackTraceImpl::Frame toFrame(v8::Local<v8::StackFrame> frame) { if (!functionNameValue.IsEmpty()) functionName = toProtocolString(functionNameValue); - int sourceLineNumber = frame->GetLineNumber(); - int sourceColumn = frame->GetColumn(); + int sourceLineNumber = frame->GetLineNumber() - 1; + int sourceColumn = frame->GetColumn() - 1; + // TODO(clemensh): Figure out a way to do this translation only right before + // sending the stack trace over wire. + if (wasmTranslation) + wasmTranslation->TranslateWasmScriptLocationToProtocolLocation( + &scriptId, &sourceLineNumber, &sourceColumn); return V8StackTraceImpl::Frame(functionName, scriptId, sourceName, - sourceLineNumber, sourceColumn); + sourceLineNumber + 1, sourceColumn + 1); } void toFramesVector(v8::Local<v8::StackTrace> stackTrace, std::vector<V8StackTraceImpl::Frame>& frames, - size_t maxStackSize, v8::Isolate* isolate) { + size_t maxStackSize, v8::Isolate* isolate, + V8Debugger* debugger, int contextGroupId) { DCHECK(isolate->InContext()); int frameCount = stackTrace->GetFrameCount(); if (frameCount > static_cast<int>(maxStackSize)) frameCount = static_cast<int>(maxStackSize); + WasmTranslation* wasmTranslation = + debugger ? debugger->wasmTranslation() : nullptr; for (int i = 0; i < frameCount; i++) { v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(i); - frames.push_back(toFrame(stackFrame)); + frames.push_back(toFrame(stackFrame, wasmTranslation, contextGroupId)); } } @@ -113,7 +122,8 @@ std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::create( v8::HandleScope scope(isolate); std::vector<V8StackTraceImpl::Frame> frames; if (!stackTrace.IsEmpty()) - toFramesVector(stackTrace, frames, maxStackSize, isolate); + toFramesVector(stackTrace, frames, maxStackSize, isolate, debugger, + contextGroupId); int maxAsyncCallChainDepth = 1; V8StackTraceImpl* asyncCallChain = nullptr; @@ -161,12 +171,6 @@ std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::capture( v8::HandleScope handleScope(isolate); v8::Local<v8::StackTrace> stackTrace; if (isolate->InContext()) { - if (debugger) { - V8InspectorImpl* inspector = debugger->inspector(); - V8ProfilerAgentImpl* profilerAgent = - inspector->enabledProfilerAgentForGroup(contextGroupId); - if (profilerAgent) profilerAgent->collectSample(); - } stackTrace = v8::StackTrace::CurrentStackTrace( isolate, static_cast<int>(maxStackSize), stackTraceOptions); } @@ -176,7 +180,7 @@ std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::capture( std::unique_ptr<V8StackTraceImpl> V8StackTraceImpl::cloneImpl() { std::vector<Frame> framesCopy(m_frames); - return wrapUnique( + return std::unique_ptr<V8StackTraceImpl>( new V8StackTraceImpl(m_contextGroupId, m_description, framesCopy, m_parent ? m_parent->cloneImpl() : nullptr)); } @@ -185,7 +189,7 @@ std::unique_ptr<V8StackTrace> V8StackTraceImpl::clone() { std::vector<Frame> frames; for (size_t i = 0; i < m_frames.size(); i++) frames.push_back(m_frames.at(i).clone()); - return wrapUnique( + return std::unique_ptr<V8StackTraceImpl>( new V8StackTraceImpl(m_contextGroupId, m_description, frames, nullptr)); } diff --git a/deps/v8/src/inspector/wasm-translation.cc b/deps/v8/src/inspector/wasm-translation.cc new file mode 100644 index 0000000000..825341e122 --- /dev/null +++ b/deps/v8/src/inspector/wasm-translation.cc @@ -0,0 +1,309 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/inspector/wasm-translation.h" + +#include <algorithm> + +#include "src/debug/debug-interface.h" +#include "src/inspector/protocol/Debugger.h" +#include "src/inspector/script-breakpoint.h" +#include "src/inspector/string-util.h" +#include "src/inspector/v8-debugger-agent-impl.h" +#include "src/inspector/v8-debugger-script.h" +#include "src/inspector/v8-debugger.h" +#include "src/inspector/v8-inspector-impl.h" + +using namespace v8_inspector; +using namespace v8; + +class WasmTranslation::TranslatorImpl { + public: + struct TransLocation { + WasmTranslation *translation; + String16 script_id; + int line; + int column; + TransLocation(WasmTranslation *translation, String16 script_id, int line, + int column) + : translation(translation), + script_id(script_id), + line(line), + column(column) {} + }; + + virtual void Translate(TransLocation *loc) = 0; + virtual void TranslateBack(TransLocation *loc) = 0; + + class RawTranslator; + class DisassemblingTranslator; +}; + +class WasmTranslation::TranslatorImpl::RawTranslator + : public WasmTranslation::TranslatorImpl { + public: + void Translate(TransLocation *loc) {} + void TranslateBack(TransLocation *loc) {} +}; + +class WasmTranslation::TranslatorImpl::DisassemblingTranslator + : public WasmTranslation::TranslatorImpl { + using OffsetTable = debug::WasmDisassembly::OffsetTable; + + public: + DisassemblingTranslator(Isolate *isolate, Local<debug::WasmScript> script, + WasmTranslation *translation, + V8DebuggerAgentImpl *agent) + : script_(isolate, script) { + // Register fake scripts for each function in this wasm module/script. + int num_functions = script->NumFunctions(); + int num_imported_functions = script->NumImportedFunctions(); + DCHECK_LE(0, num_imported_functions); + DCHECK_LE(0, num_functions); + DCHECK_GE(num_functions, num_imported_functions); + String16 script_id = String16::fromInteger(script->Id()); + for (int func_idx = num_imported_functions; func_idx < num_functions; + ++func_idx) { + AddFakeScript(isolate, script_id, func_idx, translation, agent); + } + } + + void Translate(TransLocation *loc) { + const OffsetTable &offset_table = GetOffsetTable(loc); + DCHECK(!offset_table.empty()); + uint32_t byte_offset = static_cast<uint32_t>(loc->column); + + // Binary search for the given offset. + unsigned left = 0; // inclusive + unsigned right = static_cast<unsigned>(offset_table.size()); // exclusive + while (right - left > 1) { + unsigned mid = (left + right) / 2; + if (offset_table[mid].byte_offset <= byte_offset) { + left = mid; + } else { + right = mid; + } + } + + loc->script_id = GetFakeScriptId(loc); + if (offset_table[left].byte_offset == byte_offset) { + loc->line = offset_table[left].line; + loc->column = offset_table[left].column; + } else { + loc->line = 0; + loc->column = 0; + } + } + + void TranslateBack(TransLocation *loc) { + int func_index = GetFunctionIndexFromFakeScriptId(loc->script_id); + const OffsetTable *reverse_table = GetReverseTable(func_index); + if (!reverse_table) return; + DCHECK(!reverse_table->empty()); + + // Binary search for the given line and column. + unsigned left = 0; // inclusive + unsigned right = static_cast<unsigned>(reverse_table->size()); // exclusive + while (right - left > 1) { + unsigned mid = (left + right) / 2; + auto &entry = (*reverse_table)[mid]; + if (entry.line < loc->line || + (entry.line == loc->line && entry.column <= loc->column)) { + left = mid; + } else { + right = mid; + } + } + + int found_byte_offset = 0; + // If we found an exact match, use it. Otherwise check whether the next + // bigger entry is still in the same line. Report that one then. + if ((*reverse_table)[left].line == loc->line && + (*reverse_table)[left].column == loc->column) { + found_byte_offset = (*reverse_table)[left].byte_offset; + } else if (left + 1 < reverse_table->size() && + (*reverse_table)[left + 1].line == loc->line) { + found_byte_offset = (*reverse_table)[left + 1].byte_offset; + } + + v8::Isolate *isolate = loc->translation->isolate_; + loc->script_id = String16::fromInteger(script_.Get(isolate)->Id()); + loc->line = func_index; + loc->column = found_byte_offset; + } + + private: + String16 GetFakeScriptUrl(v8::Isolate *isolate, int func_index) { + Local<debug::WasmScript> script = script_.Get(isolate); + String16 script_name = toProtocolString(script->Name().ToLocalChecked()); + int numFunctions = script->NumFunctions(); + int numImported = script->NumImportedFunctions(); + String16Builder builder; + builder.appendAll("wasm://wasm/", script_name, '/'); + if (numFunctions - numImported > 300) { + size_t digits = String16::fromInteger(numFunctions - 1).length(); + String16 thisCategory = String16::fromInteger((func_index / 100) * 100); + DCHECK_LE(thisCategory.length(), digits); + for (size_t i = thisCategory.length(); i < digits; ++i) + builder.append('0'); + builder.appendAll(thisCategory, '/'); + } + builder.appendAll(script_name, '-'); + builder.appendNumber(func_index); + return builder.toString(); + } + + String16 GetFakeScriptId(const String16 script_id, int func_index) { + return String16::concat(script_id, '-', String16::fromInteger(func_index)); + } + String16 GetFakeScriptId(const TransLocation *loc) { + return GetFakeScriptId(loc->script_id, loc->line); + } + + void AddFakeScript(v8::Isolate *isolate, const String16 &underlyingScriptId, + int func_idx, WasmTranslation *translation, + V8DebuggerAgentImpl *agent) { + String16 fake_script_id = GetFakeScriptId(underlyingScriptId, func_idx); + String16 fake_script_url = GetFakeScriptUrl(isolate, func_idx); + + v8::Local<debug::WasmScript> script = script_.Get(isolate); + // TODO(clemensh): Generate disassembly lazily when queried by the frontend. + debug::WasmDisassembly disassembly = script->DisassembleFunction(func_idx); + + DCHECK_EQ(0, offset_tables_.count(func_idx)); + offset_tables_.insert( + std::make_pair(func_idx, std::move(disassembly.offset_table))); + String16 source(disassembly.disassembly.data(), + disassembly.disassembly.length()); + std::unique_ptr<V8DebuggerScript> fake_script = + V8DebuggerScript::CreateWasm(isolate, script, fake_script_id, + std::move(fake_script_url), source); + + translation->AddFakeScript(fake_script->scriptId(), this); + agent->didParseSource(std::move(fake_script), true); + } + + int GetFunctionIndexFromFakeScriptId(const String16 &fake_script_id) { + size_t last_dash_pos = fake_script_id.reverseFind('-'); + DCHECK_GT(fake_script_id.length(), last_dash_pos); + bool ok = true; + int func_index = fake_script_id.substring(last_dash_pos + 1).toInteger(&ok); + DCHECK(ok); + return func_index; + } + + const OffsetTable &GetOffsetTable(const TransLocation *loc) { + int func_index = loc->line; + auto it = offset_tables_.find(func_index); + // TODO(clemensh): Once we load disassembly lazily, the offset table + // might not be there yet. Load it lazily then. + DCHECK(it != offset_tables_.end()); + return it->second; + } + + const OffsetTable *GetReverseTable(int func_index) { + auto it = reverse_tables_.find(func_index); + if (it != reverse_tables_.end()) return &it->second; + + // Find offset table, copy and sort it to get reverse table. + it = offset_tables_.find(func_index); + if (it == offset_tables_.end()) return nullptr; + + OffsetTable reverse_table = it->second; + // Order by line, column, then byte offset. + auto cmp = [](OffsetTable::value_type el1, OffsetTable::value_type el2) { + if (el1.line != el2.line) return el1.line < el2.line; + if (el1.column != el2.column) return el1.column < el2.column; + return el1.byte_offset < el2.byte_offset; + }; + std::sort(reverse_table.begin(), reverse_table.end(), cmp); + + auto inserted = reverse_tables_.insert( + std::make_pair(func_index, std::move(reverse_table))); + DCHECK(inserted.second); + return &inserted.first->second; + } + + Global<debug::WasmScript> script_; + + // We assume to only disassemble a subset of the functions, so store them in a + // map instead of an array. + std::unordered_map<int, const OffsetTable> offset_tables_; + std::unordered_map<int, const OffsetTable> reverse_tables_; +}; + +WasmTranslation::WasmTranslation(v8::Isolate *isolate) + : isolate_(isolate), mode_(Disassemble) {} + +WasmTranslation::~WasmTranslation() { Clear(); } + +void WasmTranslation::AddScript(Local<debug::WasmScript> script, + V8DebuggerAgentImpl *agent) { + int script_id = script->Id(); + DCHECK_EQ(0, wasm_translators_.count(script_id)); + std::unique_ptr<TranslatorImpl> impl; + switch (mode_) { + case Raw: + impl.reset(new TranslatorImpl::RawTranslator()); + break; + case Disassemble: + impl.reset(new TranslatorImpl::DisassemblingTranslator(isolate_, script, + this, agent)); + break; + } + DCHECK(impl); + wasm_translators_.insert(std::make_pair(script_id, std::move(impl))); +} + +void WasmTranslation::Clear() { + wasm_translators_.clear(); + fake_scripts_.clear(); +} + +// Translation "forward" (to artificial scripts). +bool WasmTranslation::TranslateWasmScriptLocationToProtocolLocation( + String16 *script_id, int *line_number, int *column_number) { + DCHECK(script_id && line_number && column_number); + bool ok = true; + int script_id_int = script_id->toInteger(&ok); + if (!ok) return false; + + auto it = wasm_translators_.find(script_id_int); + if (it == wasm_translators_.end()) return false; + TranslatorImpl *translator = it->second.get(); + + TranslatorImpl::TransLocation trans_loc(this, std::move(*script_id), + *line_number, *column_number); + translator->Translate(&trans_loc); + + *script_id = std::move(trans_loc.script_id); + *line_number = trans_loc.line; + *column_number = trans_loc.column; + + return true; +} + +// Translation "backward" (from artificial to real scripts). +bool WasmTranslation::TranslateProtocolLocationToWasmScriptLocation( + String16 *script_id, int *line_number, int *column_number) { + auto it = fake_scripts_.find(*script_id); + if (it == fake_scripts_.end()) return false; + TranslatorImpl *translator = it->second; + + TranslatorImpl::TransLocation trans_loc(this, std::move(*script_id), + *line_number, *column_number); + translator->TranslateBack(&trans_loc); + + *script_id = std::move(trans_loc.script_id); + *line_number = trans_loc.line; + *column_number = trans_loc.column; + + return true; +} + +void WasmTranslation::AddFakeScript(const String16 &scriptId, + TranslatorImpl *translator) { + DCHECK_EQ(0, fake_scripts_.count(scriptId)); + fake_scripts_.insert(std::make_pair(scriptId, translator)); +} diff --git a/deps/v8/src/inspector/wasm-translation.h b/deps/v8/src/inspector/wasm-translation.h new file mode 100644 index 0000000000..2162edee67 --- /dev/null +++ b/deps/v8/src/inspector/wasm-translation.h @@ -0,0 +1,75 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_INSPECTOR_WASMTRANSLATION_H_ +#define V8_INSPECTOR_WASMTRANSLATION_H_ + +#include <unordered_map> + +#include "include/v8.h" +#include "src/base/macros.h" +#include "src/debug/debug-interface.h" +#include "src/inspector/string-16.h" + +namespace v8_inspector { + +// Forward declarations. +class V8DebuggerAgentImpl; + +class WasmTranslation { + public: + enum Mode { Raw, Disassemble }; + + explicit WasmTranslation(v8::Isolate* isolate); + ~WasmTranslation(); + + // Set translation mode. + void SetMode(Mode mode) { mode_ = mode; } + + // Make a wasm script known to the translation. This will trigger a number of + // didParseScript calls to the given debugger agent. + // Only locations referencing a registered script will be translated by the + // Translate functions below. + void AddScript(v8::Local<v8::debug::WasmScript> script, + V8DebuggerAgentImpl* agent); + + // Clear all registered scripts. + void Clear(); + + // Translate a location as generated by V8 to a location that should be sent + // over protocol. + // Does nothing for locations referencing a script which was not registered + // before via AddScript. + // Line and column are 0-based. + // Returns true if the location was translated, false otherwise. + bool TranslateWasmScriptLocationToProtocolLocation(String16* script_id, + int* line_number, + int* column_number); + + // Translate back from protocol locations (potentially referencing artificial + // scripts for individual wasm functions) to locations that make sense to V8. + // Does nothing if the location was not generated by the translate method + // above. + // Returns true if the location was translated, false otherwise. + bool TranslateProtocolLocationToWasmScriptLocation(String16* script_id, + int* line_number, + int* column_number); + + private: + class TranslatorImpl; + friend class TranslatorImpl; + + void AddFakeScript(const String16& scriptId, TranslatorImpl* translator); + + v8::Isolate* isolate_; + std::unordered_map<int, std::unique_ptr<TranslatorImpl>> wasm_translators_; + std::unordered_map<String16, TranslatorImpl*> fake_scripts_; + Mode mode_; + + DISALLOW_COPY_AND_ASSIGN(WasmTranslation); +}; + +} // namespace v8_inspector + +#endif // V8_INSPECTOR_WASMTRANSLATION_H_ |