WebKit Bugzilla
Attachment 356241 Details for
Bug 176766
: Web Inspector: Implement `queryObjects` Command Line API
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-176766-20181130143828.patch (text/plain), 18.64 KB, created by
Devin Rousso
on 2018-11-30 14:38:29 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Devin Rousso
Created:
2018-11-30 14:38:29 PST
Size:
18.64 KB
patch
obsolete
>diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 676d21b7016b1699ab8d3f187cef6c068160a2e0..898d4c7ee12d8992fe5a9acc720e2cd7e8d65baa 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,45 @@ >+2018-11-30 Devin Rousso <webkit@devinrousso.com> >+ >+ Web Inspector: Implement `queryObjects` Command Line API >+ https://bugs.webkit.org/show_bug.cgi?id=176766 >+ <rdar://problem/34890689> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Introduces a new Command Line function called `queryObjects` that will return an array of >+ object that have the given constructor/prototype argument in their prototype chain. >+ - `queryObjects(Promise)` will return an array of all Promises. >+ - `queryObjects(Foo)` will return all objects created with the constructor `Foo`. >+ >+ Currently, an error is thrown if the first argument is one of the following: >+ - Object >+ - Object.prototype >+ - Function >+ - Function.prototype >+ - Array >+ - Array.prototype >+ - Map >+ - Map.prototype >+ - Set >+ - Set.prototype >+ - Proxy >+ >+ The reason for this is that we don't want to expose any internal/builtin objects, as some of >+ them are highlighy sensitive and undefined behaviour can occur if they are modified. >+ >+ * inspector/JSInjectedScriptHost.h: >+ * inspector/JSInjectedScriptHost.cpp: >+ (Inspector::checkForbiddenPrototype): >+ (Inspector::JSInjectedScriptHost::queryObjects): >+ Does a GC and then iterates over all live JSCell in the heap to find these objects. >+ >+ * inspector/JSInjectedScriptHostPrototype.cpp: >+ (Inspector::JSInjectedScriptHostPrototype::finishCreation): >+ (Inspector::jsInjectedScriptHostPrototypeFunctionQueryObjects): >+ >+ * inspector/InjectedScriptSource.js: >+ (queryObjects): >+ > 2018-11-29 Justin Michaud <justin_michaud@apple.com> > > CSS Painting API should pass 'this' correctly to paint callback, and repaint when properties change. >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index f3ca220be3f930eac7f9a58912684a33db482b2f..7c85de160f3972f7b69cc25ae2b80e0344905ae6 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,17 @@ >+2018-11-30 Devin Rousso <webkit@devinrousso.com> >+ >+ Web Inspector: Implement `queryObjects` Command Line API >+ https://bugs.webkit.org/show_bug.cgi?id=176766 >+ <rdar://problem/34890689> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Test: inspector/console/queryObjects.html >+ >+ * inspector/CommandLineAPIModuleSource.js: >+ (CommandLineAPI): >+ (CommandLineAPIImpl.prototype.queryObjects): >+ > 2018-11-29 Frederic Wang <fwang@igalia.com> > > Separate paint and scroll offsets for RenderLayerBacking::m_scrollingContentsLayer >diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog >index a8e1de9a0cfd0c5e34ea4a1df1dcb17fe8067135..cc0bf02ce83dca18eff86e1cbc7e16e089d04959 100644 >--- a/Source/WebInspectorUI/ChangeLog >+++ b/Source/WebInspectorUI/ChangeLog >@@ -1,3 +1,15 @@ >+2018-11-30 Devin Rousso <webkit@devinrousso.com> >+ >+ Web Inspector: Implement `queryObjects` Command Line API >+ https://bugs.webkit.org/show_bug.cgi?id=176766 >+ <rdar://problem/34890689> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js: >+ (WI.JavaScriptRuntimeCompletionProvider.completionControllerCompletionsNeeded.receivedPropertyNames): >+ Add `queryObjects` to the list of command line functions. >+ > 2018-11-29 Matt Baker <mattbaker@apple.com> > > Web Inspector: RTL: disclosure triangles should be flipped and aligned right >diff --git a/Source/JavaScriptCore/inspector/InjectedScriptSource.js b/Source/JavaScriptCore/inspector/InjectedScriptSource.js >index d6b75f1fecd79af702f9ed58000423238343668a..cbad50a5f14279f008f2983fce5122158abb7993 100644 >--- a/Source/JavaScriptCore/inspector/InjectedScriptSource.js >+++ b/Source/JavaScriptCore/inspector/InjectedScriptSource.js >@@ -1410,6 +1410,10 @@ BasicCommandLineAPI.methods = [ > result.push(object[key]); > return result; > }, >+ >+ function queryObjects(...args) { >+ return InjectedScriptHost.queryObjects(...args); >+ }, > ]; > > for (let i = 0; i < BasicCommandLineAPI.methods.length; ++i) { >diff --git a/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp b/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp >index 71d7c406550db7c99f67c78e9fe33a3cc99b1870..6acb93f8a3cd97ab8df858b91e051fc23cb1822c 100644 >--- a/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp >+++ b/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp >@@ -27,11 +27,14 @@ > #include "JSInjectedScriptHost.h" > > #include "ArrayIteratorPrototype.h" >+#include "ArrayPrototype.h" > #include "BuiltinNames.h" > #include "Completion.h" > #include "DateInstance.h" > #include "DirectArguments.h" > #include "Error.h" >+#include "FunctionPrototype.h" >+#include "HeapIterationScope.h" > #include "InjectedScriptHost.h" > #include "IterationKind.h" > #include "IteratorOperations.h" >@@ -51,11 +54,15 @@ > #include "JSWeakSet.h" > #include "JSWithScope.h" > #include "MapIteratorPrototype.h" >+#include "MapPrototype.h" >+#include "MarkedSpaceInlines.h" > #include "ObjectConstructor.h" >+#include "ObjectPrototype.h" > #include "ProxyObject.h" > #include "RegExpObject.h" > #include "ScopedArguments.h" > #include "SetIteratorPrototype.h" >+#include "SetPrototype.h" > #include "SourceCode.h" > #include "TypedArrayInlines.h" > >@@ -621,4 +628,77 @@ JSValue JSInjectedScriptHost::iteratorEntries(ExecState* exec) > return array; > } > >+static bool checkForbiddenPrototype(ExecState* exec, JSValue value, JSValue proto) >+{ >+ if (value == proto) >+ return true; >+ >+ // Check that the prototype chain of proto hasn't been modified to include value. >+ return JSObject::defaultHasInstance(exec, proto, value); >+} >+ >+JSValue JSInjectedScriptHost::queryObjects(ExecState* exec) >+{ >+ if (exec->argumentCount() < 1) >+ return jsUndefined(); >+ >+ VM& vm = exec->vm(); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ >+ JSValue prototypeOrConstructor = exec->uncheckedArgument(0); >+ if (!prototypeOrConstructor.isObject()) >+ return throwTypeError(exec, scope, "queryObjects first argument must be an object."_s); >+ >+ JSObject* object = asObject(prototypeOrConstructor); >+ if (object->inherits<ProxyObject>(vm)) >+ return throwTypeError(exec, scope, "queryObjects cannot be called with a Proxy."_s); >+ >+ JSValue prototype = object; >+ >+ JSValue constructorPrototype = object->get(exec, vm.propertyNames->prototype); >+ RETURN_IF_EXCEPTION(scope, { }); >+ if (constructorPrototype.isObject()) { >+ prototype = constructorPrototype; >+ object = asObject(prototype); >+ } >+ >+ if (object->inherits<ProxyObject>(vm) || prototype.inherits<ProxyObject>(vm)) >+ return throwTypeError(exec, scope, "queryObjects cannot be called with a Proxy."_s); >+ >+ // FIXME: implement a way of distinguishing between internal and user-created objects. >+ JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); >+ if (checkForbiddenPrototype(exec, object, lexicalGlobalObject->objectPrototype())) >+ return throwTypeError(exec, scope, "queryObjects cannot be called with Object."_s); >+ if (checkForbiddenPrototype(exec, object, lexicalGlobalObject->functionPrototype())) >+ return throwTypeError(exec, scope, "queryObjects cannot be called with Function."_s); >+ if (checkForbiddenPrototype(exec, object, lexicalGlobalObject->arrayPrototype())) >+ return throwTypeError(exec, scope, "queryObjects cannot be called with Array."_s); >+ if (checkForbiddenPrototype(exec, object, lexicalGlobalObject->mapPrototype())) >+ return throwTypeError(exec, scope, "queryObjects cannot be called with Map."_s); >+ if (checkForbiddenPrototype(exec, object, lexicalGlobalObject->jsSetPrototype())) >+ return throwTypeError(exec, scope, "queryObjects cannot be called with Set."_s); >+ >+ sanitizeStackForVM(&vm); >+ vm.heap.collectNow(Sync, CollectionScope::Full); >+ >+ JSArray* array = constructEmptyArray(exec, nullptr); >+ RETURN_IF_EXCEPTION(scope, { }); >+ >+ { >+ HeapIterationScope iterationScope(vm.heap); >+ vm.heap.objectSpace().forEachLiveCell(iterationScope, [&] (HeapCell* cell, HeapCell::Kind kind) { >+ if (kind != HeapCell::JSCell) >+ return IterationStatus::Continue; >+ >+ JSValue value(static_cast<JSCell*>(cell)); >+ if (JSObject::defaultHasInstance(exec, value, prototype)) >+ array->putDirectIndex(exec, array->length(), value); >+ >+ return IterationStatus::Continue; >+ }); >+ } >+ >+ return array; >+} >+ > } // namespace Inspector >diff --git a/Source/JavaScriptCore/inspector/JSInjectedScriptHost.h b/Source/JavaScriptCore/inspector/JSInjectedScriptHost.h >index 4035a69f466547ac3eb4385337f2efaffe7ff0f2..bacc37aab17308d6f21891e79c7090a5979f7643 100644 >--- a/Source/JavaScriptCore/inspector/JSInjectedScriptHost.h >+++ b/Source/JavaScriptCore/inspector/JSInjectedScriptHost.h >@@ -71,6 +71,7 @@ public: > JSC::JSValue weakSetSize(JSC::ExecState*); > JSC::JSValue weakSetEntries(JSC::ExecState*); > JSC::JSValue iteratorEntries(JSC::ExecState*); >+ JSC::JSValue queryObjects(JSC::ExecState*); > > protected: > void finishCreation(JSC::VM&); >diff --git a/Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp b/Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp >index 549332962b794de867d8a026a514418def3ae9ec..f3960de9673a12c3c36e0c7fdc17e97f3065a237 100644 >--- a/Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp >+++ b/Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp >@@ -49,6 +49,7 @@ static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakMap > static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakSetSize(ExecState*); > static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakSetEntries(ExecState*); > static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionIteratorEntries(ExecState*); >+static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionQueryObjects(ExecState*); > static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionEvaluateWithScopeExtension(ExecState*); > > static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeAttributeEvaluate(ExecState*); >@@ -72,6 +73,7 @@ void JSInjectedScriptHostPrototype::finishCreation(VM& vm, JSGlobalObject* globa > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("weakSetSize", jsInjectedScriptHostPrototypeFunctionWeakSetSize, static_cast<unsigned>(PropertyAttribute::DontEnum), 1); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("weakSetEntries", jsInjectedScriptHostPrototypeFunctionWeakSetEntries, static_cast<unsigned>(PropertyAttribute::DontEnum), 1); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("iteratorEntries", jsInjectedScriptHostPrototypeFunctionIteratorEntries, static_cast<unsigned>(PropertyAttribute::DontEnum), 1); >+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("queryObjects", jsInjectedScriptHostPrototypeFunctionQueryObjects, static_cast<unsigned>(PropertyAttribute::DontEnum), 1); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("evaluateWithScopeExtension", jsInjectedScriptHostPrototypeFunctionEvaluateWithScopeExtension, static_cast<unsigned>(PropertyAttribute::DontEnum), 1); > > JSC_NATIVE_GETTER("evaluate", jsInjectedScriptHostPrototypeAttributeEvaluate, PropertyAttribute::DontEnum | PropertyAttribute::Accessor); >@@ -194,6 +196,19 @@ EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionIteratorEntrie > return JSValue::encode(castedThis->iteratorEntries(exec)); > } > >+EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionQueryObjects(ExecState* exec) >+{ >+ VM& vm = exec->vm(); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ >+ JSValue thisValue = exec->thisValue(); >+ JSInjectedScriptHost* castedThis = jsDynamicCast<JSInjectedScriptHost*>(vm, thisValue); >+ if (!castedThis) >+ return throwVMTypeError(exec, scope); >+ >+ return JSValue::encode(castedThis->queryObjects(exec)); >+} >+ > EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionEvaluateWithScopeExtension(ExecState* exec) > { > VM& vm = exec->vm(); >diff --git a/Source/WebCore/inspector/CommandLineAPIModuleSource.js b/Source/WebCore/inspector/CommandLineAPIModuleSource.js >index 7cf4fcdaaaa2ef4d964d9f7ee6b9423a64706d0b..1f508f9899a2641d0e60f19264d7691a8daa5229 100644 >--- a/Source/WebCore/inspector/CommandLineAPIModuleSource.js >+++ b/Source/WebCore/inspector/CommandLineAPIModuleSource.js >@@ -57,9 +57,9 @@ function CommandLineAPI(commandLineAPIImpl, callFrame) > this.__defineGetter__("$" + i, bind(injectedScript._savedResult, injectedScript, i)); > > // Command Line API methods. >- for (let member of CommandLineAPI.members_) { >- this[member] = bind(commandLineAPIImpl[member], commandLineAPIImpl); >- this[member].toString = function() { return "function " + member + "() { [Command Line API] }" }; >+ for (let method of CommandLineAPI.methods) { >+ this[method] = bind(commandLineAPIImpl[method], commandLineAPIImpl); >+ this[method].toString = function() { return "function " + method + "() { [Command Line API] }" }; > } > } > >@@ -67,9 +67,24 @@ function CommandLineAPI(commandLineAPIImpl, callFrame) > * @type {Array.<string>} > * @const > */ >-CommandLineAPI.members_ = [ >- "$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd", "table", >- "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventListeners" >+CommandLineAPI.methods = [ >+ "$", >+ "$$", >+ "$x", >+ "clear", >+ "copy", >+ "dir", >+ "dirxml", >+ "getEventListeners", >+ "inspect", >+ "keys", >+ "monitorEvents", >+ "profile", >+ "profileEnd", >+ "queryObjects", >+ "table", >+ "unmonitorEvents", >+ "values", > ]; > > /** >@@ -221,6 +236,11 @@ CommandLineAPIImpl.prototype = { > return this._inspect(object); > }, > >+ queryObjects(...args) >+ { >+ return InjectedScriptHost.queryObjects(...args); >+ }, >+ > copy: function(object) > { > var string; >diff --git a/Source/WebInspectorUI/UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js b/Source/WebInspectorUI/UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js >index aebd456ca068290aa4bef51e0ceac753350065da..f23df46b130b4707a157bb1ce182996f9c40510f 100644 >--- a/Source/WebInspectorUI/UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js >+++ b/Source/WebInspectorUI/UserInterface/Controllers/JavaScriptRuntimeCompletionProvider.js >@@ -218,14 +218,14 @@ WI.JavaScriptRuntimeCompletionProvider = class JavaScriptRuntimeCompletionProvid > WI.runtimeManager.activeExecutionContext.target.RuntimeAgent.releaseObjectGroup("completion"); > > if (!base) { >- var commandLineAPI = ["$", "$$", "$x", "dir", "dirxml", "keys", "values", "profile", "profileEnd", "monitorEvents", "unmonitorEvents", "inspect", "copy", "clear", "getEventListeners", "$0", "$_"]; >+ let commandLineAPI = WI.JavaScriptRuntimeCompletionProvider._commandLineAPI.slice(0); > if (WI.debuggerManager.paused) { > let targetData = WI.debuggerManager.dataForTarget(WI.runtimeManager.activeExecutionContext.target); > if (targetData.pauseReason === WI.DebuggerManager.PauseReason.Exception) > commandLineAPI.push("$exception"); > } >- for (var i = 0; i < commandLineAPI.length; ++i) >- propertyNames[commandLineAPI[i]] = true; >+ for (let name of commandLineAPI) >+ propertyNames[name] = true; > > // FIXME: Due to caching, sometimes old $n values show up as completion results even though they are not available. We should clear that proactively. > for (var i = 1; i <= WI.ConsoleCommandResultMessage.maximumSavedResultIndex; ++i) >@@ -301,3 +301,25 @@ WI.JavaScriptRuntimeCompletionProvider = class JavaScriptRuntimeCompletionProvid > this._lastPropertyNames = null; > } > }; >+ >+WI.JavaScriptRuntimeCompletionProvider._commandLineAPI = [ >+ "$", >+ "$$", >+ "$0", >+ "$_", >+ "$x", >+ "clear", >+ "copy", >+ "dir", >+ "dirxml", >+ "getEventListeners", >+ "inspect", >+ "keys", >+ "monitorEvents", >+ "profile", >+ "profileEnd", >+ "queryObjects", >+ "table", >+ "unmonitorEvents", >+ "values", >+]; >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 8a41c60d2ded46a9440ff52ee78036448d75bf9f..123999fb1e8ba0fdd5ddff54d8ca5fe66918daa0 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,16 @@ >+2018-11-30 Devin Rousso <webkit@devinrousso.com> >+ >+ Web Inspector: Implement `queryObjects` Command Line API >+ https://bugs.webkit.org/show_bug.cgi?id=176766 >+ <rdar://problem/34890689> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * http/tests/inspector/console/cross-domain-inspected-node-access-expected.txt: >+ >+ * inspector/console/queryObjects-expected.html: >+ * inspector/console/queryObjects.html: >+ > 2018-11-29 Frederic Wang <fwang@igalia.com> > > Separate paint and scroll offsets for RenderLayerBacking::m_scrollingContentsLayer >diff --git a/LayoutTests/http/tests/inspector/dom/cross-domain-inspected-node-access-expected.txt b/LayoutTests/http/tests/inspector/dom/cross-domain-inspected-node-access-expected.txt >index d638f6bd85a72f6abd708d778f09887a1af62410..89c9c538cfc3ef860aacd4072eeec187a9596006 100644 >--- a/LayoutTests/http/tests/inspector/dom/cross-domain-inspected-node-access-expected.txt >+++ b/LayoutTests/http/tests/inspector/dom/cross-domain-inspected-node-access-expected.txt >@@ -1,5 +1,5 @@ >-CONSOLE MESSAGE: line 42: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match. >-CONSOLE MESSAGE: line 42: Blocked a frame with origin "http://localhost:8000" from accessing a frame with origin "http://127.0.0.1:8000". Protocols, domains, and ports must match. >+CONSOLE MESSAGE: line 43: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match. >+CONSOLE MESSAGE: line 43: Blocked a frame with origin "http://localhost:8000" from accessing a frame with origin "http://127.0.0.1:8000". Protocols, domains, and ports must match. > Test that code evaluated in the main frame cannot access $0 that resolves to a node in a frame from a different domain. Bug 105423. > >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 176766
:
321026
|
321032
|
321034
|
321037
|
321185
|
321187
|
321223
|
321372
|
321519
|
321618
|
321621
|
321623
|
322029
|
356241
|
356288
|
356290
|
356295
|
356300
|
358232