Extend generic fast callable entry points
This commit is contained in:
parent
6c91b77a85
commit
ee634c8dff
@ -724,41 +724,39 @@ open class Obj {
|
|||||||
scope.raiseNotImplemented()
|
scope.raiseNotImplemented()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun invoke(scope: Scope, thisObj: Obj, args: Arguments, declaringClass: ObjClass? = null): Obj {
|
private suspend fun invokeWithBoundScope(
|
||||||
val usePool = PerfFlags.SCOPE_POOL && this !is Statement
|
scope: Scope,
|
||||||
|
args: Arguments,
|
||||||
|
thisObj: Obj,
|
||||||
|
declaringClass: ObjClass? = null,
|
||||||
|
atPos: Pos = scope.pos
|
||||||
|
): Obj {
|
||||||
|
val usePool = PerfFlags.SCOPE_POOL && this !is Statement && atPos == scope.pos
|
||||||
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
|
||||||
(this as? BytecodeCallable)?.callOnFast(child) ?: callOn(child)
|
(this as? BytecodeCallable)?.callOnFast(child) ?: callOn(child)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val child = scope.createChildScope(scope.pos, args = args, newThisObj = thisObj).also {
|
val child = scope.createChildScope(atPos, args = args, newThisObj = thisObj).also {
|
||||||
if (declaringClass != null) it.currentClassCtx = declaringClass
|
if (declaringClass != null) it.currentClassCtx = declaringClass
|
||||||
}
|
}
|
||||||
(this as? BytecodeCallable)?.callOnFast(child) ?: callOn(child)
|
(this as? BytecodeCallable)?.callOnFast(child) ?: callOn(child)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun invoke(scope: Scope, thisObj: Obj, args: Arguments, declaringClass: ObjClass? = null): Obj {
|
||||||
|
return invokeWithBoundScope(scope, args, thisObj, declaringClass)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun invoke(scope: Scope, thisObj: Obj, vararg args: Obj): Obj =
|
suspend fun invoke(scope: Scope, thisObj: Obj, vararg args: Obj): Obj =
|
||||||
callOn(
|
invokeWithBoundScope(scope, Arguments(args.toList()), thisObj)
|
||||||
scope.createChildScope(
|
|
||||||
scope.pos,
|
|
||||||
args = Arguments(args.toList()),
|
|
||||||
newThisObj = thisObj
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
suspend fun invoke(scope: Scope, thisObj: Obj): Obj =
|
suspend fun invoke(scope: Scope, thisObj: Obj): Obj =
|
||||||
callOn(
|
invokeWithBoundScope(scope, Arguments.EMPTY, thisObj)
|
||||||
scope.createChildScope(
|
|
||||||
scope.pos,
|
|
||||||
args = Arguments.EMPTY,
|
|
||||||
newThisObj = thisObj
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
suspend fun invoke(scope: Scope, atPos: Pos, thisObj: Obj, args: Arguments): Obj =
|
suspend fun invoke(scope: Scope, atPos: Pos, thisObj: Obj, args: Arguments): Obj =
|
||||||
callOn(scope.createChildScope(atPos, args = args, newThisObj = thisObj))
|
invokeWithBoundScope(scope, args, thisObj, atPos = atPos)
|
||||||
|
|
||||||
|
|
||||||
val asReadonly: ObjRecord by lazy { ObjRecord(this, false) }
|
val asReadonly: ObjRecord by lazy { ObjRecord(this, false) }
|
||||||
|
|||||||
@ -58,7 +58,10 @@ abstract class Statement(
|
|||||||
val type = ObjClass("Callable")
|
val type = ObjClass("Callable")
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun call(scope: Scope, vararg args: Obj) = execute(scope.createChildScope(args = Arguments(*args)))
|
suspend fun call(scope: Scope, vararg args: Obj): Obj {
|
||||||
|
val child = scope.createChildScope(args = Arguments(*args))
|
||||||
|
return (this as? BytecodeCallable)?.callOnFast(child) ?: execute(child)
|
||||||
|
}
|
||||||
|
|
||||||
protected fun bytecodeOnly(scope: Scope, label: String): Nothing {
|
protected fun bytecodeOnly(scope: Scope, label: String): Nothing {
|
||||||
return scope.raiseIllegalState("bytecode-only execution is required; $label needs compiled bytecode")
|
return scope.raiseIllegalState("bytecode-only execution is required; $label needs compiled bytecode")
|
||||||
|
|||||||
@ -17,10 +17,12 @@
|
|||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import net.sergeych.lyng.Compiler
|
import net.sergeych.lyng.Compiler
|
||||||
import net.sergeych.lyng.Arguments
|
import net.sergeych.lyng.Arguments
|
||||||
|
import net.sergeych.lyng.Pos
|
||||||
import net.sergeych.lyng.Scope
|
import net.sergeych.lyng.Scope
|
||||||
import net.sergeych.lyng.Script
|
import net.sergeych.lyng.Script
|
||||||
import net.sergeych.lyng.ScriptError
|
import net.sergeych.lyng.ScriptError
|
||||||
import net.sergeych.lyng.Source
|
import net.sergeych.lyng.Source
|
||||||
|
import net.sergeych.lyng.Statement
|
||||||
import net.sergeych.lyng.asFacade
|
import net.sergeych.lyng.asFacade
|
||||||
import net.sergeych.lyng.obj.ObjInt
|
import net.sergeych.lyng.obj.ObjInt
|
||||||
import net.sergeych.lyng.obj.ObjString
|
import net.sergeych.lyng.obj.ObjString
|
||||||
@ -88,6 +90,66 @@ class CompilerVmReviewRegressionTest {
|
|||||||
assertEquals(42, scope.asFacade().call(callable, Arguments(ObjInt.of(40))).toInt())
|
assertEquals(42, scope.asFacade().call(callable, Arguments(ObjInt.of(40))).toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun genericInvokeHelpersUsePreparedLambdaEntryPoints() = runTest {
|
||||||
|
val unaryLambda = Compiler.compile(
|
||||||
|
Source(
|
||||||
|
"<generic-invoke-unary>",
|
||||||
|
"""
|
||||||
|
val delta = 2
|
||||||
|
{ x -> x + delta }
|
||||||
|
""".trimIndent()
|
||||||
|
),
|
||||||
|
Script.defaultImportManager
|
||||||
|
)
|
||||||
|
val nullaryLambda = Compiler.compile(
|
||||||
|
Source(
|
||||||
|
"<generic-invoke-nullary>",
|
||||||
|
"""
|
||||||
|
val base = 7
|
||||||
|
{ base }
|
||||||
|
""".trimIndent()
|
||||||
|
),
|
||||||
|
Script.defaultImportManager
|
||||||
|
)
|
||||||
|
|
||||||
|
val unaryScope = Script.newScope()
|
||||||
|
val nullaryScope = Script.newScope()
|
||||||
|
val unaryCallable = unaryLambda.execute(unaryScope)
|
||||||
|
val nullaryCallable = nullaryLambda.execute(nullaryScope)
|
||||||
|
|
||||||
|
assertEquals(42, unaryCallable.invoke(unaryScope, ObjString("receiver"), ObjInt.of(40)).toInt())
|
||||||
|
assertEquals(7, nullaryCallable.invoke(nullaryScope, ObjString("receiver")).toInt())
|
||||||
|
assertEquals(
|
||||||
|
42,
|
||||||
|
unaryCallable.invoke(
|
||||||
|
unaryScope,
|
||||||
|
Pos(Source("<generic-invoke-pos>", ""), 0, 0),
|
||||||
|
ObjString("receiver"),
|
||||||
|
Arguments(ObjInt.of(40))
|
||||||
|
).toInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun statementCallUsesPreparedLambdaFastPath() = runTest {
|
||||||
|
val unaryLambda = Compiler.compile(
|
||||||
|
Source(
|
||||||
|
"<statement-call-unary>",
|
||||||
|
"""
|
||||||
|
val delta = 2
|
||||||
|
{ x -> x + delta }
|
||||||
|
""".trimIndent()
|
||||||
|
),
|
||||||
|
Script.defaultImportManager
|
||||||
|
)
|
||||||
|
|
||||||
|
val scope = Script.newScope()
|
||||||
|
val callable = unaryLambda.execute(scope) as Statement
|
||||||
|
|
||||||
|
assertEquals(42, callable.call(scope, ObjInt.of(40)).toInt())
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun subjectlessWhenReportsScriptError() = runTest {
|
fun subjectlessWhenReportsScriptError() = runTest {
|
||||||
val ex = assertFailsWith<ScriptError> {
|
val ex = assertFailsWith<ScriptError> {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user