Skip to content

[JSC] Add emitBytecodeInConditionContext for optional chaining#61415

Merged
webkit-commit-queue merged 1 commit into
WebKit:mainfrom
sosukesuzuki:eng/optimize-optional-chaining-in-conditional-context
Apr 25, 2026
Merged

[JSC] Add emitBytecodeInConditionContext for optional chaining#61415
webkit-commit-queue merged 1 commit into
WebKit:mainfrom
sosukesuzuki:eng/optimize-optional-chaining-in-conditional-context

Conversation

@sosukesuzuki
Copy link
Copy Markdown
Contributor

@sosukesuzuki sosukesuzuki commented Mar 26, 2026

bfab895

[JSC] Add `emitBytecodeInConditionContext` for optional chaining
https://bugs.webkit.org/show_bug.cgi?id=310815

Reviewed by Yusuke Suzuki.

`if (a?.x)` emitted `mov Undefined` + `jfalse` on short-circuit, even
though undefined is always falsy. This wastes 2 instructions (8 -> 6)
and requires materializing the undefined constant.

Implement OptionalChainNode::emitBytecodeInConditionContext to route
the short-circuit bail-out directly to falseTarget instead of
materializing undefined. The optimization composes with existing
condition-context handling in LogicalNotNode, LogicalOpNode, and
ConditionalNode, so patterns like `if (!a?.x)`, `if (a?.x && b?.y)`,
`while (node?.next)`, and `a?.x ? 1 : 2` are optimized automatically.

`delete a?.x` is excluded since its short-circuit result is true, not
undefined.

Before:
    [ 1] jundefined_or_null arg1, ->12
    [ 4] get_by_id loc5, arg1, "x"
    [10] jmp ->15
    [12] mov loc5, Undefined
    [15] jfalse loc5, ->20
    [18] ret 1
    [20] ret 2

After:
    [ 1] jundefined_or_null arg1, ->15
    [ 4] get_by_id loc5, arg1, "x"
    [10] jfalse loc5, ->15
    [13] ret 1
    [15] ret 2

Test: JSTests/stress/optional-chaining-in-condition-context.js

* JSTests/stress/optional-chaining-in-condition-context.js: Added.
(shouldBe):
(testNested):
(testNot):
(testAnd):
(testOr):
(testTernary):
(testWhile):
(testDoWhile):
(testFor):
(testOptCall):
(testBracket):
(testDelete):
(testDeep5):
(testMixed):
(testPrimitive):
(testComplexLogic):
(testNestedTernary):
(testDoubleNot):
(testSideEffect):
(testBracketSideEffect):
(let.getterObj.get x):
(let.getterFalsy.get x):
(let.getterThrows.get x):
(testGetter):
(testGetterInTry):
(testProxy):
(testSymbol):
(testCompareUndef):
(testCompareNull):
(testCoalesce):
(testParenthesized):
(testIfElseChain):
(testSwitch):
(testPoly):
(testFinally):
(testGenerator):
(async testAsync):
(testThis):
(testInnerChain):
(testComma):
(get t):
(has):
* Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::pushOptionalChainTarget):
(JSC::BytecodeGenerator::discardOptionalChainTarget):
* Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h:
* Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp:
(JSC::OptionalChainNode::emitBytecodeInConditionContext):
* Source/JavaScriptCore/parser/Nodes.h:

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

25a17af

Misc iOS, visionOS, tvOS & watchOS macOS Linux Windows
✅ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe ✅ 🛠 win
✅ 🛠 ios-sim ✅ 🛠 mac-AS-debug ✅ 🧪 wpe-wk2 ✅ 🧪 win-tests
✅ 🧪 webkitperl ✅ 🧪 ios-wk2 ✅ 🧪 api-mac ✅ 🧪 api-wpe
✅ 🧪 ios-wk2-wpt ✅ 🧪 api-mac-debug ✅ 🛠 gtk3-libwebrtc
✅ 🛠 🧪 jsc ✅ 🧪 api-ios ✅ 🧪 mac-wk1 ✅ 🛠 gtk
✅ 🛠 🧪 jsc-debug-arm64 ✅ 🛠 ios-safer-cpp ✅ 🧪 mac-wk2 ✅ 🧪 gtk-wk2
✅ 🛠 vision ✅ 🧪 mac-AS-debug-wk2 ✅ 🧪 api-gtk
✅ 🛠 🧪 merge ✅ 🛠 vision-sim ✅ 🧪 mac-wk2-stress ✅ 🛠 playstation
✅ 🧪 vision-wk2 ✅ 🧪 mac-intel-wk2 ✅ 🛠 jsc-armv7
✅ 🛠 tv ✅ 🛠 mac-safer-cpp ✅ 🧪 jsc-armv7-tests
✅ 🛠 tv-sim
✅ 🛠 watch
✅ 🛠 watch-sim

@sosukesuzuki sosukesuzuki self-assigned this Mar 26, 2026
@sosukesuzuki sosukesuzuki added the JavaScriptCore For bugs in JavaScriptCore, the JS engine used by WebKit, other than kxmlcore issues. label Mar 26, 2026
@sosukesuzuki sosukesuzuki marked this pull request as ready for review March 26, 2026 19:12
@sosukesuzuki sosukesuzuki requested a review from a team as a code owner March 26, 2026 19:12
@sosukesuzuki sosukesuzuki force-pushed the eng/optimize-optional-chaining-in-conditional-context branch from f26a233 to 25a17af Compare April 22, 2026 07:58
@sosukesuzuki sosukesuzuki added the merge-queue Applied to send a pull request to merge-queue label Apr 25, 2026
https://bugs.webkit.org/show_bug.cgi?id=310815

Reviewed by Yusuke Suzuki.

`if (a?.x)` emitted `mov Undefined` + `jfalse` on short-circuit, even
though undefined is always falsy. This wastes 2 instructions (8 -> 6)
and requires materializing the undefined constant.

Implement OptionalChainNode::emitBytecodeInConditionContext to route
the short-circuit bail-out directly to falseTarget instead of
materializing undefined. The optimization composes with existing
condition-context handling in LogicalNotNode, LogicalOpNode, and
ConditionalNode, so patterns like `if (!a?.x)`, `if (a?.x && b?.y)`,
`while (node?.next)`, and `a?.x ? 1 : 2` are optimized automatically.

`delete a?.x` is excluded since its short-circuit result is true, not
undefined.

Before:
    [ 1] jundefined_or_null arg1, ->12
    [ 4] get_by_id loc5, arg1, "x"
    [10] jmp ->15
    [12] mov loc5, Undefined
    [15] jfalse loc5, ->20
    [18] ret 1
    [20] ret 2

After:
    [ 1] jundefined_or_null arg1, ->15
    [ 4] get_by_id loc5, arg1, "x"
    [10] jfalse loc5, ->15
    [13] ret 1
    [15] ret 2

Test: JSTests/stress/optional-chaining-in-condition-context.js

* JSTests/stress/optional-chaining-in-condition-context.js: Added.
(shouldBe):
(testNested):
(testNot):
(testAnd):
(testOr):
(testTernary):
(testWhile):
(testDoWhile):
(testFor):
(testOptCall):
(testBracket):
(testDelete):
(testDeep5):
(testMixed):
(testPrimitive):
(testComplexLogic):
(testNestedTernary):
(testDoubleNot):
(testSideEffect):
(testBracketSideEffect):
(let.getterObj.get x):
(let.getterFalsy.get x):
(let.getterThrows.get x):
(testGetter):
(testGetterInTry):
(testProxy):
(testSymbol):
(testCompareUndef):
(testCompareNull):
(testCoalesce):
(testParenthesized):
(testIfElseChain):
(testSwitch):
(testPoly):
(testFinally):
(testGenerator):
(async testAsync):
(testThis):
(testInnerChain):
(testComma):
(get t):
(has):
* Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::pushOptionalChainTarget):
(JSC::BytecodeGenerator::discardOptionalChainTarget):
* Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h:
* Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp:
(JSC::OptionalChainNode::emitBytecodeInConditionContext):
* Source/JavaScriptCore/parser/Nodes.h:

Canonical link: https://commits.webkit.org/312001@main
@webkit-commit-queue webkit-commit-queue force-pushed the eng/optimize-optional-chaining-in-conditional-context branch from 25a17af to bfab895 Compare April 25, 2026 02:54
@webkit-commit-queue
Copy link
Copy Markdown
Collaborator

Committed 312001@main (bfab895): https://commits.webkit.org/312001@main

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

@webkit-commit-queue webkit-commit-queue merged commit bfab895 into WebKit:main Apr 25, 2026
@webkit-commit-queue webkit-commit-queue removed the merge-queue Applied to send a pull request to merge-queue label Apr 25, 2026
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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants