Diff
Modified: trunk/LayoutTests/ChangeLog (142113 => 142114)
--- trunk/LayoutTests/ChangeLog 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/LayoutTests/ChangeLog 2013-02-07 15:00:13 UTC (rev 142114)
@@ -1,3 +1,15 @@
+2013-02-07 Peter Rybin <[email protected]>
+
+ Web Inspector: support _javascript_ variable mutation in protocol and V8 bindings
+ https://bugs.webkit.org/show_bug.cgi?id=107829
+
+ Reviewed by Pavel Feldman.
+
+ * inspector-protocol/debugger-setVariableValue-expected.txt: Added.
+ * inspector-protocol/debugger-setVariableValue.html: Added.
+ * inspector/console/command-line-api-expected.txt:
+ * platform/chromium/inspector-protocol/debugger-setVariableValue-expected.txt: Added.
+
2013-02-07 Yury Semikhatsky <[email protected]>
Web Inspector: reduce number of native memory instrumentation categories
Modified: trunk/LayoutTests/inspector/console/command-line-api-expected.txt (142113 => 142114)
--- trunk/LayoutTests/inspector/console/command-line-api-expected.txt 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/LayoutTests/inspector/console/command-line-api-expected.txt 2013-02-07 15:00:13 UTC (rev 142114)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 1060: The console function $() has changed from $=getElementById(id) to $=querySelector(selector). You might try $("#%s")
+CONSOLE MESSAGE: line 1121: The console function $() has changed from $=getElementById(id) to $=querySelector(selector). You might try $("#%s")
Tests that command line api works.
Added: trunk/LayoutTests/inspector-protocol/debugger-setVariableValue-expected.txt (0 => 142114)
--- trunk/LayoutTests/inspector-protocol/debugger-setVariableValue-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector-protocol/debugger-setVariableValue-expected.txt 2013-02-07 15:00:13 UTC (rev 142114)
@@ -0,0 +1,4 @@
+Closure returns: {"type":"string","value":"ttttrue52013"}
+ (expected: 'ttttrue52013')
+Protocol command 'Debugger.setVariableValue' failed
+
Added: trunk/LayoutTests/inspector-protocol/debugger-setVariableValue.html (0 => 142114)
--- trunk/LayoutTests/inspector-protocol/debugger-setVariableValue.html (rev 0)
+++ trunk/LayoutTests/inspector-protocol/debugger-setVariableValue.html 2013-02-07 15:00:13 UTC (rev 142114)
@@ -0,0 +1,181 @@
+<html>
+<head>
+<script type="text/_javascript_" src=""
+<script>
+
+function test()
+{
+ // A general-purpose engine for sending a sequence of protocol commands.
+ // The clients provide requests and response handlers, while the engine catches
+ // errors and makes sure that once there's nothing to do completeTest() is called.
+ // @param step is an object with command, params and callback fields
+ function runRequestSeries(step) {
+ processStep(step);
+
+ function processStep(s) {
+ try {
+ processStepOrFail(s);
+ } catch (e) {
+ InspectorTest.log(e.stack);
+ InspectorTest.completeTest();
+ }
+ }
+
+ function processStepOrFail(s) {
+ if (!s) {
+ InspectorTest.completeTest();
+ return;
+ }
+ if (!s.command) {
+ // A simple loopback step.
+ var next = s.callback();
+ processStep(next);
+ return;
+ }
+
+ var innerCallback = function(response) {
+ var next;
+ if ("error" in response) {
+ if (!("errorHandler" in s)) {
+ // Error message is not logged intentionally, it may be platform-specific.
+ InspectorTest.log("Protocol command '" + s.command + "' failed");
+ InspectorTest.completeTest();
+ return;
+ }
+ try {
+ next = s.errorHandler(response.error);
+ } catch (e) {
+ InspectorTest.log(e.stack);
+ InspectorTest.completeTest();
+ return;
+ }
+ } else {
+ try {
+ next = s.callback(response.result);
+ } catch (e) {
+ InspectorTest.log(e.stack);
+ InspectorTest.completeTest();
+ return;
+ }
+ }
+ processStep(next);
+ }
+ InspectorTest.sendCommand(s.command, s.params, innerCallback);
+ }
+ }
+
+ var firstStep = { callback: enableDebugger };
+
+ runRequestSeries(firstStep);
+
+ function enableDebugger() {
+ return { command: "Debugger.enable", params: {}, callback: evalFunction };
+ }
+
+ // Testing function/closure scopes.
+
+ function evalFunction(response) {
+ var _expression_ = "(function(p){var r=5;with({year:2013}){return function Closure(q){return p+q+r+year};}})('ttt')";
+ return { command: "Runtime.evaluate", params: {_expression_: _expression_}, callback: callbackEvalFunction };
+ }
+
+ function callbackEvalFunction(result) {
+ var id = result.result.objectId;
+ if (id === undefined)
+ throw new Error("objectId is expected");
+ return createCheckFunctionStepChain(id);
+ }
+
+ function createCheckFunctionStepChain(functionObjectId) {
+ var params = {
+ objectId: functionObjectId,
+ functionDeclaration: "function(){return this(true);}"
+ };
+ return {
+ command: "Runtime.callFunctionOn", params: params, callback: callbackLogClosureEval
+ };
+
+ function callbackLogClosureEval(result) {
+ InspectorTest.log("Closure returns: " + JSON.stringify(result.result));
+ InspectorTest.log(" (expected: 'ttttrue52013')");
+
+ var params = {
+ functionObjectId: functionObjectId,
+ scopeNumber: 1,
+ variableName: "r",
+ newValue: { value: 4 }
+ };
+ return {
+ command: "Debugger.setVariableValue", params: params, callback: setVariableCallback
+ };
+ }
+
+ function setVariableCallback() {
+ InspectorTest.log("Debugger.setVariableValue OK");
+
+ var params = {
+ objectId: functionObjectId,
+ functionDeclaration: "function(){return this(true);}"
+ };
+ return {
+ command: "Runtime.callFunctionOn", params: params, callback: callbackLogClosureEval2
+ };
+
+ }
+
+ function callbackLogClosureEval2(result) {
+ InspectorTest.log("Closure returns: " + JSON.stringify(result.result));
+ InspectorTest.log(" (expected: 'ttttrue42013')");
+
+ var params = {
+ // No target is specified
+ scopeNumber: 1,
+ variableName: "r",
+ newValue: { value: 4 }
+ };
+ return {
+ command: "Debugger.setVariableValue", params: params, errorHandler: setVariableErrorCallback3
+ };
+ }
+
+ function setVariableErrorCallback3(error) {
+ InspectorTest.log("Expected error: " + JSON.stringify(error));
+
+ var params = {
+ functionObjectId: functionObjectId,
+ scopeNumber: 100, // Wrong scope number
+ variableName: "r",
+ newValue: { value: 4 }
+ };
+ return {
+ command: "Debugger.setVariableValue", params: params, errorHandler: setVariableErrorCallback4
+ };
+ }
+
+ function setVariableErrorCallback4(error) {
+ InspectorTest.log("Expected error");
+
+ var params = {
+ functionObjectId: functionObjectId,
+ scopeNumber: 1,
+ variableName: "bad", // Wrong variable name
+ newValue: { value: 4 }
+ };
+ return {
+ command: "Debugger.setVariableValue", params: params, errorHandler: setVariableErrorCallback5
+ };
+ }
+
+ function setVariableErrorCallback5(error) {
+ InspectorTest.log("Expected error");
+
+ // End of test.
+ return;
+ }
+ }
+}
+</script>
+</head>
+<body _onLoad_="runTest();">
+</body>
+</html>
Added: trunk/LayoutTests/platform/chromium/inspector-protocol/debugger-setVariableValue-expected.txt (0 => 142114)
--- trunk/LayoutTests/platform/chromium/inspector-protocol/debugger-setVariableValue-expected.txt (rev 0)
+++ trunk/LayoutTests/platform/chromium/inspector-protocol/debugger-setVariableValue-expected.txt 2013-02-07 15:00:13 UTC (rev 142114)
@@ -0,0 +1,9 @@
+Closure returns: {"type":"string","value":"ttttrue52013"}
+ (expected: 'ttttrue52013')
+Debugger.setVariableValue OK
+Closure returns: {"type":"string","value":"ttttrue42013"}
+ (expected: 'ttttrue42013')
+Expected error: {"code":-32000,"message":"Either call frame or function object must be specified"}
+Expected error
+Expected error
+
Modified: trunk/Source/WebCore/ChangeLog (142113 => 142114)
--- trunk/Source/WebCore/ChangeLog 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/ChangeLog 2013-02-07 15:00:13 UTC (rev 142114)
@@ -1,3 +1,63 @@
+2013-02-07 Peter Rybin <[email protected]>
+
+ Web Inspector: support _javascript_ variable mutation in protocol and V8 bindings
+ https://bugs.webkit.org/show_bug.cgi?id=107829
+
+ A new command is added to protocol description and the call is passed through
+ debugger agent through injected script and debugger script down to V8 mirror
+ API. JSC bindings got a thorw exception stub.
+
+ Only declarative _javascript_ scopes are supported (local, closure, catch). Other
+ scopes (global, with) are not supported by V8 and not supported by protocol, because
+ manual approach (direct property assigment) is available for them in form of evaluate
+ commands and is more desirable because of a complex nature of operation (it can throw
+ exception in several cases such as exception in setter function).
+
+ Reviewed by Pavel Feldman.
+
+ Test: inspector-protocol/debugger-setVariableValue.html
+
+ * bindings/js/JSInjectedScriptHostCustom.cpp:
+ (WebCore::JSInjectedScriptHost::setFunctionVariableValue):
+ (WebCore):
+ * bindings/js/JSJavaScriptCallFrameCustom.cpp:
+ (WebCore::JSJavaScriptCallFrame::setVariableValue):
+ (WebCore):
+ * bindings/v8/DebuggerScript.js:
+ (.):
+ * bindings/v8/_javascript_CallFrame.cpp:
+ (WebCore::_javascript_CallFrame::setVariableValue):
+ (WebCore):
+ * bindings/v8/_javascript_CallFrame.h:
+ (_javascript_CallFrame):
+ * bindings/v8/ScriptDebugServer.cpp:
+ (WebCore::ScriptDebugServer::setFunctionVariableValue):
+ (WebCore):
+ * bindings/v8/ScriptDebugServer.h:
+ (ScriptDebugServer):
+ * bindings/v8/custom/V8InjectedScriptHostCustom.cpp:
+ (WebCore::V8InjectedScriptHost::setFunctionVariableValueCallback):
+ (WebCore):
+ * bindings/v8/custom/V8JavaScriptCallFrameCustom.cpp:
+ (WebCore::V8JavaScriptCallFrame::setVariableValueCallback):
+ (WebCore):
+ * inspector/InjectedScript.cpp:
+ (WebCore::InjectedScript::setVariableValue):
+ (WebCore):
+ * inspector/InjectedScript.h:
+ (InjectedScript):
+ * inspector/InjectedScriptHost.idl:
+ * inspector/InjectedScriptSource.js:
+ (.):
+ * inspector/Inspector.json:
+ * inspector/InspectorDebuggerAgent.cpp:
+ (WebCore::InspectorDebuggerAgent::getFunctionDetails):
+ (WebCore::InspectorDebuggerAgent::setVariableValue):
+ (WebCore):
+ * inspector/InspectorDebuggerAgent.h:
+ (InspectorDebuggerAgent):
+ * inspector/_javascript_CallFrame.idl:
+
2013-02-07 Caio Marcelo de Oliveira Filho <[email protected]>
[CoordinatedGraphics] Use ScrollingCoordinator to track fixed layers
Modified: trunk/Source/WebCore/bindings/js/JSInjectedScriptHostCustom.cpp (142113 => 142114)
--- trunk/Source/WebCore/bindings/js/JSInjectedScriptHostCustom.cpp 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/bindings/js/JSInjectedScriptHostCustom.cpp 2013-02-07 15:00:13 UTC (rev 142114)
@@ -307,6 +307,13 @@
return result;
}
+JSValue JSInjectedScriptHost::setFunctionVariableValue(JSC::ExecState* exec)
+{
+ // FIXME: implement this. https://bugs.webkit.org/show_bug.cgi?id=107830
+ throwError(exec, createTypeError(exec, "Variable value mutation is not supported"));
+ return jsUndefined();
+}
+
} // namespace WebCore
#endif // ENABLE(INSPECTOR)
Modified: trunk/Source/WebCore/bindings/js/JSJavaScriptCallFrameCustom.cpp (142113 => 142114)
--- trunk/Source/WebCore/bindings/js/JSJavaScriptCallFrameCustom.cpp 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/bindings/js/JSJavaScriptCallFrameCustom.cpp 2013-02-07 15:00:13 UTC (rev 142114)
@@ -130,6 +130,13 @@
return jsUndefined();
}
+JSValue JSJavaScriptCallFrame::setVariableValue(JSC::ExecState* exec)
+{
+ // FIXME: implement this. https://bugs.webkit.org/show_bug.cgi?id=107830
+ throwError(exec, createTypeError(exec, "Variable value mutation is not supported"));
+ return jsUndefined();
+}
+
} // namespace WebCore
#endif // ENABLE(_javascript__DEBUGGER)
Modified: trunk/Source/WebCore/bindings/v8/DebuggerScript.js (142113 => 142114)
--- trunk/Source/WebCore/bindings/v8/DebuggerScript.js 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/bindings/v8/DebuggerScript.js 2013-02-07 15:00:13 UTC (rev 142114)
@@ -93,6 +93,23 @@
return result;
}
+DebuggerScript.setFunctionVariableValue = function(functionValue, scopeIndex, variableName, newValue)
+{
+ var mirror = MakeMirror(functionValue);
+ if (!mirror.isFunction())
+ throw new Error("Function value has incorrect type");
+ return DebuggerScript._setScopeVariableValue(mirror, scopeIndex, variableName, newValue);
+}
+
+DebuggerScript._setScopeVariableValue = function(scopeHolder, scopeIndex, variableName, newValue)
+{
+ var scopeMirror = scopeHolder.scope(scopeIndex);
+ if (!scopeMirror)
+ throw new Error("Incorrect scope index");
+ scopeMirror.setVariableValue(variableName, newValue);
+ return undefined;
+}
+
DebuggerScript.getScripts = function(contextData)
{
var result = [];
@@ -295,6 +312,11 @@
return Debug.LiveEdit.RestartFrame(frameMirror);
}
+ function setVariableValue(scopeNumber, variableName, newValue)
+ {
+ return DebuggerScript._setScopeVariableValue(frameMirror, scopeNumber, variableName, newValue);
+ }
+
return {
"sourceID": sourceID,
"line": location ? location.line : 0,
@@ -305,7 +327,8 @@
"scopeType": scopeType,
"evaluate": evaluate,
"caller": callerFrame,
- "restart": restart
+ "restart": restart,
+ "setVariableValue": setVariableValue
};
}
Modified: trunk/Source/WebCore/bindings/v8/_javascript_CallFrame.cpp (142113 => 142114)
--- trunk/Source/WebCore/bindings/v8/_javascript_CallFrame.cpp 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/bindings/v8/_javascript_CallFrame.cpp 2013-02-07 15:00:13 UTC (rev 142114)
@@ -134,6 +134,17 @@
return result;
}
+v8::Handle<v8::Value> _javascript_CallFrame::setVariableValue(int scopeNumber, const String& variableName, v8::Handle<v8::Value> newValue)
+{
+ v8::Handle<v8::Function> setVariableValueFunction = v8::Handle<v8::Function>::Cast(m_callFrame.get()->Get(v8::String::NewSymbol("setVariableValue")));
+ v8::Handle<v8::Value> argv[] = {
+ v8::Handle<v8::Value>(v8::Integer::New(scopeNumber)),
+ v8String(variableName, m_debuggerContext->GetIsolate()),
+ newValue
+ };
+ return setVariableValueFunction->Call(m_callFrame.get(), 3, argv);
+}
+
} // namespace WebCore
#endif // ENABLE(_javascript__DEBUGGER)
Modified: trunk/Source/WebCore/bindings/v8/_javascript_CallFrame.h (142113 => 142114)
--- trunk/Source/WebCore/bindings/v8/_javascript_CallFrame.h 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/bindings/v8/_javascript_CallFrame.h 2013-02-07 15:00:13 UTC (rev 142114)
@@ -61,6 +61,7 @@
v8::Handle<v8::Value> evaluate(const String& _expression_);
v8::Handle<v8::Value> restart();
+ v8::Handle<v8::Value> setVariableValue(int scopeNumber, const String& variableName, v8::Handle<v8::Value> newValue);
private:
_javascript_CallFrame(v8::Handle<v8::Context> debuggerContext, v8::Handle<v8::Object> callFrame);
Modified: trunk/Source/WebCore/bindings/v8/ScriptDebugServer.cpp (142113 => 142114)
--- trunk/Source/WebCore/bindings/v8/ScriptDebugServer.cpp 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/bindings/v8/ScriptDebugServer.cpp 2013-02-07 15:00:13 UTC (rev 142114)
@@ -557,7 +557,22 @@
return callDebuggerMethod("getInternalProperties", 1, argv);
}
+v8::Local<v8::Value> ScriptDebugServer::setFunctionVariableValue(v8::Handle<v8::Value> functionValue, int scopeNumber, const String& variableName, v8::Handle<v8::Value> newValue)
+{
+ v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext();
+ if (m_debuggerScript.get().IsEmpty())
+ return *(v8::ThrowException(v8::String::New("Debugging is not enabled.")));
+ v8::Handle<v8::Value> argv[] = {
+ functionValue,
+ v8::Handle<v8::Value>(v8::Integer::New(scopeNumber)),
+ v8String(variableName, debuggerContext->GetIsolate()),
+ newValue
+ };
+ return callDebuggerMethod("setFunctionVariableValue", 4, argv);
+}
+
+
bool ScriptDebugServer::isPaused()
{
return !m_executionState.get().IsEmpty();
Modified: trunk/Source/WebCore/bindings/v8/ScriptDebugServer.h (142113 => 142114)
--- trunk/Source/WebCore/bindings/v8/ScriptDebugServer.h 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/bindings/v8/ScriptDebugServer.h 2013-02-07 15:00:13 UTC (rev 142114)
@@ -101,7 +101,9 @@
v8::Local<v8::Value> functionScopes(v8::Handle<v8::Function>);
v8::Local<v8::Value> getInternalProperties(v8::Handle<v8::Object>&);
+ v8::Local<v8::Value> setFunctionVariableValue(v8::Handle<v8::Value> functionValue, int scopeNumber, const String& variableName, v8::Handle<v8::Value> newValue);
+
virtual void compileScript(ScriptState*, const String& _expression_, const String& sourceURL, String* scriptId, String* exceptionMessage);
virtual void clearCompiledScripts();
virtual void runScript(ScriptState*, const String& scriptId, ScriptValue* result, bool* wasThrown, String* exceptionMessage);
Modified: trunk/Source/WebCore/bindings/v8/custom/V8InjectedScriptHostCustom.cpp (142113 => 142114)
--- trunk/Source/WebCore/bindings/v8/custom/V8InjectedScriptHostCustom.cpp 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/bindings/v8/custom/V8InjectedScriptHostCustom.cpp 2013-02-07 15:00:13 UTC (rev 142114)
@@ -321,6 +321,19 @@
return script->Run();
}
+v8::Handle<v8::Value> V8InjectedScriptHost::setFunctionVariableValueCallback(const v8::Arguments& args)
+{
+ v8::Handle<v8::Value> functionValue = args[0];
+ int scopeIndex = args[1]->Int32Value();
+ String variableName = toWebCoreStringWithUndefinedOrNullCheck(args[2]);
+ v8::Handle<v8::Value> newValue = args[3];
+
+ InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
+ ScriptDebugServer& debugServer = host->scriptDebugServer();
+ return debugServer.setFunctionVariableValue(functionValue, scopeIndex, variableName, newValue);
+}
+
+
} // namespace WebCore
#endif // ENABLE(INSPECTOR)
Modified: trunk/Source/WebCore/bindings/v8/custom/V8JavaScriptCallFrameCustom.cpp (142113 => 142114)
--- trunk/Source/WebCore/bindings/v8/custom/V8JavaScriptCallFrameCustom.cpp 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/bindings/v8/custom/V8JavaScriptCallFrameCustom.cpp 2013-02-07 15:00:13 UTC (rev 142114)
@@ -50,6 +50,15 @@
return impl->restart();
}
+v8::Handle<v8::Value> V8JavaScriptCallFrame::setVariableValueCallback(const v8::Arguments& args)
+{
+ _javascript_CallFrame* impl = V8JavaScriptCallFrame::toNative(args.Holder());
+ int scopeIndex = args[0]->Int32Value();
+ String variableName = toWebCoreStringWithUndefinedOrNullCheck(args[1]);
+ v8::Handle<v8::Value> newValue = args[2];
+ return impl->setVariableValue(scopeIndex, variableName, newValue);
+}
+
v8::Handle<v8::Value> V8JavaScriptCallFrame::scopeChainAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
{
_javascript_CallFrame* impl = V8JavaScriptCallFrame::toNative(info.Holder());
Modified: trunk/Source/WebCore/inspector/InjectedScript.cpp (142113 => 142114)
--- trunk/Source/WebCore/inspector/InjectedScript.cpp 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/inspector/InjectedScript.cpp 2013-02-07 15:00:13 UTC (rev 142114)
@@ -116,6 +116,36 @@
*errorString = "Internal error";
}
+void InjectedScript::setVariableValue(ErrorString* errorString, const ScriptValue& callFrames, const String* callFrameIdOpt, const String* functionObjectIdOpt, int scopeNumber, const String& variableName, const String& newValueStr)
+{
+ ScriptFunctionCall function(injectedScriptObject(), "setVariableValue");
+ if (callFrameIdOpt) {
+ function.appendArgument(callFrames);
+ function.appendArgument(*callFrameIdOpt);
+ } else {
+ function.appendArgument(false);
+ function.appendArgument(false);
+ }
+ if (functionObjectIdOpt)
+ function.appendArgument(*functionObjectIdOpt);
+ else
+ function.appendArgument(false);
+ function.appendArgument(scopeNumber);
+ function.appendArgument(variableName);
+ function.appendArgument(newValueStr);
+ RefPtr<InspectorValue> resultValue;
+ makeCall(function, &resultValue);
+ if (!resultValue) {
+ *errorString = "Internal error";
+ return;
+ }
+ if (resultValue->type() == InspectorValue::TypeString) {
+ resultValue->asString(errorString);
+ return;
+ }
+ // Normal return.
+}
+
void InjectedScript::getFunctionDetails(ErrorString* errorString, const String& functionId, RefPtr<FunctionDetails>* result)
{
ScriptFunctionCall function(injectedScriptObject(), "getFunctionDetails");
Modified: trunk/Source/WebCore/inspector/InjectedScript.h (142113 => 142114)
--- trunk/Source/WebCore/inspector/InjectedScript.h 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/inspector/InjectedScript.h 2013-02-07 15:00:13 UTC (rev 142114)
@@ -80,6 +80,7 @@
RefPtr<TypeBuilder::Runtime::RemoteObject>* result,
TypeBuilder::OptOutput<bool>* wasThrown);
void restartFrame(ErrorString*, const ScriptValue& callFrames, const String& callFrameId, RefPtr<InspectorObject>* result);
+ void setVariableValue(ErrorString*, const ScriptValue& callFrames, const String* callFrameIdOpt, const String* functionObjectIdOpt, int scopeNumber, const String& variableName, const String& newValueStr);
void getFunctionDetails(ErrorString*, const String& functionId, RefPtr<TypeBuilder::Debugger::FunctionDetails>* result);
void getProperties(ErrorString*, const String& objectId, bool ownProperties, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::PropertyDescriptor> >* result);
void getInternalProperties(ErrorString*, const String& objectId, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::InternalPropertyDescriptor> >* result);
Modified: trunk/Source/WebCore/inspector/InjectedScriptHost.idl (142113 => 142114)
--- trunk/Source/WebCore/inspector/InjectedScriptHost.idl 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/inspector/InjectedScriptHost.idl 2013-02-07 15:00:13 UTC (rev 142114)
@@ -49,4 +49,6 @@
[Custom] DOMString databaseId(in DOMObject database);
[Custom] DOMString storageId(in DOMObject storage);
[Custom] DOMObject evaluate(in DOMString text);
+ // Only declarative scope (local, with and catch) is accepted. Returns undefined.
+ [Custom] DOMObject setFunctionVariableValue(in DOMObject functionObject, in int scopeIndex, in DOMString variableName, DOMObject newValue);
};
Modified: trunk/Source/WebCore/inspector/InjectedScriptSource.js (142113 => 142114)
--- trunk/Source/WebCore/inspector/InjectedScriptSource.js 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/inspector/InjectedScriptSource.js 2013-02-07 15:00:13 UTC (rev 142114)
@@ -427,21 +427,13 @@
var resolvedArgs = [];
args = InjectedScriptHost.evaluate(args);
for (var i = 0; i < args.length; ++i) {
- objectId = args[i].objectId;
- if (objectId) {
- var parsedArgId = this._parseObjectId(objectId);
- if (!parsedArgId || parsedArgId["injectedScriptId"] !== injectedScriptId)
- return "Arguments should belong to the same _javascript_ world as the target object.";
-
- var resolvedArg = this._objectForId(parsedArgId);
- if (!this._isDefined(resolvedArg))
- return "Could not find object with given id";
-
- resolvedArgs.push(resolvedArg);
- } else if ("value" in args[i])
- resolvedArgs.push(args[i].value);
- else
- resolvedArgs.push(undefined);
+ var resolvedCallArgument;
+ try {
+ resolvedCallArgument = this._resolveCallArgument(args[i]);
+ } catch (e) {
+ return String(e);
+ }
+ resolvedArgs.push(resolvedCallArgument)
}
}
@@ -457,7 +449,31 @@
return this._createThrownValue(e, objectGroup);
}
},
+
+ /**
+ * Resolves a value from CallArgument description.
+ * @param {RuntimeAgent.CallArgument} callArgumentJson
+ * @return {*} resolved value
+ * @throw {string} error message
+ */
+ _resolveCallArgument: function(callArgumentJson) {
+ var objectId = callArgumentJson.objectId;
+ if (objectId) {
+ var parsedArgId = this._parseObjectId(objectId);
+ if (!parsedArgId || parsedArgId["injectedScriptId"] !== injectedScriptId)
+ throw "Arguments should belong to the same _javascript_ world as the target object.";
+ var resolvedArg = this._objectForId(parsedArgId);
+ if (!this._isDefined(resolvedArg))
+ throw "Could not find object with given id";
+
+ return resolvedArg;
+ } else if ("value" in callArgumentJson)
+ return callArgumentJson.value;
+ else
+ return undefined;
+ },
+
/**
* @param {Function} evalFunction
* @param {Object} object
@@ -576,7 +592,52 @@
},
/**
+ * Either callFrameId or functionObjectId must be specified.
* @param {Object} topCallFrame
+ * @param {string|boolean} callFrameId or false
+ * @param {string|boolean} functionObjectId or false
+ * @param {integer} scopeNumber
+ * @param {string} variableName
+ * @param {string} newValueJsonString RuntimeAgent.CallArgument structure serialized as string
+ * @return {string|undefined} undefined if success or an error message
+ */
+ setVariableValue: function(topCallFrame, callFrameId, functionObjectId, scopeNumber, variableName, newValueJsonString)
+ {
+ var setter;
+ if (callFrameId) {
+ var callFrame = this._callFrameForId(topCallFrame, callFrameId);
+ if (!callFrame)
+ return "Could not find call frame with given id";
+ setter = callFrame.setVariableValue.bind(callFrame);
+ } else {
+ var parsedFunctionId = this._parseObjectId(functionObjectId);
+ var func = this._objectForId(parsedFunctionId);
+ if (typeof func !== "function")
+ return "Cannot resolve function by id.";
+ setter = InjectedScriptHost.setFunctionVariableValue.bind(InjectedScriptHost, func);
+ }
+ var newValueJson;
+ try {
+ newValueJson = InjectedScriptHost.evaluate("(" + newValueJsonString + ")");
+ } catch (e) {
+ return "Failed to parse new value JSON " + newValueJsonString + " : " + e;
+ }
+ var resolvedValue;
+ try {
+ resolvedValue = this._resolveCallArgument(newValueJson);
+ } catch (e) {
+ return String(e);
+ }
+ try {
+ setter(scopeNumber, variableName, resolvedValue);
+ } catch (e) {
+ return "Failed to change variable value: " + e;
+ }
+ return undefined;
+ },
+
+ /**
+ * @param {Object} topCallFrame
* @param {string} callFrameId
* @return {Object}
*/
Modified: trunk/Source/WebCore/inspector/Inspector.json (142113 => 142114)
--- trunk/Source/WebCore/inspector/Inspector.json 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/inspector/Inspector.json 2013-02-07 15:00:13 UTC (rev 142114)
@@ -2933,6 +2933,18 @@
],
"hidden": true,
"description": "Sets overlay message."
+ },
+ {
+ "name": "setVariableValue",
+ "parameters": [
+ { "name": "callFrameId", "$ref": "CallFrameId", "optional": true, "description": "Id of callframe that holds variable." },
+ { "name": "functionObjectId", "$ref": "Runtime.RemoteObjectId", "optional": true, "description": "Object id of closure (function) that holds variable." },
+ { "name": "scopeNumber", "type": "integer", "description": "0-based number of scope as was listed in scope chain. Only 'local', 'closure' and 'catch' scope types are allowed. Other scopes could be manipulated manually." },
+ { "name": "variableName", "type": "string", "description": "Variable name." },
+ { "name": "newValue", "$ref": "Runtime.CallArgument", "description": "New variable value." }
+ ],
+ "hidden": true,
+ "description": "Changes value of variable in a callframe or a closure. Either callframe or function must be specified. Object-based scopes are not supported and must be mutated manually."
}
],
"events": [
Modified: trunk/Source/WebCore/inspector/InspectorDebuggerAgent.cpp (142113 => 142114)
--- trunk/Source/WebCore/inspector/InspectorDebuggerAgent.cpp 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/inspector/InspectorDebuggerAgent.cpp 2013-02-07 15:00:13 UTC (rev 142114)
@@ -411,7 +411,7 @@
{
InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(functionId);
if (injectedScript.hasNoValue()) {
- *errorString = "Inspected frame has gone";
+ *errorString = "Function object id is obsolete";
return;
}
injectedScript.getFunctionDetails(errorString, functionId, &details);
@@ -580,6 +580,30 @@
{
}
+void InspectorDebuggerAgent::setVariableValue(ErrorString* errorString, const String* callFrameId, const String* functionObjectId, int scopeNumber, const String& variableName, const RefPtr<InspectorObject>& newValue)
+{
+ InjectedScript injectedScript;
+ if (callFrameId) {
+ injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*callFrameId);
+ if (injectedScript.hasNoValue()) {
+ *errorString = "Inspected frame has gone";
+ return;
+ }
+ } else if (functionObjectId) {
+ injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*functionObjectId);
+ if (injectedScript.hasNoValue()) {
+ *errorString = "Function object id cannot be resolved";
+ return;
+ }
+ } else {
+ *errorString = "Either call frame or function object must be specified";
+ return;
+ }
+ String newValueString = newValue->toJSONString();
+
+ injectedScript.setVariableValue(errorString, m_currentCallStack, callFrameId, functionObjectId, scopeNumber, variableName, newValueString);
+}
+
void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String& directiveText)
{
if (scriptDebugServer().pauseOnExceptionsState() != ScriptDebugServer::DontPauseOnExceptions) {
Modified: trunk/Source/WebCore/inspector/InspectorDebuggerAgent.h (142113 => 142114)
--- trunk/Source/WebCore/inspector/InspectorDebuggerAgent.h 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/inspector/InspectorDebuggerAgent.h 2013-02-07 15:00:13 UTC (rev 142114)
@@ -113,6 +113,7 @@
void compileScript(ErrorString*, const String& _expression_, const String& sourceURL, TypeBuilder::OptOutput<TypeBuilder::Debugger::ScriptId>*, TypeBuilder::OptOutput<String>* syntaxErrorMessage);
void runScript(ErrorString*, const TypeBuilder::Debugger::ScriptId&, const int* executionContextId, const String* objectGroup, const bool* doNotPauseOnExceptionsAndMuteConsole, RefPtr<TypeBuilder::Runtime::RemoteObject>& result, TypeBuilder::OptOutput<bool>* wasThrown);
virtual void setOverlayMessage(ErrorString*, const String*);
+ virtual void setVariableValue(ErrorString*, const String* in_callFrame, const String* in_functionObjectId, int in_scopeNumber, const String& in_variableName, const RefPtr<InspectorObject>& in_newValue);
void schedulePauseOnNextStatement(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<InspectorObject> data);
void cancelPauseOnNextStatement();
Modified: trunk/Source/WebCore/inspector/_javascript_CallFrame.idl (142113 => 142114)
--- trunk/Source/WebCore/inspector/_javascript_CallFrame.idl 2013-02-07 14:56:30 UTC (rev 142113)
+++ trunk/Source/WebCore/inspector/_javascript_CallFrame.idl 2013-02-07 15:00:13 UTC (rev 142114)
@@ -39,6 +39,9 @@
[Custom] void evaluate(in DOMString script);
[Custom] DOMObject restart();
+
+ // Only declarative scope (local, with and catch) is accepted. Returns undefined.
+ [Custom] DOMObject setVariableValue(in int scopeIndex, in DOMString variableName, DOMObject newValue);
readonly attribute _javascript_CallFrame caller;
readonly attribute long sourceID;