Fast-path bytecode statement execution
This commit is contained in:
parent
a61b5a31be
commit
fc7d26ee4b
@ -28,6 +28,7 @@ internal suspend fun executeBytecodeWithSeed(scope: Scope, stmt: Statement, labe
|
||||
else -> null
|
||||
} ?: scope.raiseIllegalState("$label requires bytecode statement")
|
||||
scope.pos = bytecode.pos
|
||||
bytecode.callOnFast(scope)?.let { return it }
|
||||
return CmdVm().execute(bytecode.bytecodeFunction(), scope, scope.args) { frame, _ ->
|
||||
seedFrameLocalsFromScope(frame, scope)
|
||||
}
|
||||
|
||||
@ -23,19 +23,36 @@ import net.sergeych.lyng.obj.*
|
||||
class BytecodeStatement private constructor(
|
||||
val original: Statement,
|
||||
private val function: CmdFunction,
|
||||
) : Statement(original.isStaticConst, original.isConst, original.returnType) {
|
||||
) : Statement(original.isStaticConst, original.isConst, original.returnType), BytecodeCallable {
|
||||
override val pos: Pos = original.pos
|
||||
|
||||
private val declaredLocalNames: Set<String> by lazy(LazyThreadSafetyMode.NONE) {
|
||||
function.constants
|
||||
.mapNotNull { it as? BytecodeConst.LocalDecl }
|
||||
.mapTo(mutableSetOf()) { it.name }
|
||||
}
|
||||
|
||||
override fun callOnFast(scope: Scope): Obj? {
|
||||
scope.pos = pos
|
||||
if (!function.fastOnly) return null
|
||||
if (!canFastSeedUndeclaredLocals(function, declaredLocalNames, emptySet())) return null
|
||||
val binder: (CmdFrame, Arguments) -> Unit = { frame, _ ->
|
||||
if (!trySeedFrameLocalsFromScopeFast(frame, scope)) {
|
||||
scope.raiseIllegalState("fast local seeding is not available")
|
||||
}
|
||||
}
|
||||
return CmdVm().executeFastOnlyNoSuspend(function, scope, scope.args, binder)
|
||||
}
|
||||
|
||||
override suspend fun execute(scope: Scope): Obj {
|
||||
scope.pos = pos
|
||||
val declaredNames = function.constants
|
||||
.mapNotNull { it as? BytecodeConst.LocalDecl }
|
||||
.mapTo(mutableSetOf()) { it.name }
|
||||
val fastResult = callOnFast(scope)
|
||||
if (fastResult != null) return fastResult
|
||||
val binder: suspend (CmdFrame, Arguments) -> Unit = { frame, _ ->
|
||||
val localNames = frame.fn.localSlotNames
|
||||
for (i in localNames.indices) {
|
||||
val name = localNames[i] ?: continue
|
||||
if (declaredNames.contains(name)) continue
|
||||
if (declaredLocalNames.contains(name)) continue
|
||||
val slotType = frame.getLocalSlotTypeCode(i)
|
||||
if (slotType != SlotType.UNKNOWN.code && slotType != SlotType.OBJ.code) {
|
||||
continue
|
||||
|
||||
@ -17,7 +17,11 @@
|
||||
package net.sergeych.lyng.bytecode
|
||||
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.FrameSlotRef
|
||||
import net.sergeych.lyng.RecordSlotRef
|
||||
import net.sergeych.lyng.ScopeSlotRef
|
||||
import net.sergeych.lyng.obj.ObjRecord
|
||||
import net.sergeych.lyng.obj.ObjProperty
|
||||
|
||||
internal fun canFastSeedUndeclaredLocals(
|
||||
fn: CmdFunction,
|
||||
@ -35,6 +39,37 @@ internal fun canFastSeedUndeclaredLocals(
|
||||
return true
|
||||
}
|
||||
|
||||
internal fun trySeedFrameLocalsFromScopeFast(frame: CmdFrame, scope: Scope): Boolean {
|
||||
val localNames = frame.fn.localSlotNames
|
||||
if (localNames.isEmpty()) return true
|
||||
val base = frame.fn.scopeSlotCount
|
||||
for (i in localNames.indices) {
|
||||
val name = localNames[i] ?: continue
|
||||
val slotType = frame.getLocalSlotTypeCode(i)
|
||||
if (slotType != SlotType.UNKNOWN.code && slotType != SlotType.OBJ.code) continue
|
||||
if (slotType == SlotType.OBJ.code && frame.frame.getRawObj(i) != null) continue
|
||||
val record = scope.getLocalRecordDirect(name)
|
||||
?: scope.chainLookupIgnoreClosure(name, followClosure = true)
|
||||
?: continue
|
||||
val value = when {
|
||||
record.type == ObjRecord.Type.Delegated -> return false
|
||||
record.type == ObjRecord.Type.Property -> return false
|
||||
record.value is ObjProperty -> return false
|
||||
else -> when (val direct = record.value) {
|
||||
is FrameSlotRef -> direct.resolvedCaptureValueOrNull() ?: return false
|
||||
is RecordSlotRef -> direct.resolvedCaptureValueOrNull() ?: return false
|
||||
is ScopeSlotRef -> direct.resolvedCaptureValueOrNull() ?: return false
|
||||
else -> direct
|
||||
}
|
||||
}
|
||||
if (value is FrameSlotRef && value.refersTo(frame.frame, i)) {
|
||||
continue
|
||||
}
|
||||
frame.setObjUnchecked(base + i, value)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
internal suspend fun seedFrameLocalsFromScope(frame: CmdFrame, scope: Scope) {
|
||||
val localNames = frame.fn.localSlotNames
|
||||
if (localNames.isEmpty()) return
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user