Step 26C: remove forceScopeSlots
This commit is contained in:
parent
b9af80a1b2
commit
6efdfc1964
@ -123,7 +123,7 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
|
|||||||
- [ ] Step 26: Bytecode-backed lambdas (remove `ValueFnRef` runtime execution).
|
- [ ] Step 26: Bytecode-backed lambdas (remove `ValueFnRef` runtime execution).
|
||||||
- [x] Compile lambda bodies to bytecode and emit an opcode to create a callable from bytecode + capture plan.
|
- [x] Compile lambda bodies to bytecode and emit an opcode to create a callable from bytecode + capture plan.
|
||||||
- [x] Remove `containsValueFnRef` helper now that lambdas are bytecode-backed.
|
- [x] Remove `containsValueFnRef` helper now that lambdas are bytecode-backed.
|
||||||
- [ ] Remove `forceScopeSlots` branches once no bytecode paths depend on scope slots.
|
- [x] Remove `forceScopeSlots` branches once no bytecode paths depend on scope slots.
|
||||||
- [x] Add JVM tests for captured locals and delegated locals inside lambdas on the bytecode path.
|
- [x] Add JVM tests for captured locals and delegated locals inside lambdas on the bytecode path.
|
||||||
- [ ] Step 27: Remove interpreter opcodes and constants from bytecode runtime.
|
- [ ] Step 27: Remove interpreter opcodes and constants from bytecode runtime.
|
||||||
- [ ] Delete `BytecodeConst.ValueFn`, `CmdMakeValueFn`, and `MAKE_VALUE_FN`.
|
- [ ] Delete `BytecodeConst.ValueFn`, `CmdMakeValueFn`, and `MAKE_VALUE_FN`.
|
||||||
|
|||||||
@ -70,7 +70,6 @@ class BytecodeCompiler(
|
|||||||
private val intLoopVarNames = LinkedHashSet<String>()
|
private val intLoopVarNames = LinkedHashSet<String>()
|
||||||
private val valueFnRefs = LinkedHashSet<ValueFnRef>()
|
private val valueFnRefs = LinkedHashSet<ValueFnRef>()
|
||||||
private val loopStack = ArrayDeque<LoopContext>()
|
private val loopStack = ArrayDeque<LoopContext>()
|
||||||
private var forceScopeSlots = false
|
|
||||||
private var currentPos: Pos? = null
|
private var currentPos: Pos? = null
|
||||||
|
|
||||||
private data class LoopContext(
|
private data class LoopContext(
|
||||||
@ -372,7 +371,6 @@ class BytecodeCompiler(
|
|||||||
return CompiledValue(slot, resolved)
|
return CompiledValue(slot, resolved)
|
||||||
}
|
}
|
||||||
if (allowLocalSlots) {
|
if (allowLocalSlots) {
|
||||||
if (!forceScopeSlots) {
|
|
||||||
val localIndex = localSlotIndexByName[ref.name]
|
val localIndex = localSlotIndexByName[ref.name]
|
||||||
if (localIndex != null) {
|
if (localIndex != null) {
|
||||||
val slot = scopeSlotCount + localIndex
|
val slot = scopeSlotCount + localIndex
|
||||||
@ -384,13 +382,6 @@ class BytecodeCompiler(
|
|||||||
return CompiledValue(slot, resolved)
|
return CompiledValue(slot, resolved)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (forceScopeSlots) {
|
|
||||||
scopeSlotIndexByName[ref.name]?.let { slot ->
|
|
||||||
val resolved = slotTypes[slot] ?: SlotType.UNKNOWN
|
|
||||||
return CompiledValue(slot, resolved)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
is FastLocalVarRef -> {
|
is FastLocalVarRef -> {
|
||||||
@ -402,7 +393,6 @@ class BytecodeCompiler(
|
|||||||
return CompiledValue(slot, resolved)
|
return CompiledValue(slot, resolved)
|
||||||
}
|
}
|
||||||
if (allowLocalSlots) {
|
if (allowLocalSlots) {
|
||||||
if (!forceScopeSlots) {
|
|
||||||
val localIndex = localSlotIndexByName[ref.name]
|
val localIndex = localSlotIndexByName[ref.name]
|
||||||
if (localIndex != null) {
|
if (localIndex != null) {
|
||||||
val slot = scopeSlotCount + localIndex
|
val slot = scopeSlotCount + localIndex
|
||||||
@ -414,13 +404,6 @@ class BytecodeCompiler(
|
|||||||
return CompiledValue(slot, resolved)
|
return CompiledValue(slot, resolved)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (forceScopeSlots) {
|
|
||||||
scopeSlotIndexByName[ref.name]?.let { slot ->
|
|
||||||
val resolved = slotTypes[slot] ?: SlotType.UNKNOWN
|
|
||||||
return CompiledValue(slot, resolved)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
is BoundLocalVarRef -> {
|
is BoundLocalVarRef -> {
|
||||||
@ -3620,7 +3603,6 @@ class BytecodeCompiler(
|
|||||||
return CompiledValue(slot, resolved)
|
return CompiledValue(slot, resolved)
|
||||||
}
|
}
|
||||||
if (!allowLocalSlots) return null
|
if (!allowLocalSlots) return null
|
||||||
if (!forceScopeSlots) {
|
|
||||||
scopeSlotIndexByName[name]?.let { slot ->
|
scopeSlotIndexByName[name]?.let { slot ->
|
||||||
val resolved = slotTypes[slot] ?: SlotType.UNKNOWN
|
val resolved = slotTypes[slot] ?: SlotType.UNKNOWN
|
||||||
return CompiledValue(slot, resolved)
|
return CompiledValue(slot, resolved)
|
||||||
@ -3632,12 +3614,6 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
scopeSlotIndexByName[name]?.let { slot ->
|
|
||||||
val resolved = slotTypes[slot] ?: SlotType.UNKNOWN
|
|
||||||
return CompiledValue(slot, resolved)
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun resolveAssignableSlotByName(name: String): Pair<Int, Boolean>? {
|
private fun resolveAssignableSlotByName(name: String): Pair<Int, Boolean>? {
|
||||||
localSlotIndexByName[name]?.let { localIndex ->
|
localSlotIndexByName[name]?.let { localIndex ->
|
||||||
@ -4560,7 +4536,7 @@ class BytecodeCompiler(
|
|||||||
emitInlineStatements(stmt.statements(), needResult)
|
emitInlineStatements(stmt.statements(), needResult)
|
||||||
|
|
||||||
private fun shouldInlineBlock(stmt: BlockStatement): Boolean {
|
private fun shouldInlineBlock(stmt: BlockStatement): Boolean {
|
||||||
return allowLocalSlots && !forceScopeSlots
|
return allowLocalSlots
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compileInlineBlock(name: String, stmt: net.sergeych.lyng.InlineBlockStatement): CmdFunction? {
|
private fun compileInlineBlock(name: String, stmt: net.sergeych.lyng.InlineBlockStatement): CmdFunction? {
|
||||||
@ -4585,7 +4561,7 @@ class BytecodeCompiler(
|
|||||||
private fun compileLoopBody(stmt: Statement, needResult: Boolean): CompiledValue? {
|
private fun compileLoopBody(stmt: Statement, needResult: Boolean): CompiledValue? {
|
||||||
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
val target = if (stmt is BytecodeStatement) stmt.original else stmt
|
||||||
if (target is BlockStatement) {
|
if (target is BlockStatement) {
|
||||||
val useInline = !forceScopeSlots && target.slotPlan.isEmpty() && target.captureSlots.isEmpty()
|
val useInline = target.slotPlan.isEmpty() && target.captureSlots.isEmpty()
|
||||||
return if (useInline) emitInlineBlock(target, needResult) else emitBlock(target, needResult)
|
return if (useInline) emitInlineBlock(target, needResult) else emitBlock(target, needResult)
|
||||||
}
|
}
|
||||||
return compileStatementValueOrFallback(target, needResult)
|
return compileStatementValueOrFallback(target, needResult)
|
||||||
@ -4650,7 +4626,7 @@ class BytecodeCompiler(
|
|||||||
updateSlotObjClass(localSlot, stmt.initializer, stmt.initializerObjClass)
|
updateSlotObjClass(localSlot, stmt.initializer, stmt.initializerObjClass)
|
||||||
updateNameObjClassFromSlot(stmt.name, localSlot)
|
updateNameObjClassFromSlot(stmt.name, localSlot)
|
||||||
val shadowedScopeSlot = scopeSlotIndexByName.containsKey(stmt.name)
|
val shadowedScopeSlot = scopeSlotIndexByName.containsKey(stmt.name)
|
||||||
if (forceScopeSlots || !shadowedScopeSlot) {
|
if (!shadowedScopeSlot) {
|
||||||
val declId = builder.addConst(
|
val declId = builder.addConst(
|
||||||
BytecodeConst.LocalDecl(
|
BytecodeConst.LocalDecl(
|
||||||
stmt.name,
|
stmt.name,
|
||||||
@ -4867,14 +4843,14 @@ class BytecodeCompiler(
|
|||||||
slot
|
slot
|
||||||
}
|
}
|
||||||
var emitDeclLocal = usedOverride
|
var emitDeclLocal = usedOverride
|
||||||
if (useLoopScope && !forceScopeSlots) {
|
if (useLoopScope) {
|
||||||
val loopVarOnly = loopSlotPlan.size == 1 && loopSlotPlan.containsKey(stmt.loopVarName)
|
val loopVarOnly = loopSlotPlan.size == 1 && loopSlotPlan.containsKey(stmt.loopVarName)
|
||||||
val loopVarIsLocal = loopSlotId >= scopeSlotCount
|
val loopVarIsLocal = loopSlotId >= scopeSlotCount
|
||||||
if (loopVarOnly && loopVarIsLocal) {
|
if (loopVarOnly && loopVarIsLocal) {
|
||||||
useLoopScope = false
|
useLoopScope = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (useLoopScope && allowLocalSlots && !forceScopeSlots) {
|
if (useLoopScope && allowLocalSlots) {
|
||||||
val needsScope = allowedScopeNames?.let { names ->
|
val needsScope = allowedScopeNames?.let { names ->
|
||||||
loopSlotPlan.keys.any { names.contains(it) }
|
loopSlotPlan.keys.any { names.contains(it) }
|
||||||
} == true
|
} == true
|
||||||
@ -4883,7 +4859,7 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
emitDeclLocal = emitDeclLocal && useLoopScope
|
emitDeclLocal = emitDeclLocal && useLoopScope
|
||||||
if (!forceScopeSlots && loopSlotId < scopeSlotCount) {
|
if (loopSlotId < scopeSlotCount) {
|
||||||
val localSlot = allocSlot()
|
val localSlot = allocSlot()
|
||||||
loopSlotOverrides[stmt.loopVarName] = localSlot
|
loopSlotOverrides[stmt.loopVarName] = localSlot
|
||||||
usedOverride = true
|
usedOverride = true
|
||||||
@ -5738,7 +5714,7 @@ class BytecodeCompiler(
|
|||||||
val loopKeys = loopSlotOverrides.keys.sorted().joinToString(prefix = "[", postfix = "]")
|
val loopKeys = loopSlotOverrides.keys.sorted().joinToString(prefix = "[", postfix = "]")
|
||||||
val localKeys = localSlotIndexByName.keys.sorted().joinToString(prefix = "[", postfix = "]")
|
val localKeys = localSlotIndexByName.keys.sorted().joinToString(prefix = "[", postfix = "]")
|
||||||
val scopeKeys = scopeSlotIndexByName.keys.sorted().joinToString(prefix = "[", postfix = "]")
|
val scopeKeys = scopeSlotIndexByName.keys.sorted().joinToString(prefix = "[", postfix = "]")
|
||||||
val info = " ref=$refKind loopSlots=$loopKeys localSlots=$localKeys scopeSlots=$scopeKeys forceScopeSlots=$forceScopeSlots"
|
val info = " ref=$refKind loopSlots=$loopKeys localSlots=$localKeys scopeSlots=$scopeKeys"
|
||||||
throw BytecodeCompileException("Unresolved name '$name'.$info", pos)
|
throw BytecodeCompileException("Unresolved name '$name'.$info", pos)
|
||||||
}
|
}
|
||||||
val refInfo = when (ref) {
|
val refInfo = when (ref) {
|
||||||
@ -6169,10 +6145,6 @@ class BytecodeCompiler(
|
|||||||
val nameIndex = localSlotIndexByName[ref.name]
|
val nameIndex = localSlotIndexByName[ref.name]
|
||||||
if (nameIndex != null) return scopeSlotCount + nameIndex
|
if (nameIndex != null) return scopeSlotCount + nameIndex
|
||||||
}
|
}
|
||||||
if (forceScopeSlots) {
|
|
||||||
val scopeKey = ScopeSlotKey(refScopeId(ref), refSlot(ref))
|
|
||||||
return scopeSlotMap[scopeKey]
|
|
||||||
}
|
|
||||||
val localKey = ScopeSlotKey(refScopeId(ref), refSlot(ref))
|
val localKey = ScopeSlotKey(refScopeId(ref), refSlot(ref))
|
||||||
val localIndex = localSlotIndexByKey[localKey]
|
val localIndex = localSlotIndexByKey[localKey]
|
||||||
if (localIndex != null) return scopeSlotCount + localIndex
|
if (localIndex != null) return scopeSlotCount + localIndex
|
||||||
@ -6223,7 +6195,6 @@ class BytecodeCompiler(
|
|||||||
valueFnRefs.clear()
|
valueFnRefs.clear()
|
||||||
addrSlotByScopeSlot.clear()
|
addrSlotByScopeSlot.clear()
|
||||||
loopStack.clear()
|
loopStack.clear()
|
||||||
forceScopeSlots = false
|
|
||||||
if (slotTypeByScopeId.isNotEmpty()) {
|
if (slotTypeByScopeId.isNotEmpty()) {
|
||||||
for ((scopeId, slots) in slotTypeByScopeId) {
|
for ((scopeId, slots) in slotTypeByScopeId) {
|
||||||
for ((slotIndex, cls) in slots) {
|
for ((slotIndex, cls) in slots) {
|
||||||
@ -6366,7 +6337,7 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val isModuleSlot = isModuleSlot(scopeId, stmt.name)
|
val isModuleSlot = isModuleSlot(scopeId, stmt.name)
|
||||||
if (allowLocalSlots && !forceScopeSlots && slotIndex != null && !isModuleSlot) {
|
if (allowLocalSlots && slotIndex != null && !isModuleSlot) {
|
||||||
val key = ScopeSlotKey(scopeId, slotIndex)
|
val key = ScopeSlotKey(scopeId, slotIndex)
|
||||||
declaredLocalKeys.add(key)
|
declaredLocalKeys.add(key)
|
||||||
if (!localSlotInfoMap.containsKey(key)) {
|
if (!localSlotInfoMap.containsKey(key)) {
|
||||||
@ -6463,56 +6434,6 @@ class BytecodeCompiler(
|
|||||||
collectLoopSlotPlans(stmt.original, scopeDepth)
|
collectLoopSlotPlans(stmt.original, scopeDepth)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (forceScopeSlots) {
|
|
||||||
when (stmt) {
|
|
||||||
is net.sergeych.lyng.ForInStatement -> {
|
|
||||||
collectLoopSlotPlans(stmt.source, scopeDepth)
|
|
||||||
val loopDepth = scopeDepth + 1
|
|
||||||
collectLoopSlotPlans(stmt.body, loopDepth)
|
|
||||||
stmt.elseStatement?.let { collectLoopSlotPlans(it, loopDepth) }
|
|
||||||
}
|
|
||||||
is net.sergeych.lyng.WhileStatement -> {
|
|
||||||
collectLoopSlotPlans(stmt.condition, scopeDepth)
|
|
||||||
val loopDepth = scopeDepth + 1
|
|
||||||
collectLoopSlotPlans(stmt.body, loopDepth)
|
|
||||||
stmt.elseStatement?.let { collectLoopSlotPlans(it, loopDepth) }
|
|
||||||
}
|
|
||||||
is net.sergeych.lyng.DoWhileStatement -> {
|
|
||||||
val loopDepth = scopeDepth + 1
|
|
||||||
collectLoopSlotPlans(stmt.body, loopDepth)
|
|
||||||
collectLoopSlotPlans(stmt.condition, loopDepth)
|
|
||||||
stmt.elseStatement?.let { collectLoopSlotPlans(it, loopDepth) }
|
|
||||||
}
|
|
||||||
is BlockStatement -> {
|
|
||||||
val nextDepth = scopeDepth + 1
|
|
||||||
for (child in stmt.statements()) {
|
|
||||||
collectLoopSlotPlans(child, nextDepth)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is net.sergeych.lyng.InlineBlockStatement -> {
|
|
||||||
for (child in stmt.statements()) {
|
|
||||||
collectLoopSlotPlans(child, scopeDepth)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is IfStatement -> {
|
|
||||||
collectLoopSlotPlans(stmt.condition, scopeDepth)
|
|
||||||
collectLoopSlotPlans(stmt.ifBody, scopeDepth)
|
|
||||||
stmt.elseBody?.let { collectLoopSlotPlans(it, scopeDepth) }
|
|
||||||
}
|
|
||||||
is VarDeclStatement -> {
|
|
||||||
stmt.initializer?.let { collectLoopSlotPlans(it, scopeDepth) }
|
|
||||||
}
|
|
||||||
is ExpressionStatement -> {}
|
|
||||||
is net.sergeych.lyng.ReturnStatement -> {
|
|
||||||
stmt.resultExpr?.let { collectLoopSlotPlans(it, scopeDepth) }
|
|
||||||
}
|
|
||||||
is net.sergeych.lyng.ThrowStatement -> {
|
|
||||||
collectLoopSlotPlans(stmt.throwExpr, scopeDepth)
|
|
||||||
}
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
when (stmt) {
|
when (stmt) {
|
||||||
is net.sergeych.lyng.ForInStatement -> {
|
is net.sergeych.lyng.ForInStatement -> {
|
||||||
collectLoopSlotPlans(stmt.source, scopeDepth)
|
collectLoopSlotPlans(stmt.source, scopeDepth)
|
||||||
@ -6682,9 +6603,8 @@ class BytecodeCompiler(
|
|||||||
captureSlotKeys.add(key)
|
captureSlotKeys.add(key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val shouldLocalize = ref.isDelegated || !forceScopeSlots || intLoopVarNames.contains(ref.name)
|
|
||||||
val isModuleSlot = if (ref.isDelegated) false else isModuleSlot(scopeId, ref.name)
|
val isModuleSlot = if (ref.isDelegated) false else isModuleSlot(scopeId, ref.name)
|
||||||
if (allowLocalSlots && shouldLocalize && !isModuleSlot) {
|
if (allowLocalSlots && !isModuleSlot) {
|
||||||
if (!localSlotInfoMap.containsKey(key)) {
|
if (!localSlotInfoMap.containsKey(key)) {
|
||||||
localSlotInfoMap[key] = LocalSlotInfo(ref.name, ref.isMutable, ref.isDelegated)
|
localSlotInfoMap[key] = LocalSlotInfo(ref.name, ref.isMutable, ref.isDelegated)
|
||||||
}
|
}
|
||||||
@ -6731,9 +6651,8 @@ class BytecodeCompiler(
|
|||||||
}
|
}
|
||||||
captureSlotKeys.add(key)
|
captureSlotKeys.add(key)
|
||||||
} else {
|
} else {
|
||||||
val shouldLocalize = target.isDelegated || !forceScopeSlots || intLoopVarNames.contains(target.name)
|
|
||||||
val isModuleSlot = if (target.isDelegated) false else isModuleSlot(scopeId, target.name)
|
val isModuleSlot = if (target.isDelegated) false else isModuleSlot(scopeId, target.name)
|
||||||
if (allowLocalSlots && shouldLocalize && !isModuleSlot) {
|
if (allowLocalSlots && !isModuleSlot) {
|
||||||
if (!localSlotInfoMap.containsKey(key)) {
|
if (!localSlotInfoMap.containsKey(key)) {
|
||||||
localSlotInfoMap[key] = LocalSlotInfo(target.name, target.isMutable, target.isDelegated)
|
localSlotInfoMap[key] = LocalSlotInfo(target.name, target.isMutable, target.isDelegated)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user