Compilation pipeline
The compilation process consists of several distinct phases:Phase 1: Parse Python source
Shed Skin begins by parsing your Python source code into an Abstract Syntax Tree (AST) using Python’s built-inast module:
Shed Skin uses the same AST format as Python itself, which is why it requires compatible Python versions (3.8-3.14) to run.
Phase 2: Build constraint graph
Next, Shed Skin builds a constraint graph representing how types flow through your program. This graph tracks:- Variable assignments and uses
- Function calls and returns
- Data structure operations
- Class relationships
Phase 3: Type inference
This is the most complex phase. Shed Skin uses sophisticated algorithms to determine the type of every variable, expression, and function in your program.Type inference algorithms
Shed Skin combines two powerful type inference techniques: Cartesian Product Algorithm (CPA): Handles function polymorphism- When a function is called with different argument types, CPA creates specialized versions
- Each version has concrete types for that specific usage
- Prevents type imprecision from different call sites mixing together
- When container types (lists, classes) are used polymorphically, IFA creates specialized versions
- Tracks which specialized version is used at each allocation site
- Allows the same class or list to have different element types in different contexts
identity—one for integers, one for strings.
Iterative dataflow analysis process
Type inference proceeds iteratively: Forward phase:- Propagate known types through the constraint graph
- Create function specializations using CPA where needed
- Seed allocation points with initial types
- Identify points where type precision is lost (type mixing)
- Trace backward through the graph to find related allocation points
- Create specialized versions of classes/containers to separate types
- Distribute specialized versions across allocation points
- If imprecision points remain, reset and restart analysis with new specializations
- Continue until no imprecision remains or further analysis won’t help
- Build final type information for code generation
Why iterative analysis?
Why iterative analysis?
A naive approach would create all possible specializations up front, but this leads to exponential blowup. Instead, Shed Skin incrementally analyzes small sets of functions and allocation sites, only creating specializations when actual imprecision is detected.This is similar to how JIT compilers work—specialize only what’s needed, when it’s needed.
Phase 4: Generate C++ code
Once types are known, Shed Skin generates C++ code by traversing the AST and emitting corresponding C++ constructs:- Template generation: For polymorphic functions
- Virtual method tables: For class hierarchies
- Type declarations: Converting Python types to C++ types
- Memory management: Integration with Boehm GC
- Exception handling: Python exceptions to C++ exceptions
- Module structure: Namespaces and includes
Phase 5: Compile C++ to binary
The generated C++ code is compiled using a C++ compiler (typically GCC or Clang):- A standalone executable (for programs)
- A Python extension module (for libraries)
Type inference deep dive
Type seeds
Type inference starts from type seeds—places where types are explicitly known:Type propagation
Types flow through the constraint graph along edges:- Assignments: Type flows from right side to left side
- Function calls: Argument types flow to parameters; return types flow back
- Operations: Operand types determine result types
- Containers: Element types determine container types
Handling polymorphism
When a function is used with multiple types:Memory management
Shed Skin integrates the Boehm-Demers-Weiser garbage collector for automatic memory management.Boehm GC integration
The Boehm GC is a conservative garbage collector for C/C++:- Conservative scanning: Treats anything that looks like a pointer as a pointer
- Non-moving: Objects stay at the same memory address
- Thread-safe: Supports multi-threaded programs (with appropriate configuration)
- Incremental: Can run in incremental mode to reduce pause times
Memory allocation
All Python objects are allocated using the GC:(GC) placement new syntax tells the GC to manage this memory.
When GC runs
The GC runs automatically when:- Memory pressure increases
- Explicit collection is requested via
gc.collect() - A threshold of allocated memory is exceeded
--nogc for maximum performance, but this means memory leaks:
Performance characteristics
Why C++ is faster
Shed Skin generates fast code because:- Static types: No runtime type checking or boxing/unboxing
- Direct calls: Function calls compile to direct C++ calls, not dictionary lookups
- Inlining: C++ compiler can inline small functions
- Memory layout: Objects use efficient C++ memory layout, not Python dicts
- Native integers: Integer operations use CPU instructions directly
- Loop optimization: C++ compiler optimizes loops aggressively
Performance trade-offs
Fast paths:- Numeric computations
- Loop-heavy code
- String operations (except Unicode)
- Container operations (list, dict, set)
- Extension module overhead (crossing Python/C++ boundary)
- Memory allocation (Boehm GC has some overhead)
- Exception handling (comparable to C++ exceptions)
Optimization tips
Shed Skin provides several compiler flags to optimize further:Scalability limitations
Shed Skin’s type inference doesn’t scale well beyond several thousand lines of code:- Largest successful program: ~6,000 lines (measured with sloccount)
- Reason: Constraint graph grows large; analysis becomes slow
- Workaround: Split large programs into multiple modules
For larger projects, compile performance-critical modules separately as extension modules, then import them from regular Python code.
Architecture overview
Key modules in Shed Skin’s codebase:shedskin.graph: Builds the constraint graph from the ASTshedskin.infer: Performs type inference (CPA + IFA)shedskin.cpp: Generates C++ code from typed ASTshedskin.python: Python type models (Class, Function, Variable, etc.)shedskin.config: Global compiler configurationshedskin.error: Error reporting and diagnostics
Further reading
For deep technical details:- Ole Agesen’s PhD thesis: Describes the Cartesian Product Algorithm
- John Plevyak’s work: Describes Iterative Flow Analysis
- Mark Dufour’s MSc thesis: Describes Shed Skin’s implementation in detail
- Source code:
shedskin/infer.pyandshedskin/graph.pycontain extensive documentation
Learning from generated code
Learning from generated code
One of the best ways to understand Shed Skin is to look at the C++ code it generates:The generated code is readable and includes comments. Seeing how your Python constructs map to C++ will deepen your understanding of the compilation process.