Propagate exact lambda refs across bytecode slots

This commit is contained in:
Sergey Chernov 2026-04-21 13:20:27 +03:00
parent db3a780645
commit 30c9a5a565
2 changed files with 28 additions and 0 deletions

View File

@ -909,6 +909,7 @@ class BytecodeCompiler(
val slot = allocSlot()
builder.emit(Opcode.MAKE_LAMBDA_FN, id, slot)
updateSlotType(slot, SlotType.OBJ)
trackExactLambdaAtSlot(slot, ref)
return CompiledValue(slot, SlotType.OBJ)
}
val pos = (ref as? LambdaFnRef)?.pos ?: Pos.builtIn
@ -7724,6 +7725,7 @@ class BytecodeCompiler(
private fun emitMove(value: CompiledValue, dstSlot: Int) {
val srcSlot = value.slot
if (srcSlot == dstSlot) return
val srcIsScope = srcSlot < scopeSlotCount
val dstIsScope = dstSlot < scopeSlotCount
if (value.type != SlotType.UNKNOWN) {
@ -7731,12 +7733,14 @@ class BytecodeCompiler(
val addrSlot = ensureScopeAddr(srcSlot)
emitLoadFromAddr(addrSlot, dstSlot, value.type)
propagateObjClass(value.type, srcSlot, dstSlot)
propagateExactLambdaRef(value.type, srcSlot, dstSlot)
return
}
if (dstIsScope) {
val addrSlot = ensureScopeAddr(dstSlot)
emitStoreToAddr(srcSlot, addrSlot, value.type)
propagateObjClass(value.type, srcSlot, dstSlot)
propagateExactLambdaRef(value.type, srcSlot, dstSlot)
return
}
}
@ -7748,6 +7752,7 @@ class BytecodeCompiler(
else -> builder.emit(Opcode.BOX_OBJ, srcSlot, dstSlot)
}
propagateObjClass(value.type, srcSlot, dstSlot)
propagateExactLambdaRef(value.type, srcSlot, dstSlot)
}
private fun propagateObjClass(type: SlotType, srcSlot: Int, dstSlot: Int) {
@ -7776,6 +7781,14 @@ class BytecodeCompiler(
}
}
private fun propagateExactLambdaRef(type: SlotType, srcSlot: Int, dstSlot: Int) {
if (type == SlotType.OBJ || type == SlotType.UNKNOWN) {
trackExactLambdaAtSlot(dstSlot, exactLambdaRefBySlot[srcSlot])
} else {
trackExactLambdaAtSlot(dstSlot, null)
}
}
private fun setPos(pos: Pos?) {
currentPos = pos
builder.setPos(pos)

View File

@ -346,6 +346,21 @@ class BytecodeRecentOpsTest {
assertEquals(12, scope.eval("calc()").toInt())
}
@Test
fun nestedInlineLambdaParamCallAvoidsCallSlot() = runTest {
val scope = Script.newScope()
scope.eval(
"""
fun calc() {
{ g -> g(10) }({ x -> x + 1 })
}
""".trimIndent()
)
val disasm = scope.disassembleSymbol("calc")
assertFalse(disasm.contains("CALL_SLOT"), disasm)
assertEquals(11, scope.eval("calc()").toInt())
}
@Test
fun letLiteralUsesInlineBytecode() = runTest {
val scope = Script.newScope()