Commit ffa4cda6 authored by Benedikt Meurer's avatar Benedikt Meurer Committed by V8 LUCI CQ

[inspector] Add nonIndexedPropertiesOnly to Runtime.getProperties.

This introduces a new, optional `nonIndexedPropertiesOnly` flag to the
`Runtime.getProperties` inspector request, which tells the inspector to
only report properties whose name is not an (typed) array index. This is
to support retrieving all properties except for the indexed ones when
the DevTools front-end decides to use the array bucketing mechanism.
Previously the DevTools front-end had some quite complicated logic in
place to simulate this via injected JavaScript, but that logic didn't
pick up internal properties and was also interfering with the inherited
accessor mechanism. With this new flag, it's straight-forward to
implement the correct behavior in the DevTools front-end.

The corresponding devtools-frontend CL is https://crrev.com/c/3099011.

Before: https://imgur.com/hMX6vaV.png
After: https://imgur.com/MGgiuJQ.png
Bug: chromium:1199701
Change-Id: Iacbe9756ed8a2e6982efaebe1e7c606d37c05379
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3099686
Auto-Submit: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarPhilip Pfaffe <pfaffe@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/main@{#76360}
parent f46dec2e
...@@ -1427,6 +1427,8 @@ domain Runtime ...@@ -1427,6 +1427,8 @@ domain Runtime
experimental optional boolean accessorPropertiesOnly experimental optional boolean accessorPropertiesOnly
# Whether preview should be generated for the results. # Whether preview should be generated for the results.
experimental optional boolean generatePreview experimental optional boolean generatePreview
# If true, returns non-indexed properties only.
experimental optional boolean nonIndexedPropertiesOnly
returns returns
# Object properties. # Object properties.
array of PropertyDescriptor result array of PropertyDescriptor result
......
...@@ -354,8 +354,8 @@ class PropertyAccumulator : public ValueMirror::PropertyAccumulator { ...@@ -354,8 +354,8 @@ class PropertyAccumulator : public ValueMirror::PropertyAccumulator {
Response InjectedScript::getProperties( Response InjectedScript::getProperties(
v8::Local<v8::Object> object, const String16& groupName, bool ownProperties, v8::Local<v8::Object> object, const String16& groupName, bool ownProperties,
bool accessorPropertiesOnly, WrapMode wrapMode, bool accessorPropertiesOnly, bool nonIndexedPropertiesOnly,
std::unique_ptr<Array<PropertyDescriptor>>* properties, WrapMode wrapMode, std::unique_ptr<Array<PropertyDescriptor>>* properties,
Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) { Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
v8::HandleScope handles(m_context->isolate()); v8::HandleScope handles(m_context->isolate());
v8::Local<v8::Context> context = m_context->context(); v8::Local<v8::Context> context = m_context->context();
...@@ -367,7 +367,8 @@ Response InjectedScript::getProperties( ...@@ -367,7 +367,8 @@ Response InjectedScript::getProperties(
std::vector<PropertyMirror> mirrors; std::vector<PropertyMirror> mirrors;
PropertyAccumulator accumulator(&mirrors); PropertyAccumulator accumulator(&mirrors);
if (!ValueMirror::getProperties(context, object, ownProperties, if (!ValueMirror::getProperties(context, object, ownProperties,
accessorPropertiesOnly, &accumulator)) { accessorPropertiesOnly,
nonIndexedPropertiesOnly, &accumulator)) {
return createExceptionDetails(tryCatch, groupName, exceptionDetails); return createExceptionDetails(tryCatch, groupName, exceptionDetails);
} }
for (const PropertyMirror& mirror : mirrors) { for (const PropertyMirror& mirror : mirrors) {
......
...@@ -76,7 +76,8 @@ class InjectedScript final { ...@@ -76,7 +76,8 @@ class InjectedScript final {
Response getProperties( Response getProperties(
v8::Local<v8::Object>, const String16& groupName, bool ownProperties, v8::Local<v8::Object>, const String16& groupName, bool ownProperties,
bool accessorPropertiesOnly, WrapMode wrapMode, bool accessorPropertiesOnly, bool nonIndexedPropertiesOnly,
WrapMode wrapMode,
std::unique_ptr<protocol::Array<protocol::Runtime::PropertyDescriptor>>* std::unique_ptr<protocol::Array<protocol::Runtime::PropertyDescriptor>>*
result, result,
Maybe<protocol::Runtime::ExceptionDetails>*); Maybe<protocol::Runtime::ExceptionDetails>*);
......
...@@ -418,6 +418,7 @@ void V8RuntimeAgentImpl::callFunctionOn( ...@@ -418,6 +418,7 @@ void V8RuntimeAgentImpl::callFunctionOn(
Response V8RuntimeAgentImpl::getProperties( Response V8RuntimeAgentImpl::getProperties(
const String16& objectId, Maybe<bool> ownProperties, const String16& objectId, Maybe<bool> ownProperties,
Maybe<bool> accessorPropertiesOnly, Maybe<bool> generatePreview, Maybe<bool> accessorPropertiesOnly, Maybe<bool> generatePreview,
Maybe<bool> nonIndexedPropertiesOnly,
std::unique_ptr<protocol::Array<protocol::Runtime::PropertyDescriptor>>* std::unique_ptr<protocol::Array<protocol::Runtime::PropertyDescriptor>>*
result, result,
Maybe<protocol::Array<protocol::Runtime::InternalPropertyDescriptor>>* Maybe<protocol::Array<protocol::Runtime::InternalPropertyDescriptor>>*
...@@ -442,6 +443,7 @@ Response V8RuntimeAgentImpl::getProperties( ...@@ -442,6 +443,7 @@ Response V8RuntimeAgentImpl::getProperties(
response = scope.injectedScript()->getProperties( response = scope.injectedScript()->getProperties(
object, scope.objectGroupName(), ownProperties.fromMaybe(false), object, scope.objectGroupName(), ownProperties.fromMaybe(false),
accessorPropertiesOnly.fromMaybe(false), accessorPropertiesOnly.fromMaybe(false),
nonIndexedPropertiesOnly.fromMaybe(false),
generatePreview.fromMaybe(false) ? WrapMode::kWithPreview generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
: WrapMode::kNoPreview, : WrapMode::kNoPreview,
result, exceptionDetails); result, exceptionDetails);
......
...@@ -88,6 +88,7 @@ class V8RuntimeAgentImpl : public protocol::Runtime::Backend { ...@@ -88,6 +88,7 @@ class V8RuntimeAgentImpl : public protocol::Runtime::Backend {
Response getProperties( Response getProperties(
const String16& objectId, Maybe<bool> ownProperties, const String16& objectId, Maybe<bool> ownProperties,
Maybe<bool> accessorPropertiesOnly, Maybe<bool> generatePreview, Maybe<bool> accessorPropertiesOnly, Maybe<bool> generatePreview,
Maybe<bool> nonIndexedPropertiesOnly,
std::unique_ptr<protocol::Array<protocol::Runtime::PropertyDescriptor>>* std::unique_ptr<protocol::Array<protocol::Runtime::PropertyDescriptor>>*
result, result,
Maybe<protocol::Array<protocol::Runtime::InternalPropertyDescriptor>>* Maybe<protocol::Array<protocol::Runtime::InternalPropertyDescriptor>>*
......
...@@ -844,7 +844,7 @@ bool getPropertiesForPreview(v8::Local<v8::Context> context, ...@@ -844,7 +844,7 @@ bool getPropertiesForPreview(v8::Local<v8::Context> context,
: -1; : -1;
PreviewPropertyAccumulator accumulator(blocklist, skipIndex, nameLimit, PreviewPropertyAccumulator accumulator(blocklist, skipIndex, nameLimit,
indexLimit, overflow, properties); indexLimit, overflow, properties);
return ValueMirror::getProperties(context, object, false, false, return ValueMirror::getProperties(context, object, false, false, false,
&accumulator); &accumulator);
} }
...@@ -1178,6 +1178,7 @@ ValueMirror::~ValueMirror() = default; ...@@ -1178,6 +1178,7 @@ ValueMirror::~ValueMirror() = default;
bool ValueMirror::getProperties(v8::Local<v8::Context> context, bool ValueMirror::getProperties(v8::Local<v8::Context> context,
v8::Local<v8::Object> object, v8::Local<v8::Object> object,
bool ownProperties, bool accessorPropertiesOnly, bool ownProperties, bool accessorPropertiesOnly,
bool nonIndexedPropertiesOnly,
PropertyAccumulator* accumulator) { PropertyAccumulator* accumulator) {
v8::Isolate* isolate = context->GetIsolate(); v8::Isolate* isolate = context->GetIsolate();
v8::TryCatch tryCatch(isolate); v8::TryCatch tryCatch(isolate);
...@@ -1209,6 +1210,14 @@ bool ValueMirror::getProperties(v8::Local<v8::Context> context, ...@@ -1209,6 +1210,14 @@ bool ValueMirror::getProperties(v8::Local<v8::Context> context,
while (!iterator->Done()) { while (!iterator->Done()) {
bool isOwn = iterator->is_own(); bool isOwn = iterator->is_own();
if (!isOwn && ownProperties) break; if (!isOwn && ownProperties) break;
bool isIndex = iterator->is_array_index();
if (isIndex && nonIndexedPropertiesOnly) {
if (!iterator->Advance().FromMaybe(false)) {
CHECK(tryCatch.HasCaught());
return false;
}
continue;
}
v8::Local<v8::Name> v8Name = iterator->name(); v8::Local<v8::Name> v8Name = iterator->name();
v8::Maybe<bool> result = set->Has(context, v8Name); v8::Maybe<bool> result = set->Has(context, v8Name);
if (result.IsNothing()) return false; if (result.IsNothing()) return false;
...@@ -1301,7 +1310,7 @@ bool ValueMirror::getProperties(v8::Local<v8::Context> context, ...@@ -1301,7 +1310,7 @@ bool ValueMirror::getProperties(v8::Local<v8::Context> context,
configurable, configurable,
enumerable, enumerable,
isOwn, isOwn,
iterator->is_array_index(), isIndex,
isAccessorProperty && valueMirror, isAccessorProperty && valueMirror,
std::move(valueMirror), std::move(valueMirror),
std::move(getterMirror), std::move(getterMirror),
......
...@@ -75,6 +75,7 @@ class ValueMirror { ...@@ -75,6 +75,7 @@ class ValueMirror {
static bool getProperties(v8::Local<v8::Context> context, static bool getProperties(v8::Local<v8::Context> context,
v8::Local<v8::Object> object, bool ownProperties, v8::Local<v8::Object> object, bool ownProperties,
bool accessorPropertiesOnly, bool accessorPropertiesOnly,
bool nonIndexedPropertiesOnly,
PropertyAccumulator* accumulator); PropertyAccumulator* accumulator);
static void getInternalProperties( static void getInternalProperties(
v8::Local<v8::Context> context, v8::Local<v8::Object> object, v8::Local<v8::Context> context, v8::Local<v8::Object> object,
......
...@@ -185,3 +185,12 @@ Running test: testObjectWithProtoProperty ...@@ -185,3 +185,12 @@ Running test: testObjectWithProtoProperty
__proto__ own object undefined __proto__ own object undefined
Internal properties Internal properties
[[Prototype]] object undefined [[Prototype]] object undefined
Running test: testArrayNonIndexedPropertiesOnly
length own number 2
Internal properties
[[Prototype]] object undefined
Running test: testTypedArrayNonIndexedPropertiesOnly
Internal properties
[[Prototype]] object undefined
...@@ -106,6 +106,14 @@ InspectorTest.runAsyncTestSuite([ ...@@ -106,6 +106,14 @@ InspectorTest.runAsyncTestSuite([
async function testObjectWithProtoProperty() { async function testObjectWithProtoProperty() {
await logExpressionProperties('Object.defineProperty({}, "__proto__", {enumerable: true, value: {b:"aaa"}})'); await logExpressionProperties('Object.defineProperty({}, "__proto__", {enumerable: true, value: {b:"aaa"}})');
},
function testArrayNonIndexedPropertiesOnly() {
return logExpressionProperties('[1, 2]', {nonIndexedPropertiesOnly: true, ownProperties: true});
},
function testTypedArrayNonIndexedPropertiesOnly() {
return logExpressionProperties('new Int8Array(1)', {nonIndexedPropertiesOnly: true, ownProperties: true});
} }
]); ]);
......
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