From 205f78b94c410044e95732bd532150e73f30aa56 Mon Sep 17 00:00:00 2001 From: Pavel Koneski Date: Tue, 3 Nov 2026 16:09:44 -0700 Subject: [PATCH] Compile functions to IL when adaptive compilation is off --- src/core/IronPython/Runtime/FunctionCode.cs | 3 +- .../Cases/IronPythonCasesManifest.ini | 4 ++ tests/suite/test_noadaptivecompilation.py | 58 +++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 tests/suite/test_noadaptivecompilation.py diff --git a/src/core/IronPython/Runtime/FunctionCode.cs b/src/core/IronPython/Runtime/FunctionCode.cs index 276f66248..a392cae5d 100644 --- a/src/core/IronPython/Runtime/FunctionCode.cs +++ b/src/core/IronPython/Runtime/FunctionCode.cs @@ -893,7 +893,8 @@ private Delegate CompileLambda(LightLambdaExpression code, EventHandler handler) { diff --git a/tests/IronPython.Tests/Cases/IronPythonCasesManifest.ini b/tests/IronPython.Tests/Cases/IronPythonCasesManifest.ini index 562c0b39e..4df53aa39 100644 --- a/tests/IronPython.Tests/Cases/IronPythonCasesManifest.ini +++ b/tests/IronPython.Tests/Cases/IronPythonCasesManifest.ini @@ -52,6 +52,10 @@ IsolationLevel=PROCESS # to avoid having a long list of object subtypes RunCondition=NOT $(IS_MONO) AND NOT $(IS_OSX) Reason=Memory allocation on Mono may not match MS.NET +[IronPython.test_noadaptivecompilation] +IsolationLevel=PROCESS +Arguments=-X NoAdaptiveCompilation "$(TEST_FILE)" # the test is skipped without the option + [IronPython.test_number] Timeout=300000 # 5 minute timeout - slow on macOS diff --git a/tests/suite/test_noadaptivecompilation.py b/tests/suite/test_noadaptivecompilation.py new file mode 100644 index 000000000..06ec30672 --- /dev/null +++ b/tests/suite/test_noadaptivecompilation.py @@ -0,0 +1,58 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the Apache 2.0 License. +# See the LICENSE file in the project root for more information. + +""" +Test that functions are compiled up front with -X:NoAdaptiveCompilation. +""" + +import unittest + +from iptest import IronPythonTestCase, is_cli, run_test + +if is_cli: + import clr + from System.Reflection import BindingFlags + + def is_interpreted(func): + """Returns whether the function, which must have been called at least once, runs in the interpreter.""" + field = clr.GetClrType(type(func.__code__)).GetField('_normalDelegate', BindingFlags.NonPublic | BindingFlags.Instance) + delegate = field.GetValue(func.__code__) + return delegate.Target.GetType().Name == 'LightLambda' + + no_adaptive_compilation = clr.GetCurrentRuntime().GetLanguageByName('python').Options.NoAdaptiveCompilation +else: + no_adaptive_compilation = False + +def no_loop(n): + return n + +def with_for(n): + for i in range(n): + pass + +def with_while(n): + i = 0 + while i < n: + i += 1 + +def generator(n): + for i in range(n): + yield i + +@unittest.skipUnless(no_adaptive_compilation, 'requires -X NoAdaptiveCompilation') +class NoAdaptiveCompilationTest(IronPythonTestCase): + def test_functions(self): + def nested(n): + return n + + class C: + def method(self, n): + return n + + calls = [(no_loop, 1), (with_for, 1), (with_while, 1), (generator, 1), (nested, 1), (lambda n: n, 1), (C.method, C(), 1)] + for func, *args in calls: + func(*args) # for a generator, this runs the function that creates the generator object + self.assertFalse(is_interpreted(func), func.__name__) + +run_test(__name__)