Replies: 3 comments
-
ProposalI propose adding a new decorator, The earlier background example can be rewritten as follows: @codon.jitclass
class A:
x: int
y: int
def __init__(self, x: int, y: int) -> None:
self.x = x
self.y = y
def hello(self):
return self.x + self.y
a = A(1, 2)
print(a.hello()) # 3
a.x = 10
print(a.hello()) # 12Unlike the For instance, when executing Realizing this proposal requires the following components. 1. Class-level JIT compilationWhen a class is decorated with The decorator supports:
For example: @codon.jitclass
class Counter:
value: int
def __init__(self, value: int):
self.value = value
def inc(self, n: int) -> int:
self.value += n
return self.valueis compiled into a native Codon class. Python calls to 2. Native object constructionCalling a Internally, construction goes through a JIT-generated wrapper similar to: @export
def __codon_jitclass_new(args: cobj) -> cobj:
...
obj = NativeClass(...)
return obj.__raw__()The returned native pointer is stored in a JIT-side handle table. Python receives a lightweight proxy object that refers to this handle. This means the object is not repeatedly converted back and forth. Instead, the native object remains alive in the JIT runtime and is accessed through stable handles. 3. Method dispatchEach Python method call on a For example, This gives users a natural Python object-oriented interface while executing the actual method body in native Codon code. 4. Field accessField access is supported through generated getter and setter methods. For a field declaration: x: intthe implementation internally generates methods equivalent to: def _codon_jitclass_get_x(self) -> int:
return self.x
def _codon_jitclass_set_x(self, value: int) -> int:
self.x = value
return valuePython descriptors then expose this as normal attribute access: a.x # native getter
a.y = 10 # native setterThis allows mutable native state to be observed and updated from Python naturally. 5. Lifecycle managementA The proxy supports explicit release and context-manager usage: a = A(1, 2)
a.close()with A(1, 2) as a:
print(a.hello())Once released, further access raises a JIT error instead of using an invalid native pointer. The implementation also tracks the active JIT generation. If the JIT context is reset because of a compilation error or runtime failure, old 6. GC root safetyCodon objects are allocated in the Codon runtime and may be managed by the runtime GC. Since To achieve this, each native struct JITClassRoot {
std::unique_ptr<void *> slot;
explicit JITClassRoot(void *ptr);
~JITClassRoot();
};The root is added when the native object is stored in the JIT handle table and removed automatically when the handle is released. This prevents the Codon GC from collecting native objects that are still reachable from Python. Expected Effect
Compared with
|
Beta Was this translation helpful? Give feedback.
-
Initial Implementation |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Motivation & Background
Codon already provides
codon.convertas a mechanism to expose Python classes to Codon JIT-compiled functions. This approach is suitable for simple interoperability scenarios: a Python object is converted into a Codon-compatible representation, passed into compiled code, and then used within JIT-compiled functions.To illustrate, consider the following example:
When a class is decorated with
codon.convert, the Codon JIT side generates a native Codon tuple-like classA[T0, T1]. The@codon.jitdecorator on a member function behaves exactly as it does on a standalone function—it treatsselfas an ordinary parameter.The expression
a = A(1, 2)still executes the original Python__init__and produces a standardPyObject. Whena.hello()is invoked, the Codon JIT first converts thePyObjectainto an instance of the generatedA[T0, T1]class and then passes that converted object to the JIT-compiledhellofunction.However,
codon.converthas several inherent limitations when the goal is to model Python classes as native Codon objects:Object identity and lifetime are not naturally preserved
codon.convertprimarily treats Python objects as values that can be transformed into Codon-side data structures. This works well for immutable or value-like objects, but it is not ideal for class instances that are expected to behave as long-lived mutable objects with stable identity.Mutation semantics are limited
For Python classes with fields, users often expect operations such as
to operate on the same underlying object. With conversion-based interop, field mutations may not naturally map to persistent native state unless the object is explicitly reconstructed or round-tripped between Python and Codon representations.
Methods are not represented as native class methods
codon.convertallows converted objects to be consumed by JIT functions, but it does not make the Python class itself a native Codon class with compiled methods, constructors, and field accessors. This prevents object-oriented workloads from being expressed directly in the JIT layer.Performance opportunities are left on the table
A conversion-based approach introduces boundaries between Python objects and Codon values. For class-heavy workloads, repeatedly converting objects or routing behavior through Python-level wrappers can erode the performance gains expected from JIT compilation.
The user model is less direct
Users who write ordinary Python classes typically expect a decorator-based workflow in which the class itself becomes compiled, rather than manually converting instances or authoring separate JIT functions that operate on them.
Because of these limitations, we propose adding first-class support for JIT-compiled classes through
codon.jitclass.Beta Was this translation helpful? Give feedback.
All reactions