Skip to content

slides#4

Merged
naugtur merged 4 commits into
mainfrom
naugtur/slides
Jul 23, 2025
Merged

slides#4
naugtur merged 4 commits into
mainfrom
naugtur/slides

Conversation

@naugtur
Copy link
Copy Markdown
Member

@naugtur naugtur commented Jul 22, 2025

No description provided.

@naugtur naugtur requested a review from kriskowal July 22, 2025 13:48
@github-actions
Copy link
Copy Markdown

The rendered spec for this PR is available at https://endojs.github.io/proposal-new-global/pr/4.

Comment thread README.md Outdated
Comment on lines +70 to +72
AsyncFunction: typeof AsyncFunction,
GeneratorFunction: typeof GeneratorFunction,
AsyncGeneratorFunction: typeof AsyncGeneratorFunction,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I’m not sure how we would express that the new global would have unique versions of these intrinsics, but that they would not be own properties of the new global. They are accessible by evaluating syntax using the eval of the global. It might be good to add an Intersection Semantics section for Jordan’s Get Intrinsics proposal. My expectation is that newGlobal.getIntrinsic by whatever name, would also be a unique own property of each new global, and be able to address %AsyncFunction% and %AsyncFunctionPrototype% directly from internal slots of the global.

https://github.com/tc39/proposal-get-intrinsic

Comment thread README.md Outdated
Comment on lines +82 to +88
const thatGlobal = new globalThis.Global({
keys: ['Buffer'],
importHook,
importMeta,
});

thatGlobal.process = { env: process.env }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe we should spell these like newGlobal so newGlobal.globalThis is not confusing.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

that is almost a keyword for me from the times of arrow functions not being available and the popularity of Backbone and other class emulation, but the more times we can repeat the sequence new Global the better.

Comment thread slides/slides.md Outdated
Comment thread slides/slides.md Outdated
Global: typeof Global,
eval: typeof eval,
Function: typeof Function,
// and all permutations of Async and Generator
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
// and all permutations of Async and Generator

Oddly enough, all of the properties of the new global are covered by keys of the old global. Calling these three out just reïnforces the notion that they are not identical, where the others are, and that all the permutations on function constructor are also non-identical. We might need to turn to a single specific example of newGlobal.eval to make that point clear.

(async () => {}).constructor !==
new Global().eval('async () => {}').constructor

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

addressed it in details slide

Comment thread slides/slides.md Outdated
Comment thread slides/slides.md Outdated
Comment thread slides/slides.md
Comment thread slides/slides.md
> It also eliminates the concern where evaluators accepting any globalThis to use would clash with the host implementation's desire to use special objects only the host can create.
> No API to set a custom reference as global context for evaluators if it's not created via `new Global`
> When a new global is created it inherits all properties from parent global unless user specifies a list. Spec offers no opinions on minimal global, only demands that all evaluators are present.
---
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We need to take a position on the prototype chain of new global.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I know we do. I'm not sure now is the time.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I don't see how the prototype chain could become anything other than a reference to the same prototype chain that was originally there and for the isolation/sandboxing usecase it could be replaced or hardened depending on the needs.
Some complications around window.on etc. that are methods on the prototype is what we need to take into account

Comment thread slides/slides.md Outdated
Comment on lines +89 to +109
### Details - invariants
```js
globalThis.x = {};
const thatGlobal = new globalThis.Global({
keys: Object.keys(globalThis),
});
thatGlobal.eval !== thisGlobal.eval;
thatGlobal.Global !== thisGlobal.Global;
thatGlobal.Function !== thisGlobal.Function;
thatGlobal.eval("Object.getPrototypeOf(async () => {})") !==
Object.getPrototypeOf(async () => {});
thatGlobal.eval("Object.getPrototypeOf(function *() {})") !==
Object.getPrototypeOf(function* () {});
thatGlobal.eval("Object.getPrototypeOf(async function *() {})") !==
Object.getPrototypeOf(async function* () {});
const source = new ModuleSource("export default {}");
(await thatGlobal.eval("(...args) => import(...args)")(source)) !==
(await import(source));
thatGlobal.ModuleSource === thisGlobal.ModuleSource;
thatGlobal.Array === thisGlobal.Array;
thatGlobal.x === thisGlobal.x;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

All properties grafted by default

globalThis.x = {};
const newGlobal = new globalThis.Global();
newGlobal.Object === globalThis.Object;
newGlobal.x === globalThis.x;

Properties can be selectively grafted

globalThis.x = {};
const newGlobal = new Global({
  keys: [],
});
newGlobal.x === undefined;

Some properties undeniable

const newGlobal = new Global({
  keys: []
});
newGlobal.Object === globalThis.Object;

Own unique evaluators

const newGlobal = new Global();
newGlobal.eval !== thisGlobal.eval;
newGlobal.Global !== thisGlobal.Global;
newGlobal.Function !== thisGlobal.Function;

Other unique intrinsic evaluators

const newGlobal = new Global();
newGlobal.eval("Object.getPrototypeOf(async () => {})") !==
  Object.getPrototypeOf(async () => {});
newGlobal.eval("Object.getPrototypeOf(function *() {})") !==
  Object.getPrototypeOf(function* () {});
newGlobal.eval("Object.getPrototypeOf(async function *() {})") !==
  Object.getPrototypeOf(async function* () {});

Inherits host import hook and module map by default

const newGlobal = new Global();
const fs1 = await import("node:fs");
const fs2 = await newGlobal.eval('import("node:fs")');
fs1 === fs2; // if present

Can override import hook

const newGlobal = new Global({
  async importHook(specifier) {
    if (specifier === 'node:fs') {
      return import.source('mock-fs.js');
    } else {
      return import.source(specifier);
    }
  }
});
const fs = await newGlobal.eval('import("node:fs"))');

Closed holes

const fs = await (0, eval)('import("node:fs");
const AsyncFunction = (async () => {}).constructor;
const fs = await new AsyncFunction('return import("node:fs"))');
const fs = await import(new ModuleSource(`
  export default new Function('return import("node:fs")')();
`));

Closing every escape gadget requires rigor — but is possible!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'm not so sure about the undeniables. Might as well rely on their undeniability or on getIntrinsics.
When we discussed this, the idea to insert no opinions about the list of globals being available as a minimum was established and I thought that means with keys: [] the only globals that exist are Global and evaluator. Maybe no Global even.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Earlier, we had this:

const source = new ModuleSource("export default {}");
(await thatGlobal.eval("(...args) => import(...args)")(source)) !==
  (await import(source));
thatGlobal.ModuleSource === thisGlobal.ModuleSource;

and now it's fs1 === fs2; // if present

I think that's a change in assumptions about ModuleSource instantiation and module map. When is module map not inherited? If an import hook is created?

naugtur and others added 2 commits July 23, 2025 10:34
Co-authored-by: Kris Kowal <kriskowal@kriskowal.com>
@naugtur
Copy link
Copy Markdown
Member Author

naugtur commented Jul 23, 2025

Two comment threads are still open, but I'll merge and offer the slides link in the agenda.

@naugtur naugtur merged commit 151fe74 into main Jul 23, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants