Add non-suspending fast calls for bytecode callables
This commit is contained in:
parent
33d170f525
commit
a61b5a31be
@ -16,4 +16,8 @@
|
|||||||
|
|
||||||
package net.sergeych.lyng
|
package net.sergeych.lyng
|
||||||
|
|
||||||
interface BytecodeCallable
|
import net.sergeych.lyng.obj.Obj
|
||||||
|
|
||||||
|
interface BytecodeCallable {
|
||||||
|
fun callOnFast(scope: Scope): Obj? = null
|
||||||
|
}
|
||||||
|
|||||||
@ -3553,11 +3553,82 @@ class Compiler(
|
|||||||
val ref = LambdaFnRef(
|
val ref = LambdaFnRef(
|
||||||
valueFn = { closureScope ->
|
valueFn = { closureScope ->
|
||||||
val captureRecords = closureScope.captureRecords
|
val captureRecords = closureScope.captureRecords
|
||||||
val stmt = object : Statement(), BytecodeBodyProvider {
|
val stmt = object : Statement(), BytecodeBodyProvider, BytecodeCallable {
|
||||||
override val pos: Pos = fnStatements.pos
|
override val pos: Pos = fnStatements.pos
|
||||||
|
|
||||||
override fun bytecodeBody(): BytecodeStatement? = fnStatements as? BytecodeStatement
|
override fun bytecodeBody(): BytecodeStatement? = fnStatements as? BytecodeStatement
|
||||||
|
|
||||||
|
override fun callOnFast(scope: Scope): Obj? {
|
||||||
|
val context = scope.applyClosureForBytecode(closureScope, preferredThisType = expectedReceiverType).also {
|
||||||
|
it.args = scope.args
|
||||||
|
}
|
||||||
|
if (captureSlots.isNotEmpty()) {
|
||||||
|
if (captureRecords != null) {
|
||||||
|
context.captureRecords = captureRecords
|
||||||
|
context.captureNames = captureSlots.map { it.name }
|
||||||
|
} else {
|
||||||
|
val resolvedRecords = ArrayList<ObjRecord>(captureSlots.size)
|
||||||
|
val resolvedNames = ArrayList<String>(captureSlots.size)
|
||||||
|
for (capture in captureSlots) {
|
||||||
|
val rec = resolveStableCaptureRecord(
|
||||||
|
closureScope,
|
||||||
|
capture.name,
|
||||||
|
context.currentClassCtx
|
||||||
|
) ?: closureScope.raiseSymbolNotFound("symbol ${capture.name} not found")
|
||||||
|
resolvedRecords.add(freezeImmutableCaptureRecord(rec))
|
||||||
|
resolvedNames.add(capture.name)
|
||||||
|
}
|
||||||
|
context.captureRecords = resolvedRecords
|
||||||
|
context.captureNames = resolvedNames
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val bytecodeBody = fnStatements as? BytecodeStatement ?: return null
|
||||||
|
val bytecodeFn = bytecodeBody.bytecodeFunction()
|
||||||
|
if (!supportsDirectInvokeFastPath || !bytecodeFn.fastOnly) return null
|
||||||
|
val fastPreboundNames = if (argsDeclaration == null) {
|
||||||
|
setOf("it")
|
||||||
|
} else {
|
||||||
|
argsDeclaration.params.mapTo(LinkedHashSet()) { it.name }
|
||||||
|
}
|
||||||
|
val declaredNames = bytecodeFn.constants
|
||||||
|
.mapNotNull { it as? BytecodeConst.LocalDecl }
|
||||||
|
.mapTo(mutableSetOf()) { it.name }
|
||||||
|
if (!canFastSeedUndeclaredLocals(bytecodeFn, declaredNames, fastPreboundNames)) return null
|
||||||
|
if (argsDeclaration != null && !argsDeclaration.supportsFastFrameBinding(scope.args)) return null
|
||||||
|
val slotPlan = bytecodeFn.localSlotPlanByName()
|
||||||
|
val binder: (net.sergeych.lyng.bytecode.CmdFrame, Arguments) -> Unit = { frame, arguments ->
|
||||||
|
if (argsDeclaration == null) {
|
||||||
|
val l = arguments.list
|
||||||
|
val itValue: Obj = when (l.size) {
|
||||||
|
0 -> ObjVoid
|
||||||
|
1 -> l[0]
|
||||||
|
else -> ObjList(l.toMutableList())
|
||||||
|
}
|
||||||
|
val itSlot = slotPlan["it"]
|
||||||
|
if (itSlot != null) {
|
||||||
|
when (itValue) {
|
||||||
|
is ObjInt -> frame.frame.setInt(itSlot, itValue.value)
|
||||||
|
is ObjReal -> frame.frame.setReal(itSlot, itValue.value)
|
||||||
|
is ObjBool -> frame.frame.setBool(itSlot, itValue.value)
|
||||||
|
else -> frame.frame.setObj(itSlot, itValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
argsDeclaration.assignToFrameFast(
|
||||||
|
context,
|
||||||
|
arguments,
|
||||||
|
slotPlan,
|
||||||
|
frame.frame
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return try {
|
||||||
|
net.sergeych.lyng.bytecode.CmdVm().executeFastOnlyNoSuspend(bytecodeFn, context, scope.args, binder)
|
||||||
|
} catch (e: ReturnException) {
|
||||||
|
if (e.label == null || returnLabels.contains(e.label)) e.result else throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
val context = scope.applyClosureForBytecode(closureScope, preferredThisType = expectedReceiverType).also {
|
val context = scope.applyClosureForBytecode(closureScope, preferredThisType = expectedReceiverType).also {
|
||||||
it.args = scope.args
|
it.args = scope.args
|
||||||
@ -9439,9 +9510,76 @@ class Compiler(
|
|||||||
val closureBox = FunctionClosureBox()
|
val closureBox = FunctionClosureBox()
|
||||||
|
|
||||||
val captureSlots = capturePlan.captures.toList()
|
val captureSlots = capturePlan.captures.toList()
|
||||||
val fnBody = object : Statement(), BytecodeBodyProvider {
|
val fnBody = object : Statement(), BytecodeBodyProvider, BytecodeCallable {
|
||||||
override val pos: Pos = start
|
override val pos: Pos = start
|
||||||
override fun bytecodeBody(): BytecodeStatement? = fnStatements as? BytecodeStatement
|
override fun bytecodeBody(): BytecodeStatement? = fnStatements as? BytecodeStatement
|
||||||
|
|
||||||
|
override fun callOnFast(scope: Scope): Obj? {
|
||||||
|
scope.pos = start
|
||||||
|
val context = closureBox.closure?.let { closure ->
|
||||||
|
scope.applyClosureForBytecode(closure).also {
|
||||||
|
it.args = scope.args
|
||||||
|
}
|
||||||
|
} ?: scope
|
||||||
|
|
||||||
|
val captureBase = closureBox.captureContext ?: closureBox.closure
|
||||||
|
val bytecodeBody = (fnStatements as? BytecodeStatement) ?: return null
|
||||||
|
val bytecodeFn = bytecodeBody.bytecodeFunction()
|
||||||
|
if (!bytecodeFn.fastOnly || !argsDeclaration.supportsFastFrameBinding(scope.args)) return null
|
||||||
|
val declaredNames = bytecodeFn.constants
|
||||||
|
.mapNotNull { it as? BytecodeConst.LocalDecl }
|
||||||
|
.mapTo(mutableSetOf()) { it.name }
|
||||||
|
val preboundNames = LinkedHashSet<String>()
|
||||||
|
argsDeclaration.params.mapTo(preboundNames) { it.name }
|
||||||
|
mergedTypeParamDecls.mapTo(preboundNames) { it.name }
|
||||||
|
if (!canFastSeedUndeclaredLocals(bytecodeFn, declaredNames, preboundNames)) return null
|
||||||
|
val captureNames = captureNamesForBytecodeFunction(
|
||||||
|
bytecodeFn,
|
||||||
|
captureSlots.map { it.name }
|
||||||
|
)
|
||||||
|
val prebuiltCaptures = closureBox.captureRecords
|
||||||
|
if (prebuiltCaptures != null && captureNames.isNotEmpty()) {
|
||||||
|
context.captureRecords = prebuiltCaptures
|
||||||
|
context.captureNames = captureNames
|
||||||
|
} else if (captureBase != null && captureNames.isNotEmpty()) {
|
||||||
|
val resolvedRecords = ArrayList<ObjRecord>(captureNames.size)
|
||||||
|
for (name in captureNames) {
|
||||||
|
val rec = resolveStableCaptureRecord(
|
||||||
|
captureBase,
|
||||||
|
name,
|
||||||
|
context.currentClassCtx
|
||||||
|
) ?: captureBase.raiseSymbolNotFound("symbol $name not found")
|
||||||
|
resolvedRecords.add(freezeImmutableCaptureRecord(rec))
|
||||||
|
}
|
||||||
|
context.captureRecords = resolvedRecords
|
||||||
|
context.captureNames = captureNames
|
||||||
|
}
|
||||||
|
val slotPlan = bytecodeFn.localSlotPlanByName()
|
||||||
|
val binder: (net.sergeych.lyng.bytecode.CmdFrame, Arguments) -> Unit = { frame, arguments ->
|
||||||
|
argsDeclaration.assignToFrameFast(
|
||||||
|
context,
|
||||||
|
arguments,
|
||||||
|
slotPlan,
|
||||||
|
frame.frame
|
||||||
|
)
|
||||||
|
val typeBindings = bindTypeParamsAtRuntime(context, argsDeclaration, mergedTypeParamDecls)
|
||||||
|
if (typeBindings.isNotEmpty()) {
|
||||||
|
for ((name, bound) in typeBindings) {
|
||||||
|
val slot = slotPlan[name] ?: continue
|
||||||
|
frame.frame.setObj(slot, bound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (extTypeName != null) {
|
||||||
|
context.thisObj = scope.thisObj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return try {
|
||||||
|
net.sergeych.lyng.bytecode.CmdVm().executeFastOnlyNoSuspend(bytecodeFn, context, scope.args, binder)
|
||||||
|
} catch (e: ReturnException) {
|
||||||
|
if (e.label == null || e.label == name || e.label == outerLabel) e.result else throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
scope.pos = start
|
scope.pos = start
|
||||||
|
|
||||||
|
|||||||
@ -66,7 +66,8 @@ internal class ScopeBridge(internal val scope: Scope) : ScopeFacade {
|
|||||||
override fun raiseIllegalState(message: String): Nothing = scope.raiseIllegalState(message)
|
override fun raiseIllegalState(message: String): Nothing = scope.raiseIllegalState(message)
|
||||||
override fun raiseNotImplemented(what: String): Nothing = scope.raiseNotImplemented(what)
|
override fun raiseNotImplemented(what: String): Nothing = scope.raiseNotImplemented(what)
|
||||||
override suspend fun call(callee: Obj, args: Arguments, newThisObj: Obj?): Obj {
|
override suspend fun call(callee: Obj, args: Arguments, newThisObj: Obj?): Obj {
|
||||||
return callee.callOn(scope.createChildScope(scope.pos, args = args, newThisObj = newThisObj))
|
val child = scope.createChildScope(scope.pos, args = args, newThisObj = newThisObj)
|
||||||
|
return (callee as? BytecodeCallable)?.callOnFast(child) ?: callee.callOn(child)
|
||||||
}
|
}
|
||||||
override suspend fun toStringOf(obj: Obj, forInspect: Boolean): ObjString = obj.toString(scope, forInspect)
|
override suspend fun toStringOf(obj: Obj, forInspect: Boolean): ObjString = obj.toString(scope, forInspect)
|
||||||
override suspend fun inspect(obj: Obj): String = obj.inspect(scope)
|
override suspend fun inspect(obj: Obj): String = obj.inspect(scope)
|
||||||
|
|||||||
@ -58,6 +58,31 @@ class CmdVm {
|
|||||||
return execute(fn, scope0, Arguments.from(args))
|
return execute(fn, scope0, Arguments.from(args))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun executeFastOnlyNoSuspend(
|
||||||
|
fn: CmdFunction,
|
||||||
|
scope0: Scope,
|
||||||
|
args: Arguments,
|
||||||
|
binder: ((CmdFrame, Arguments) -> Unit)? = null
|
||||||
|
): Obj {
|
||||||
|
require(fn.fastOnly) { "fast-only execution requested for non-fast function ${fn.name}" }
|
||||||
|
result = null
|
||||||
|
val frame = CmdFrame(this, fn, scope0, args.list)
|
||||||
|
frame.applyCaptureRecords()
|
||||||
|
binder?.invoke(frame, args)
|
||||||
|
val cmds = fn.cmds
|
||||||
|
try {
|
||||||
|
while (result == null) {
|
||||||
|
val cmd = cmds[frame.ip++]
|
||||||
|
if (!cmd.performFast(frame)) {
|
||||||
|
error("fast-only command not supported: ${cmd::class.simpleName}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
throw frame.normalizeThrowableFast(e)
|
||||||
|
}
|
||||||
|
return result ?: ObjVoid
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun executeFastOnly(
|
suspend fun executeFastOnly(
|
||||||
fn: CmdFunction,
|
fn: CmdFunction,
|
||||||
scope0: Scope,
|
scope0: Scope,
|
||||||
@ -3270,7 +3295,7 @@ class CmdCallDirect(
|
|||||||
} else {
|
} else {
|
||||||
val scope = frame.ensureScope()
|
val scope = frame.ensureScope()
|
||||||
if (callee is BytecodeLambdaCallable && callee.supportsDirectInvokeFastPath()) {
|
if (callee is BytecodeLambdaCallable && callee.supportsDirectInvokeFastPath()) {
|
||||||
callee.invokeWithArgs(scope, args)
|
callee.invokeWithArgsFast(scope, args) ?: callee.invokeWithArgs(scope, args)
|
||||||
} else {
|
} else {
|
||||||
callee.callOn(scope.createChildScope(scope.pos, args = args))
|
callee.callOn(scope.createChildScope(scope.pos, args = args))
|
||||||
}
|
}
|
||||||
@ -3312,7 +3337,7 @@ class CmdCallSlot(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (callee is BytecodeLambdaCallable && callee.supportsDirectInvokeFastPath()) {
|
if (callee is BytecodeLambdaCallable && callee.supportsDirectInvokeFastPath()) {
|
||||||
callee.invokeWithArgs(scope, args)
|
callee.invokeWithArgsFast(scope, args) ?: callee.invokeWithArgs(scope, args)
|
||||||
} else {
|
} else {
|
||||||
callee.callOn(scope.createChildScope(scope.pos, args = args))
|
callee.callOn(scope.createChildScope(scope.pos, args = args))
|
||||||
}
|
}
|
||||||
@ -3399,9 +3424,10 @@ class CmdListFillInt(
|
|||||||
val result = ObjList(LongArray(size))
|
val result = ObjList(LongArray(size))
|
||||||
for (i in 0 until size) {
|
for (i in 0 until size) {
|
||||||
val value = if (callable is BytecodeLambdaCallable && callable.supportsImplicitIntFillFastPath()) {
|
val value = if (callable is BytecodeLambdaCallable && callable.supportsImplicitIntFillFastPath()) {
|
||||||
callable.invokeImplicitIntArg(scope, i.toLong())
|
callable.invokeImplicitIntArgFast(scope, i.toLong()) ?: callable.invokeImplicitIntArg(scope, i.toLong())
|
||||||
} else if (callable is BytecodeLambdaCallable && callable.supportsDirectInvokeFastPath()) {
|
} else if (callable is BytecodeLambdaCallable && callable.supportsDirectInvokeFastPath()) {
|
||||||
callable.invokeWithArgs(scope, Arguments(ObjInt.of(i.toLong())))
|
callable.invokeWithArgsFast(scope, Arguments(ObjInt.of(i.toLong())))
|
||||||
|
?: callable.invokeWithArgs(scope, Arguments(ObjInt.of(i.toLong())))
|
||||||
} else {
|
} else {
|
||||||
callable.callOn(scope.createChildScope(scope.pos, args = Arguments(ObjInt.of(i.toLong()))))
|
callable.callOn(scope.createChildScope(scope.pos, args = Arguments(ObjInt.of(i.toLong()))))
|
||||||
}
|
}
|
||||||
@ -4014,16 +4040,18 @@ class BytecodeLambdaCallable(
|
|||||||
|
|
||||||
fun supportsDirectInvokeFastPath(): Boolean = supportsDirectInvokeFastPath
|
fun supportsDirectInvokeFastPath(): Boolean = supportsDirectInvokeFastPath
|
||||||
|
|
||||||
private val supportsFastUndeclaredLocalInit: Boolean by lazy(LazyThreadSafetyMode.NONE) {
|
private val fastPreboundLocalNames: Set<String> by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
val parameterSlots = paramSlotPlan.values.toHashSet()
|
if (argsDeclaration == null) {
|
||||||
fn.localSlotNames.indices.all { localIndex ->
|
setOf("it")
|
||||||
val name = fn.localSlotNames[localIndex] ?: return@all true
|
} else {
|
||||||
if (declaredLocalNames.contains(name)) return@all true
|
argsDeclaration.params.mapTo(LinkedHashSet()) { it.name }
|
||||||
if (fn.localSlotCaptures.getOrNull(localIndex) == true) return@all true
|
|
||||||
parameterSlots.contains(fn.scopeSlotCount + localIndex)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val supportsFastUndeclaredLocalInit: Boolean by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
|
canFastSeedUndeclaredLocals(fn, declaredLocalNames, fastPreboundLocalNames)
|
||||||
|
}
|
||||||
|
|
||||||
private fun supportsFastOnlyVm(arguments: Arguments): Boolean {
|
private fun supportsFastOnlyVm(arguments: Arguments): Boolean {
|
||||||
if (!supportsDirectInvokeFastPath || !fn.fastOnly) return false
|
if (!supportsDirectInvokeFastPath || !fn.fastOnly) return false
|
||||||
if (!supportsFastUndeclaredLocalInit) return false
|
if (!supportsFastUndeclaredLocalInit) return false
|
||||||
@ -4139,6 +4167,21 @@ class BytecodeLambdaCallable(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun invokeImplicitIntArgFast(scope: Scope, arg: Long): Obj? {
|
||||||
|
if (!supportsFastOnlyVm(Arguments.EMPTY)) return null
|
||||||
|
val context = buildContext(scope, Arguments.EMPTY)
|
||||||
|
val binder: (CmdFrame, Arguments) -> Unit = { frame, _ ->
|
||||||
|
slotPlanByName["it"]?.let { itSlot ->
|
||||||
|
frame.frame.setInt(itSlot, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return try {
|
||||||
|
CmdVm().executeFastOnlyNoSuspend(fn, context, Arguments.EMPTY, binder)
|
||||||
|
} catch (e: ReturnException) {
|
||||||
|
if (e.label == null || returnLabels.contains(e.label)) e.result else throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun invokeWithArgs(scope: Scope, args: Arguments): Obj {
|
suspend fun invokeWithArgs(scope: Scope, args: Arguments): Obj {
|
||||||
val context = buildContext(scope, args)
|
val context = buildContext(scope, args)
|
||||||
return try {
|
return try {
|
||||||
@ -4160,6 +4203,21 @@ class BytecodeLambdaCallable(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun invokeWithArgsFast(scope: Scope, args: Arguments): Obj? {
|
||||||
|
if (!supportsFastOnlyVm(args)) return null
|
||||||
|
val context = buildContext(scope, args)
|
||||||
|
val binder: (CmdFrame, Arguments) -> Unit = { frame, arguments ->
|
||||||
|
bindArgumentsFast(frame, context, arguments)
|
||||||
|
}
|
||||||
|
return try {
|
||||||
|
CmdVm().executeFastOnlyNoSuspend(fn, context, args, binder)
|
||||||
|
} catch (e: ReturnException) {
|
||||||
|
if (e.label == null || returnLabels.contains(e.label)) e.result else throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun callOnFast(scope: Scope): Obj? = invokeWithArgsFast(scope, scope.args)
|
||||||
|
|
||||||
override suspend fun execute(scope: Scope): Obj {
|
override suspend fun execute(scope: Scope): Obj {
|
||||||
return invokeWithArgs(scope, scope.args)
|
return invokeWithArgs(scope, scope.args)
|
||||||
}
|
}
|
||||||
@ -4611,6 +4669,19 @@ class CmdFrame(
|
|||||||
return ExecutionError(errorObject, pos, message, t)
|
return ExecutionError(errorObject, pos, message, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun normalizeThrowableFast(t: Throwable): Throwable {
|
||||||
|
if (t is ExecutionError || t is ReturnException || t is LoopBreakContinueException) return t
|
||||||
|
val parentScope = ensureScope()
|
||||||
|
val pos = (t as? ScriptError)?.pos ?: currentErrorPos() ?: parentScope.pos
|
||||||
|
val throwScope = parentScope.createChildScope(pos = pos)
|
||||||
|
val message = when (t) {
|
||||||
|
is ScriptError -> t.errorMessage
|
||||||
|
else -> t.message ?: t.toString()
|
||||||
|
}
|
||||||
|
val errorObject = ObjUnknownException(throwScope, message)
|
||||||
|
return ExecutionError(errorObject, pos, message, t)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun handleException(t: Throwable): Boolean {
|
suspend fun handleException(t: Throwable): Boolean {
|
||||||
val handler = tryStack.lastOrNull() ?: return false
|
val handler = tryStack.lastOrNull() ?: return false
|
||||||
vmIterDebug {
|
vmIterDebug {
|
||||||
|
|||||||
@ -19,6 +19,22 @@ package net.sergeych.lyng.bytecode
|
|||||||
import net.sergeych.lyng.Scope
|
import net.sergeych.lyng.Scope
|
||||||
import net.sergeych.lyng.obj.ObjRecord
|
import net.sergeych.lyng.obj.ObjRecord
|
||||||
|
|
||||||
|
internal fun canFastSeedUndeclaredLocals(
|
||||||
|
fn: CmdFunction,
|
||||||
|
declaredLocalNames: Set<String>,
|
||||||
|
preboundLocalNames: Set<String>
|
||||||
|
): Boolean {
|
||||||
|
if (fn.localSlotNames.isEmpty()) return true
|
||||||
|
for (i in fn.localSlotNames.indices) {
|
||||||
|
val name = fn.localSlotNames[i] ?: continue
|
||||||
|
if (declaredLocalNames.contains(name)) continue
|
||||||
|
if (fn.localSlotCaptures.getOrNull(i) == true) continue
|
||||||
|
if (preboundLocalNames.contains(name)) continue
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
internal suspend fun seedFrameLocalsFromScope(frame: CmdFrame, scope: Scope) {
|
internal suspend fun seedFrameLocalsFromScope(frame: CmdFrame, scope: Scope) {
|
||||||
val localNames = frame.fn.localSlotNames
|
val localNames = frame.fn.localSlotNames
|
||||||
if (localNames.isEmpty()) return
|
if (localNames.isEmpty()) return
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import kotlinx.serialization.json.Json
|
|||||||
import kotlinx.serialization.json.JsonElement
|
import kotlinx.serialization.json.JsonElement
|
||||||
import kotlinx.serialization.json.JsonNull
|
import kotlinx.serialization.json.JsonNull
|
||||||
import kotlinx.serialization.serializer
|
import kotlinx.serialization.serializer
|
||||||
|
import net.sergeych.lyng.BytecodeCallable
|
||||||
import net.sergeych.lyng.*
|
import net.sergeych.lyng.*
|
||||||
import net.sergeych.lyng.InteropOperator
|
import net.sergeych.lyng.InteropOperator
|
||||||
import net.sergeych.lyng.OperatorInteropRegistry
|
import net.sergeych.lyng.OperatorInteropRegistry
|
||||||
@ -728,12 +729,13 @@ open class Obj {
|
|||||||
return if (usePool) {
|
return if (usePool) {
|
||||||
scope.withChildFrame(args, newThisObj = thisObj) { child ->
|
scope.withChildFrame(args, newThisObj = thisObj) { child ->
|
||||||
if (declaringClass != null) child.currentClassCtx = declaringClass
|
if (declaringClass != null) child.currentClassCtx = declaringClass
|
||||||
callOn(child)
|
(this as? BytecodeCallable)?.callOnFast(child) ?: callOn(child)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
callOn(scope.createChildScope(scope.pos, args = args, newThisObj = thisObj).also {
|
val child = scope.createChildScope(scope.pos, args = args, newThisObj = thisObj).also {
|
||||||
if (declaringClass != null) it.currentClassCtx = declaringClass
|
if (declaringClass != null) it.currentClassCtx = declaringClass
|
||||||
})
|
}
|
||||||
|
(this as? BytecodeCallable)?.callOnFast(child) ?: callOn(child)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user