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.
Set timer for test function.
Script execution paused.
Script execution resumed.
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
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
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()
......
......@@ -35,13 +35,6 @@
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)
{
JavaScriptCallFrame* impl = V8JavaScriptCallFrame::toImpl(info.Holder());
......
......@@ -616,7 +616,7 @@ InjectedScript.prototype = {
*/
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 = {
},
/**
* @param {?function(string):*} evalFunction
* @param {?Object} object
* @param {?JavaScriptCallFrame} callFrame
* @param {string} expression
* @param {string} objectGroup
* @param {boolean} isEvalOnCallFrame
* @param {boolean} injectCommandLineAPI
* @param {boolean} returnByValue
* @param {boolean} generatePreview
* @param {!Array.<!Object>=} scopeChain
* @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) {
return { wasThrown: false,
result: this._wrapObject(wrappedResult.result, objectGroup, returnByValue, generatePreview),
......@@ -730,36 +728,36 @@ InjectedScript.prototype = {
},
/**
* @param {?function(string):*} evalFunction
* @param {?Object} object
* @param {?JavaScriptCallFrame} callFrame
* @param {string} objectGroup
* @param {string} expression
* @param {boolean} isEvalOnCallFrame
* @param {boolean} injectCommandLineAPI
* @param {!Array.<!Object>=} scopeChain
* @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.
// 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.
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);
try {
var prefix = "";
var suffix = "";
if (injectCommandLineAPI) {
InjectedScriptHost.setNonEnumProperty(inspectedWindow, "__commandLineAPI", new CommandLineAPI(this._commandLineAPIImpl, isEvalOnCallFrame ? object : null));
prefix = "with (__commandLineAPI || { __proto__: null }) {";
InjectedScriptHost.setNonEnumProperty(inspectedWindow, "__commandLineAPI", new CommandLineAPI(this._commandLineAPIImpl, callFrame));
prefix = "with (typeof __commandLineAPI !== 'undefined' ? __commandLineAPI : { __proto__: null }) {";
suffix = "}";
}
if (injectScopeChain) {
InjectedScriptHost.setNonEnumProperty(inspectedWindow, "__scopeChainForEval", scopeChain);
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)
suffix += " }";
else
......@@ -769,7 +767,7 @@ InjectedScript.prototype = {
if (prefix)
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)
this._lastResult = wrappedResult.result;
return wrappedResult;
......@@ -802,8 +800,8 @@ InjectedScript.prototype = {
},
/**
* @param {!Object} topCallFrame
* @param {!Array.<!Object>} asyncCallStacks
* @param {!JavaScriptCallFrame} topCallFrame
* @param {!Array.<!JavaScriptCallFrame>} asyncCallStacks
* @param {string} callFrameId
* @param {string} expression
* @param {string} objectGroup
......@@ -819,12 +817,12 @@ InjectedScript.prototype = {
if (!callFrame)
return "Could not find call frame with given id";
if (parsedCallFrameId["asyncOrdinal"])
return this._evaluateAndWrap(null, null, expression, objectGroup, false, injectCommandLineAPI, returnByValue, generatePreview, callFrame.scopeChain);
return this._evaluateAndWrap(callFrame.evaluateWithExceptionDetails, callFrame, expression, objectGroup, true, injectCommandLineAPI, returnByValue, generatePreview);
return this._evaluateAndWrap(null, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, callFrame.scopeChain);
return this._evaluateAndWrap(callFrame, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview);
},
/**
* @param {!Object} topCallFrame
* @param {!JavaScriptCallFrame} topCallFrame
* @param {string} callFrameId
* @return {*}
*/
......@@ -840,7 +838,7 @@ InjectedScript.prototype = {
},
/**
* @param {!Object} topCallFrame
* @param {!JavaScriptCallFrame} topCallFrame
* @param {string} callFrameId
* @return {*} a stepIn position array ready for protocol JSON or a string error
*/
......@@ -857,7 +855,7 @@ InjectedScript.prototype = {
/**
* Either callFrameId or functionObjectId must be specified.
* @param {!Object} topCallFrame
* @param {!JavaScriptCallFrame} topCallFrame
* @param {string|boolean} callFrameId or false
* @param {string|boolean} functionObjectId or false
* @param {number} scopeNumber
......@@ -889,9 +887,9 @@ InjectedScript.prototype = {
},
/**
* @param {!Object} topCallFrame
* @param {!JavaScriptCallFrame} topCallFrame
* @param {string} callFrameId
* @return {?Object}
* @return {?JavaScriptCallFrame}
*/
_callFrameForId: function(topCallFrame, callFrameId)
{
......@@ -900,10 +898,10 @@ InjectedScript.prototype = {
},
/**
* @param {!Object} topCallFrame
* @param {!JavaScriptCallFrame} topCallFrame
* @param {!Object} parsedCallFrameId
* @param {!Array.<!Object>} asyncCallStacks
* @return {?Object}
* @param {!Array.<!JavaScriptCallFrame>} asyncCallStacks
* @return {?JavaScriptCallFrame}
*/
_callFrameForParsedId: function(topCallFrame, parsedCallFrameId, asyncCallStacks)
{
......@@ -1448,7 +1446,7 @@ InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeOb
/**
* @constructor
* @param {!CommandLineAPIImpl} commandLineAPIImpl
* @param {?Object} callFrame
* @param {?JavaScriptCallFrame} callFrame
*/
function CommandLineAPI(commandLineAPIImpl, callFrame)
{
......@@ -1459,7 +1457,7 @@ function CommandLineAPI(commandLineAPIImpl, callFrame)
function inScopeVariables(member)
{
if (!callFrame)
return false;
return (member in inspectedWindow);
var scopeChain = callFrame.scopeChain;
for (var i = 0; i < scopeChain.length; ++i) {
......@@ -1493,7 +1491,7 @@ function CommandLineAPI(commandLineAPIImpl, callFrame)
for (var i = 0; i < CommandLineAPI.members_.length; ++i) {
var member = CommandLineAPI.members_[i];
if (member in inspectedWindow || inScopeVariables(member))
if (inScopeVariables(member))
continue;
this[member] = bind(commandLineAPIImpl[member], commandLineAPIImpl);
......@@ -1502,7 +1500,7 @@ function CommandLineAPI(commandLineAPIImpl, callFrame)
for (var i = 0; i < 5; ++i) {
var member = "$" + i;
if (member in inspectedWindow || inScopeVariables(member))
if (inScopeVariables(member))
continue;
this.__defineGetter__("$" + i, bind(commandLineAPIImpl._inspectedObject, commandLineAPIImpl, i));
......
......@@ -151,11 +151,15 @@ v8::Handle<v8::Value> JavaScriptCallFrame::returnValue() const
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::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::Handle<v8::Value> result = evalFunction->Call(callFrame, WTF_ARRAY_LENGTH(argv), argv);
......@@ -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, "exceptionDetails"), v8::Undefined(m_isolate));
}
return wrappedResult;
return ScriptValue(scriptState, wrappedResult);
}
v8::Handle<v8::Value> JavaScriptCallFrame::restart()
......
......@@ -68,7 +68,7 @@ public:
bool isAtReturn() 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();
ScriptValue setVariableValue(ScriptState*, int scopeNumber, const String& variableName, const ScriptValue& newValue);
......
......@@ -36,7 +36,7 @@
const unsigned short CLOSURE_SCOPE = 3;
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();
// Only declarative scope (local, with and catch) is accepted. Returns undefined.
......@@ -46,7 +46,7 @@
readonly attribute long sourceID;
readonly attribute long line;
readonly attribute long column;
[Custom=Getter] readonly attribute object scopeChain;
[Custom=Getter] readonly attribute object[] scopeChain;
[Custom] unsigned short scopeType(long scopeIndex);
[Custom=Getter] readonly attribute object thisObject;
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