Conversation
This commit introduces support for the with statement via IR, by replacing the previous AST transformation with a more robust alternative. **Logic:** - Identifiers are replaced with a conditional chain that checks the presence of a key in the object properties. - We need to keep track of each `with` statement depth. Hermes also uses a task queue to lazily compile functions, and for this reason, we also need to copy the `with` depths when adding the declaration to the queue. - Compared to an AST transformation, `buildConditionalChain` any call to the Builder will be executed in the same called order. This means we cannot generate the nested conditional chain starting from the inner condition. **Test262 results:** 92.98%. Cooled by trossimel
|
Hi @trossimel-sc! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
|
While the output is correct, I've noticed that when running in debug mode, it occasionally fails with the following message: And in this case the IR output seems to be incorrectly generated. This issue arises specifically when a store operation is present within the let e = 20;
with (obj) {
e = 30;
}Is there a straightforward way to handle this case? I'm not very familiar with Hermes IR, so I'm unsure why this failure occurs, while the output is still correct. Thank you for your help! Please feel free to respond once my CLA is signed, if needed. —I hope this process won't take much longer. 🫤 |
|
@trossimel-sc I haven't reviewed the PR, but I compiled it and looked at the IR output of your example: You are calling a helper method to check if AFAICT, instruction BTW, I think that we probably want a new bytecode instruction for this instead of calling a helper, but we can do that incrementally. Also, the helper should just be a "builtin", which is safer and easier to call. But these are details that we can address when we start the review. (We don't want to start reviewing before we know that we can accept the PR, I hope you understand) |
|
Thanks for the response and the assistance @tmikov |
|
great work 🎉 adding Fixes: #1056 to description should link the issue to this PR (auto-close on merge) |
|
Any progress here? |
- Lock down realm for a Hardened JavaScript (tamper-resistant JS) runtime execution environment (irreversible frozen realm)
- Remove ambient authority (unpermitted intrinsics) from global scope (PoLA/PoLP/zero-trust), replace dangerous legacy and non-standard properties (+ known JS engine bugs)
- Recursively/transitively (deep) freeze (lock down) ECMA262 (not host) built-in objects (i.e. primordials including hidden intrinsics) and tame (not scuttle) globals
- Turn JavaScript system into a Secure ECMAScript system with now enforced OCap (not identity/ACL based) security (an OCap language) to write defensively consistent programs
- Protect against prototype poisoning/pollution supply chain attacks from vulnerable/compromised (untrusted/malicious) 3rd party code/dependencies (attempting to access e.g. I/Onetwork,reading/stealing private data)
- ECMAScript > ES-strict (static+dynamic i.e. parse+runtime) > Secure ECMAScript (dynamic i.e. runtime)
- Use Endo (Agoric) production-grade (prev audited) SES lockdown (Hermes/JSC) shims
- SES Proposal partitioned into: Hardened JS (Lockdown) pattern (prerequisite for Compartments), TC39 Compartments (Stage 1), TC39 ShadowRealm (Stage 4 / ES2026)
- Supporting Compartments: TC39 Source Phase Imports (Stage 3), TC39 Module Expressions (prev: Blocks) (Stage 2) (e.g. const m = module { export const leet = 1337; }), TC39 Module Declarations (Stage 1)
- Noting already: (Moddable) XS (JS) engine - native SES and Compartments; TC53 (IoT) - SES and Compartments; Node.js core --frozen-intrinsics; Salesforce (Lightning Web Security) - SES
- github.com/tc39/proposal-compartments, github.com/tc39/proposal-source-phase-imports, github.com/tc39/proposal-module-declarations, github.com/tc39/proposal-module-expressions
- github.com/nodejs/node/blob/main/lib/internal/freeze_intrinsics.js, per_context/primordials.js
- Prepare realm for code/dependency isolation/sandboxing via new Compartments (stripped non-deterministic Math.random and Date.now) with LavaMoat
- Hook into JS bundler (Metro) final stage (resolve -> transform -> serialize)
- Polyfills: SES (Hermes) shim, repairIntrinsics (called with RN opts and preserved RN Promise), @react-native/js-polyfills, [no user vetted shims yet]
- github.com/LavaMoat/LavaMoat/blob/main/packages/react-native-lockdown/src/index.js
- Modules: RN InitializeCore -> (hardenIntrinsics) -> entry file (index.js)
- github.com/facebook/react-native/blob/main/packages/community-cli-plugin/src/utils/loadMetroConfig.js serializer, packages/metro-config/src/index.flow.js types
- Exclude SES shims from Babel transformation to preserve integrity (endojs/endo#662 Detect if ses is being transformed)
- Both Hermes and React Native (for legacy JSC/V8 during InitializeCore) load 'then/promise' polyfill
- SES removes the exposed internals `Promise._<onHandle|onReject|noop>` (`Promise._<l|m|n>`) so we restore them after repair as a vetted shim
- github.com/LavaMoat/LavaMoat/blob/main/packages/react-native-lockdown/src/repair.js, github.com/endojs/endo/blob/master/docs/lockdown.md
- github.com/facebook/hermes/blob/main/utils/promise/index.js, github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Core/polyfillPromise.js
- github.com/then/promise/blob/master/src/core.js (`Promise._<onHandle|onReject|noop`), github.com/then/promise/blob/master/src/es6-extensions.js
- Evade property override mistake ('Cannot assign to read-only property') via lockdown opt (`overrideTaming: 'severe'`)
- i.e. keep prototype immutable, but allow local instances to override methods (e.g. myObj.toString)
- endojs/endo#1855 Property override mistake, endojs/endo#2037 Ecosystem Compat (2024-02-05+)
- endojs/endo#1511 JSC compat, endojs/endo#1891 Hermes compat
- facebook/hermes#957 eval issue, facebook/hermes#1515 eval PR
- facebook/hermes#1056 eval issue, facebook/hermes#1571 eval PR
- hardenedjs.org, papers.agoric.com/documentation/guides/js-programming/hardened-js.html
- github.com/endojs/endo/blob/master/packages/ses/src/lockdown-shim.js, compartment-shim.js, make-evaluate.js (quad backflip), commons.js
- github.com/endojs/endo/blob/master/docs/guide.md, github.com/endojs/endo/blob/master/docs/reference.md
- github.com/tc39/how-we-work/blob/main/terminology.md, lavamoat.github.io/reference/glossary
- github.com/Moddable-OpenSource/moddable/blob/public/xs/sources/xsLockdown.c, xsModule.c, documentation/xs/XS%20Compartment.md
Resolve: #1803
- Lock down realm for a Hardened JavaScript (tamper-resistant JS) runtime execution environment (irreversible frozen realm)
- Remove ambient authority (unpermitted intrinsics) from global scope (PoLA/PoLP/zero-trust), replace dangerous legacy and non-standard properties (+ known JS engine bugs)
- Recursively/transitively (deep) freeze (lock down) ECMA262 (not host) built-in objects (i.e. primordials including hidden intrinsics) and tame (not scuttle) globals
- Turn JavaScript system into a Secure ECMAScript system with now enforced OCap (not identity/ACL based) security (an OCap language) to write defensively consistent programs
- Protect against prototype poisoning/pollution supply chain attacks from vulnerable/compromised (untrusted/malicious) 3rd party code/dependencies (attempting to access e.g. I/Onetwork,reading/stealing private data)
- ECMAScript > ES-strict (static+dynamic i.e. parse+runtime) > Secure ECMAScript (dynamic i.e. runtime)
- Use Endo (Agoric) production-grade (prev audited) SES lockdown (Hermes/JSC) shims
- SES Proposal partitioned into: Hardened JS (Lockdown) pattern (prerequisite for Compartments), TC39 Compartments (Stage 1), TC39 ShadowRealm (Stage 4 / ES2026)
- Supporting Compartments: TC39 Source Phase Imports (Stage 3), TC39 Module Expressions (prev: Blocks) (Stage 2) (e.g. const m = module { export const leet = 1337; }), TC39 Module Declarations (Stage 1)
- Noting already: (Moddable) XS (JS) engine - native SES and Compartments; TC53 (IoT) - SES and Compartments; Node.js core --frozen-intrinsics; Salesforce (Lightning Web Security) - SES
- github.com/tc39/proposal-compartments, github.com/tc39/proposal-source-phase-imports, github.com/tc39/proposal-module-declarations, github.com/tc39/proposal-module-expressions
- github.com/nodejs/node/blob/main/lib/internal/freeze_intrinsics.js, per_context/primordials.js
- Prepare realm for code/dependency isolation/sandboxing via new Compartments (stripped non-deterministic Math.random and Date.now) with LavaMoat
- Hook into JS bundler (Metro) final stage (resolve -> transform -> serialize)
- Polyfills: SES (Hermes) shim, repairIntrinsics (called with RN opts and preserved RN Promise), @react-native/js-polyfills, [no user vetted shims yet]
- github.com/LavaMoat/LavaMoat/blob/main/packages/react-native-lockdown/src/index.js
- Modules: RN InitializeCore -> (hardenIntrinsics) -> entry file (index.js)
- github.com/facebook/react-native/blob/main/packages/community-cli-plugin/src/utils/loadMetroConfig.js serializer, packages/metro-config/src/index.flow.js types
- Exclude SES shims from Babel transformation to preserve integrity (endojs/endo#662 Detect if ses is being transformed)
- Both Hermes and React Native (for legacy JSC/V8 during InitializeCore) load 'then/promise' polyfill
- SES removes the exposed internals `Promise._<onHandle|onReject|noop>` (`Promise._<l|m|n>`) so we restore them after repair as a vetted shim
- github.com/LavaMoat/LavaMoat/blob/main/packages/react-native-lockdown/src/repair.js, github.com/endojs/endo/blob/master/docs/lockdown.md
- github.com/facebook/hermes/blob/main/utils/promise/index.js, github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Core/polyfillPromise.js
- github.com/then/promise/blob/master/src/core.js (`Promise._<onHandle|onReject|noop`), github.com/then/promise/blob/master/src/es6-extensions.js
- Evade property override mistake ('Cannot assign to read-only property') via lockdown opt (`overrideTaming: 'severe'`)
- i.e. keep prototype immutable, but allow local instances to override methods (e.g. myObj.toString)
- endojs/endo#1855 Property override mistake, endojs/endo#2037 Ecosystem Compat (2024-02-05+)
- endojs/endo#1511 JSC compat, endojs/endo#1891 Hermes compat
- facebook/hermes#957 eval fn issue, facebook/hermes#1515 PR
- facebook/hermes#1056 with statement issue, facebook/hermes#1571 eval PR
- hardenedjs.org, papers.agoric.com/documentation/guides/js-programming/hardened-js.html
- github.com/endojs/endo/blob/master/packages/ses/src/lockdown-shim.js, compartment-shim.js, make-evaluate.js (quad backflip), commons.js
- github.com/endojs/endo/blob/master/docs/guide.md, github.com/endojs/endo/blob/master/docs/reference.md
- github.com/tc39/how-we-work/blob/main/terminology.md, lavamoat.github.io/reference/glossary
- github.com/Moddable-OpenSource/moddable/blob/public/xs/sources/xsLockdown.c, xsModule.c, documentation/xs/XS%20Compartment.md
Resolve: #1803
- Lock down realm for a Hardened JavaScript (tamper-resistant JS) runtime execution environment (irreversible frozen realm)
- Remove ambient authority (unpermitted intrinsics) from global scope (PoLA/PoLP/zero-trust), replace dangerous legacy and non-standard properties (+ known JS engine bugs)
- Recursively/transitively (deep) freeze (lock down) ECMA262 (not host) built-in objects (i.e. primordials including hidden intrinsics) and tame (not scuttle) globals
- Turn JavaScript system into a Secure ECMAScript system with now enforced OCap (not identity/ACL based) security (an OCap language) to write defensively consistent programs
- Protect against prototype poisoning/pollution supply chain attacks from vulnerable/compromised (untrusted/malicious) 3rd party code/dependencies (attempting to access e.g. I/Onetwork,reading/stealing private data)
- ECMAScript > ES-strict (static+dynamic i.e. parse+runtime) > Secure ECMAScript (dynamic i.e. runtime)
- Use Endo (Agoric) production-grade (prev audited) SES lockdown (Hermes/JSC) shims
- SES Proposal partitioned into: Hardened JS (Lockdown) pattern (prerequisite for Compartments), TC39 Compartments (Stage 1), TC39 ShadowRealm (Stage 4 / ES2026)
- Supporting Compartments: TC39 Source Phase Imports (Stage 3), TC39 Module Expressions (prev: Blocks) (Stage 2) (e.g. const m = module { export const leet = 1337; }), TC39 Module Declarations (Stage 1)
- Noting already: (Moddable) XS (JS) engine - native SES and Compartments; TC53 (IoT) - SES and Compartments; Node.js core --frozen-intrinsics; Salesforce (Lightning Web Security) - SES
- github.com/tc39/proposal-compartments, github.com/tc39/proposal-source-phase-imports, github.com/tc39/proposal-module-declarations, github.com/tc39/proposal-module-expressions
- github.com/nodejs/node/blob/main/lib/internal/freeze_intrinsics.js, per_context/primordials.js
- Prepare realm for code/dependency isolation/sandboxing via new Compartments (stripped non-deterministic Math.random and Date.now) with LavaMoat
- Hook into JS bundler (Metro) final stage (resolve -> transform -> serialize)
- Polyfills: SES (Hermes) shim, repairIntrinsics (called with RN opts and preserved RN Promise), @react-native/js-polyfills, [no user vetted shims yet]
- github.com/LavaMoat/LavaMoat/blob/main/packages/react-native-lockdown/src/index.js
- Modules: RN InitializeCore -> (hardenIntrinsics) -> entry file (index.js)
- github.com/facebook/react-native/blob/main/packages/community-cli-plugin/src/utils/loadMetroConfig.js serializer, packages/metro-config/src/index.flow.js types
- Exclude SES shims from Babel transformation to preserve integrity (endojs/endo#662 Detect if ses is being transformed)
- Both Hermes and React Native (for legacy JSC/V8 during InitializeCore) load 'then/promise' polyfill
- SES removes the exposed internals `Promise._<onHandle|onReject|noop>` (`Promise._<l|m|n>`) so we restore them after repair as a vetted shim
- github.com/LavaMoat/LavaMoat/blob/main/packages/react-native-lockdown/src/repair.js, github.com/endojs/endo/blob/master/docs/lockdown.md
- github.com/facebook/hermes/blob/main/utils/promise/index.js, github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Core/polyfillPromise.js
- github.com/then/promise/blob/master/src/core.js (`Promise._<onHandle|onReject|noop`), github.com/then/promise/blob/master/src/es6-extensions.js
- Evade property override mistake ('Cannot assign to read-only property') via lockdown opt (`overrideTaming: 'severe'`)
- i.e. keep prototype immutable, but allow local instances to override methods (e.g. myObj.toString)
- endojs/endo#1855 Property override mistake, endojs/endo#2037 Ecosystem Compat (2024-02-05+)
- endojs/endo#1511 JSC compat, endojs/endo#1891 Hermes compat
- facebook/hermes#957 eval fn issue, facebook/hermes#1515 PR
- facebook/hermes#1056 with statement issue, facebook/hermes#1571 PR
- hardenedjs.org, papers.agoric.com/documentation/guides/js-programming/hardened-js.html
- github.com/endojs/endo/blob/master/packages/ses/src/lockdown-shim.js, compartment-shim.js, make-evaluate.js (quad backflip), commons.js
- github.com/endojs/endo/blob/master/docs/guide.md, github.com/endojs/endo/blob/master/docs/reference.md
- github.com/tc39/how-we-work/blob/main/terminology.md, lavamoat.github.io/reference/glossary
- github.com/Moddable-OpenSource/moddable/blob/public/xs/sources/xsLockdown.c, xsModule.c, documentation/xs/XS%20Compartment.md
Resolve: #1803
Summary
This PR introduces support for the with statement via IR
createConditionalChainImplThe changes are designed to minimize disruption. The logic only activates when a with statement is present, and the bulk of the implementation is located in a separate file,
ESTreeIRGen-with.Test Plan