Files
lyng/lynglib/src/jvmTest/kotlin/DeepPoolingStressJvmTest.kt
T

94 lines
2.8 KiB
Kotlin

/*
* Copyright 2025 Sergey S. Chernov real.sergeych@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* JVM stress tests for scope frame pooling (deep nesting and recursion).
*/
import kotlinx.coroutines.runBlocking
import net.sergeych.lyng.PerfFlags
import net.sergeych.lyng.Scope
import net.sergeych.lyng.obj.ObjInt
import kotlin.test.Test
import kotlin.test.assertEquals
class DeepPoolingStressJvmTest {
@Test
fun deepNestedCalls_noLeak_and_correct_with_and_without_pooling() = runBlocking {
val depth = 200
val script = """
fun f0(x) { x + 1 }
fun f1(x) { f0(x) + 1 }
fun f2(x) { f1(x) + 1 }
fun f3(x) { f2(x) + 1 }
fun f4(x) { f3(x) + 1 }
fun f5(x) { f4(x) + 1 }
fun chain(x, d) {
var i = 0
var s = x
while (i < d) {
// 5 nested calls per iteration
s = f5(s)
i = i + 1
}
s
}
chain(0, $depth)
""".trimIndent()
// Pool OFF
PerfFlags.SCOPE_POOL = false
val scope1 = Scope()
val r1 = (scope1.eval(script) as ObjInt).value
// Pool ON
PerfFlags.SCOPE_POOL = true
val scope2 = Scope()
val r2 = (scope2.eval(script) as ObjInt).value
// Each loop adds 6 (f0..f5 adds 6)
val expected = 6L * depth
assertEquals(expected, r1)
assertEquals(expected, r2)
// Reset
PerfFlags.SCOPE_POOL = false
}
@Test
fun recursion_factorial_correct_with_and_without_pooling() = runBlocking {
val n = 10
val script = """
fun fact(x) {
if (x <= 1) 1 else x * fact(x - 1)
}
fact($n)
""".trimIndent()
// OFF
PerfFlags.SCOPE_POOL = false
val scope1 = Scope()
val r1 = (scope1.eval(script) as ObjInt).value
// ON
PerfFlags.SCOPE_POOL = true
val scope2 = Scope()
val r2 = (scope2.eval(script) as ObjInt).value
// 10! = 3628800
val expected = 3628800L
assertEquals(expected, r1)
assertEquals(expected, r2)
PerfFlags.SCOPE_POOL = false
}
}