Skip to content

Commit

Permalink
lib: add SafeArray to primordials and use it for FreeList
Browse files Browse the repository at this point in the history
  • Loading branch information
ExE-Boss committed Dec 22, 2020
1 parent 656ce92 commit 283189f
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 4 deletions.
3 changes: 2 additions & 1 deletion lib/internal/freelist.js
Expand Up @@ -2,14 +2,15 @@

const {
ReflectApply,
SafeArray,
} = primordials;

class FreeList {
constructor(name, max, ctor) {
this.name = name;
this.ctor = ctor;
this.max = max;
this.list = [];
this.list = new SafeArray();
}

alloc() {
Expand Down
40 changes: 37 additions & 3 deletions lib/internal/per_context/primordials.js
Expand Up @@ -109,19 +109,23 @@ const createSafeIterator = (factory, next) => {
return SafeIterator;
};

function makeSafe(unsafe, safe) {
function makeSafe(unsafe, safe, {
iteratorMethods = null,
constructorProperties = null,
prototypeProperties = null,
} = {}) {
if (Symbol.iterator in unsafe.prototype) {
const dummy = new unsafe();
let next; // We can reuse the same `next` method.

for (const key of Reflect.ownKeys(unsafe.prototype)) {
if (!Reflect.getOwnPropertyDescriptor(safe.prototype, key)) {
const desc = Reflect.getOwnPropertyDescriptor(unsafe.prototype, key);
if (
if (iteratorMethods?.includes(key) ?? (
typeof desc.value === 'function' &&
desc.value.length === 0 &&
Symbol.iterator in (desc.value.call(dummy) ?? {})
) {
)) {
const createIterator = uncurryThis(desc.value);
next ??= uncurryThis(createIterator(dummy).next);
const SafeIterator = createSafeIterator(createIterator, next);
Expand All @@ -135,7 +139,14 @@ function makeSafe(unsafe, safe) {
} else {
copyProps(unsafe.prototype, safe.prototype);
}
if (prototypeProperties !== null) {
Object.defineProperties(safe, prototypeProperties);
}

copyProps(unsafe, safe);
if (constructorProperties !== null) {
Object.defineProperties(safe, constructorProperties);
}

Object.setPrototypeOf(safe.prototype, null);
Object.freeze(safe.prototype);
Expand All @@ -146,6 +157,29 @@ primordials.makeSafe = makeSafe;

// Subclass the constructors because we need to use their prototype
// methods later.
primordials.SafeArray = makeSafe(
Array,
class SafeArray extends Array {
// This ensures that only the length taking overload is supported,
// all other uses should use `SafeArray.from` or `SafeArray.of`.
// This is necessary to support `ArraySpeciesCreate`, which invokes
// the constructor with argument `length`:
// https://tc39.es/ecma262/#sec-arrayspeciescreate
constructor(length = 0) {
super(+length);
}
},
{
// Many of the array methods have a length of 0 and return
// a primitive or an iterable that isn't an iterator, which breaks
// the assumptions about which methods return iterators in `makeSafe`
iteratorMethods: ['entries', 'keys', 'values', Symbol.iterator],
// `Array` doesn't have a `Symbol.toStringTag` by default
prototypeProperties: {
[Symbol.toStringTag]: { value: 'SafeArray' }
}
}
);
primordials.SafeMap = makeSafe(
Map,
class SafeMap extends Map {}
Expand Down

0 comments on commit 283189f

Please sign in to comment.