Step 24C: remove scope mirroring in bytecode runtime
This commit is contained in:
parent
6c0b86f6e6
commit
c066dc7150
@ -97,10 +97,10 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
|
|||||||
- [x] Read captured values via `FrameSlotRef` only.
|
- [x] Read captured values via `FrameSlotRef` only.
|
||||||
- [x] Forbid `resolveCaptureRecord` in bytecode paths; keep only in interpreter.
|
- [x] Forbid `resolveCaptureRecord` in bytecode paths; keep only in interpreter.
|
||||||
- [x] JVM tests must be green before commit.
|
- [x] JVM tests must be green before commit.
|
||||||
- [ ] Step 24C: Remove scope local mirroring in bytecode execution.
|
- [x] Step 24C: Remove scope local mirroring in bytecode execution.
|
||||||
- [ ] Remove/disable any bytecode runtime code that writes locals into Scope for execution.
|
- [x] Remove/disable any bytecode runtime code that writes locals into Scope for execution.
|
||||||
- [ ] Keep Scope creation only for reflection/Kotlin interop paths.
|
- [x] Keep Scope creation only for reflection/Kotlin interop paths.
|
||||||
- [ ] JVM tests must be green before commit.
|
- [x] JVM tests must be green before commit.
|
||||||
- [ ] Step 24D: Eliminate `ClosureScope` usage on bytecode execution paths.
|
- [ ] Step 24D: Eliminate `ClosureScope` usage on bytecode execution paths.
|
||||||
- [ ] Avoid `ClosureScope` in bytecode-related call paths (Block/Lambda/ObjDynamic/ObjProperty).
|
- [ ] Avoid `ClosureScope` in bytecode-related call paths (Block/Lambda/ObjDynamic/ObjProperty).
|
||||||
- [ ] Keep interpreter path using `ClosureScope` until interpreter removal.
|
- [ ] Keep interpreter path using `ClosureScope` until interpreter removal.
|
||||||
|
|||||||
@ -4236,8 +4236,7 @@ class BytecodeCompiler(
|
|||||||
if (shouldInlineBlock(stmt)) {
|
if (shouldInlineBlock(stmt)) {
|
||||||
return emitInlineStatements(stmt.statements(), needResult)
|
return emitInlineStatements(stmt.statements(), needResult)
|
||||||
}
|
}
|
||||||
val captureNames = if (stmt.captureSlots.isEmpty()) emptyList() else stmt.captureSlots.map { it.name }
|
val planId = builder.addConst(BytecodeConst.SlotPlan(stmt.slotPlan, emptyList()))
|
||||||
val planId = builder.addConst(BytecodeConst.SlotPlan(stmt.slotPlan, captureNames))
|
|
||||||
builder.emit(Opcode.PUSH_SCOPE, planId)
|
builder.emit(Opcode.PUSH_SCOPE, planId)
|
||||||
resetAddrCache()
|
resetAddrCache()
|
||||||
val statements = stmt.statements()
|
val statements = stmt.statements()
|
||||||
@ -4384,8 +4383,7 @@ class BytecodeCompiler(
|
|||||||
builder.emit(Opcode.DECL_LOCAL, declId, exceptionSlot)
|
builder.emit(Opcode.DECL_LOCAL, declId, exceptionSlot)
|
||||||
return compileStatementValueOrFallback(block, needResult)
|
return compileStatementValueOrFallback(block, needResult)
|
||||||
}
|
}
|
||||||
val captureNames = if (stmt.captureSlots.isEmpty()) emptyList() else stmt.captureSlots.map { it.name }
|
val planId = builder.addConst(BytecodeConst.SlotPlan(stmt.slotPlan, emptyList()))
|
||||||
val planId = builder.addConst(BytecodeConst.SlotPlan(stmt.slotPlan, captureNames))
|
|
||||||
builder.emit(Opcode.PUSH_SCOPE, planId)
|
builder.emit(Opcode.PUSH_SCOPE, planId)
|
||||||
resetAddrCache()
|
resetAddrCache()
|
||||||
val declId = builder.addConst(BytecodeConst.LocalDecl(catchVarName, false, Visibility.Public, false))
|
val declId = builder.addConst(BytecodeConst.LocalDecl(catchVarName, false, Visibility.Public, false))
|
||||||
|
|||||||
@ -1316,15 +1316,9 @@ class CmdDeclDelegated(internal val constId: Int, internal val slot: Int) : Cmd(
|
|||||||
|
|
||||||
class CmdDeclExec(internal val constId: Int, internal val slot: Int) : Cmd() {
|
class CmdDeclExec(internal val constId: Int, internal val slot: Int) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncFrameToScope(useRefs = true)
|
|
||||||
}
|
|
||||||
val decl = frame.fn.constants[constId] as? BytecodeConst.DeclExec
|
val decl = frame.fn.constants[constId] as? BytecodeConst.DeclExec
|
||||||
?: error("DECL_EXEC expects DeclExec at $constId")
|
?: error("DECL_EXEC expects DeclExec at $constId")
|
||||||
val result = decl.executable.execute(frame.ensureScope())
|
val result = decl.executable.execute(frame.ensureScope())
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncScopeToFrame()
|
|
||||||
}
|
|
||||||
frame.storeObjResult(slot, result)
|
frame.storeObjResult(slot, result)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1414,9 +1408,6 @@ class CmdCallDirect(
|
|||||||
internal val dst: Int,
|
internal val dst: Int,
|
||||||
) : Cmd() {
|
) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncFrameToScope(useRefs = true)
|
|
||||||
}
|
|
||||||
val ref = frame.fn.constants.getOrNull(id) as? BytecodeConst.ObjRef
|
val ref = frame.fn.constants.getOrNull(id) as? BytecodeConst.ObjRef
|
||||||
?: error("CALL_DIRECT expects ObjRef at $id")
|
?: error("CALL_DIRECT expects ObjRef at $id")
|
||||||
val callee = ref.value
|
val callee = ref.value
|
||||||
@ -1426,9 +1417,6 @@ class CmdCallDirect(
|
|||||||
} else {
|
} else {
|
||||||
callee.callOn(frame.ensureScope().createChildScope(frame.ensureScope().pos, args = args))
|
callee.callOn(frame.ensureScope().createChildScope(frame.ensureScope().pos, args = args))
|
||||||
}
|
}
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncScopeToFrame()
|
|
||||||
}
|
|
||||||
frame.storeObjResult(dst, result)
|
frame.storeObjResult(dst, result)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1441,9 +1429,6 @@ class CmdCallSlot(
|
|||||||
internal val dst: Int,
|
internal val dst: Int,
|
||||||
) : Cmd() {
|
) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncFrameToScope(useRefs = true)
|
|
||||||
}
|
|
||||||
val callee = frame.slotToObj(calleeSlot)
|
val callee = frame.slotToObj(calleeSlot)
|
||||||
if (callee === ObjUnset) {
|
if (callee === ObjUnset) {
|
||||||
val name = if (calleeSlot < frame.fn.scopeSlotCount) {
|
val name = if (calleeSlot < frame.fn.scopeSlotCount) {
|
||||||
@ -1465,9 +1450,6 @@ class CmdCallSlot(
|
|||||||
val scope = frame.ensureScope()
|
val scope = frame.ensureScope()
|
||||||
callee.callOn(scope.createChildScope(scope.pos, args = args))
|
callee.callOn(scope.createChildScope(scope.pos, args = args))
|
||||||
}
|
}
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncScopeToFrame()
|
|
||||||
}
|
|
||||||
frame.storeObjResult(dst, result)
|
frame.storeObjResult(dst, result)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1664,18 +1646,12 @@ class CmdGetDynamicMember(
|
|||||||
internal val dst: Int,
|
internal val dst: Int,
|
||||||
) : Cmd() {
|
) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncFrameToScope(useRefs = true)
|
|
||||||
}
|
|
||||||
val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal
|
val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal
|
||||||
?: error("GET_DYNAMIC_MEMBER expects StringVal at $nameId")
|
?: error("GET_DYNAMIC_MEMBER expects StringVal at $nameId")
|
||||||
val scope = frame.ensureScope()
|
val scope = frame.ensureScope()
|
||||||
val receiver = frame.slotToObj(recvSlot)
|
val receiver = frame.slotToObj(recvSlot)
|
||||||
val rec = receiver.readField(scope, nameConst.value)
|
val rec = receiver.readField(scope, nameConst.value)
|
||||||
val value = resolveDynamicFieldValue(scope, receiver, nameConst.value, rec)
|
val value = resolveDynamicFieldValue(scope, receiver, nameConst.value, rec)
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncScopeToFrame()
|
|
||||||
}
|
|
||||||
frame.storeObjResult(dst, value)
|
frame.storeObjResult(dst, value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1687,17 +1663,11 @@ class CmdSetDynamicMember(
|
|||||||
internal val valueSlot: Int,
|
internal val valueSlot: Int,
|
||||||
) : Cmd() {
|
) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncFrameToScope(useRefs = true)
|
|
||||||
}
|
|
||||||
val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal
|
val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal
|
||||||
?: error("SET_DYNAMIC_MEMBER expects StringVal at $nameId")
|
?: error("SET_DYNAMIC_MEMBER expects StringVal at $nameId")
|
||||||
val scope = frame.ensureScope()
|
val scope = frame.ensureScope()
|
||||||
val receiver = frame.slotToObj(recvSlot)
|
val receiver = frame.slotToObj(recvSlot)
|
||||||
receiver.writeField(scope, nameConst.value, frame.slotToObj(valueSlot))
|
receiver.writeField(scope, nameConst.value, frame.slotToObj(valueSlot))
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncScopeToFrame()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1710,18 +1680,12 @@ class CmdCallDynamicMember(
|
|||||||
internal val dst: Int,
|
internal val dst: Int,
|
||||||
) : Cmd() {
|
) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncFrameToScope(useRefs = true)
|
|
||||||
}
|
|
||||||
val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal
|
val nameConst = frame.fn.constants.getOrNull(nameId) as? BytecodeConst.StringVal
|
||||||
?: error("CALL_DYNAMIC_MEMBER expects StringVal at $nameId")
|
?: error("CALL_DYNAMIC_MEMBER expects StringVal at $nameId")
|
||||||
val scope = frame.ensureScope()
|
val scope = frame.ensureScope()
|
||||||
val receiver = frame.slotToObj(recvSlot)
|
val receiver = frame.slotToObj(recvSlot)
|
||||||
val callArgs = frame.buildArguments(argBase, argCount)
|
val callArgs = frame.buildArguments(argBase, argCount)
|
||||||
val result = receiver.invokeInstanceMethod(scope, nameConst.value, callArgs)
|
val result = receiver.invokeInstanceMethod(scope, nameConst.value, callArgs)
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncScopeToFrame()
|
|
||||||
}
|
|
||||||
frame.storeObjResult(dst, result)
|
frame.storeObjResult(dst, result)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1735,9 +1699,6 @@ class CmdCallMemberSlot(
|
|||||||
internal val dst: Int,
|
internal val dst: Int,
|
||||||
) : Cmd() {
|
) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncFrameToScope(useRefs = true)
|
|
||||||
}
|
|
||||||
val receiver = frame.slotToObj(recvSlot)
|
val receiver = frame.slotToObj(recvSlot)
|
||||||
val inst = receiver as? ObjInstance
|
val inst = receiver as? ObjInstance
|
||||||
val cls = receiver as? ObjClass
|
val cls = receiver as? ObjClass
|
||||||
@ -1758,9 +1719,6 @@ class CmdCallMemberSlot(
|
|||||||
}
|
}
|
||||||
if (receiver is ObjQualifiedView) {
|
if (receiver is ObjQualifiedView) {
|
||||||
val result = receiver.invokeInstanceMethod(frame.ensureScope(), name, callArgs)
|
val result = receiver.invokeInstanceMethod(frame.ensureScope(), name, callArgs)
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncScopeToFrame()
|
|
||||||
}
|
|
||||||
frame.storeObjResult(dst, result)
|
frame.storeObjResult(dst, result)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1799,9 +1757,6 @@ class CmdCallMemberSlot(
|
|||||||
}
|
}
|
||||||
else -> frame.ensureScope().raiseError("member $name is not callable")
|
else -> frame.ensureScope().raiseError("member $name is not callable")
|
||||||
}
|
}
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncScopeToFrame()
|
|
||||||
}
|
|
||||||
frame.storeObjResult(dst, result)
|
frame.storeObjResult(dst, result)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1864,9 +1819,6 @@ class CmdEvalStmt(internal val id: Int, internal val dst: Int) : Cmd() {
|
|||||||
|
|
||||||
class CmdMakeValueFn(internal val id: Int, internal val dst: Int) : Cmd() {
|
class CmdMakeValueFn(internal val id: Int, internal val dst: Int) : Cmd() {
|
||||||
override suspend fun perform(frame: CmdFrame) {
|
override suspend fun perform(frame: CmdFrame) {
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncFrameToScope(useRefs = true)
|
|
||||||
}
|
|
||||||
val valueFn = frame.fn.constants.getOrNull(id) as? BytecodeConst.ValueFn
|
val valueFn = frame.fn.constants.getOrNull(id) as? BytecodeConst.ValueFn
|
||||||
?: error("MAKE_VALUE_FN expects ValueFn at $id")
|
?: error("MAKE_VALUE_FN expects ValueFn at $id")
|
||||||
val scope = frame.ensureScope()
|
val scope = frame.ensureScope()
|
||||||
@ -1875,9 +1827,6 @@ class CmdMakeValueFn(internal val id: Int, internal val dst: Int) : Cmd() {
|
|||||||
scope.captureRecords = captureRecords
|
scope.captureRecords = captureRecords
|
||||||
val result = valueFn.fn(scope).value
|
val result = valueFn.fn(scope).value
|
||||||
scope.captureRecords = previousCaptures
|
scope.captureRecords = previousCaptures
|
||||||
if (frame.fn.localSlotNames.isNotEmpty()) {
|
|
||||||
frame.syncScopeToFrame()
|
|
||||||
}
|
|
||||||
frame.storeObjResult(dst, result)
|
frame.storeObjResult(dst, result)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2113,19 +2062,6 @@ class CmdFrame(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun pushScope(plan: Map<String, Int>, captures: List<String>) {
|
fun pushScope(plan: Map<String, Int>, captures: List<String>) {
|
||||||
val parentScope = scope
|
|
||||||
if (captures.isNotEmpty()) {
|
|
||||||
syncFrameToScope(useRefs = true)
|
|
||||||
}
|
|
||||||
val captureRecords = if (captures.isNotEmpty()) {
|
|
||||||
captures.map { name ->
|
|
||||||
val rec = parentScope.resolveCaptureRecord(name)
|
|
||||||
?: parentScope.raiseSymbolNotFound("symbol $name not found")
|
|
||||||
name to rec
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
if (scope.skipScopeCreation) {
|
if (scope.skipScopeCreation) {
|
||||||
val snapshot = scope.applySlotPlanWithSnapshot(plan)
|
val snapshot = scope.applySlotPlanWithSnapshot(plan)
|
||||||
slotPlanStack.addLast(snapshot)
|
slotPlanStack.addLast(snapshot)
|
||||||
@ -2140,11 +2076,6 @@ class CmdFrame(
|
|||||||
scope.applySlotPlan(plan)
|
scope.applySlotPlan(plan)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (captureRecords.isNotEmpty()) {
|
|
||||||
for ((name, rec) in captureRecords) {
|
|
||||||
scope.updateSlotFor(name, rec)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
captureStack.addLast(captures)
|
captureStack.addLast(captures)
|
||||||
scopeDepth += 1
|
scopeDepth += 1
|
||||||
}
|
}
|
||||||
@ -2162,9 +2093,6 @@ class CmdFrame(
|
|||||||
?: error("Scope stack underflow in POP_SCOPE")
|
?: error("Scope stack underflow in POP_SCOPE")
|
||||||
val captures = captureStack.removeLastOrNull() ?: emptyList()
|
val captures = captureStack.removeLastOrNull() ?: emptyList()
|
||||||
scopeDepth -= 1
|
scopeDepth -= 1
|
||||||
if (captures.isNotEmpty()) {
|
|
||||||
syncFrameToScope(useRefs = true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pushIterator(iter: Obj) {
|
fun pushIterator(iter: Obj) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user