Step 24D: bytecode-only closure path for lambdas
This commit is contained in:
parent
c066dc7150
commit
abbebec153
@ -2877,7 +2877,12 @@ class Compiler(
|
|||||||
override val pos: Pos = body.pos
|
override val pos: Pos = body.pos
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
// and the source closure of the lambda which might have other thisObj.
|
// and the source closure of the lambda which might have other thisObj.
|
||||||
val context = scope.applyClosure(closureScope, preferredThisType = expectedReceiverType)
|
val useBytecodeClosure = closureScope.captureRecords != null
|
||||||
|
val context = if (useBytecodeClosure) {
|
||||||
|
scope.applyClosureForBytecode(closureScope, preferredThisType = expectedReceiverType)
|
||||||
|
} else {
|
||||||
|
scope.applyClosure(closureScope, preferredThisType = expectedReceiverType)
|
||||||
|
}
|
||||||
if (paramSlotPlanSnapshot.isNotEmpty()) context.applySlotPlan(paramSlotPlanSnapshot)
|
if (paramSlotPlanSnapshot.isNotEmpty()) context.applySlotPlan(paramSlotPlanSnapshot)
|
||||||
if (captureSlots.isNotEmpty()) {
|
if (captureSlots.isNotEmpty()) {
|
||||||
val captureRecords = closureScope.captureRecords
|
val captureRecords = closureScope.captureRecords
|
||||||
|
|||||||
@ -832,6 +832,20 @@ open class Scope(
|
|||||||
open fun applyClosure(closure: Scope, preferredThisType: String? = null): Scope =
|
open fun applyClosure(closure: Scope, preferredThisType: String? = null): Scope =
|
||||||
ClosureScope(this, closure, preferredThisType)
|
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
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve and evaluate a qualified identifier exactly as compiled code would.
|
* Resolve and evaluate a qualified identifier exactly as compiled code would.
|
||||||
* For input like `A.B.C`, it builds the same ObjRef chain the compiler emits:
|
* For input like `A.B.C`, it builds the same ObjRef chain the compiler emits:
|
||||||
|
|||||||
@ -18,7 +18,6 @@
|
|||||||
package net.sergeych.lyng.obj
|
package net.sergeych.lyng.obj
|
||||||
|
|
||||||
import net.sergeych.lyng.Arguments
|
import net.sergeych.lyng.Arguments
|
||||||
import net.sergeych.lyng.ClosureScope
|
|
||||||
import net.sergeych.lyng.Scope
|
import net.sergeych.lyng.Scope
|
||||||
import net.sergeych.lyng.Statement
|
import net.sergeych.lyng.Statement
|
||||||
|
|
||||||
@ -63,7 +62,7 @@ open class ObjDynamic(var readCallback: Statement? = null, var writeCallback: St
|
|||||||
* with method invocation which is implemented separately in [invokeInstanceMethod] below.
|
* with method invocation which is implemented separately in [invokeInstanceMethod] below.
|
||||||
*/
|
*/
|
||||||
override suspend fun readField(scope: Scope, name: String): ObjRecord {
|
override suspend fun readField(scope: Scope, name: String): ObjRecord {
|
||||||
val execBase = builderScope?.let { ClosureScope(scope, it) } ?: scope
|
val execBase = builderScope?.let { scope.applyClosure(it) } ?: scope
|
||||||
return readCallback?.execute(execBase.createChildScope(Arguments(ObjString(name))))?.let {
|
return readCallback?.execute(execBase.createChildScope(Arguments(ObjString(name))))?.let {
|
||||||
if (writeCallback != null)
|
if (writeCallback != null)
|
||||||
it.asMutable
|
it.asMutable
|
||||||
@ -83,26 +82,26 @@ open class ObjDynamic(var readCallback: Statement? = null, var writeCallback: St
|
|||||||
args: Arguments,
|
args: Arguments,
|
||||||
onNotFoundResult: (suspend () -> Obj?)?
|
onNotFoundResult: (suspend () -> Obj?)?
|
||||||
): Obj {
|
): Obj {
|
||||||
val execBase = builderScope?.let { ClosureScope(scope, it) } ?: scope
|
val execBase = builderScope?.let { scope.applyClosure(it) } ?: scope
|
||||||
val over = readCallback?.execute(execBase.createChildScope(Arguments(ObjString(name))))
|
val over = readCallback?.execute(execBase.createChildScope(Arguments(ObjString(name))))
|
||||||
return over?.invoke(scope, scope.thisObj, args)
|
return over?.invoke(scope, scope.thisObj, args)
|
||||||
?: super.invokeInstanceMethod(scope, name, args, onNotFoundResult)
|
?: super.invokeInstanceMethod(scope, name, args, onNotFoundResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun writeField(scope: Scope, name: String, newValue: Obj) {
|
override suspend fun writeField(scope: Scope, name: String, newValue: Obj) {
|
||||||
val execBase = builderScope?.let { ClosureScope(scope, it) } ?: scope
|
val execBase = builderScope?.let { scope.applyClosure(it) } ?: scope
|
||||||
writeCallback?.execute(execBase.createChildScope(Arguments(ObjString(name), newValue)))
|
writeCallback?.execute(execBase.createChildScope(Arguments(ObjString(name), newValue)))
|
||||||
?: super.writeField(scope, name, newValue)
|
?: super.writeField(scope, name, newValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getAt(scope: Scope, index: Obj): Obj {
|
override suspend fun getAt(scope: Scope, index: Obj): Obj {
|
||||||
val execBase = builderScope?.let { ClosureScope(scope, it) } ?: scope
|
val execBase = builderScope?.let { scope.applyClosure(it) } ?: scope
|
||||||
return readCallback?.execute(execBase.createChildScope(Arguments(index)))
|
return readCallback?.execute(execBase.createChildScope(Arguments(index)))
|
||||||
?: super.getAt(scope, index)
|
?: super.getAt(scope, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun putAt(scope: Scope, index: Obj, newValue: Obj) {
|
override suspend fun putAt(scope: Scope, index: Obj, newValue: Obj) {
|
||||||
val execBase = builderScope?.let { ClosureScope(scope, it) } ?: scope
|
val execBase = builderScope?.let { scope.applyClosure(it) } ?: scope
|
||||||
writeCallback?.execute(execBase.createChildScope(Arguments(index, newValue)))
|
writeCallback?.execute(execBase.createChildScope(Arguments(index, newValue)))
|
||||||
?: super.putAt(scope, index, newValue)
|
?: super.putAt(scope, index, newValue)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,6 @@
|
|||||||
package net.sergeych.lyng.obj
|
package net.sergeych.lyng.obj
|
||||||
|
|
||||||
import net.sergeych.lyng.Arguments
|
import net.sergeych.lyng.Arguments
|
||||||
import net.sergeych.lyng.ClosureScope
|
|
||||||
import net.sergeych.lyng.Scope
|
import net.sergeych.lyng.Scope
|
||||||
import net.sergeych.lyng.Statement
|
import net.sergeych.lyng.Statement
|
||||||
|
|
||||||
@ -35,9 +34,9 @@ class ObjProperty(
|
|||||||
suspend fun callGetter(scope: Scope, instance: Obj, declaringClass: ObjClass? = null): Obj {
|
suspend fun callGetter(scope: Scope, instance: Obj, declaringClass: ObjClass? = null): Obj {
|
||||||
val g = getter ?: scope.raiseError("property $name has no getter")
|
val g = getter ?: scope.raiseError("property $name has no getter")
|
||||||
// Execute getter in a child scope of the instance with 'this' properly set
|
// Execute getter in a child scope of the instance with 'this' properly set
|
||||||
// Use ClosureScope to match extension function behavior (access to instance scope + call scope)
|
// Match extension function behavior (access to instance scope + call scope).
|
||||||
val instanceScope = (instance as? ObjInstance)?.instanceScope ?: instance.autoInstanceScope(scope)
|
val instanceScope = (instance as? ObjInstance)?.instanceScope ?: instance.autoInstanceScope(scope)
|
||||||
val execScope = ClosureScope(scope, instanceScope).createChildScope(newThisObj = instance)
|
val execScope = scope.applyClosure(instanceScope).createChildScope(newThisObj = instance)
|
||||||
execScope.currentClassCtx = declaringClass
|
execScope.currentClassCtx = declaringClass
|
||||||
return g.execute(execScope)
|
return g.execute(execScope)
|
||||||
}
|
}
|
||||||
@ -45,9 +44,9 @@ class ObjProperty(
|
|||||||
suspend fun callSetter(scope: Scope, instance: Obj, value: Obj, declaringClass: ObjClass? = null) {
|
suspend fun callSetter(scope: Scope, instance: Obj, value: Obj, declaringClass: ObjClass? = null) {
|
||||||
val s = setter ?: scope.raiseError("property $name has no setter")
|
val s = setter ?: scope.raiseError("property $name has no setter")
|
||||||
// Execute setter in a child scope of the instance with 'this' properly set and the value as an argument
|
// Execute setter in a child scope of the instance with 'this' properly set and the value as an argument
|
||||||
// Use ClosureScope to match extension function behavior
|
// Match extension function behavior (access to instance scope + call scope).
|
||||||
val instanceScope = (instance as? ObjInstance)?.instanceScope ?: instance.autoInstanceScope(scope)
|
val instanceScope = (instance as? ObjInstance)?.instanceScope ?: instance.autoInstanceScope(scope)
|
||||||
val execScope = ClosureScope(scope, instanceScope).createChildScope(args = Arguments(value), newThisObj = instance)
|
val execScope = scope.applyClosure(instanceScope).createChildScope(args = Arguments(value), newThisObj = instance)
|
||||||
execScope.currentClassCtx = declaringClass
|
execScope.currentClassCtx = declaringClass
|
||||||
s.execute(execScope)
|
s.execute(execScope)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user