Skip to content

Commit e77e449

Browse files
committed
Web Inspector: Support ES2022 Private Fields
https://bugs.webkit.org/show_bug.cgi?id=254961 Reviewed by Patrick Angle and Justin Michaud. Web Inspector should show private fields when logging objects in the Console. As private field usage becomes more and more popular, not being able to see private fields in the Console will become increasingly disruptive to the debugging experience. * Source/JavaScriptCore/inspector/InjectedScriptSource.js: (InjectedScript.prototype._forEachPropertyDescriptor): (InjectedScript.prototype._forEachPropertyDescriptor.processProperty): * Source/JavaScriptCore/inspector/JSInjectedScriptHost.h: * Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp: (Inspector::JSInjectedScriptHost::getOwnPrivatePropertyDescriptors): Added. * Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp: (Inspector::JSInjectedScriptHostPrototype::finishCreation): (Inspector::jsInjectedScriptHostPrototypeFunctionGetOwnPrivatePropertyDescriptors): Added. Create a `InjectedScriptHost` method similar to `Object.getOwnPropertyDescriptors` but only for private fields. Use it when fetching property descriptors for the frontend to grab private fields just like all other public fields. * Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp: (JSC::PropertyListNode::emitDeclarePrivateFieldNames): Pass along the `PropertyNode::name` when creating a private symbol for the private field. * Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::emitCreatePrivateBrand): AFAIK there is no name in this scenario, just a private symbol to mark with a private brand, so use an empty string for the name. * Source/JavaScriptCore/runtime/JSGlobalObject.cpp: (JSC::createPrivateSymbol): (JSC::JSGlobalObject::init): Require a name when calling `@createPrivateSymbol`. * Source/JavaScriptCore/runtime/PrivateName.h: (JSC::PrivateName::PrivateName): Deleted. * Source/JavaScriptCore/runtime/Symbol.cpp: (JSC::Symbol::Symbol): * Source/WTF/wtf/text/SymbolImpl.h: * Source/WTF/wtf/text/SymbolImpl.cpp: (WTF::PrivateSymbolImpl::createNullSymbol): Deleted. * Source/WebKit/WebProcess/WebPage/IPCTestingAPI.cpp: (WebKit::IPCTestingAPI::JSMessageListener::JSMessageListener): Require that all `PrivateName` and `PrivateSymbolImpl` be created with a name (or at least an empty string). * Source/JavaScriptCore/inspector/protocol/Runtime.json: * Source/WebInspectorUI/UserInterface/Models/PropertyDescriptor.js: (WI.PropertyDescriptor): (WI.PropertyDescriptor.fromPayload): (WI.PropertyDescriptor.get isPrivateProperty): Added. Expose a way for clients to know that this `WI.PropertyDescriptor` is for a private field. * Source/WebInspectorUI/UserInterface/Models/PropertyPath.js: (WI.PropertyPath.prototype.appendPrivatePropertyName): Added. (WI.PropertyPath.prototype.appendPropertyDescriptor): Make sure that private fields are sufficiently hidden (i.e. do not show "Copy Path to Property" since it won't work). * Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.js: (WI.ObjectTreeView.comparePropertyDescriptors): Sort private fields above all other non-internal properties. * Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.js: (WI.ObjectTreePropertyTreeElement.prototype._createTitlePropertyStyle): * Source/WebInspectorUI/UserInterface/Views/ObjectTreePropertyTreeElement.css: (.object-tree-property .property-name:is(.private, .not-enumerable)): Renamed from `.object-tree-property .property-name.not-enumerable`. Display private fields as a greyed out property (similar to internal properties) in order to help emphasize their semi-unreachable nature. * LayoutTests/inspector/runtime/getDisplayableProperties.html: * LayoutTests/inspector/runtime/getDisplayableProperties-expected.txt: * LayoutTests/inspector/runtime/getProperties.html: * LayoutTests/inspector/runtime/getProperties-expected.txt: * LayoutTests/inspector/runtime/resources/property-descriptor-utilities.js: (ProtocolTest.PropertyDescriptorUtilities.logForEach): Canonical link: https://commits.webkit.org/262870@main
1 parent a465a8a commit e77e449

23 files changed

Lines changed: 291 additions & 31 deletions

‎LayoutTests/inspector/runtime/getDisplayableProperties-expected.txt‎

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,51 @@ Internal Properties:
132132
"boundThis" => null (object null) []
133133
"boundArgs" => "Array" (object array) []
134134

135+
-- Running test case: Runtime.getDisplayableProperties.Private.Instance
136+
Evaluating expression...
137+
Getting displayable properties...
138+
Properties:
139+
"#parentInstancePrivateProperty" => "parentInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | private]
140+
"#childInstancePrivateProperty" => "childInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | private]
141+
"parentInstancePublicProperty" => "parentInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
142+
"childInstancePublicProperty" => "childInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
143+
"__proto__" => "PrivateMembersTestClassChild" (object) [writable | configurable | isOwn]
144+
145+
-- Running test case: Runtime.getDisplayableProperties.Private.Constructor
146+
Evaluating expression...
147+
Getting displayable properties...
148+
Properties:
149+
"#childClassPrivateProperty" => "childClassPrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | private]
150+
"length" => 0 (number) [configurable | isOwn]
151+
"prototype" => "PrivateMembersTestClassChild" (object) [isOwn]
152+
"childClassPublicMethod" => "function childClassPublicMethod() { }" (function) [writable | configurable | isOwn]
153+
"childClassPublicGetter" => get "function () { }" (function) [configurable | isOwn]
154+
"childClassPublicGetter" => set undefined (undefined) [configurable | isOwn]
155+
"childClassPublicSetter" => get undefined (undefined) [configurable | isOwn]
156+
"childClassPublicSetter" => set "function (x) { }" (function) [configurable | isOwn]
157+
"childClassPublicGetterSetter" => get "function () { }" (function) [configurable | isOwn]
158+
"childClassPublicGetterSetter" => set "function (x) { }" (function) [configurable | isOwn]
159+
"toString" => "function toString() { return \"<redacted>\"; }" (function) [writable | configurable | isOwn]
160+
"childClassPublicProperty" => "childClassPublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
161+
"name" => "PrivateMembersTestClassChild" (string) [configurable | isOwn]
162+
"arguments" => "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error) [wasThrown]
163+
"caller" => "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error) [wasThrown]
164+
"__proto__" => "<redacted>" (function class) [writable | configurable | isOwn]
165+
166+
-- Running test case: Runtime.getDisplayableProperties.Private.Prototype
167+
Evaluating expression...
168+
Getting displayable properties...
169+
Properties:
170+
"constructor" => "<redacted>" (function class) [writable | configurable | isOwn]
171+
"childInstancePublicMethod" => "function childInstancePublicMethod() { }" (function) [writable | configurable | isOwn]
172+
"childInstancePublicGetter" => get "function () { }" (function) [configurable | isOwn]
173+
"childInstancePublicGetter" => set undefined (undefined) [configurable | isOwn]
174+
"childInstancePublicSetter" => get undefined (undefined) [configurable | isOwn]
175+
"childInstancePublicSetter" => set "function (x) { }" (function) [configurable | isOwn]
176+
"childInstancePublicGetterSetter" => get "function () { }" (function) [configurable | isOwn]
177+
"childInstancePublicGetterSetter" => set "function (x) { }" (function) [configurable | isOwn]
178+
"__proto__" => "PrivateMembersTestClassParent" (object) [writable | configurable | isOwn]
179+
135180
-- Running test case: Runtime.getDisplayableProperties.Promise.Resolved
136181
Evaluating expression...
137182
Getting displayable properties...

‎LayoutTests/inspector/runtime/getDisplayableProperties.html‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,24 @@
109109
expression: `(function(){}).bind(null, 1, 2, 3)`,
110110
});
111111

112+
addTestCase({
113+
name: "Runtime.getDisplayableProperties.Private.Instance",
114+
expression: `new PrivateMembersTestClassChild`,
115+
ownProperties: true,
116+
});
117+
118+
addTestCase({
119+
name: "Runtime.getDisplayableProperties.Private.Constructor",
120+
expression: `PrivateMembersTestClassChild`,
121+
ownProperties: true,
122+
});
123+
124+
addTestCase({
125+
name: "Runtime.getDisplayableProperties.Private.Prototype",
126+
expression: `PrivateMembersTestClassChild.prototype`,
127+
ownProperties: true,
128+
});
129+
112130
addTestCase({
113131
name: "Runtime.getDisplayableProperties.Promise.Resolved",
114132
expression: `Promise.resolve(123)`,

‎LayoutTests/inspector/runtime/getProperties-expected.txt‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,49 @@ Internal Properties:
114114
"boundThis" => null (object null) []
115115
"boundArgs" => "Array" (object array) []
116116

117+
-- Running test case: Runtime.getProperties.Private.Instance
118+
Evaluating expression...
119+
Getting own properties...
120+
Properties:
121+
"#parentInstancePrivateProperty" => "parentInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | private]
122+
"#childInstancePrivateProperty" => "childInstancePrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | private]
123+
"parentInstancePublicProperty" => "parentInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
124+
"childInstancePublicProperty" => "childInstancePublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
125+
"__proto__" => "PrivateMembersTestClassChild" (object) [writable | configurable | isOwn]
126+
127+
-- Running test case: Runtime.getProperties.Private.Constructor
128+
Evaluating expression...
129+
Getting own properties...
130+
Properties:
131+
"#childClassPrivateProperty" => "childClassPrivatePropertyValue" (string) [writable | enumerable | configurable | isOwn | private]
132+
"length" => 0 (number) [configurable | isOwn]
133+
"prototype" => "PrivateMembersTestClassChild" (object) [isOwn]
134+
"childClassPublicMethod" => "function childClassPublicMethod() { }" (function) [writable | configurable | isOwn]
135+
"childClassPublicGetter" => get "function () { }" (function) [configurable | isOwn]
136+
"childClassPublicGetter" => set undefined (undefined) [configurable | isOwn]
137+
"childClassPublicSetter" => get undefined (undefined) [configurable | isOwn]
138+
"childClassPublicSetter" => set "function (x) { }" (function) [configurable | isOwn]
139+
"childClassPublicGetterSetter" => get "function () { }" (function) [configurable | isOwn]
140+
"childClassPublicGetterSetter" => set "function (x) { }" (function) [configurable | isOwn]
141+
"toString" => "function toString() { return \"<redacted>\"; }" (function) [writable | configurable | isOwn]
142+
"childClassPublicProperty" => "childClassPublicPropertyValue" (string) [writable | enumerable | configurable | isOwn]
143+
"name" => "PrivateMembersTestClassChild" (string) [configurable | isOwn]
144+
"__proto__" => "<redacted>" (function class) [writable | configurable | isOwn]
145+
146+
-- Running test case: Runtime.getProperties.Private.Prototype
147+
Evaluating expression...
148+
Getting own properties...
149+
Properties:
150+
"constructor" => "<redacted>" (function class) [writable | configurable | isOwn]
151+
"childInstancePublicMethod" => "function childInstancePublicMethod() { }" (function) [writable | configurable | isOwn]
152+
"childInstancePublicGetter" => get "function () { }" (function) [configurable | isOwn]
153+
"childInstancePublicGetter" => set undefined (undefined) [configurable | isOwn]
154+
"childInstancePublicSetter" => get undefined (undefined) [configurable | isOwn]
155+
"childInstancePublicSetter" => set "function (x) { }" (function) [configurable | isOwn]
156+
"childInstancePublicGetterSetter" => get "function () { }" (function) [configurable | isOwn]
157+
"childInstancePublicGetterSetter" => set "function (x) { }" (function) [configurable | isOwn]
158+
"__proto__" => "PrivateMembersTestClassParent" (object) [writable | configurable | isOwn]
159+
117160
-- Running test case: Runtime.getProperties.Promise.Resolved
118161
Evaluating expression...
119162
Getting own properties...

‎LayoutTests/inspector/runtime/getProperties.html‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,24 @@
124124
ownProperties: true,
125125
});
126126

127+
addTestCase({
128+
name: "Runtime.getProperties.Private.Instance",
129+
expression: `new PrivateMembersTestClassChild`.replaceAll(/\s+/g, ' '),
130+
ownProperties: true,
131+
});
132+
133+
addTestCase({
134+
name: "Runtime.getProperties.Private.Constructor",
135+
expression: `PrivateMembersTestClassChild`.replaceAll(/\s+/g, ' '),
136+
ownProperties: true,
137+
});
138+
139+
addTestCase({
140+
name: "Runtime.getProperties.Private.Prototype",
141+
expression: `PrivateMembersTestClassChild.prototype`.replaceAll(/\s+/g, ' '),
142+
ownProperties: true,
143+
});
144+
127145
addTestCase({
128146
name: "Runtime.getProperties.Promise.Resolved",
129147
expression: `Promise.resolve(123)`,

‎LayoutTests/inspector/runtime/resources/property-descriptor-utilities.js‎

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,59 @@
1+
class PrivateMembersTestClassParent {
2+
parentInstancePublicProperty = 'parentInstancePublicPropertyValue';
3+
#parentInstancePrivateProperty = 'parentInstancePrivatePropertyValue';
4+
parentInstancePublicMethod() { }
5+
#parentInstancePrivateMethod() { }
6+
get parentInstancePublicGetter() { }
7+
set parentInstancePublicSetter(x) { }
8+
get parentInstancePublicGetterSetter() { }
9+
set parentInstancePublicGetterSetter(x) { }
10+
get #parentInstancePrivateGetter() { }
11+
set #parentInstancePrivateSetter(x) { }
12+
get #parentInstancePrivateGetterSetter() { }
13+
set #parentInstancePrivateGetterSetter(x) { }
14+
static parentClassPublicProperty = 'parentClassPublicPropertyValue';
15+
static #parentClassPrivateProperty = 'parentClassPrivatePropertyValue';
16+
static parentClassPublicMethod() { }
17+
static #parentClassPrivateMethod() { }
18+
static get parentClassPublicGetter() { }
19+
static set parentClassPublicSetter(x) { }
20+
static get parentClassPublicGetterSetter() { }
21+
static set parentClassPublicGetterSetter(x) { }
22+
static get #parentClassPrivateGetter() { }
23+
static set #parentClassPrivateSetter(x) { }
24+
static get #parentClassPrivateGetterSetter() { }
25+
static set #parentClassPrivateGetterSetter(x) { }
26+
static toString() { return "<redacted>"; }
27+
}
28+
29+
class PrivateMembersTestClassChild extends PrivateMembersTestClassParent {
30+
childInstancePublicProperty = 'childInstancePublicPropertyValue';
31+
#childInstancePrivateProperty = 'childInstancePrivatePropertyValue';
32+
childInstancePublicMethod() { }
33+
#childInstancePrivateMethod() { }
34+
get childInstancePublicGetter() { }
35+
set childInstancePublicSetter(x) { }
36+
get childInstancePublicGetterSetter() { }
37+
set childInstancePublicGetterSetter(x) { }
38+
get #childInstancePrivateGetter() { }
39+
set #childInstancePrivateSetter(x) { }
40+
get #childInstancePrivateGetterSetter() { }
41+
set #childInstancePrivateGetterSetter(x) { }
42+
static childClassPublicProperty = 'childClassPublicPropertyValue';
43+
static #childClassPrivateProperty = 'childClassPrivatePropertyValue';
44+
static childClassPublicMethod() { }
45+
static #childClassPrivateMethod() { }
46+
static get childClassPublicGetter() { }
47+
static set childClassPublicSetter(x) { }
48+
static get childClassPublicGetterSetter() { }
49+
static set childClassPublicGetterSetter(x) { }
50+
static get #childClassPrivateGetter() { }
51+
static set #childClassPrivateSetter(x) { }
52+
static get #childClassPrivateGetterSetter() { }
53+
static set #childClassPrivateGetterSetter(x) { }
54+
static toString() { return "<redacted>"; }
55+
}
56+
157
function makeArray(length) {
258
return Array(length).fill().map((item, i) => {
359
let code = (i % 2) ? ("Z".charCodeAt(0) - i) : ("A".charCodeAt(0) + i);
@@ -32,18 +88,23 @@ function makeWeakSet(length) {
3288
TestPage.registerInitializer(() => {
3389
ProtocolTest.PropertyDescriptorUtilities = {};
3490

35-
ProtocolTest.PropertyDescriptorUtilities.logForEach = function({name, value, ...extra}, index, array) {
91+
ProtocolTest.PropertyDescriptorUtilities.logForEach = function({name, value, get, set, ...extra}, index, array) {
3692
let maxPropertyNameLength = array.reduce((max, {name}) => name.length > max ? name.length : max, 0) + 2; // add 2 for the surrounding quotes
3793
let paddedName = JSON.stringify(name).padEnd(maxPropertyNameLength, " ");
3894
let descriptorKeys = [];
3995
for (let [key, value] of Object.entries(extra)) {
4096
if (value) {
41-
ProtocolTest.assert(typeof value === "boolean", `Property descriptor '${key}' has a non-boolean value '${value}'.`);
97+
ProtocolTest.assert(typeof value === "boolean", `Property descriptor '${key}' has a non-boolean value '${JSON.stringify(value)}'.`);
4298
descriptorKeys.push(key);
4399
}
44100
}
45101

46-
ProtocolTest.log(` ${paddedName} => ${ProtocolTest.PropertyDescriptorUtilities.stringifyRemoteObject(value)} [${descriptorKeys.join(" | ")}]`);
102+
if (value)
103+
ProtocolTest.log(` ${paddedName} => ${ProtocolTest.PropertyDescriptorUtilities.stringifyRemoteObject(value)} [${descriptorKeys.join(" | ")}]`);
104+
if (get)
105+
ProtocolTest.log(` ${paddedName} => get ${ProtocolTest.PropertyDescriptorUtilities.stringifyRemoteObject(get)} [${descriptorKeys.join(" | ")}]`);
106+
if (set)
107+
ProtocolTest.log(` ${paddedName} => set ${ProtocolTest.PropertyDescriptorUtilities.stringifyRemoteObject(set)} [${descriptorKeys.join(" | ")}]`);
47108
};
48109

49110
ProtocolTest.PropertyDescriptorUtilities.stringifyRemoteObject = function(remoteObject) {

‎Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2848,8 +2848,9 @@ void BytecodeGenerator::emitCreatePrivateBrand(const JSTextPosition& divot, cons
28482848
{
28492849
RefPtr<RegisterID> createPrivateSymbol = moveLinkTimeConstant(nullptr, LinkTimeConstant::createPrivateSymbol);
28502850

2851-
CallArguments arguments(*this, nullptr, 0);
2851+
CallArguments arguments(*this, nullptr, 1);
28522852
emitLoad(arguments.thisRegister(), jsUndefined());
2853+
emitLoad(arguments.argumentRegister(0), jsEmptyString(m_vm));
28532854
RegisterID* newSymbol = emitCall(finalDestination(nullptr, createPrivateSymbol.get()), createPrivateSymbol.get(), NoExpectedFunction, arguments, divot, divotStart, divotEnd, DebuggableCall::No);
28542855

28552856
Variable privateBrandVar = variable(propertyNames().builtinNames().privateBrandPrivateName());

‎Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,9 @@ void PropertyListNode::emitDeclarePrivateFieldNames(BytecodeGenerator& generator
572572
if (!createPrivateSymbol)
573573
createPrivateSymbol = generator.moveLinkTimeConstant(nullptr, LinkTimeConstant::createPrivateSymbol);
574574

575-
CallArguments arguments(generator, nullptr, 0);
575+
CallArguments arguments(generator, nullptr, 1);
576576
generator.emitLoad(arguments.thisRegister(), jsUndefined());
577+
generator.emitLoad(arguments.argumentRegister(0), *node.name());
577578
RefPtr<RegisterID> symbol = generator.emitCall(generator.finalDestination(nullptr, createPrivateSymbol.get()), createPrivateSymbol.get(), NoExpectedFunction, arguments, position(), position(), position(), DebuggableCall::No);
578579

579580
Variable var = generator.variable(*node.name());

‎Source/JavaScriptCore/inspector/InjectedScriptSource.js‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,7 @@ let InjectedScript = class InjectedScript extends PrototypelessObjectBase
768768
}
769769
}
770770

771-
function processProperty(o, propertyName, isOwnProperty)
771+
function processProperty(o, propertyName, isOwnProperty, privateDescriptor)
772772
{
773773
if (nameProcessed.@has(propertyName))
774774
return InjectedScript.PropertyFetchAction.Continue;
@@ -778,7 +778,7 @@ let InjectedScript = class InjectedScript extends PrototypelessObjectBase
778778
let name = toString(propertyName);
779779
let symbol = isSymbol(propertyName) ? propertyName : null;
780780

781-
let descriptor = @Object.@getOwnPropertyDescriptor(o, propertyName);
781+
let descriptor = privateDescriptor || @Object.@getOwnPropertyDescriptor(o, propertyName);
782782
if (!descriptor) {
783783
// FIXME: Bad descriptor. Can we get here?
784784
// Fall back to very restrictive settings.
@@ -800,6 +800,8 @@ let InjectedScript = class InjectedScript extends PrototypelessObjectBase
800800
descriptor.isOwn = true;
801801
if (symbol)
802802
descriptor.symbol = symbol;
803+
if (privateDescriptor)
804+
descriptor.private = true;
803805
return processDescriptor(descriptor, isOwnProperty);
804806
}
805807

@@ -812,6 +814,19 @@ let InjectedScript = class InjectedScript extends PrototypelessObjectBase
812814
let isOwnProperty = o === object;
813815
let shouldBreak = false;
814816

817+
let privatePropertyDescriptors = InjectedScriptHost.getOwnPrivatePropertyDescriptors(o);
818+
let privatePropertyNames = @Object.@getOwnPropertyNames(privatePropertyDescriptors);
819+
for (let i = 0; i < privatePropertyNames.length; ++i) {
820+
let privatePropertyName = privatePropertyNames[i];
821+
let result = processProperty(o, privatePropertyName, isOwnProperty, privatePropertyDescriptors[privatePropertyName]);
822+
shouldBreak = result === InjectedScript.PropertyFetchAction.Stop;
823+
if (shouldBreak)
824+
break;
825+
}
826+
827+
if (shouldBreak)
828+
break;
829+
815830
// FIXME: <https://webkit.org/b/201861> Web Inspector: show autocomplete entries for non-index properties on arrays
816831
if (isArrayLike && isOwnProperty) {
817832
for (let i = 0; i < o.length; ++i) {

‎Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "DateInstance.h"
3232
#include "DeferGCInlines.h"
3333
#include "DirectArguments.h"
34+
#include "EnumerationMode.h"
3435
#include "FunctionPrototype.h"
3536
#include "HeapAnalyzer.h"
3637
#include "HeapIterationScope.h"
@@ -56,6 +57,7 @@
5657
#include "MarkedSpaceInlines.h"
5758
#include "ObjectConstructor.h"
5859
#include "PreventCollectionScope.h"
60+
#include "PropertyNameArray.h"
5961
#include "ProxyObject.h"
6062
#include "RegExpObject.h"
6163
#include "ScopedArguments.h"
@@ -293,6 +295,38 @@ static JSObject* constructInternalProperty(JSGlobalObject* globalObject, const S
293295
return result;
294296
}
295297

298+
JSValue JSInjectedScriptHost::getOwnPrivatePropertyDescriptors(JSGlobalObject* globalObject, CallFrame* callFrame)
299+
{
300+
if (callFrame->argumentCount() < 1)
301+
return jsUndefined();
302+
303+
VM& vm = globalObject->vm();
304+
auto scope = DECLARE_THROW_SCOPE(vm);
305+
JSValue value = callFrame->uncheckedArgument(0);
306+
307+
JSObject* result = constructEmptyObject(globalObject);
308+
RETURN_IF_EXCEPTION(scope, JSValue());
309+
310+
JSObject* object = jsDynamicCast<JSObject*>(value);
311+
if (!object)
312+
return result;
313+
314+
PropertyNameArray propertyNames(vm, PropertyNameMode::StringsAndSymbols, PrivateSymbolMode::Include);
315+
JSObject::getOwnPropertyNames(object, globalObject, propertyNames, DontEnumPropertiesMode::Include);
316+
for (const auto& propertyName : propertyNames) {
317+
if (!propertyName.isPrivateName())
318+
continue;
319+
320+
// Authored private properties are indistinguishable from internal private properties except for their use of the `#` prefix.
321+
if (!propertyName.string().startsWith('#'))
322+
continue;
323+
324+
result->putDirect(vm, Identifier::fromString(vm, String(propertyName.impl()->isolatedCopy())), objectConstructorGetOwnPropertyDescriptor(globalObject, object, propertyName));
325+
}
326+
327+
return result;
328+
}
329+
296330
JSValue JSInjectedScriptHost::getInternalProperties(JSGlobalObject* globalObject, CallFrame* callFrame)
297331
{
298332
if (callFrame->argumentCount() < 1)

0 commit comments

Comments
 (0)