Stabilize bytecode interpreter and fallbacks

This commit is contained in:
sergeych committed 2026-01-26 22:13:30 +03:00
1 parent 2f4462858b
commit 7de856fc62
15 files changed
+728 -115

No files matched your search

@@ -17,7 +17,12 @@
import kotlinx.coroutines.test.runTest
import net.sergeych.lyng.Benchmarks
import net.sergeych.lyng.eval
import net.sergeych.lyng.Compiler
import net.sergeych.lyng.ForInStatement
import net.sergeych.lyng.Script
import net.sergeych.lyng.Statement
import net.sergeych.lyng.bytecode.BytecodeDisassembler
import net.sergeych.lyng.bytecode.BytecodeStatement
import net.sergeych.lyng.obj.ObjInt
import kotlin.time.TimeSource
import kotlin.test.Test
@@ -27,25 +32,65 @@ class NestedRangeBenchmarkTest {
@Test
fun benchmarkHappyNumbersNestedRanges() = runTest {
if (!Benchmarks.enabled) return@runTest
val script = """
fun naiveCountHappyNumbers() {
var count = 0
for( n1 in 0..9 )
for( n2 in 0..9 )
for( n3 in 0..9 )
for( n4 in 0..9 )
for( n5 in 0..9 )
for( n6 in 0..9 )
if( n1 + n2 + n3 == n4 + n5 + n6 ) count++
count
}
naiveCountHappyNumbers()
val bodyScript = """
var count = 0
for( n1 in 0..9 )
for( n2 in 0..9 )
for( n3 in 0..9 )
for( n4 in 0..9 )
for( n5 in 0..9 )
for( n6 in 0..9 )
if( n1 + n2 + n3 == n4 + n5 + n6 ) count++
count
""".trimIndent()
val compiled = Compiler.compile(bodyScript)
dumpNestedLoopBytecode(compiled.debugStatements())
val script = """
fun naiveCountHappyNumbers() {
$bodyScript
}
""".trimIndent()
val scope = Script.newScope()
scope.eval(script)
val fnDisasm = scope.disassembleSymbol("naiveCountHappyNumbers")
println("[DEBUG_LOG] [BENCH] nested-happy function naiveCountHappyNumbers bytecode:\n$fnDisasm")
val start = TimeSource.Monotonic.markNow()
val result = eval(script) as ObjInt
val result = scope.eval("naiveCountHappyNumbers()") as ObjInt
val elapsedMs = start.elapsedNow().inWholeMilliseconds
println("[DEBUG_LOG] [BENCH] nested-happy elapsed=${elapsedMs} ms")
assertEquals(55252L, result.value)
}
private fun dumpNestedLoopBytecode(statements: List<Statement>) {
var current: Statement? = statements.firstOrNull { stmt ->
stmt is BytecodeStatement && stmt.original is ForInStatement
}
var depth = 1
while (current is BytecodeStatement && current.original is ForInStatement) {
val original = current.original as ForInStatement
println(
"[DEBUG_LOG] [BENCH] nested-happy loop depth=$depth " +
"constRange=${original.constRange} canBreak=${original.canBreak} " +
"loopSlotPlan=${original.loopSlotPlan}"
)
val fn = current.bytecodeFunction()
val slots = fn.scopeSlotNames.mapIndexed { idx, name ->
val slotName = name ?: "s$idx"
"$slotName@${fn.scopeSlotDepths[idx]}:${fn.scopeSlotIndices[idx]}"
}
println("[DEBUG_LOG] [BENCH] nested-happy slots depth=$depth: ${slots.joinToString(", ")}")
val disasm = BytecodeDisassembler.disassemble(fn)
println("[DEBUG_LOG] [BENCH] nested-happy bytecode depth=$depth:\n$disasm")
current = original.body
depth += 1
}
if (depth == 1) {
println("[DEBUG_LOG] [BENCH] nested-happy bytecode: <not found>")
}
}
}
+1 -1
View File
@@ -3989,6 +3989,7 @@ class ScriptTest {
)
}
@Test
fun testParserOverflow() = runTest {
try {
@@ -5044,4 +5045,3 @@ class ScriptTest {
""".trimIndent())
}
}