Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: use null-prototype objects for property descriptors #43270

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 42 additions & 39 deletions lib/internal/encoding.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
// https://encoding.spec.whatwg.org

const {
ArrayPrototypeMap,
ObjectCreate,
ObjectDefineProperties,
ObjectEntries,
ObjectFromEntries,
ObjectGetOwnPropertyDescriptors,
ObjectSetPrototypeOf,
ObjectValues,
SafeMap,
StringPrototypeSlice,
Symbol,
Expand Down Expand Up @@ -533,48 +532,52 @@ function makeTextDecoderJS() {
}

// Mix in some shared properties.
ObjectDefineProperties(
TextDecoder.prototype,
ObjectFromEntries(ArrayPrototypeMap(ObjectEntries(ObjectGetOwnPropertyDescriptors({
get encoding() {
validateDecoder(this);
return this[kEncoding];
},

get fatal() {
validateDecoder(this);
return (this[kFlags] & CONVERTER_FLAGS_FATAL) === CONVERTER_FLAGS_FATAL;
},

get ignoreBOM() {
validateDecoder(this);
return (this[kFlags] & CONVERTER_FLAGS_IGNORE_BOM) ===
const sharedProperties = ObjectGetOwnPropertyDescriptors({
get encoding() {
validateDecoder(this);
return this[kEncoding];
},

get fatal() {
validateDecoder(this);
return (this[kFlags] & CONVERTER_FLAGS_FATAL) === CONVERTER_FLAGS_FATAL;
},

get ignoreBOM() {
validateDecoder(this);
return (this[kFlags] & CONVERTER_FLAGS_IGNORE_BOM) ===
CONVERTER_FLAGS_IGNORE_BOM;
},
},

[inspect](depth, opts) {
validateDecoder(this);
if (typeof depth === 'number' && depth < 0)
return this;
const constructor = getConstructorOf(this) || TextDecoder;
const obj = ObjectCreate({ constructor });
obj.encoding = this.encoding;
obj.fatal = this.fatal;
obj.ignoreBOM = this.ignoreBOM;
if (opts.showHidden) {
obj[kFlags] = this[kFlags];
obj[kHandle] = this[kHandle];
}
// Lazy to avoid circular dependency
const { inspect } = require('internal/util/inspect');
return `${constructor.name} ${inspect(obj)}`;
[inspect](depth, opts) {
validateDecoder(this);
if (typeof depth === 'number' && depth < 0)
return this;
const constructor = getConstructorOf(this) || TextDecoder;
const obj = ObjectCreate({ constructor });
obj.encoding = this.encoding;
obj.fatal = this.fatal;
obj.ignoreBOM = this.ignoreBOM;
if (opts.showHidden) {
obj[kFlags] = this[kFlags];
obj[kHandle] = this[kHandle];
}
})), ({ 0: key, 1: desc }) => [key, { __proto__: null, ...desc }]))
);
// Lazy to avoid circular dependency
const { inspect } = require('internal/util/inspect');
return `${constructor.name} ${inspect(obj)}`;
}
});
const propertiesValues = ObjectValues(sharedProperties);
for (let i = 0; i < propertiesValues.length; i++) {
// We want to use null-prototype objects to not rely on globally mutable
// %Object.prototype%.
ObjectSetPrototypeOf(propertiesValues[i], null);
}
sharedProperties[inspect].enumerable = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why mutate it instead of spreading it in like below?:

Copy link
Contributor Author

@aduh95 aduh95 Jun 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not mutate it instead? If mutating is not an option, I think I'd prefer ObjectDefineProperty(TextDecoder.prototype, inspect, { __proto__: null, enumerable: false }); over your suggestion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mutation is something that both slows things down (by changing the object's shape) and is also conceptually distasteful, so in general it's nicer to create objects wholesale rather than ever altering one.

go with whatever you prefer, obviously

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless someone else wants to take a side, I think I'm going to keep it as is. I'm fine with whichever solution, but mutating sharedProperties seems the most natural to me in this instance.


ObjectDefineProperties(TextDecoder.prototype, {
decode: kEnumerableProperty,
[inspect]: { __proto__: null, enumerable: false },
...sharedProperties,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
...sharedProperties,
...sharedProperties,
[inspect]: { __proto__: null, ...sharedProperties[inspect], enumerable: false },

[SymbolToStringTag]: {
__proto__: null,
configurable: true,
Expand Down
17 changes: 9 additions & 8 deletions lib/internal/worker/js_transferable.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
'use strict';
const {
ArrayPrototypeMap,
Error,
ObjectDefineProperties,
ObjectEntries,
ObjectFromEntries,
ObjectGetOwnPropertyDescriptors,
ObjectGetPrototypeOf,
ObjectSetPrototypeOf,
ObjectValues,
ReflectConstruct,
StringPrototypeSplit,
} = primordials;
Expand Down Expand Up @@ -43,11 +41,14 @@ function setup() {

function makeTransferable(obj) {
const inst = ReflectConstruct(JSTransferable, [], obj.constructor);
ObjectDefineProperties(inst,
ObjectFromEntries(ArrayPrototypeMap(
ObjectEntries(ObjectGetOwnPropertyDescriptors(obj)),
({ 0: key, 1: desc }) => [key, { __proto__: null, ...desc }]
)));
const properties = ObjectGetOwnPropertyDescriptors(obj);
const propertiesValues = ObjectValues(properties);
for (let i = 0; i < propertiesValues.length; i++) {
// We want to use null-prototype objects to not rely on globally mutable
// %Object.prototype%.
ObjectSetPrototypeOf(propertiesValues[i], null);
}
ObjectDefineProperties(inst, properties);
ObjectSetPrototypeOf(inst, ObjectGetPrototypeOf(obj));
return inst;
}
Expand Down