Step 24D: bytecode closure scope
This commit is contained in:
parent
1271f347bd
commit
c14c7d43d9
@ -102,9 +102,9 @@ Goal: migrate the compiler so all values live in frames/bytecode, keeping JVM te
|
||||
- [x] Keep Scope creation only for reflection/Kotlin interop paths.
|
||||
- [x] JVM tests must be green before commit.
|
||||
- [x] Step 24D: Eliminate `ClosureScope` usage on bytecode execution paths.
|
||||
- [ ] Avoid `ClosureScope` in bytecode-related call paths (Block/Lambda/ObjDynamic/ObjProperty).
|
||||
- [ ] Keep interpreter path using `ClosureScope` until interpreter removal.
|
||||
- [ ] JVM tests must be green before commit.
|
||||
- [x] Avoid `ClosureScope` in bytecode-related call paths (Block/Lambda/ObjDynamic/ObjProperty).
|
||||
- [x] Keep interpreter path using `ClosureScope` until interpreter removal.
|
||||
- [x] JVM tests must be green before commit.
|
||||
- [x] Step 24E: Isolate interpreter-only capture logic.
|
||||
- [ ] Mark `resolveCaptureRecord` paths as interpreter-only.
|
||||
- [ ] Guard or delete any bytecode path that tries to sync captures into scopes.
|
||||
|
||||
@ -84,6 +84,32 @@ class ClosureScope(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bytecode-oriented closure scope that keeps the call scope parent chain for stack traces
|
||||
* while carrying the lexical closure for `this` variants and module resolution.
|
||||
* Unlike [ClosureScope], it does not override name lookup.
|
||||
*/
|
||||
class BytecodeClosureScope(
|
||||
val callScope: Scope,
|
||||
val closureScope: Scope,
|
||||
private val preferredThisType: String? = null
|
||||
) :
|
||||
Scope(callScope, callScope.args, thisObj = closureScope.thisObj) {
|
||||
|
||||
init {
|
||||
val desired = preferredThisType?.let { typeName ->
|
||||
callScope.thisVariants.firstOrNull { it.objClass.className == typeName }
|
||||
}
|
||||
val primaryThis = closureScope.thisObj
|
||||
val merged = ArrayList<Obj>(callScope.thisVariants.size + closureScope.thisVariants.size + 1)
|
||||
desired?.let { merged.add(it) }
|
||||
merged.addAll(callScope.thisVariants)
|
||||
merged.addAll(closureScope.thisVariants)
|
||||
setThisVariants(primaryThis, merged)
|
||||
this.currentClassCtx = closureScope.currentClassCtx ?: callScope.currentClassCtx
|
||||
}
|
||||
}
|
||||
|
||||
class ApplyScope(val callScope: Scope, val applied: Scope) :
|
||||
Scope(callScope, thisObj = applied.thisObj) {
|
||||
|
||||
|
||||
@ -6929,8 +6929,15 @@ class Compiler(
|
||||
// restore closure where the function was defined, and making a copy of it
|
||||
// for local space. If there is no closure, we are in, say, class context where
|
||||
// the closure is in the class initialization and we needn't more:
|
||||
val context = closureBox.closure?.let { ClosureScope(callerContext, it) }
|
||||
?: callerContext
|
||||
val context = closureBox.closure?.let { closure ->
|
||||
if (fnStatements is BytecodeStatement) {
|
||||
callerContext.applyClosureForBytecode(closure).also {
|
||||
it.args = callerContext.args
|
||||
}
|
||||
} else {
|
||||
ClosureScope(callerContext, closure)
|
||||
}
|
||||
} ?: callerContext
|
||||
|
||||
// Capacity hint: parameters + declared locals + small overhead
|
||||
val capacityHint = paramNames.size + fnLocalDecls + 4
|
||||
|
||||
@ -192,7 +192,14 @@ internal suspend fun executeFunctionDecl(scope: Scope, spec: FunctionDeclSpec):
|
||||
override val pos: Pos = spec.startPos
|
||||
override suspend fun execute(scope: Scope): Obj {
|
||||
val result = (scope.thisObj as? ObjInstance)?.let { i ->
|
||||
compiledFnBody.execute(ClosureScope(scope, i.instanceScope))
|
||||
val execScope = if (compiledFnBody is net.sergeych.lyng.bytecode.BytecodeStatement) {
|
||||
scope.applyClosureForBytecode(i.instanceScope).also {
|
||||
it.args = scope.args
|
||||
}
|
||||
} else {
|
||||
ClosureScope(scope, i.instanceScope)
|
||||
}
|
||||
compiledFnBody.execute(execScope)
|
||||
} ?: compiledFnBody.execute(scope.thisObj.autoInstanceScope(scope))
|
||||
return result
|
||||
}
|
||||
|
||||
@ -836,17 +836,7 @@ open class Scope(
|
||||
ClosureScope(this, closure, preferredThisType)
|
||||
|
||||
internal fun applyClosureForBytecode(closure: Scope, preferredThisType: String? = null): Scope {
|
||||
val context = createChildScope(newThisObj = closure.thisObj)
|
||||
val desired = preferredThisType?.let { typeName ->
|
||||
thisVariants.firstOrNull { it.objClass.className == typeName }
|
||||
}
|
||||
val merged = ArrayList<Obj>(thisVariants.size + closure.thisVariants.size + 1)
|
||||
desired?.let { merged.add(it) }
|
||||
merged.addAll(thisVariants)
|
||||
merged.addAll(closure.thisVariants)
|
||||
context.setThisVariants(closure.thisObj, merged)
|
||||
context.currentClassCtx = closure.currentClassCtx ?: currentClassCtx
|
||||
return context
|
||||
return BytecodeClosureScope(this, closure, preferredThisType)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -2004,6 +2004,8 @@ class CmdFrame(
|
||||
current.parent?.let { queue.add(it) }
|
||||
if (current is ClosureScope) {
|
||||
queue.add(current.closureScope)
|
||||
} else if (current is BytecodeClosureScope) {
|
||||
queue.add(current.closureScope)
|
||||
} else if (current is ApplyScope) {
|
||||
queue.add(current.applied)
|
||||
}
|
||||
@ -2023,6 +2025,28 @@ class CmdFrame(
|
||||
current.parent?.let { queue.add(it) }
|
||||
if (current is ClosureScope) {
|
||||
queue.add(current.closureScope)
|
||||
} else if (current is BytecodeClosureScope) {
|
||||
queue.add(current.closureScope)
|
||||
} else if (current is ApplyScope) {
|
||||
queue.add(current.applied)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun findScopeWithRecord(scope: Scope, name: String): Scope? {
|
||||
val visited = HashSet<Scope>(16)
|
||||
val queue = ArrayDeque<Scope>()
|
||||
queue.add(scope)
|
||||
while (queue.isNotEmpty()) {
|
||||
val current = queue.removeFirst()
|
||||
if (!visited.add(current)) continue
|
||||
if (current.getLocalRecordDirect(name) != null) return current
|
||||
current.parent?.let { queue.add(it) }
|
||||
if (current is ClosureScope) {
|
||||
queue.add(current.closureScope)
|
||||
} else if (current is BytecodeClosureScope) {
|
||||
queue.add(current.closureScope)
|
||||
} else if (current is ApplyScope) {
|
||||
queue.add(current.applied)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user