Commit c93de20d authored by aandrey@chromium.org's avatar aandrey@chromium.org

DevTools: Fix __commandLineAPI is not defined error and remove the with- hack...

DevTools: Fix __commandLineAPI is not defined error and remove the with- hack for eval on call frame.

BUG=415578, 110163
R=yurys, pfeldman

Review URL: https://codereview.chromium.org/644403003

git-svn-id: svn://svn.chromium.org/blink/trunk@184283 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 203ebb30
CONSOLE ERROR: line 2: 42 CONSOLE ERROR: line 1: 42
Tests that console.error does not throw exception when executed in console on call frame. Tests that console.error does not throw exception when executed in console on call frame.
Set timer for test function. Set timer for test function.
Script execution paused. Script execution paused.
Script execution resumed. Script execution resumed.
console.error(42) console.error(42)
(program):2:9 42(program):2:9 (anonymous function)(program):450:28 evaluate InjectedScript._evaluateOn InjectedScript._evaluateAndWrap InjectedScript.evaluateOnCallFrameconsole-error-on-call-frame.html:10 testFunction (program):1:9 42(program):1:9 (anonymous function)(program):450:28 evaluate InjectedScript._evaluateOn InjectedScript._evaluateAndWrap InjectedScript.evaluateOnCallFrameconsole-error-on-call-frame.html:10 testFunction
undefined undefined
Test that evaluation on call frame works across all inspected windows in the call stack.
Set timer for test function.
Call stack:
0) pauseInsideIframe (:6)
1) testFunction (debugger-eval-on-call-frame-inside-iframe.html:34)
=== Evaluating on iframe ===
dir() = "overridden dir() in iframe"
dirxml() = undefined
table = "local in iframe"
clear = function clear() { [Command Line API] }
x: = (program):1:2 Uncaught SyntaxError {stack: (...), message: "Unexpected end of input"}
=== Evaluating on top frame ===
dir() = undefined
dirxml() = "overridden dirxml() in top frame"
table = function table(data, [columns]) { [Command Line API] }
clear = "local in top frame"
x: = (program):1:2 Uncaught SyntaxError {stack: (...), message: "Unexpected end of input"}
<html>
<head>
<script src="../../../http/tests/inspector/inspector-test.js"></script>
<script src="../../../http/tests/inspector/console-test.js"></script>
<script src="../../../http/tests/inspector/debugger-test.js"></script>
<script>
function dirxml() { return "overridden dirxml() in top frame"; }
function onload()
{
var iframe = document.getElementById("iframe");
var doc = iframe.contentWindow.document;
var html = "<html><head><script>\n" +
"function dir() { return 'overridden dir() in iframe'; }\n" +
"function pauseInsideIframe()\n" +
"{\n" +
" var table = 'local in iframe';\n" +
" debugger;\n" +
"}\n" +
"</" + "script></" + "head><" + "body></" + "body></" + "html>";
doc.open();
doc.write(html);
doc.close();
runTest();
}
function testFunction()
{
var clear = "local in top frame";
var iframe = document.getElementById("iframe");
iframe.contentWindow.pauseInsideIframe.call({foo: 42});
}
var test = function()
{
var expressions = [
"dir()",
"dirxml()",
"table",
"clear",
"x:", // print correct syntax error: crbug.com/110163
];
function evaluateInConsoleAndDump(callback)
{
var copy = expressions.slice();
inner();
function inner()
{
var expression = copy.shift();
if (expression)
InspectorTest.evaluateInConsoleAndDump(expression, inner);
else
callback();
}
}
InspectorTest.startDebuggerTest(step1, true);
function step1()
{
InspectorTest.runTestFunctionAndWaitUntilPaused(step2);
}
function step2(callFrames)
{
InspectorTest.captureStackTrace(callFrames);
InspectorTest.addResult("\n=== Evaluating on iframe ===");
evaluateInConsoleAndDump(step3);
}
function step3()
{
var pane = WebInspector.panels.sources.sidebarPanes.callstack;
pane._placardSelected(pane.placards[1]);
InspectorTest.runAfterPendingDispatches(step4);
}
function step4()
{
InspectorTest.addResult("\n=== Evaluating on top frame ===");
evaluateInConsoleAndDump(step5);
}
function step5()
{
InspectorTest.completeDebuggerTest();
}
}
</script>
</head>
<body onload="onload()">
<iframe id="iframe"></iframe>
<p>
Test that evaluation on call frame works across all inspected windows in the call stack.
</p>
</body>
</html>
...@@ -445,9 +445,9 @@ DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror, callerFrame, sc ...@@ -445,9 +445,9 @@ DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror, callerFrame, sc
return displayName || func.name() || func.inferredName(); return displayName || func.name() || func.inferredName();
} }
function evaluate(expression) function evaluate(expression, scopeExtension)
{ {
return frameMirror.evaluate(expression, false).value(); return frameMirror.evaluate(expression, false, scopeExtension).value();
} }
function restart() function restart()
......
...@@ -35,13 +35,6 @@ ...@@ -35,13 +35,6 @@
namespace blink { namespace blink {
void V8JavaScriptCallFrame::evaluateWithExceptionDetailsMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{
JavaScriptCallFrame* impl = V8JavaScriptCallFrame::toImpl(info.Holder());
String expression = toCoreStringWithUndefinedOrNullCheck(info[0]);
v8SetReturnValue(info, impl->evaluateWithExceptionDetails(expression));
}
void V8JavaScriptCallFrame::restartMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info) void V8JavaScriptCallFrame::restartMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
{ {
JavaScriptCallFrame* impl = V8JavaScriptCallFrame::toImpl(info.Holder()); JavaScriptCallFrame* impl = V8JavaScriptCallFrame::toImpl(info.Holder());
......
...@@ -616,7 +616,7 @@ InjectedScript.prototype = { ...@@ -616,7 +616,7 @@ InjectedScript.prototype = {
*/ */
evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview) evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview)
{ {
return this._evaluateAndWrap(null, null, expression, objectGroup, false, injectCommandLineAPI, returnByValue, generatePreview); return this._evaluateAndWrap(null, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview);
}, },
/** /**
...@@ -689,20 +689,18 @@ InjectedScript.prototype = { ...@@ -689,20 +689,18 @@ InjectedScript.prototype = {
}, },
/** /**
* @param {?function(string):*} evalFunction * @param {?JavaScriptCallFrame} callFrame
* @param {?Object} object
* @param {string} expression * @param {string} expression
* @param {string} objectGroup * @param {string} objectGroup
* @param {boolean} isEvalOnCallFrame
* @param {boolean} injectCommandLineAPI * @param {boolean} injectCommandLineAPI
* @param {boolean} returnByValue * @param {boolean} returnByValue
* @param {boolean} generatePreview * @param {boolean} generatePreview
* @param {!Array.<!Object>=} scopeChain * @param {!Array.<!Object>=} scopeChain
* @return {!Object} * @return {!Object}
*/ */
_evaluateAndWrap: function(evalFunction, object, expression, objectGroup, isEvalOnCallFrame, injectCommandLineAPI, returnByValue, generatePreview, scopeChain) _evaluateAndWrap: function(callFrame, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, scopeChain)
{ {
var wrappedResult = this._evaluateOn(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, scopeChain); var wrappedResult = this._evaluateOn(callFrame, objectGroup, expression, injectCommandLineAPI, scopeChain);
if (!wrappedResult.exceptionDetails) { if (!wrappedResult.exceptionDetails) {
return { wasThrown: false, return { wasThrown: false,
result: this._wrapObject(wrappedResult.result, objectGroup, returnByValue, generatePreview), result: this._wrapObject(wrappedResult.result, objectGroup, returnByValue, generatePreview),
...@@ -730,36 +728,36 @@ InjectedScript.prototype = { ...@@ -730,36 +728,36 @@ InjectedScript.prototype = {
}, },
/** /**
* @param {?function(string):*} evalFunction * @param {?JavaScriptCallFrame} callFrame
* @param {?Object} object
* @param {string} objectGroup * @param {string} objectGroup
* @param {string} expression * @param {string} expression
* @param {boolean} isEvalOnCallFrame
* @param {boolean} injectCommandLineAPI * @param {boolean} injectCommandLineAPI
* @param {!Array.<!Object>=} scopeChain * @param {!Array.<!Object>=} scopeChain
* @return {*} * @return {*}
*/ */
_evaluateOn: function(evalFunction, object, objectGroup, expression, isEvalOnCallFrame, injectCommandLineAPI, scopeChain) _evaluateOn: function(callFrame, objectGroup, expression, injectCommandLineAPI, scopeChain)
{ {
// Only install command line api object for the time of evaluation. // 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 // Surround the expression in with statements to inject our command line API so that
// the window object properties still take more precedent than our API functions. // the window object properties still take more precedent than our API functions.
injectCommandLineAPI = injectCommandLineAPI && !("__commandLineAPI" in inspectedWindow); var scopeExtensionForEval = (callFrame && injectCommandLineAPI) ? new CommandLineAPI(this._commandLineAPIImpl, callFrame) : undefined;
injectCommandLineAPI = !scopeExtensionForEval && !callFrame && injectCommandLineAPI && !("__commandLineAPI" in inspectedWindow);
var injectScopeChain = scopeChain && scopeChain.length && !("__scopeChainForEval" in inspectedWindow); var injectScopeChain = scopeChain && scopeChain.length && !("__scopeChainForEval" in inspectedWindow);
try { try {
var prefix = ""; var prefix = "";
var suffix = ""; var suffix = "";
if (injectCommandLineAPI) { if (injectCommandLineAPI) {
InjectedScriptHost.setNonEnumProperty(inspectedWindow, "__commandLineAPI", new CommandLineAPI(this._commandLineAPIImpl, isEvalOnCallFrame ? object : null)); InjectedScriptHost.setNonEnumProperty(inspectedWindow, "__commandLineAPI", new CommandLineAPI(this._commandLineAPIImpl, callFrame));
prefix = "with (__commandLineAPI || { __proto__: null }) {"; prefix = "with (typeof __commandLineAPI !== 'undefined' ? __commandLineAPI : { __proto__: null }) {";
suffix = "}"; suffix = "}";
} }
if (injectScopeChain) { if (injectScopeChain) {
InjectedScriptHost.setNonEnumProperty(inspectedWindow, "__scopeChainForEval", scopeChain); InjectedScriptHost.setNonEnumProperty(inspectedWindow, "__scopeChainForEval", scopeChain);
for (var i = 0; i < scopeChain.length; ++i) { for (var i = 0; i < scopeChain.length; ++i) {
prefix = "with (__scopeChainForEval[" + i + "] || { __proto__: null }) {" + (suffix ? " " : "") + prefix; prefix = "with (typeof __scopeChainForEval !== 'undefined' ? __scopeChainForEval[" + i + "] : { __proto__: null }) {" + (suffix ? " " : "") + prefix;
if (suffix) if (suffix)
suffix += " }"; suffix += " }";
else else
...@@ -769,7 +767,7 @@ InjectedScript.prototype = { ...@@ -769,7 +767,7 @@ InjectedScript.prototype = {
if (prefix) if (prefix)
expression = prefix + "\n" + expression + "\n" + suffix; expression = prefix + "\n" + expression + "\n" + suffix;
var wrappedResult = evalFunction ? InjectedScriptHost.callFunction(evalFunction, object, [expression]) : InjectedScriptHost.evaluateWithExceptionDetails(expression); var wrappedResult = callFrame ? callFrame.evaluateWithExceptionDetails(expression, scopeExtensionForEval) : InjectedScriptHost.evaluateWithExceptionDetails(expression);
if (objectGroup === "console" && !wrappedResult.exceptionDetails) if (objectGroup === "console" && !wrappedResult.exceptionDetails)
this._lastResult = wrappedResult.result; this._lastResult = wrappedResult.result;
return wrappedResult; return wrappedResult;
...@@ -802,8 +800,8 @@ InjectedScript.prototype = { ...@@ -802,8 +800,8 @@ InjectedScript.prototype = {
}, },
/** /**
* @param {!Object} topCallFrame * @param {!JavaScriptCallFrame} topCallFrame
* @param {!Array.<!Object>} asyncCallStacks * @param {!Array.<!JavaScriptCallFrame>} asyncCallStacks
* @param {string} callFrameId * @param {string} callFrameId
* @param {string} expression * @param {string} expression
* @param {string} objectGroup * @param {string} objectGroup
...@@ -819,12 +817,12 @@ InjectedScript.prototype = { ...@@ -819,12 +817,12 @@ InjectedScript.prototype = {
if (!callFrame) if (!callFrame)
return "Could not find call frame with given id"; return "Could not find call frame with given id";
if (parsedCallFrameId["asyncOrdinal"]) if (parsedCallFrameId["asyncOrdinal"])
return this._evaluateAndWrap(null, null, expression, objectGroup, false, injectCommandLineAPI, returnByValue, generatePreview, callFrame.scopeChain); return this._evaluateAndWrap(null, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, callFrame.scopeChain);
return this._evaluateAndWrap(callFrame.evaluateWithExceptionDetails, callFrame, expression, objectGroup, true, injectCommandLineAPI, returnByValue, generatePreview); return this._evaluateAndWrap(callFrame, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview);
}, },
/** /**
* @param {!Object} topCallFrame * @param {!JavaScriptCallFrame} topCallFrame
* @param {string} callFrameId * @param {string} callFrameId
* @return {*} * @return {*}
*/ */
...@@ -840,7 +838,7 @@ InjectedScript.prototype = { ...@@ -840,7 +838,7 @@ InjectedScript.prototype = {
}, },
/** /**
* @param {!Object} topCallFrame * @param {!JavaScriptCallFrame} topCallFrame
* @param {string} callFrameId * @param {string} callFrameId
* @return {*} a stepIn position array ready for protocol JSON or a string error * @return {*} a stepIn position array ready for protocol JSON or a string error
*/ */
...@@ -857,7 +855,7 @@ InjectedScript.prototype = { ...@@ -857,7 +855,7 @@ InjectedScript.prototype = {
/** /**
* Either callFrameId or functionObjectId must be specified. * Either callFrameId or functionObjectId must be specified.
* @param {!Object} topCallFrame * @param {!JavaScriptCallFrame} topCallFrame
* @param {string|boolean} callFrameId or false * @param {string|boolean} callFrameId or false
* @param {string|boolean} functionObjectId or false * @param {string|boolean} functionObjectId or false
* @param {number} scopeNumber * @param {number} scopeNumber
...@@ -889,9 +887,9 @@ InjectedScript.prototype = { ...@@ -889,9 +887,9 @@ InjectedScript.prototype = {
}, },
/** /**
* @param {!Object} topCallFrame * @param {!JavaScriptCallFrame} topCallFrame
* @param {string} callFrameId * @param {string} callFrameId
* @return {?Object} * @return {?JavaScriptCallFrame}
*/ */
_callFrameForId: function(topCallFrame, callFrameId) _callFrameForId: function(topCallFrame, callFrameId)
{ {
...@@ -900,10 +898,10 @@ InjectedScript.prototype = { ...@@ -900,10 +898,10 @@ InjectedScript.prototype = {
}, },
/** /**
* @param {!Object} topCallFrame * @param {!JavaScriptCallFrame} topCallFrame
* @param {!Object} parsedCallFrameId * @param {!Object} parsedCallFrameId
* @param {!Array.<!Object>} asyncCallStacks * @param {!Array.<!JavaScriptCallFrame>} asyncCallStacks
* @return {?Object} * @return {?JavaScriptCallFrame}
*/ */
_callFrameForParsedId: function(topCallFrame, parsedCallFrameId, asyncCallStacks) _callFrameForParsedId: function(topCallFrame, parsedCallFrameId, asyncCallStacks)
{ {
...@@ -1448,7 +1446,7 @@ InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeOb ...@@ -1448,7 +1446,7 @@ InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeOb
/** /**
* @constructor * @constructor
* @param {!CommandLineAPIImpl} commandLineAPIImpl * @param {!CommandLineAPIImpl} commandLineAPIImpl
* @param {?Object} callFrame * @param {?JavaScriptCallFrame} callFrame
*/ */
function CommandLineAPI(commandLineAPIImpl, callFrame) function CommandLineAPI(commandLineAPIImpl, callFrame)
{ {
...@@ -1459,7 +1457,7 @@ function CommandLineAPI(commandLineAPIImpl, callFrame) ...@@ -1459,7 +1457,7 @@ function CommandLineAPI(commandLineAPIImpl, callFrame)
function inScopeVariables(member) function inScopeVariables(member)
{ {
if (!callFrame) if (!callFrame)
return false; return (member in inspectedWindow);
var scopeChain = callFrame.scopeChain; var scopeChain = callFrame.scopeChain;
for (var i = 0; i < scopeChain.length; ++i) { for (var i = 0; i < scopeChain.length; ++i) {
...@@ -1493,7 +1491,7 @@ function CommandLineAPI(commandLineAPIImpl, callFrame) ...@@ -1493,7 +1491,7 @@ function CommandLineAPI(commandLineAPIImpl, callFrame)
for (var i = 0; i < CommandLineAPI.members_.length; ++i) { for (var i = 0; i < CommandLineAPI.members_.length; ++i) {
var member = CommandLineAPI.members_[i]; var member = CommandLineAPI.members_[i];
if (member in inspectedWindow || inScopeVariables(member)) if (inScopeVariables(member))
continue; continue;
this[member] = bind(commandLineAPIImpl[member], commandLineAPIImpl); this[member] = bind(commandLineAPIImpl[member], commandLineAPIImpl);
...@@ -1502,7 +1500,7 @@ function CommandLineAPI(commandLineAPIImpl, callFrame) ...@@ -1502,7 +1500,7 @@ function CommandLineAPI(commandLineAPIImpl, callFrame)
for (var i = 0; i < 5; ++i) { for (var i = 0; i < 5; ++i) {
var member = "$" + i; var member = "$" + i;
if (member in inspectedWindow || inScopeVariables(member)) if (inScopeVariables(member))
continue; continue;
this.__defineGetter__("$" + i, bind(commandLineAPIImpl._inspectedObject, commandLineAPIImpl, i)); this.__defineGetter__("$" + i, bind(commandLineAPIImpl._inspectedObject, commandLineAPIImpl, i));
......
...@@ -151,11 +151,15 @@ v8::Handle<v8::Value> JavaScriptCallFrame::returnValue() const ...@@ -151,11 +151,15 @@ v8::Handle<v8::Value> JavaScriptCallFrame::returnValue() const
return m_callFrame.newLocal(m_isolate)->Get(v8AtomicString(m_isolate, "returnValue")); return m_callFrame.newLocal(m_isolate)->Get(v8AtomicString(m_isolate, "returnValue"));
} }
v8::Handle<v8::Value> JavaScriptCallFrame::evaluateWithExceptionDetails(const String& expression) ScriptValue JavaScriptCallFrame::evaluateWithExceptionDetails(ScriptState* scriptState, const String& expression, const ScriptValue& scopeExtension)
{ {
ScriptState::Scope scriptScope(scriptState);
v8::Handle<v8::Object> callFrame = m_callFrame.newLocal(m_isolate); v8::Handle<v8::Object> callFrame = m_callFrame.newLocal(m_isolate);
v8::Handle<v8::Function> evalFunction = v8::Handle<v8::Function>::Cast(callFrame->Get(v8AtomicString(m_isolate, "evaluate"))); v8::Handle<v8::Function> evalFunction = v8::Handle<v8::Function>::Cast(callFrame->Get(v8AtomicString(m_isolate, "evaluate")));
v8::Handle<v8::Value> argv[] = { v8String(m_debuggerContext.newLocal(m_isolate)->GetIsolate(), expression) }; v8::Handle<v8::Value> argv[] = {
v8String(m_debuggerContext.newLocal(m_isolate)->GetIsolate(), expression),
scopeExtension.isEmpty() ? v8::Handle<v8::Value>::Cast(v8::Undefined(m_isolate)) : scopeExtension.v8Value()
};
v8::TryCatch tryCatch; v8::TryCatch tryCatch;
v8::Handle<v8::Value> result = evalFunction->Call(callFrame, WTF_ARRAY_LENGTH(argv), argv); v8::Handle<v8::Value> result = evalFunction->Call(callFrame, WTF_ARRAY_LENGTH(argv), argv);
...@@ -167,7 +171,7 @@ v8::Handle<v8::Value> JavaScriptCallFrame::evaluateWithExceptionDetails(const St ...@@ -167,7 +171,7 @@ v8::Handle<v8::Value> JavaScriptCallFrame::evaluateWithExceptionDetails(const St
wrappedResult->Set(v8::String::NewFromUtf8(m_isolate, "result"), result); wrappedResult->Set(v8::String::NewFromUtf8(m_isolate, "result"), result);
wrappedResult->Set(v8::String::NewFromUtf8(m_isolate, "exceptionDetails"), v8::Undefined(m_isolate)); wrappedResult->Set(v8::String::NewFromUtf8(m_isolate, "exceptionDetails"), v8::Undefined(m_isolate));
} }
return wrappedResult; return ScriptValue(scriptState, wrappedResult);
} }
v8::Handle<v8::Value> JavaScriptCallFrame::restart() v8::Handle<v8::Value> JavaScriptCallFrame::restart()
......
...@@ -68,7 +68,7 @@ public: ...@@ -68,7 +68,7 @@ public:
bool isAtReturn() const; bool isAtReturn() const;
v8::Handle<v8::Value> returnValue() const; v8::Handle<v8::Value> returnValue() const;
v8::Handle<v8::Value> evaluateWithExceptionDetails(const String& expression); ScriptValue evaluateWithExceptionDetails(ScriptState*, const String& expression, const ScriptValue& scopeExtension);
v8::Handle<v8::Value> restart(); v8::Handle<v8::Value> restart();
ScriptValue setVariableValue(ScriptState*, int scopeNumber, const String& variableName, const ScriptValue& newValue); ScriptValue setVariableValue(ScriptState*, int scopeNumber, const String& variableName, const ScriptValue& newValue);
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
const unsigned short CLOSURE_SCOPE = 3; const unsigned short CLOSURE_SCOPE = 3;
const unsigned short CATCH_SCOPE = 4; const unsigned short CATCH_SCOPE = 4;
[Custom] void evaluateWithExceptionDetails(DOMString script); [CallWith=ScriptState] any evaluateWithExceptionDetails(DOMString script, [Default=Undefined] optional object scopeExtension);
[Custom] any restart(); [Custom] any restart();
// Only declarative scope (local, with and catch) is accepted. Returns undefined. // Only declarative scope (local, with and catch) is accepted. Returns undefined.
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
readonly attribute long sourceID; readonly attribute long sourceID;
readonly attribute long line; readonly attribute long line;
readonly attribute long column; readonly attribute long column;
[Custom=Getter] readonly attribute object scopeChain; [Custom=Getter] readonly attribute object[] scopeChain;
[Custom] unsigned short scopeType(long scopeIndex); [Custom] unsigned short scopeType(long scopeIndex);
[Custom=Getter] readonly attribute object thisObject; [Custom=Getter] readonly attribute object thisObject;
readonly attribute DOMString stepInPositions; readonly attribute DOMString stepInPositions;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment