-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[JSC] Redeclaring parameter of a generator / async function makes it …
…`undefined` https://bugs.webkit.org/show_bug.cgi?id=223533 <rdar://problem/75899149> Reviewed by Yusuke Suzuki. Since under the hood, a generator / async function is implemented using two functions (wrapper and body), parameter redeclaration with `var` requires special care. Given the bytecode for a generator / async body function is generated with the result of reparsing, we can't consult parent scope in parser and detect which declarations shadow parameters of the wrapper function, hence the only way to pass that information is via bytecode generator, in rare data of UnlinkedFunctionExecutable. This patch prevents createVariable() from being called on `var` declarations that would otherwise erroneously shadow generator / async wrapper function parameters, downgrading them to VarKind::Invalid and emitting extra get_from_scope / resolve_scope ops as if `var foo;` declarations were missing. It's sensible and safe as long as Annex B function hoisting [1] is aligned and shadowed generator / async wrapper function parameters are marked as captured (done conservatively for all parameters). Fixes long-standing bug that resulted in Safari breaking on minified code produced by UglifyJS in default configuration [2]. [1]: https://tc39.es/ecma262/#sec-web-compat-functiondeclarationinstantiation (step 29.a.ii) [2]: mishoo/UglifyJS#5032 * JSTests/stress/regress-223533.js: Added. * Source/JavaScriptCore/builtins/BuiltinExecutables.cpp: (JSC::BuiltinExecutables::createExecutable): * Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp: (JSC::generateUnlinkedFunctionCodeBlock): (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): * Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h: * Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::BytecodeGenerator): (JSC::BytecodeGenerator::hoistSloppyModeFunctionIfNecessary): (JSC::BytecodeGenerator::getParameterNames const): (JSC::BytecodeGenerator::emitNewClassFieldInitializerFunction): * Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h: (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::makeFunction): * Source/JavaScriptCore/runtime/CachedTypes.cpp: (JSC::CachedFunctionExecutableRareData::encode): (JSC::CachedFunctionExecutableRareData::decode const): * Source/JavaScriptCore/runtime/CodeCache.cpp: (JSC::generateUnlinkedCodeBlockImpl): (JSC::CodeCache::getUnlinkedGlobalFunctionExecutable): Canonical link: https://commits.webkit.org/272666@main
- Loading branch information
Alexey Shvayka
committed
Jan 5, 2024
1 parent
f4776fc
commit 8f6b201
Showing
8 changed files
with
135 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
function shouldBe(actual, expected) { | ||
if (actual !== expected) | ||
throw new Error(`Bad value: ${actual}!`); | ||
} | ||
|
||
function* test1(foo) { | ||
shouldBe(foo, 1); | ||
var foo; | ||
shouldBe(foo, 1); | ||
} | ||
|
||
function* test2(...foo) { | ||
shouldBe(`${foo}`, "2,2,2"); | ||
var foo = 2; | ||
shouldBe(foo, 2); | ||
} | ||
|
||
async function test3([foo]) { | ||
shouldBe(foo, 3); | ||
var foo; | ||
shouldBe(foo, 3); | ||
} | ||
|
||
async function test4(foo) { | ||
shouldBe(foo, 4); | ||
var foo; | ||
shouldBe(foo, 4); | ||
} | ||
|
||
async function* test5({foo}) { | ||
shouldBe(foo, 5); | ||
var foo = 5; | ||
shouldBe(foo, 5); | ||
} | ||
|
||
function* hoistingTest1(foo) { | ||
shouldBe(foo, 1); | ||
{ | ||
function foo() { return "hoisted"; } | ||
} | ||
shouldBe(foo, 1); | ||
} | ||
|
||
async function* hoistingTest2([foo]) { | ||
shouldBe(foo, 2); | ||
if (true) { | ||
function foo() { return "hoisted"; } | ||
} | ||
shouldBe(foo, 2); | ||
} | ||
|
||
(async function() { | ||
try { | ||
for (let _ of test1(1)) {} | ||
for (let _ of test2(2, 2, 2)) {} | ||
await test3([3]); | ||
await test4(4); | ||
for await (let _ of test5({foo: 5})) {} | ||
|
||
for (let _ of hoistingTest1(1)) {} | ||
for await (let _ of hoistingTest2([2])) {} | ||
} catch (error) { | ||
print(`FAIL! ${error}\n${error.stack}`); | ||
$vm.abort(); | ||
} | ||
})(); | ||
|
||
drainMicrotasks(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.