zexus 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +0 -0
- package/README.md +2513 -0
- package/bin/zexus +2 -0
- package/bin/zpics +2 -0
- package/bin/zpm +2 -0
- package/bin/zx +2 -0
- package/bin/zx-deploy +2 -0
- package/bin/zx-dev +2 -0
- package/bin/zx-run +2 -0
- package/package.json +66 -0
- package/scripts/README.md +24 -0
- package/scripts/postinstall.js +44 -0
- package/shared_config.json +24 -0
- package/src/README.md +1525 -0
- package/src/tests/run_zexus_tests.py +117 -0
- package/src/tests/test_all_phases.zx +346 -0
- package/src/tests/test_blockchain_features.zx +306 -0
- package/src/tests/test_complexity_features.zx +321 -0
- package/src/tests/test_core_integration.py +185 -0
- package/src/tests/test_phase10_ecosystem.zx +177 -0
- package/src/tests/test_phase1_modifiers.zx +87 -0
- package/src/tests/test_phase2_plugins.zx +80 -0
- package/src/tests/test_phase3_security.zx +97 -0
- package/src/tests/test_phase4_vfs.zx +116 -0
- package/src/tests/test_phase5_types.zx +117 -0
- package/src/tests/test_phase6_metaprogramming.zx +125 -0
- package/src/tests/test_phase7_optimization.zx +132 -0
- package/src/tests/test_phase9_advanced_types.zx +157 -0
- package/src/tests/test_security_features.py +419 -0
- package/src/tests/test_security_features.zx +276 -0
- package/src/tests/test_simple_zx.zx +1 -0
- package/src/tests/test_verification_simple.zx +69 -0
- package/src/zexus/__init__.py +28 -0
- package/src/zexus/__main__.py +5 -0
- package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/advanced_types.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/builtin_modules.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/complexity_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/concurrency_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/config.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/dependency_injection.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/ecosystem.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/hybrid_orchestrator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/metaprogramming.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/optimization.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/plugin_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/policy_engine.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/stdlib_integration.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/strategy_recovery.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/type_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/virtual_filesystem.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
- package/src/zexus/advanced_types.py +401 -0
- package/src/zexus/blockchain/__init__.py +40 -0
- package/src/zexus/blockchain/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/crypto.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/ledger.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/transaction.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/crypto.py +463 -0
- package/src/zexus/blockchain/ledger.py +255 -0
- package/src/zexus/blockchain/transaction.py +267 -0
- package/src/zexus/builtin_modules.py +284 -0
- package/src/zexus/builtin_plugins.py +317 -0
- package/src/zexus/capability_system.py +372 -0
- package/src/zexus/cli/__init__.py +2 -0
- package/src/zexus/cli/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
- package/src/zexus/cli/main.py +707 -0
- package/src/zexus/cli/zpm.py +203 -0
- package/src/zexus/compare_interpreter_compiler.py +146 -0
- package/src/zexus/compiler/__init__.py +169 -0
- package/src/zexus/compiler/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/compiler/bytecode.py +266 -0
- package/src/zexus/compiler/compat_runtime.py +277 -0
- package/src/zexus/compiler/lexer.py +257 -0
- package/src/zexus/compiler/parser.py +779 -0
- package/src/zexus/compiler/semantic.py +118 -0
- package/src/zexus/compiler/zexus_ast.py +454 -0
- package/src/zexus/complexity_system.py +575 -0
- package/src/zexus/concurrency_system.py +493 -0
- package/src/zexus/config.py +201 -0
- package/src/zexus/crypto_bridge.py +19 -0
- package/src/zexus/dependency_injection.py +423 -0
- package/src/zexus/ecosystem.py +434 -0
- package/src/zexus/environment.py +101 -0
- package/src/zexus/environment_manager.py +119 -0
- package/src/zexus/error_reporter.py +314 -0
- package/src/zexus/evaluator/__init__.py +12 -0
- package/src/zexus/evaluator/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/integration.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/bytecode_compiler.py +700 -0
- package/src/zexus/evaluator/core.py +891 -0
- package/src/zexus/evaluator/expressions.py +827 -0
- package/src/zexus/evaluator/functions.py +3989 -0
- package/src/zexus/evaluator/integration.py +396 -0
- package/src/zexus/evaluator/statements.py +4303 -0
- package/src/zexus/evaluator/utils.py +126 -0
- package/src/zexus/evaluator_original.py +2041 -0
- package/src/zexus/external_bridge.py +16 -0
- package/src/zexus/find_affected_imports.sh +155 -0
- package/src/zexus/hybrid_orchestrator.py +152 -0
- package/src/zexus/input_validation.py +259 -0
- package/src/zexus/lexer.py +571 -0
- package/src/zexus/logging.py +89 -0
- package/src/zexus/lsp/__init__.py +9 -0
- package/src/zexus/lsp/completion_provider.py +207 -0
- package/src/zexus/lsp/definition_provider.py +22 -0
- package/src/zexus/lsp/hover_provider.py +71 -0
- package/src/zexus/lsp/server.py +269 -0
- package/src/zexus/lsp/symbol_provider.py +31 -0
- package/src/zexus/metaprogramming.py +321 -0
- package/src/zexus/module_cache.py +89 -0
- package/src/zexus/module_manager.py +107 -0
- package/src/zexus/object.py +973 -0
- package/src/zexus/optimization.py +424 -0
- package/src/zexus/parser/__init__.py +31 -0
- package/src/zexus/parser/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
- package/src/zexus/parser/integration.py +86 -0
- package/src/zexus/parser/parser.py +3977 -0
- package/src/zexus/parser/strategy_context.py +7254 -0
- package/src/zexus/parser/strategy_structural.py +1033 -0
- package/src/zexus/persistence.py +391 -0
- package/src/zexus/plugin_system.py +290 -0
- package/src/zexus/policy_engine.py +365 -0
- package/src/zexus/profiler/__init__.py +5 -0
- package/src/zexus/profiler/profiler.py +233 -0
- package/src/zexus/purity_system.py +398 -0
- package/src/zexus/runtime/__init__.py +20 -0
- package/src/zexus/runtime/async_runtime.py +324 -0
- package/src/zexus/search_old_imports.sh +65 -0
- package/src/zexus/security.py +1407 -0
- package/src/zexus/stack_trace.py +233 -0
- package/src/zexus/stdlib/__init__.py +27 -0
- package/src/zexus/stdlib/blockchain.py +341 -0
- package/src/zexus/stdlib/compression.py +167 -0
- package/src/zexus/stdlib/crypto.py +124 -0
- package/src/zexus/stdlib/datetime.py +163 -0
- package/src/zexus/stdlib/db_mongo.py +199 -0
- package/src/zexus/stdlib/db_mysql.py +162 -0
- package/src/zexus/stdlib/db_postgres.py +163 -0
- package/src/zexus/stdlib/db_sqlite.py +133 -0
- package/src/zexus/stdlib/encoding.py +230 -0
- package/src/zexus/stdlib/fs.py +195 -0
- package/src/zexus/stdlib/http.py +219 -0
- package/src/zexus/stdlib/http_server.py +248 -0
- package/src/zexus/stdlib/json_module.py +61 -0
- package/src/zexus/stdlib/math.py +360 -0
- package/src/zexus/stdlib/os_module.py +265 -0
- package/src/zexus/stdlib/regex.py +148 -0
- package/src/zexus/stdlib/sockets.py +253 -0
- package/src/zexus/stdlib/test_framework.zx +208 -0
- package/src/zexus/stdlib/test_runner.zx +119 -0
- package/src/zexus/stdlib_integration.py +341 -0
- package/src/zexus/strategy_recovery.py +256 -0
- package/src/zexus/syntax_validator.py +356 -0
- package/src/zexus/testing/zpics.py +407 -0
- package/src/zexus/testing/zpics_runtime.py +369 -0
- package/src/zexus/type_system.py +374 -0
- package/src/zexus/validation_system.py +569 -0
- package/src/zexus/virtual_filesystem.py +355 -0
- package/src/zexus/vm/__init__.py +8 -0
- package/src/zexus/vm/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/memory_manager.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/memory_pool.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/peephole_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/profiler.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/register_allocator.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/register_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/ssa_converter.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/async_optimizer.py +420 -0
- package/src/zexus/vm/bytecode.py +428 -0
- package/src/zexus/vm/bytecode_converter.py +297 -0
- package/src/zexus/vm/cache.py +532 -0
- package/src/zexus/vm/jit.py +720 -0
- package/src/zexus/vm/memory_manager.py +520 -0
- package/src/zexus/vm/memory_pool.py +511 -0
- package/src/zexus/vm/optimizer.py +478 -0
- package/src/zexus/vm/parallel_vm.py +899 -0
- package/src/zexus/vm/peephole_optimizer.py +452 -0
- package/src/zexus/vm/profiler.py +527 -0
- package/src/zexus/vm/register_allocator.py +462 -0
- package/src/zexus/vm/register_vm.py +520 -0
- package/src/zexus/vm/ssa_converter.py +757 -0
- package/src/zexus/vm/vm.py +1392 -0
- package/src/zexus/zexus_ast.py +1782 -0
- package/src/zexus/zexus_token.py +253 -0
- package/src/zexus/zpm/__init__.py +15 -0
- package/src/zexus/zpm/installer.py +116 -0
- package/src/zexus/zpm/package_manager.py +208 -0
- package/src/zexus/zpm/publisher.py +98 -0
- package/src/zexus/zpm/registry.py +110 -0
- package/src/zexus.egg-info/PKG-INFO +2235 -0
- package/src/zexus.egg-info/SOURCES.txt +876 -0
- package/src/zexus.egg-info/dependency_links.txt +1 -0
- package/src/zexus.egg-info/entry_points.txt +3 -0
- package/src/zexus.egg-info/not-zip-safe +1 -0
- package/src/zexus.egg-info/requires.txt +14 -0
- package/src/zexus.egg-info/top_level.txt +2 -0
- package/zexus.json +14 -0
|
@@ -0,0 +1,720 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Just-In-Time Compiler for Zexus VM
|
|
3
|
+
|
|
4
|
+
Provides tiered compilation:
|
|
5
|
+
- Tier 0: Interpreted execution (slowest, most flexible)
|
|
6
|
+
- Tier 1: Bytecode VM execution (fast, portable)
|
|
7
|
+
- Tier 2: JIT-compiled native code (fastest, hot paths only)
|
|
8
|
+
|
|
9
|
+
Features:
|
|
10
|
+
- Hot path detection via execution counters
|
|
11
|
+
- Bytecode optimization passes (via BytecodeOptimizer)
|
|
12
|
+
- Native code generation via Python compile()
|
|
13
|
+
- JIT cache for compiled code
|
|
14
|
+
- Automatic tier promotion
|
|
15
|
+
- Stack state simulation for accurate Python code generation
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import hashlib
|
|
19
|
+
import time
|
|
20
|
+
import dis
|
|
21
|
+
from typing import Dict, Any, Optional, Tuple, Callable, List, Set
|
|
22
|
+
from dataclasses import dataclass, field
|
|
23
|
+
from enum import Enum
|
|
24
|
+
|
|
25
|
+
# Import optimizer for advanced optimization
|
|
26
|
+
try:
|
|
27
|
+
from .optimizer import BytecodeOptimizer
|
|
28
|
+
OPTIMIZER_AVAILABLE = True
|
|
29
|
+
except ImportError:
|
|
30
|
+
OPTIMIZER_AVAILABLE = False
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ExecutionTier(Enum):
|
|
34
|
+
"""Execution tiers for tiered compilation"""
|
|
35
|
+
INTERPRETED = 0 # AST interpretation (slowest)
|
|
36
|
+
BYTECODE = 1 # Stack-based VM (fast)
|
|
37
|
+
JIT_NATIVE = 2 # JIT-compiled native code (fastest)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class HotPathInfo:
|
|
42
|
+
"""Information about a hot execution path"""
|
|
43
|
+
bytecode_hash: str
|
|
44
|
+
execution_count: int = 0
|
|
45
|
+
total_time: float = 0.0
|
|
46
|
+
average_time: float = 0.0
|
|
47
|
+
last_execution: float = 0.0
|
|
48
|
+
compiled_version: Optional[Callable] = None
|
|
49
|
+
compilation_time: float = 0.0
|
|
50
|
+
tier: ExecutionTier = ExecutionTier.BYTECODE
|
|
51
|
+
speedup_factor: float = 1.0
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
55
|
+
class JITStats:
|
|
56
|
+
"""JIT compilation statistics"""
|
|
57
|
+
hot_paths_detected: int = 0
|
|
58
|
+
compilations: int = 0
|
|
59
|
+
compilation_time: float = 0.0
|
|
60
|
+
average_compilation_time: float = 0.0
|
|
61
|
+
jit_executions: int = 0
|
|
62
|
+
total_jit_execution_time: float = 0.0
|
|
63
|
+
total_bytecode_execution_time: float = 0.0
|
|
64
|
+
cache_hits: int = 0
|
|
65
|
+
cache_misses: int = 0
|
|
66
|
+
tier_promotions: int = 0
|
|
67
|
+
compilation_failures: int = 0
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass
|
|
71
|
+
class StackFrame:
|
|
72
|
+
"""Represents stack state at a point in bytecode"""
|
|
73
|
+
stack: List[str] = field(default_factory=list) # Variable names on stack
|
|
74
|
+
variables: Dict[str, str] = field(default_factory=dict) # Variable -> expression
|
|
75
|
+
constants: Dict[int, Any] = field(default_factory=dict) # Constant ID -> value
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class JITCompiler:
|
|
79
|
+
"""
|
|
80
|
+
Just-In-Time compiler for Zexus VM bytecode
|
|
81
|
+
|
|
82
|
+
Implements a tiered compilation strategy:
|
|
83
|
+
1. Detect hot paths via execution counting
|
|
84
|
+
2. Optimize bytecode with peephole passes
|
|
85
|
+
3. Compile to native Python code for maximum speed
|
|
86
|
+
4. Cache compiled code for reuse
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
def __init__(self, hot_threshold: int = 100, optimization_level: int = 1, debug: bool = False):
|
|
90
|
+
"""
|
|
91
|
+
Initialize JIT compiler
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
hot_threshold: Number of executions before JIT compilation
|
|
95
|
+
optimization_level: 0=none, 1=basic (default), 2=aggressive, 3=experimental
|
|
96
|
+
debug: Enable debug output
|
|
97
|
+
"""
|
|
98
|
+
self.hot_threshold = hot_threshold
|
|
99
|
+
self.optimization_level = optimization_level
|
|
100
|
+
self.debug = debug
|
|
101
|
+
self.verbose = debug # Alias for compatibility
|
|
102
|
+
|
|
103
|
+
# Hot path tracking
|
|
104
|
+
self.hot_paths: Dict[str, HotPathInfo] = {}
|
|
105
|
+
|
|
106
|
+
# Compilation cache: bytecode_hash -> compiled_function
|
|
107
|
+
self.compilation_cache: Dict[str, Callable] = {}
|
|
108
|
+
|
|
109
|
+
# Statistics
|
|
110
|
+
self.stats = JITStats()
|
|
111
|
+
|
|
112
|
+
# Use advanced optimizer if available
|
|
113
|
+
if OPTIMIZER_AVAILABLE and optimization_level > 0:
|
|
114
|
+
self.optimizer = BytecodeOptimizer(level=optimization_level, max_passes=3, debug=False)
|
|
115
|
+
if self.debug:
|
|
116
|
+
print(f"🔧 JIT: Using BytecodeOptimizer (level {optimization_level})")
|
|
117
|
+
else:
|
|
118
|
+
self.optimizer = None
|
|
119
|
+
if self.debug and optimization_level > 0:
|
|
120
|
+
print("⚠️ JIT: BytecodeOptimizer not available, using basic optimization")
|
|
121
|
+
|
|
122
|
+
# Supported opcodes for JIT compilation
|
|
123
|
+
self.supported_opcodes = {
|
|
124
|
+
'LOAD_CONST', 'LOAD_NAME', 'STORE_NAME', 'STORE_CONST',
|
|
125
|
+
'ADD', 'SUB', 'MUL', 'DIV', 'MOD', 'POW',
|
|
126
|
+
'EQ', 'NEQ', 'LT', 'GT', 'LTE', 'GTE',
|
|
127
|
+
'AND', 'OR', 'NOT',
|
|
128
|
+
'RETURN', 'JUMP', 'JUMP_IF_FALSE',
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
def should_compile(self, bytecode_hash: str) -> bool:
|
|
132
|
+
"""
|
|
133
|
+
Determine if bytecode should be JIT compiled
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
bytecode_hash: Hash of the bytecode
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
True if code is hot enough for JIT compilation
|
|
140
|
+
"""
|
|
141
|
+
if bytecode_hash not in self.hot_paths:
|
|
142
|
+
return False
|
|
143
|
+
|
|
144
|
+
info = self.hot_paths[bytecode_hash]
|
|
145
|
+
|
|
146
|
+
# Check if already compiled
|
|
147
|
+
if info.tier == ExecutionTier.JIT_NATIVE:
|
|
148
|
+
return False
|
|
149
|
+
|
|
150
|
+
# Promote to JIT after threshold executions
|
|
151
|
+
if info.execution_count >= self.hot_threshold:
|
|
152
|
+
return True
|
|
153
|
+
|
|
154
|
+
return False
|
|
155
|
+
|
|
156
|
+
def track_execution(self, bytecode, execution_time: float = 0.0) -> HotPathInfo:
|
|
157
|
+
"""
|
|
158
|
+
Track bytecode execution for hot path detection
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
bytecode: Bytecode object or instructions
|
|
162
|
+
execution_time: Time taken to execute
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
HotPathInfo for the tracked bytecode
|
|
166
|
+
"""
|
|
167
|
+
# Hash the bytecode for identification
|
|
168
|
+
bytecode_hash = self._hash_bytecode(bytecode)
|
|
169
|
+
|
|
170
|
+
if bytecode_hash not in self.hot_paths:
|
|
171
|
+
self.hot_paths[bytecode_hash] = HotPathInfo(
|
|
172
|
+
bytecode_hash=bytecode_hash,
|
|
173
|
+
tier=ExecutionTier.BYTECODE
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
info = self.hot_paths[bytecode_hash]
|
|
177
|
+
info.execution_count += 1
|
|
178
|
+
info.total_time += execution_time
|
|
179
|
+
info.average_time = info.total_time / info.execution_count
|
|
180
|
+
info.last_execution = time.time()
|
|
181
|
+
|
|
182
|
+
# Check for tier promotion
|
|
183
|
+
if info.execution_count == self.hot_threshold:
|
|
184
|
+
self.stats.hot_paths_detected += 1
|
|
185
|
+
if self.debug:
|
|
186
|
+
print(f"🔥 JIT: Hot path detected! Executed {info.execution_count} times "
|
|
187
|
+
f"(avg: {info.average_time*1000:.2f}ms)")
|
|
188
|
+
|
|
189
|
+
return info
|
|
190
|
+
|
|
191
|
+
def compile_hot_path(self, bytecode) -> Optional[Callable]:
|
|
192
|
+
"""
|
|
193
|
+
Compile hot bytecode to optimized native code
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
bytecode: Bytecode object with instructions and constants
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
Compiled function or None if compilation failed
|
|
200
|
+
"""
|
|
201
|
+
# First check if bytecode is JIT-compatible
|
|
202
|
+
if not self._is_jit_compatible(bytecode):
|
|
203
|
+
if self.debug:
|
|
204
|
+
print(f"⚠️ JIT: Bytecode contains unsupported opcodes, skipping JIT")
|
|
205
|
+
return None
|
|
206
|
+
|
|
207
|
+
bytecode_hash = self._hash_bytecode(bytecode)
|
|
208
|
+
|
|
209
|
+
# Check cache first
|
|
210
|
+
if bytecode_hash in self.compilation_cache:
|
|
211
|
+
self.stats.cache_hits += 1
|
|
212
|
+
if self.debug:
|
|
213
|
+
print(f"✅ JIT: Cache hit for {bytecode_hash[:8]}")
|
|
214
|
+
return self.compilation_cache[bytecode_hash]
|
|
215
|
+
|
|
216
|
+
self.stats.cache_misses += 1
|
|
217
|
+
|
|
218
|
+
start_time = time.time()
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
# Step 1: Analyze stack behavior
|
|
222
|
+
stack_frames = self._analyze_stack_behavior(bytecode)
|
|
223
|
+
if not stack_frames:
|
|
224
|
+
if self.debug:
|
|
225
|
+
print(f"❌ JIT: Failed to analyze stack behavior")
|
|
226
|
+
return None
|
|
227
|
+
|
|
228
|
+
# Step 2: Optimize bytecode
|
|
229
|
+
optimized_instructions, updated_constants = self._optimize_bytecode(bytecode)
|
|
230
|
+
|
|
231
|
+
# Step 3: Generate efficient Python source code
|
|
232
|
+
python_code = self._generate_efficient_python_code(
|
|
233
|
+
optimized_instructions,
|
|
234
|
+
updated_constants,
|
|
235
|
+
stack_frames
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
if self.debug and self.verbose:
|
|
239
|
+
print(f"📝 JIT Generated Python code:\n{python_code[:500]}...")
|
|
240
|
+
|
|
241
|
+
# Step 4: Compile to native Python bytecode
|
|
242
|
+
compiled = compile(python_code, f'<jit:{bytecode_hash[:8]}>', 'exec')
|
|
243
|
+
|
|
244
|
+
# Step 5: Create executable function
|
|
245
|
+
namespace = {'__builtins__': {}}
|
|
246
|
+
exec(compiled, namespace)
|
|
247
|
+
jit_function = namespace.get('jit_execute')
|
|
248
|
+
|
|
249
|
+
if jit_function:
|
|
250
|
+
# Verify the compiled function works
|
|
251
|
+
verification_result = self._verify_compilation(bytecode, jit_function)
|
|
252
|
+
if not verification_result:
|
|
253
|
+
if self.debug:
|
|
254
|
+
print(f"❌ JIT: Verification failed for {bytecode_hash[:8]}")
|
|
255
|
+
self.stats.compilation_failures += 1
|
|
256
|
+
return None
|
|
257
|
+
|
|
258
|
+
# Cache the compiled function
|
|
259
|
+
self.compilation_cache[bytecode_hash] = jit_function
|
|
260
|
+
|
|
261
|
+
# Update stats
|
|
262
|
+
compilation_time = time.time() - start_time
|
|
263
|
+
self.stats.compilations += 1
|
|
264
|
+
self.stats.compilation_time += compilation_time
|
|
265
|
+
self.stats.average_compilation_time = (
|
|
266
|
+
self.stats.compilation_time / self.stats.compilations
|
|
267
|
+
)
|
|
268
|
+
self.stats.tier_promotions += 1
|
|
269
|
+
|
|
270
|
+
# Update hot path info
|
|
271
|
+
if bytecode_hash in self.hot_paths:
|
|
272
|
+
info = self.hot_paths[bytecode_hash]
|
|
273
|
+
info.compiled_version = jit_function
|
|
274
|
+
info.compilation_time = compilation_time
|
|
275
|
+
info.tier = ExecutionTier.JIT_NATIVE
|
|
276
|
+
|
|
277
|
+
if self.debug:
|
|
278
|
+
print(f"✅ JIT: Compiled {bytecode_hash[:8]} in {compilation_time*1000:.2f}ms "
|
|
279
|
+
f"({len(optimized_instructions)} instructions)")
|
|
280
|
+
|
|
281
|
+
return jit_function
|
|
282
|
+
|
|
283
|
+
except Exception as e:
|
|
284
|
+
if self.debug:
|
|
285
|
+
print(f"❌ JIT: Compilation failed for {bytecode_hash[:8]}: {e}")
|
|
286
|
+
import traceback
|
|
287
|
+
traceback.print_exc()
|
|
288
|
+
self.stats.compilation_failures += 1
|
|
289
|
+
return None
|
|
290
|
+
|
|
291
|
+
return None
|
|
292
|
+
|
|
293
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
294
|
+
"""Get JIT compilation statistics"""
|
|
295
|
+
# Calculate speedup if we have enough data
|
|
296
|
+
speedup = 0.0
|
|
297
|
+
if (self.stats.total_jit_execution_time > 0 and
|
|
298
|
+
self.stats.total_bytecode_execution_time > 0 and
|
|
299
|
+
self.stats.jit_executions > 0):
|
|
300
|
+
avg_jit_time = self.stats.total_jit_execution_time / self.stats.jit_executions
|
|
301
|
+
avg_bytecode_time = self.stats.total_bytecode_execution_time / max(self.stats.jit_executions, 1)
|
|
302
|
+
speedup = avg_bytecode_time / avg_jit_time if avg_jit_time > 0 else 0
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
'hot_paths_detected': self.stats.hot_paths_detected,
|
|
306
|
+
'compilations': self.stats.compilations,
|
|
307
|
+
'compilation_time': round(self.stats.compilation_time, 4),
|
|
308
|
+
'average_compilation_time': round(self.stats.average_compilation_time, 6),
|
|
309
|
+
'jit_executions': self.stats.jit_executions,
|
|
310
|
+
'total_jit_execution_time': round(self.stats.total_jit_execution_time, 4),
|
|
311
|
+
'total_bytecode_execution_time': round(self.stats.total_bytecode_execution_time, 4),
|
|
312
|
+
'speedup_factor': round(speedup, 2),
|
|
313
|
+
'cache_hits': self.stats.cache_hits,
|
|
314
|
+
'cache_misses': self.stats.cache_misses,
|
|
315
|
+
'cache_size': len(self.compilation_cache),
|
|
316
|
+
'tier_promotions': self.stats.tier_promotions,
|
|
317
|
+
'compilation_failures': self.stats.compilation_failures,
|
|
318
|
+
'cache_hit_rate': round(
|
|
319
|
+
self.stats.cache_hits / max(self.stats.cache_hits + self.stats.cache_misses, 1) * 100,
|
|
320
|
+
1
|
|
321
|
+
),
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
def clear_cache(self):
|
|
325
|
+
"""Clear compilation cache"""
|
|
326
|
+
self.compilation_cache.clear()
|
|
327
|
+
self.hot_paths.clear()
|
|
328
|
+
self.stats = JITStats() # Reset stats
|
|
329
|
+
if self.debug:
|
|
330
|
+
print("🗑️ JIT: Cache cleared and stats reset")
|
|
331
|
+
|
|
332
|
+
def record_execution_time(self, bytecode_hash: str, execution_time: float, tier: ExecutionTier):
|
|
333
|
+
"""
|
|
334
|
+
Record execution time for performance tracking
|
|
335
|
+
|
|
336
|
+
Args:
|
|
337
|
+
bytecode_hash: Hash of executed bytecode
|
|
338
|
+
execution_time: Time taken for execution
|
|
339
|
+
tier: Which tier was used for execution
|
|
340
|
+
"""
|
|
341
|
+
if tier == ExecutionTier.JIT_NATIVE:
|
|
342
|
+
self.stats.jit_executions += 1
|
|
343
|
+
self.stats.total_jit_execution_time += execution_time
|
|
344
|
+
|
|
345
|
+
# Update speedup calculation in hot path info
|
|
346
|
+
if bytecode_hash in self.hot_paths:
|
|
347
|
+
info = self.hot_paths[bytecode_hash]
|
|
348
|
+
# Track for speedup calculation
|
|
349
|
+
if info.average_time > 0:
|
|
350
|
+
info.speedup_factor = info.average_time / execution_time
|
|
351
|
+
elif tier == ExecutionTier.BYTECODE:
|
|
352
|
+
# Track bytecode execution time for comparison
|
|
353
|
+
self.stats.total_bytecode_execution_time += execution_time
|
|
354
|
+
|
|
355
|
+
# ==================== Private Methods ====================
|
|
356
|
+
|
|
357
|
+
def _hash_bytecode(self, bytecode) -> str:
|
|
358
|
+
"""Generate hash for bytecode identification"""
|
|
359
|
+
if hasattr(bytecode, 'instructions'):
|
|
360
|
+
# Bytecode object - include both instructions and constants
|
|
361
|
+
data = str(bytecode.instructions) + str(bytecode.constants)
|
|
362
|
+
elif hasattr(bytecode, '__iter__'):
|
|
363
|
+
# List of instructions
|
|
364
|
+
data = str(list(bytecode))
|
|
365
|
+
else:
|
|
366
|
+
data = str(bytecode)
|
|
367
|
+
|
|
368
|
+
return hashlib.sha256(data.encode()).hexdigest()[:16]
|
|
369
|
+
|
|
370
|
+
def _is_jit_compatible(self, bytecode) -> bool:
|
|
371
|
+
"""Check if bytecode contains only JIT-supported opcodes"""
|
|
372
|
+
instructions = bytecode.instructions if hasattr(bytecode, 'instructions') else bytecode
|
|
373
|
+
|
|
374
|
+
for opcode, _ in instructions:
|
|
375
|
+
if opcode not in self.supported_opcodes:
|
|
376
|
+
if self.debug:
|
|
377
|
+
print(f"⚠️ JIT: Unsupported opcode: {opcode}")
|
|
378
|
+
return False
|
|
379
|
+
return True
|
|
380
|
+
|
|
381
|
+
def _analyze_stack_behavior(self, bytecode) -> List[StackFrame]:
|
|
382
|
+
"""
|
|
383
|
+
Analyze stack behavior to generate efficient Python code
|
|
384
|
+
|
|
385
|
+
Returns:
|
|
386
|
+
List of StackFrame objects representing stack state at each instruction
|
|
387
|
+
"""
|
|
388
|
+
instructions = bytecode.instructions if hasattr(bytecode, 'instructions') else bytecode
|
|
389
|
+
constants = bytecode.constants if hasattr(bytecode, 'constants') else []
|
|
390
|
+
|
|
391
|
+
frames = []
|
|
392
|
+
current_frame = StackFrame()
|
|
393
|
+
|
|
394
|
+
for i, (opcode, operand) in enumerate(instructions):
|
|
395
|
+
# Record current frame state
|
|
396
|
+
frames.append(StackFrame(
|
|
397
|
+
stack=list(current_frame.stack),
|
|
398
|
+
variables=dict(current_frame.variables),
|
|
399
|
+
constants=dict(current_frame.constants)
|
|
400
|
+
))
|
|
401
|
+
|
|
402
|
+
# Update frame based on opcode
|
|
403
|
+
if opcode == 'LOAD_CONST':
|
|
404
|
+
# Create a unique variable name for this constant
|
|
405
|
+
var_name = f"const_{operand}_{i}"
|
|
406
|
+
current_frame.stack.append(var_name)
|
|
407
|
+
current_frame.constants[operand] = constants[operand] if operand < len(constants) else None
|
|
408
|
+
current_frame.variables[var_name] = repr(constants[operand]) if operand < len(constants) else 'None'
|
|
409
|
+
|
|
410
|
+
elif opcode == 'LOAD_NAME':
|
|
411
|
+
var_name = f"var_{operand}_{i}"
|
|
412
|
+
current_frame.stack.append(var_name)
|
|
413
|
+
# We don't know the value yet, will be looked up from env
|
|
414
|
+
current_frame.variables[var_name] = f"env.get({repr(constants[operand])}, None)" if operand < len(constants) else 'None'
|
|
415
|
+
|
|
416
|
+
elif opcode == 'STORE_NAME':
|
|
417
|
+
if current_frame.stack:
|
|
418
|
+
value_expr = current_frame.stack.pop()
|
|
419
|
+
name = constants[operand] if operand < len(constants) else f'unknown_{operand}'
|
|
420
|
+
current_frame.variables[name] = current_frame.variables.get(value_expr, value_expr)
|
|
421
|
+
|
|
422
|
+
elif opcode in ['ADD', 'SUB', 'MUL', 'DIV', 'MOD', 'POW']:
|
|
423
|
+
if len(current_frame.stack) >= 2:
|
|
424
|
+
b_expr = current_frame.stack.pop()
|
|
425
|
+
a_expr = current_frame.stack.pop()
|
|
426
|
+
result_expr = f"result_{i}"
|
|
427
|
+
|
|
428
|
+
a_val = current_frame.variables.get(a_expr, a_expr)
|
|
429
|
+
b_val = current_frame.variables.get(b_expr, b_expr)
|
|
430
|
+
|
|
431
|
+
# Try to evaluate if both are constants
|
|
432
|
+
try:
|
|
433
|
+
if (a_expr.startswith('const_') and b_expr.startswith('const_')):
|
|
434
|
+
# Both are constants, can pre-compute
|
|
435
|
+
a_const = eval(a_val) if isinstance(a_val, str) and a_val[0].isdigit() else a_val
|
|
436
|
+
b_const = eval(b_val) if isinstance(b_val, str) and b_val[0].isdigit() else b_val
|
|
437
|
+
|
|
438
|
+
if opcode == 'ADD':
|
|
439
|
+
result = a_const + b_const
|
|
440
|
+
elif opcode == 'SUB':
|
|
441
|
+
result = a_const - b_const
|
|
442
|
+
elif opcode == 'MUL':
|
|
443
|
+
result = a_const * b_const
|
|
444
|
+
elif opcode == 'DIV':
|
|
445
|
+
result = a_const / b_const if b_const != 0 else 0
|
|
446
|
+
elif opcode == 'MOD':
|
|
447
|
+
result = a_const % b_const if b_const != 0 else 0
|
|
448
|
+
elif opcode == 'POW':
|
|
449
|
+
result = a_const ** b_const
|
|
450
|
+
|
|
451
|
+
current_frame.variables[result_expr] = repr(result)
|
|
452
|
+
else:
|
|
453
|
+
# Runtime computation needed
|
|
454
|
+
current_frame.variables[result_expr] = f"({a_val} {self._opcode_to_operator(opcode)} {b_val})"
|
|
455
|
+
except (TypeError, ValueError, KeyError, NameError):
|
|
456
|
+
# Fallback to runtime computation
|
|
457
|
+
current_frame.variables[result_expr] = f"({a_val} {self._opcode_to_operator(opcode)} {b_val})"
|
|
458
|
+
|
|
459
|
+
current_frame.stack.append(result_expr)
|
|
460
|
+
|
|
461
|
+
elif opcode == 'RETURN':
|
|
462
|
+
if current_frame.stack:
|
|
463
|
+
return_expr = current_frame.stack[-1]
|
|
464
|
+
current_frame.variables['__return__'] = current_frame.variables.get(return_expr, return_expr)
|
|
465
|
+
|
|
466
|
+
return frames
|
|
467
|
+
|
|
468
|
+
def _opcode_to_operator(self, opcode: str) -> str:
|
|
469
|
+
"""Convert opcode to Python operator"""
|
|
470
|
+
return {
|
|
471
|
+
'ADD': '+',
|
|
472
|
+
'SUB': '-',
|
|
473
|
+
'MUL': '*',
|
|
474
|
+
'DIV': '/',
|
|
475
|
+
'MOD': '%',
|
|
476
|
+
'POW': '**',
|
|
477
|
+
'EQ': '==',
|
|
478
|
+
'NEQ': '!=',
|
|
479
|
+
'LT': '<',
|
|
480
|
+
'GT': '>',
|
|
481
|
+
'LTE': '<=',
|
|
482
|
+
'GTE': '>=',
|
|
483
|
+
'AND': 'and',
|
|
484
|
+
'OR': 'or',
|
|
485
|
+
}.get(opcode, opcode)
|
|
486
|
+
|
|
487
|
+
def _optimize_bytecode(self, bytecode) -> Tuple[List, List]:
|
|
488
|
+
"""
|
|
489
|
+
Apply optimization passes to bytecode
|
|
490
|
+
|
|
491
|
+
Returns: (optimized_instructions, updated_constants)
|
|
492
|
+
"""
|
|
493
|
+
instructions = list(bytecode.instructions) if hasattr(bytecode, 'instructions') else list(bytecode)
|
|
494
|
+
constants = list(bytecode.constants) if hasattr(bytecode, 'constants') else []
|
|
495
|
+
|
|
496
|
+
if self.optimizer:
|
|
497
|
+
try:
|
|
498
|
+
optimized, updated_constants = self.optimizer.optimize(instructions, constants)
|
|
499
|
+
if self.debug:
|
|
500
|
+
stats = self.optimizer.get_stats()
|
|
501
|
+
if stats['total_optimizations'] > 0:
|
|
502
|
+
print(f"🔧 JIT Optimizer: {stats['original_size']} → {stats['optimized_size']} instructions "
|
|
503
|
+
f"({stats['size_reduction_pct']:.1f}% reduction)")
|
|
504
|
+
return optimized, updated_constants
|
|
505
|
+
except Exception as e:
|
|
506
|
+
if self.debug:
|
|
507
|
+
print(f"⚠️ JIT: Optimizer failed: {e}")
|
|
508
|
+
return instructions, constants
|
|
509
|
+
|
|
510
|
+
# Fallback: apply basic optimizations
|
|
511
|
+
optimized = self._apply_basic_optimizations(instructions, constants)
|
|
512
|
+
return optimized, constants
|
|
513
|
+
|
|
514
|
+
def _apply_basic_optimizations(self, instructions: List, constants: List) -> List:
|
|
515
|
+
"""Apply basic peephole optimizations"""
|
|
516
|
+
optimized = []
|
|
517
|
+
i = 0
|
|
518
|
+
|
|
519
|
+
while i < len(instructions):
|
|
520
|
+
opcode, operand = instructions[i]
|
|
521
|
+
|
|
522
|
+
# Skip useless patterns
|
|
523
|
+
if i + 1 < len(instructions):
|
|
524
|
+
next_op, next_operand = instructions[i + 1]
|
|
525
|
+
|
|
526
|
+
# LOAD_CONST + POP -> skip both
|
|
527
|
+
if opcode == 'LOAD_CONST' and next_op == 'POP':
|
|
528
|
+
i += 2
|
|
529
|
+
continue
|
|
530
|
+
|
|
531
|
+
# LOAD_NAME + POP -> skip both
|
|
532
|
+
if opcode == 'LOAD_NAME' and next_op == 'POP':
|
|
533
|
+
i += 2
|
|
534
|
+
continue
|
|
535
|
+
|
|
536
|
+
optimized.append((opcode, operand))
|
|
537
|
+
i += 1
|
|
538
|
+
|
|
539
|
+
return optimized
|
|
540
|
+
|
|
541
|
+
def _generate_efficient_python_code(self, instructions: List, constants: List, stack_frames: List[StackFrame]) -> str:
|
|
542
|
+
"""
|
|
543
|
+
Generate efficient Python source code from optimized bytecode
|
|
544
|
+
using stack analysis to minimize runtime checks
|
|
545
|
+
"""
|
|
546
|
+
lines = [
|
|
547
|
+
"def jit_execute(vm, stack, env):",
|
|
548
|
+
" # JIT-compiled native code",
|
|
549
|
+
]
|
|
550
|
+
|
|
551
|
+
# Track variable assignments for efficient code generation
|
|
552
|
+
local_vars = set()
|
|
553
|
+
stack_height = 0
|
|
554
|
+
|
|
555
|
+
for i, (opcode, operand) in enumerate(instructions):
|
|
556
|
+
if i >= len(stack_frames):
|
|
557
|
+
break
|
|
558
|
+
|
|
559
|
+
frame = stack_frames[i]
|
|
560
|
+
|
|
561
|
+
if opcode == 'LOAD_CONST':
|
|
562
|
+
if operand < len(constants):
|
|
563
|
+
const_val = constants[operand]
|
|
564
|
+
var_name = f"const_{operand}_{i}"
|
|
565
|
+
if var_name in frame.variables:
|
|
566
|
+
# Use pre-computed value if available
|
|
567
|
+
lines.append(f" {var_name} = {frame.variables[var_name]}")
|
|
568
|
+
local_vars.add(var_name)
|
|
569
|
+
lines.append(f" stack.append({var_name})")
|
|
570
|
+
else:
|
|
571
|
+
lines.append(f" stack.append({repr(const_val)})")
|
|
572
|
+
stack_height += 1
|
|
573
|
+
|
|
574
|
+
elif opcode == 'LOAD_NAME':
|
|
575
|
+
if operand < len(constants):
|
|
576
|
+
name = constants[operand]
|
|
577
|
+
var_name = f"var_{operand}_{i}"
|
|
578
|
+
if var_name in frame.variables:
|
|
579
|
+
# Use efficient lookup
|
|
580
|
+
lines.append(f" {var_name} = env.get({repr(name)}, None)")
|
|
581
|
+
local_vars.add(var_name)
|
|
582
|
+
lines.append(f" stack.append({var_name})")
|
|
583
|
+
else:
|
|
584
|
+
lines.append(f" stack.append(env.get({repr(name)}, None))")
|
|
585
|
+
stack_height += 1
|
|
586
|
+
|
|
587
|
+
elif opcode == 'STORE_NAME':
|
|
588
|
+
if operand < len(constants):
|
|
589
|
+
name = constants[operand]
|
|
590
|
+
if stack_height > 0:
|
|
591
|
+
lines.append(f" env[{repr(name)}] = stack.pop()")
|
|
592
|
+
stack_height -= 1
|
|
593
|
+
|
|
594
|
+
elif opcode == 'STORE_CONST':
|
|
595
|
+
if isinstance(operand, tuple) and len(operand) == 2:
|
|
596
|
+
name_idx, const_idx = operand
|
|
597
|
+
if name_idx < len(constants) and const_idx < len(constants):
|
|
598
|
+
name = constants[name_idx]
|
|
599
|
+
const_val = constants[const_idx]
|
|
600
|
+
lines.append(f" env[{repr(name)}] = {repr(const_val)}")
|
|
601
|
+
|
|
602
|
+
elif opcode in ['ADD', 'SUB', 'MUL', 'DIV', 'MOD', 'POW']:
|
|
603
|
+
if stack_height >= 2:
|
|
604
|
+
# Generate efficient arithmetic
|
|
605
|
+
operator = self._opcode_to_operator(opcode)
|
|
606
|
+
result_var = f"result_{i}"
|
|
607
|
+
|
|
608
|
+
# Try to use pre-computed values from stack analysis
|
|
609
|
+
if i > 0 and i-1 < len(stack_frames):
|
|
610
|
+
prev_frame = stack_frames[i-1]
|
|
611
|
+
if len(prev_frame.stack) >= 2:
|
|
612
|
+
a_expr = prev_frame.stack[-2]
|
|
613
|
+
b_expr = prev_frame.stack[-1]
|
|
614
|
+
|
|
615
|
+
if a_expr in frame.variables and b_expr in frame.variables:
|
|
616
|
+
# Both values are known, use pre-computation
|
|
617
|
+
a_val = frame.variables[a_expr]
|
|
618
|
+
b_val = frame.variables[b_expr]
|
|
619
|
+
|
|
620
|
+
# Check if we can compute at compile time
|
|
621
|
+
try:
|
|
622
|
+
if (a_expr.startswith('const_') and b_expr.startswith('const_')):
|
|
623
|
+
# Already computed by optimizer
|
|
624
|
+
computed = eval(f"{a_val} {operator} {b_val}")
|
|
625
|
+
lines.append(f" {result_var} = {repr(computed)}")
|
|
626
|
+
else:
|
|
627
|
+
lines.append(f" {result_var} = {a_val} {operator} {b_val}")
|
|
628
|
+
except (TypeError, ValueError, NameError, SyntaxError):
|
|
629
|
+
lines.append(f" {result_var} = {a_val} {operator} {b_val}")
|
|
630
|
+
else:
|
|
631
|
+
lines.append(f" b = stack.pop()")
|
|
632
|
+
lines.append(f" a = stack.pop()")
|
|
633
|
+
lines.append(f" {result_var} = a {operator} b")
|
|
634
|
+
else:
|
|
635
|
+
lines.append(f" b = stack.pop()")
|
|
636
|
+
lines.append(f" a = stack.pop()")
|
|
637
|
+
lines.append(f" {result_var} = a {operator} b")
|
|
638
|
+
|
|
639
|
+
local_vars.add(result_var)
|
|
640
|
+
lines.append(f" stack.append({result_var})")
|
|
641
|
+
stack_height -= 1 # 2 popped, 1 pushed = net -1
|
|
642
|
+
|
|
643
|
+
elif opcode == 'RETURN':
|
|
644
|
+
if stack_height > 0:
|
|
645
|
+
lines.append(" return stack[-1]")
|
|
646
|
+
else:
|
|
647
|
+
lines.append(" return None")
|
|
648
|
+
break
|
|
649
|
+
|
|
650
|
+
# Default return if no RETURN encountered
|
|
651
|
+
if not any(opcode == 'RETURN' for opcode, _ in instructions):
|
|
652
|
+
if stack_height > 0:
|
|
653
|
+
lines.append(" return stack[-1] if stack else None")
|
|
654
|
+
else:
|
|
655
|
+
lines.append(" return None")
|
|
656
|
+
|
|
657
|
+
return "\n".join(lines)
|
|
658
|
+
|
|
659
|
+
def _verify_compilation(self, original_bytecode, jit_function) -> bool:
|
|
660
|
+
"""
|
|
661
|
+
Verify that JIT-compiled code produces same results as bytecode
|
|
662
|
+
|
|
663
|
+
Args:
|
|
664
|
+
original_bytecode: Original bytecode to verify against
|
|
665
|
+
jit_function: JIT-compiled function to verify
|
|
666
|
+
|
|
667
|
+
Returns:
|
|
668
|
+
True if verification passes
|
|
669
|
+
"""
|
|
670
|
+
try:
|
|
671
|
+
# Create test environment
|
|
672
|
+
from .vm import VM
|
|
673
|
+
|
|
674
|
+
# Test with a few different inputs
|
|
675
|
+
test_cases = [
|
|
676
|
+
({}, []), # Empty
|
|
677
|
+
({'x': 5, 'y': 3}, []), # Some variables
|
|
678
|
+
({'a': 10, 'b': 20, 'c': 30}, []), # More variables
|
|
679
|
+
]
|
|
680
|
+
|
|
681
|
+
for env_dict, stack in test_cases:
|
|
682
|
+
# Run bytecode version
|
|
683
|
+
vm_bytecode = VM(use_jit=False)
|
|
684
|
+
vm_bytecode.env = env_dict.copy()
|
|
685
|
+
vm_bytecode.stack = stack.copy()
|
|
686
|
+
bytecode_result = vm_bytecode.execute(original_bytecode)
|
|
687
|
+
|
|
688
|
+
# Run JIT version
|
|
689
|
+
vm_jit = VM(use_jit=False)
|
|
690
|
+
vm_jit.env = env_dict.copy()
|
|
691
|
+
vm_jit.stack = stack.copy()
|
|
692
|
+
jit_result = jit_function(vm_jit, vm_jit.stack, vm_jit.env)
|
|
693
|
+
|
|
694
|
+
# Compare results
|
|
695
|
+
if bytecode_result != jit_result:
|
|
696
|
+
if self.debug:
|
|
697
|
+
print(f"❌ JIT Verification failed:")
|
|
698
|
+
print(f" Bytecode result: {bytecode_result}")
|
|
699
|
+
print(f" JIT result: {jit_result}")
|
|
700
|
+
print(f" Environment: {env_dict}")
|
|
701
|
+
return False
|
|
702
|
+
|
|
703
|
+
return True
|
|
704
|
+
|
|
705
|
+
except Exception as e:
|
|
706
|
+
if self.debug:
|
|
707
|
+
print(f"❌ JIT Verification error: {e}")
|
|
708
|
+
return False
|
|
709
|
+
|
|
710
|
+
def get_hot_path_info(self, bytecode_hash: str) -> Optional[HotPathInfo]:
|
|
711
|
+
"""Get information about a hot path"""
|
|
712
|
+
return self.hot_paths.get(bytecode_hash)
|
|
713
|
+
|
|
714
|
+
def get_compilation_cache_info(self) -> Dict[str, Any]:
|
|
715
|
+
"""Get information about compilation cache"""
|
|
716
|
+
return {
|
|
717
|
+
'size': len(self.compilation_cache),
|
|
718
|
+
'entries': list(self.compilation_cache.keys()),
|
|
719
|
+
'hit_rate': self.stats.cache_hits / max(self.stats.cache_hits + self.stats.cache_misses, 1),
|
|
720
|
+
}
|