-
Notifications
You must be signed in to change notification settings - Fork 28
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
Implements globalThis slots #175
Conversation
Generally, this LGTM. I have a small preference that we check in some form of relevant test along side this change. @ptomato and @justingrant - this makes the slot map accessible outside the module (and so I suppose users could mess with said slot map to cause all sorts of problems). Of course this diverges from the spec, but is that an acceptable change to you both / do either of you have thoughts on how two versions of this polyfill could "communicate" with each other to avoid dual package hazards? |
I'm also curious about something — I can no longer find the comment but at one time I suggested that we migrate over time away from a private slots WeakMap and towards "Impl" objects that share their private members with each other. (This is not happening imminently; I haven't done any work whatsoever towards it.) I wonder if the dual package hazard would still be present in that case? I suspect it would, and would no longer be able to be solved by a global symbol. |
This sounds similar to #105 which was trying to replace the usage of GetIntrinsic with circular dependencies - maybe that helps narrow down where your comment was? I think that would have similar problems - at a high-level, if we intend to verify that something "is a specific Temporal thing", then we need access to that from independent executions of a script in order to avoid dual-(multi-?)package hazards, and more generally we need to ensure that any local state that can change the output of function calls remains in sync between the N versions. Slots was the first thing that came to mind, but I haven't delved deeply into the other pieces of module-local state to see whether there's more problems here. Conversely, I think the caches we have would not be a problem though they would affect the performance of an application as the caches would be out of sync. |
Agreed, which is why I wanted your opinion. Unlike the capturing of VM intrinsic functions I don't think there's a way to make sure that the WeakMap we get back from this Symbol can only be changed by the polyfill sources - anyone could easily get this weakmap even after the polyfill sources have loaded and adjust the content. |
I think we should move forward with this change, and we can consider alternatives to the static Symbol key (release build time hashing?) if needed. My only concern is setting up some CI testing that covers this, which I think should probably end up as part of |
I wonder if we could avoid exposing the slot map, by instead exposing a function that gets a value from the slot map given an object and a slot name, and another function that sets all the slots at once of an object that wasn't previously in the slot map? That way, slots couldn't be overwritten once an object was created, so the objects would still be immutable even if user code accessed the private symbols. |
I think that's a great idea - reducing the API surface down to only what we need seems reasonable. @tars0x9752 is that something you can look into? We'd need two symbols, one for each exposed function, but that seems pretty reasonable. We probably also want to adjust the map to be "write-once" - if something already has set a key we should throw. |
I'm not quit sure yet, but I'll look into it when I have time. And let me clarify one thing: When you say "expose", I read it as "expose through globalThis". Am I correct? |
Right - in the same way we are currently making the map itself accessible via the globalThis[symbol]. |
I did a quick test, and I might be wrong, but just exposing |
Depends on what rewriting you have in mind, I guess 😄 but that seems like it should be OK? |
Now the fixes are almost done and here's how it looks like. Sorry if it's not what you guys wanted to be. If it looks OK, I'll commit these changes to this PR branch as well, and let me know if it's not what you guys are looking for. Here's what I do:
|
I'd have probably changed CreateSlots to just take an argument that provides all the slots and their values at once, and removed SetSlot altogether. But I don't see anything wrong with doing it this way, either. |
9b5b46d
to
829c58b
Compare
Thanks for your responses. I've just updated this branch as well. And for now, I minimized the changes as in the comment here instead. Let me know if you prefer to remove SetSlot altogether. |
lib/slots.ts
Outdated
throw new TypeError('Missing slots for the given container'); | ||
} | ||
|
||
if (id in slots) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be better to write this as
const existingSlot = slots[id];
if (existingSlot) throw new TypeError(...);
slots[id] = value;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed it as suggested!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm so sorry @tars0x9752 - I didn't realize this was waiting for my review. One small comment, but otherwise this LGTM.
One more question: you confirmed this didn't have any dual-package hazards - is it possible (in a follow-up PR) to run an automated test for some of these things? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
Sorry, honestly I forgot about the details of this PR. So I don't think I'll be able to provide such a follow-up PR anytime soon. |
Oops, it looks like test262 is failing in Node v18 and above. 🤔 I'll look into it again when I have more time. |
Hmm, I have a feeling that the problem is related to A NARROW NO-BREAK SPACE (U+202f), do you know what the cause is? |
Arrrgh, this was caused by a regression in V8 (https://bugs.chromium.org/p/chromium/issues/detail?id=1416538) which broke Test262. Specifically broke changes that I made recently to prevent Node-version-specific behavior from breaking tests. Sigh. The fix will have to be made inside Test262. As long as those are the only tests that are failing, @12wrigja I think it's OK to ignore those failures since they're unrelated to this PR. |
I've sent #230 to add those to the expected failure list which will fix the CI. Your changes otherwise look good to me, so I'm going to rebase this in. Thanks for contributing! |
#164
Implements globalThis slots mentioned in #164 (comment) to fix the slots issue with dual package hazard.