Chromium Code Reviews| Index: Source/core/inspector/InjectedScriptSource.js |
| diff --git a/Source/core/inspector/InjectedScriptSource.js b/Source/core/inspector/InjectedScriptSource.js |
| index 022f48c7ef07551db8550e64ccb369deb775f787..3c7da7faf4d844777ee7dde6bb3754e8dd823b20 100644 |
| --- a/Source/core/inspector/InjectedScriptSource.js |
| +++ b/Source/core/inspector/InjectedScriptSource.js |
| @@ -78,20 +78,21 @@ function toStringDescription(obj) |
| * Please use this bind, not the one from Function.prototype |
| * @param {function(...)} func |
| * @param {Object} thisObject |
| - * @param {...number} var_args |
| + * @param {...} var_args |
| */ |
| function bind(func, thisObject, var_args) |
| { |
| var args = slice(arguments, 2); |
| /** |
| - * @param {...number} var_args |
| + * @param {...} var_args |
| */ |
| function bound(var_args) |
| { |
| return func.apply(thisObject, args.concat(slice(arguments))); |
| } |
| - bound.toString = function() { |
| + bound.toString = function() |
| + { |
| return "bound: " + func; |
| }; |
| return bound; |
| @@ -538,7 +539,8 @@ InjectedScript.prototype = { |
| * @return {*} resolved value |
| * @throws {string} error message |
| */ |
| - _resolveCallArgument: function(callArgumentJson) { |
| + _resolveCallArgument: function(callArgumentJson) |
| + { |
| var objectId = callArgumentJson.objectId; |
| if (objectId) { |
| var parsedArgId = this._parseObjectId(objectId); |
| @@ -564,13 +566,14 @@ InjectedScript.prototype = { |
| * @param {boolean} injectCommandLineAPI |
| * @param {boolean} returnByValue |
| * @param {boolean} generatePreview |
| + * @param {!Object=} contextExtension |
| * @return {*} |
| */ |
| - _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, isEvalOnCallFrame, injectCommandLineAPI, returnByValue, generatePreview) |
| + _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, isEvalOnCallFrame, injectCommandLineAPI, returnByValue, generatePreview, contextExtension) |
| { |
| try { |
| return { wasThrown: false, |
| - result: this._wrapObject(this._evaluateOn(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI), objectGroup, returnByValue, generatePreview) }; |
| + result: this._wrapObject(this._evaluateOn(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, contextExtension), objectGroup, returnByValue, generatePreview) }; |
| } catch (e) { |
| return this._createThrownValue(e, objectGroup); |
| } |
| @@ -597,9 +600,10 @@ InjectedScript.prototype = { |
| * @param {string} expression |
| * @param {boolean} isEvalOnCallFrame |
| * @param {boolean} injectCommandLineAPI |
| + * @param {!Object=} contextExtension |
| * @return {*} |
| */ |
| - _evaluateOn: function(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI) |
| + _evaluateOn: function(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, contextExtension) |
| { |
| // Only install command line api object for the time of evaluation. |
| // Surround the expression in with statements to inject our command line API so that |
| @@ -610,7 +614,7 @@ InjectedScript.prototype = { |
| inspectedWindow.console._commandLineAPI = new CommandLineAPI(this._commandLineAPIImpl, isEvalOnCallFrame ? object : null); |
| expression = "with ((console && console._commandLineAPI) || { __proto__: null }) {\n" + expression + "\n}"; |
| } |
| - var result = evalFunction.call(object, expression); |
| + var result = evalFunction.call(object, expression, contextExtension); |
| if (objectGroup === "console") |
| this._lastResult = result; |
| return result; |
| @@ -621,10 +625,11 @@ InjectedScript.prototype = { |
| }, |
| /** |
| - * @param {Object} callFrame |
| - * @return {!Array.<InjectedScript.CallFrameProxy>|boolean} |
| + * @param {?Object} callFrame |
| + * @param {number} asyncOrdinal |
| + * @return {!Array.<!InjectedScript.CallFrameProxy>|boolean} |
| */ |
| - wrapCallFrames: function(callFrame) |
| + wrapCallFrames: function(callFrame, asyncOrdinal) |
| { |
| if (!callFrame) |
| return false; |
| @@ -632,14 +637,15 @@ InjectedScript.prototype = { |
| var result = []; |
| var depth = 0; |
| do { |
| - result.push(new InjectedScript.CallFrameProxy(depth++, callFrame)); |
| + result.push(new InjectedScript.CallFrameProxy(depth++, callFrame, asyncOrdinal)); |
| callFrame = callFrame.caller; |
| } while (callFrame); |
| return result; |
| }, |
| /** |
| - * @param {Object} topCallFrame |
| + * @param {!Object} topCallFrame |
| + * @param {!Array.<!Object>} asyncCallStacks |
| * @param {string} callFrameId |
| * @param {string} expression |
| * @param {string} objectGroup |
| @@ -648,16 +654,19 @@ InjectedScript.prototype = { |
| * @param {boolean} generatePreview |
| * @return {*} |
| */ |
| - evaluateOnCallFrame: function(topCallFrame, callFrameId, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview) |
| + evaluateOnCallFrame: function(topCallFrame, asyncCallStacks, callFrameId, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview) |
| { |
| - var callFrame = this.callFrameForId(topCallFrame, callFrameId); |
| + var parsedCallFrameId = InjectedScriptHost.evaluate("(" + callFrameId + ")"); |
| + var callFrame = this._callFrameForParsedId(topCallFrame, parsedCallFrameId, asyncCallStacks); |
| if (!callFrame) |
| return "Could not find call frame with given id"; |
| + if (parsedCallFrameId["asyncOrdinal"]) |
| + return this._evaluateAndWrap(topCallFrame.evaluateGlobal, topCallFrame, expression, objectGroup, true, injectCommandLineAPI, returnByValue, generatePreview, InjectedScript.CallFrameProxy._toProtoChainedScope(callFrame)); |
|
yurys
2014/01/21 11:56:52
Why do we use topCallFrame as object argument but
aandrey
2014/01/21 13:30:22
We can evaluate only on the call frames of the cur
yurys
2014/01/21 13:54:43
Sound like we should have a version of evaluateGlo
|
| return this._evaluateAndWrap(callFrame.evaluate, callFrame, expression, objectGroup, true, injectCommandLineAPI, returnByValue, generatePreview); |
| }, |
| /** |
| - * @param {Object} topCallFrame |
| + * @param {!Object} topCallFrame |
| * @param {string} callFrameId |
| * @return {*} |
| */ |
| @@ -673,7 +682,7 @@ InjectedScript.prototype = { |
| }, |
| /** |
| - * @param {Object} topCallFrame |
| + * @param {!Object} topCallFrame |
| * @param {string} callFrameId |
| * @return {*} a stepIn position array ready for protocol JSON or a string error |
| */ |
| @@ -690,7 +699,7 @@ InjectedScript.prototype = { |
| /** |
| * Either callFrameId or functionObjectId must be specified. |
| - * @param {Object} topCallFrame |
| + * @param {!Object} topCallFrame |
| * @param {string|boolean} callFrameId or false |
| * @param {string|boolean} functionObjectId or false |
| * @param {number} scopeNumber |
| @@ -734,15 +743,29 @@ InjectedScript.prototype = { |
| }, |
| /** |
| - * @param {Object} topCallFrame |
| + * @param {!Object} topCallFrame |
| * @param {string} callFrameId |
| - * @return {Object} |
| + * @return {?Object} |
| */ |
| callFrameForId: function(topCallFrame, callFrameId) |
| { |
| var parsedCallFrameId = InjectedScriptHost.evaluate("(" + callFrameId + ")"); |
| - var ordinal = parsedCallFrameId["ordinal"]; |
| + return this._callFrameForParsedId(topCallFrame, parsedCallFrameId, []); |
| + }, |
| + |
| + /** |
| + * @param {!Object} topCallFrame |
| + * @param {!Object} parsedCallFrameId |
| + * @param {!Array.<!Object>} asyncCallStacks |
| + * @return {?Object} |
| + */ |
| + _callFrameForParsedId: function(topCallFrame, parsedCallFrameId, asyncCallStacks) |
| + { |
| + var asyncOrdinal = parsedCallFrameId["asyncOrdinal"] || 0; // 1-based index |
|
yurys
2014/01/21 11:56:52
You don't really need "|| 0" part.
aandrey
2014/01/21 13:30:22
Done.
|
| + if (asyncOrdinal) |
| + topCallFrame = asyncCallStacks[asyncOrdinal - 1]; |
| var callFrame = topCallFrame; |
| + var ordinal = parsedCallFrameId["ordinal"]; |
| while (--ordinal >= 0 && callFrame) |
| callFrame = callFrame.caller; |
| return callFrame; |
| @@ -1114,10 +1137,11 @@ InjectedScript.RemoteObject.prototype = { |
| * @constructor |
| * @param {number} ordinal |
| * @param {!Object} callFrame |
| + * @param {number} asyncOrdinal |
| */ |
| -InjectedScript.CallFrameProxy = function(ordinal, callFrame) |
| +InjectedScript.CallFrameProxy = function(ordinal, callFrame, asyncOrdinal) |
| { |
| - this.callFrameId = "{\"ordinal\":" + ordinal + ",\"injectedScriptId\":" + injectedScriptId + "}"; |
| + this.callFrameId = "{\"ordinal\":" + ordinal + ",\"injectedScriptId\":" + injectedScriptId + (asyncOrdinal ? ",\"asyncOrdinal\":" + asyncOrdinal : "") + "}"; |
| this.functionName = (callFrame.type === "function" ? callFrame.functionName : ""); |
| this.location = { scriptId: toString(callFrame.sourceID), lineNumber: callFrame.line, columnNumber: callFrame.column }; |
| this.scopeChain = this._wrapScopeChain(callFrame); |
| @@ -1135,7 +1159,7 @@ InjectedScript.CallFrameProxy.prototype = { |
| { |
| var scopeChain = callFrame.scopeChain; |
| var scopeChainProxy = []; |
| - for (var i = 0; i < scopeChain.length; i++) { |
| + for (var i = 0; i < scopeChain.length; ++i) { |
| var scope = InjectedScript.CallFrameProxy._createScopeJson(callFrame.scopeType(i), scopeChain[i], "backtrace"); |
| scopeChainProxy.push(scope); |
| } |
| @@ -1149,7 +1173,8 @@ InjectedScript.CallFrameProxy.prototype = { |
| * @param {string} groupId |
| * @return {!DebuggerAgent.Scope} |
| */ |
| -InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeObject, groupId) { |
| +InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeObject, groupId) |
| +{ |
| const GLOBAL_SCOPE = 0; |
| const LOCAL_SCOPE = 1; |
| const WITH_SCOPE = 2; |
| @@ -1171,6 +1196,43 @@ InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeOb |
| } |
| /** |
| + * @param {!Object} callFrame |
| + * @return {!Object} |
| + */ |
| +InjectedScript.CallFrameProxy._toProtoChainedScope = function(callFrame) |
| +{ |
| + /** |
| + * @this {Object} |
| + */ |
| + function getter(name) |
| + { |
| + return this[name]; |
| + } |
| + |
| + function addProperties(object) |
| + { |
| + for (var o = object; injectedScript._isDefined(o); o = o.__proto__) { |
| + var names = Object.getOwnPropertyNames(/** @type {!Object} */ (o)); |
| + for (var i = 0, n = names.length; i < n; ++i) { |
| + var name = names[i]; |
| + if (name in proxy || name === "__proto__") |
| + continue; |
| + Object.prototype.__defineGetter__.call(proxy, name, bind(getter, object, name)); |
|
yurys
2014/01/21 11:56:52
Why not simply copy the value: proxy[name] = o[nam
aandrey
2014/01/21 13:30:22
To avoid side effects.
For example, accessing wind
yurys
2014/01/21 13:54:43
I'm concerned about the performance here. We may e
|
| + } |
| + } |
| + return proxy; |
| + } |
| + |
| + var proxy = { __proto__: null }; |
| + |
| + var scopeChain = callFrame.scopeChain; |
| + for (var i = 0; i < scopeChain.length; ++i) |
| + addProperties(scopeChain[i]); |
| + |
| + return proxy; |
| +} |
| + |
| +/** |
| * @constructor |
| * @param {CommandLineAPIImpl} commandLineAPIImpl |
| * @param {Object} callFrame |
| @@ -1448,7 +1510,8 @@ CommandLineAPIImpl.prototype = { |
| InjectedScriptHost.monitorFunction(fn); |
| }, |
| - unmonitor: function(fn) { |
| + unmonitor: function(fn) |
| + { |
| InjectedScriptHost.unmonitorFunction(fn); |
| }, |