Step 9: module-level bytecode execution

This commit is contained in:
Sergey Chernov 2026-02-09 02:09:29 +03:00
parent e2f503744d
commit 58581d6bf0
3 changed files with 23 additions and 17 deletions

View File

@ -29,9 +29,9 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
- [x] Support `ClassScopeMemberRef` without scope-map fallback. - [x] Support `ClassScopeMemberRef` without scope-map fallback.
- [x] Step 8: ObjDynamic member access in bytecode. - [x] Step 8: ObjDynamic member access in bytecode.
- [x] Allow dynamic receiver field/method lookup without falling back to interpreter. - [x] Allow dynamic receiver field/method lookup without falling back to interpreter.
- [ ] Step 9: Module-level bytecode execution. - [x] Step 9: Module-level bytecode execution.
- [ ] Compile `Script` bodies to bytecode instead of interpreting at module scope. - [x] Compile `Script` bodies to bytecode instead of interpreting at module scope.
- [ ] Keep import/module slot seeding in frame-only flow. - [x] Keep import/module slot seeding in frame-only flow.
## Notes ## Notes

View File

@ -1526,25 +1526,24 @@ class Compiler(
resolutionScriptDepth == 1 && resolutionScriptDepth == 1 &&
statements.none { containsUnsupportedForBytecode(it) } && statements.none { containsUnsupportedForBytecode(it) } &&
statements.none { containsDelegatedRefs(it) } statements.none { containsDelegatedRefs(it) }
val finalStatements = if (wrapScriptBytecode) { val (finalStatements, moduleBytecode) = if (wrapScriptBytecode) {
val unwrapped = statements.map { unwrapBytecodeDeep(it) } val unwrapped = statements.map { unwrapBytecodeDeep(it) }
val block = InlineBlockStatement(unwrapped, start) val block = InlineBlockStatement(unwrapped, start)
listOf( val bytecodeStmt = BytecodeStatement.wrap(
BytecodeStatement.wrap( block,
block, "<script>",
"<script>", allowLocalSlots = true,
allowLocalSlots = true, allowedScopeNames = modulePlan.keys,
allowedScopeNames = modulePlan.keys, moduleScopeId = moduleSlotPlan()?.id,
moduleScopeId = moduleSlotPlan()?.id, slotTypeByScopeId = slotTypeByScopeId,
slotTypeByScopeId = slotTypeByScopeId, knownNameObjClass = knownClassMapForBytecode()
knownNameObjClass = knownClassMapForBytecode() ) as BytecodeStatement
) unwrapped to bytecodeStmt.bytecodeFunction()
)
} else { } else {
statements statements to null
} }
val moduleRefs = importedModules.map { ImportBindingSource.Module(it.scope.packageName, it.pos) } val moduleRefs = importedModules.map { ImportBindingSource.Module(it.scope.packageName, it.pos) }
Script(start, finalStatements, modulePlan, importBindings.toMap(), moduleRefs) Script(start, finalStatements, modulePlan, importBindings.toMap(), moduleRefs, moduleBytecode)
}.also { }.also {
// Best-effort script end notification (use current position) // Best-effort script end notification (use current position)
miniSink?.onScriptEnd( miniSink?.onScriptEnd(

View File

@ -20,6 +20,8 @@ package net.sergeych.lyng
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.yield import kotlinx.coroutines.yield
import net.sergeych.lyng.Script.Companion.defaultImportManager import net.sergeych.lyng.Script.Companion.defaultImportManager
import net.sergeych.lyng.bytecode.CmdFunction
import net.sergeych.lyng.bytecode.CmdVm
import net.sergeych.lyng.miniast.* import net.sergeych.lyng.miniast.*
import net.sergeych.lyng.obj.* import net.sergeych.lyng.obj.*
import net.sergeych.lyng.pacman.ImportManager import net.sergeych.lyng.pacman.ImportManager
@ -35,10 +37,12 @@ class Script(
private val moduleSlotPlan: Map<String, Int> = emptyMap(), private val moduleSlotPlan: Map<String, Int> = emptyMap(),
private val importBindings: Map<String, ImportBinding> = emptyMap(), private val importBindings: Map<String, ImportBinding> = emptyMap(),
private val importedModules: List<ImportBindingSource.Module> = emptyList(), private val importedModules: List<ImportBindingSource.Module> = emptyList(),
private val moduleBytecode: CmdFunction? = null,
// private val catchReturn: Boolean = false, // private val catchReturn: Boolean = false,
) : Statement() { ) : Statement() {
override suspend fun execute(scope: Scope): Obj { override suspend fun execute(scope: Scope): Obj {
scope.pos = pos
val isModuleScope = scope is ModuleScope val isModuleScope = scope is ModuleScope
val shouldSeedModule = isModuleScope || scope.thisObj === ObjVoid val shouldSeedModule = isModuleScope || scope.thisObj === ObjVoid
val moduleTarget = scope val moduleTarget = scope
@ -79,6 +83,9 @@ class Script(
if (shouldSeedModule) { if (shouldSeedModule) {
seedModuleSlots(moduleTarget) seedModuleSlots(moduleTarget)
} }
moduleBytecode?.let { fn ->
return CmdVm().execute(fn, scope, scope.args.list)
}
var lastResult: Obj = ObjVoid var lastResult: Obj = ObjVoid
for (s in statements) { for (s in statements) {
lastResult = s.execute(scope) lastResult = s.execute(scope)