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

[JSC] Top-level function declarations should be lexical in module code #19207

Conversation

shvaikalesh
Copy link
Member

@shvaikalesh shvaikalesh commented Oct 18, 2023

2838f14

[JSC] Top-level function declarations should be lexical in module code
https://bugs.webkit.org/show_bug.cgi?id=263269
<rdar://problem/117086061>

Reviewed by Ross Kirsling.

The spec has at least 8 occurrences of

> It is a Syntax Error if the LexicallyDeclaredNames of X contains any duplicate entries.

early error rules that preclude duplicate lexical declarations. For backwards-compatibility,
LexicallyDeclaredNames [1] skips top-level function declarations inside `ScriptBody : StatementList`
by invoking TopLevelLexicallyDeclaredNames [2], which returns an empty list for them [3].

However, the semantics of LexicallyDeclaredNames is entirely different for `ModuleItem`
(also please see note #1). The fact that top-level function declarations are lexical in module code
is also evident during binding initialization [4].

This change makes top-level function declarations in module code behave like `let` rather than `var`,
introducing early errors that come with it, like disallowing duplicates with `var` and `function`.

Since inside declareFunction() we can't rely neither on `m_scriptMode` (which is always `Module`,
even for nested functions that absolutely should not throw SyntaxError for duplicate declarations),
nor on `m_parseMode` (it's already the parse mode of the declared function itself), this change
introduces isModuleCode() [5], refactoring parse mode handling in Scope.

Also, this patch aligns declareFunctionAsLet() with declareVariable(), called for `let` declarations,
by adding `m_declaredVariables` check, which may fail only in module code. Removes now incorrect
(for module code only) ASSERT that isn't particularly useful given how simple declareFunction() now is.

Aligns JSC with V8 and SpiderMonkey.

[1]: https://tc39.es/ecma262/#sec-static-semantics-lexicallydeclarednames
[2]: https://tc39.es/ecma262/#sec-static-semantics-toplevellexicallydeclarednames
[3]: https://tc39.es/ecma262/#prod-HoistableDeclaration
[4]: https://tc39.es/ecma262/#sec-source-text-module-record-initialize-environment (step 24.iii)
[5]: https://tc39.es/ecma262/#sec-types-of-source-code

* JSTests/modules/async-function-export.js: Moved to JSTests/stress/modules-syntax-error.js.
* JSTests/stress/modules-syntax-error.js:
* JSTests/test262/expectations.yaml: Mark 8 tests as passing.
* Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
* Source/JavaScriptCore/parser/Parser.cpp:
(JSC::Parser<LexerType>::Parser):
(JSC::Parser<LexerType>::parseFunctionInfo):
(JSC::Parser<LexerType>::parseMemberExpression):
* Source/JavaScriptCore/parser/Parser.h:
(JSC::Scope::setSourceParseMode):
(JSC::Scope::isGlobalCode const):
(JSC::Scope::isModuleCode const):
(JSC::Scope::declareFunctionAsLet):
(JSC::Scope::setIsGlobalCode):
(JSC::Scope::setIsModuleCode):
(JSC::Parser::declareFunction):
(JSC::Scope::setIsGlobalCodeScope): Deleted.
(JSC::Scope::isGlobalCodeScope const): Deleted.

Canonical link: https://commits.webkit.org/269485@main

fdc9b00

Misc iOS, tvOS & watchOS macOS Linux Windows
  πŸ§ͺ style   πŸ›  ios   πŸ›  mac   πŸ›  wpe   πŸ›  wincairo
  πŸ›  ios-sim   πŸ›  mac-AS-debug   πŸ§ͺ wpe-wk2
  πŸ§ͺ webkitperl   πŸ§ͺ ios-wk2   πŸ§ͺ api-mac   πŸ›  gtk
  πŸ§ͺ ios-wk2-wpt   πŸ§ͺ mac-wk1   πŸ§ͺ gtk-wk2
  πŸ›  πŸ§ͺ jsc   πŸ§ͺ api-ios   πŸ§ͺ mac-wk2   πŸ§ͺ api-gtk
  πŸ›  πŸ§ͺ jsc-arm64   πŸ›  tv   πŸ§ͺ mac-AS-debug-wk2   πŸ›  jsc-armv7
  πŸ›  tv-sim   πŸ§ͺ mac-wk2-stress   πŸ§ͺ jsc-armv7-tests
  πŸ›  watch   πŸ›  jsc-mips
βœ… πŸ›  πŸ§ͺ unsafe-merge   πŸ›  watch-sim   πŸ§ͺ jsc-mips-tests

@shvaikalesh shvaikalesh requested a review from a team as a code owner October 18, 2023 02:08
@shvaikalesh shvaikalesh self-assigned this Oct 18, 2023
@shvaikalesh shvaikalesh added the JavaScriptCore For bugs in JavaScriptCore, the JS engine used by WebKit, other than kxmlcore issues. label Oct 18, 2023
Copy link
Member

@rkirsling rkirsling left a comment

Choose a reason for hiding this comment

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

Fantastic! r=me

@shvaikalesh shvaikalesh force-pushed the eng/JSC-Top-level-function-declarations-should-be-lexical-in-module-code branch from a0cfa03 to fdc9b00 Compare October 18, 2023 20:25
@shvaikalesh shvaikalesh added the skip-ews Applied to prevent a change from being run on EWS label Oct 18, 2023
@shvaikalesh
Copy link
Member Author

Thank you Ross! Much appreciated πŸ™‡

@shvaikalesh shvaikalesh added the unsafe-merge-queue Applied to send a pull request to merge-queue, but skip building and testing label Oct 18, 2023
https://bugs.webkit.org/show_bug.cgi?id=263269
<rdar://problem/117086061>

Reviewed by Ross Kirsling.

The spec has at least 8 occurrences of

> It is a Syntax Error if the LexicallyDeclaredNames of X contains any duplicate entries.

early error rules that preclude duplicate lexical declarations. For backwards-compatibility,
LexicallyDeclaredNames [1] skips top-level function declarations inside `ScriptBody : StatementList`
by invoking TopLevelLexicallyDeclaredNames [2], which returns an empty list for them [3].

However, the semantics of LexicallyDeclaredNames is entirely different for `ModuleItem`
(also please see note WebKit#1). The fact that top-level function declarations are lexical in module code
is also evident during binding initialization [4].

This change makes top-level function declarations in module code behave like `let` rather than `var`,
introducing early errors that come with it, like disallowing duplicates with `var` and `function`.

Since inside declareFunction() we can't rely neither on `m_scriptMode` (which is always `Module`,
even for nested functions that absolutely should not throw SyntaxError for duplicate declarations),
nor on `m_parseMode` (it's already the parse mode of the declared function itself), this change
introduces isModuleCode() [5], refactoring parse mode handling in Scope.

Also, this patch aligns declareFunctionAsLet() with declareVariable(), called for `let` declarations,
by adding `m_declaredVariables` check, which may fail only in module code. Removes now incorrect
(for module code only) ASSERT that isn't particularly useful given how simple declareFunction() now is.

Aligns JSC with V8 and SpiderMonkey.

[1]: https://tc39.es/ecma262/#sec-static-semantics-lexicallydeclarednames
[2]: https://tc39.es/ecma262/#sec-static-semantics-toplevellexicallydeclarednames
[3]: https://tc39.es/ecma262/#prod-HoistableDeclaration
[4]: https://tc39.es/ecma262/#sec-source-text-module-record-initialize-environment (step 24.iii)
[5]: https://tc39.es/ecma262/#sec-types-of-source-code

* JSTests/modules/async-function-export.js: Moved to JSTests/stress/modules-syntax-error.js.
* JSTests/stress/modules-syntax-error.js:
* JSTests/test262/expectations.yaml: Mark 8 tests as passing.
* Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
* Source/JavaScriptCore/parser/Parser.cpp:
(JSC::Parser<LexerType>::Parser):
(JSC::Parser<LexerType>::parseFunctionInfo):
(JSC::Parser<LexerType>::parseMemberExpression):
* Source/JavaScriptCore/parser/Parser.h:
(JSC::Scope::setSourceParseMode):
(JSC::Scope::isGlobalCode const):
(JSC::Scope::isModuleCode const):
(JSC::Scope::declareFunctionAsLet):
(JSC::Scope::setIsGlobalCode):
(JSC::Scope::setIsModuleCode):
(JSC::Parser::declareFunction):
(JSC::Scope::setIsGlobalCodeScope): Deleted.
(JSC::Scope::isGlobalCodeScope const): Deleted.

Canonical link: https://commits.webkit.org/269485@main
@webkit-commit-queue webkit-commit-queue force-pushed the eng/JSC-Top-level-function-declarations-should-be-lexical-in-module-code branch from fdc9b00 to 2838f14 Compare October 18, 2023 20:30
@webkit-commit-queue
Copy link
Collaborator

Committed 269485@main (2838f14): https://commits.webkit.org/269485@main

Reviewed commits have been landed. Closing PR #19207 and removing active labels.

@webkit-commit-queue webkit-commit-queue merged commit 2838f14 into WebKit:main Oct 18, 2023
@webkit-commit-queue webkit-commit-queue removed the unsafe-merge-queue Applied to send a pull request to merge-queue, but skip building and testing label Oct 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
JavaScriptCore For bugs in JavaScriptCore, the JS engine used by WebKit, other than kxmlcore issues. skip-ews Applied to prevent a change from being run on EWS
Projects
None yet
4 participants