zexus 1.6.8 → 1.7.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/README.md +12 -5
- package/package.json +1 -1
- package/src/__init__.py +7 -0
- package/src/zexus/__init__.py +1 -1
- package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/debug_sanitizer.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__/input_validation.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/module_manager.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/security_enforcement.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/syntax_validator.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/access_control_system/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/access_control_system/__pycache__/access_control.cpython-312.pyc +0 -0
- package/src/zexus/advanced_types.py +17 -2
- package/src/zexus/blockchain/__init__.py +411 -0
- package/src/zexus/blockchain/accelerator.py +1160 -0
- package/src/zexus/blockchain/chain.py +660 -0
- package/src/zexus/blockchain/consensus.py +821 -0
- package/src/zexus/blockchain/contract_vm.py +1019 -0
- package/src/zexus/blockchain/crypto.py +79 -14
- package/src/zexus/blockchain/events.py +526 -0
- package/src/zexus/blockchain/loadtest.py +721 -0
- package/src/zexus/blockchain/monitoring.py +350 -0
- package/src/zexus/blockchain/mpt.py +716 -0
- package/src/zexus/blockchain/multichain.py +951 -0
- package/src/zexus/blockchain/multiprocess_executor.py +338 -0
- package/src/zexus/blockchain/network.py +886 -0
- package/src/zexus/blockchain/node.py +666 -0
- package/src/zexus/blockchain/rpc.py +1203 -0
- package/src/zexus/blockchain/rust_bridge.py +421 -0
- package/src/zexus/blockchain/storage.py +423 -0
- package/src/zexus/blockchain/tokens.py +750 -0
- package/src/zexus/blockchain/upgradeable.py +1004 -0
- package/src/zexus/blockchain/verification.py +1602 -0
- package/src/zexus/blockchain/wallet.py +621 -0
- package/src/zexus/capability_system.py +184 -9
- package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
- package/src/zexus/cli/main.py +383 -34
- package/src/zexus/cli/zpm.py +1 -1
- package/src/zexus/compiler/__pycache__/bytecode.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__/semantic.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/compiler/bytecode.py +124 -7
- package/src/zexus/compiler/compat_runtime.py +6 -2
- package/src/zexus/compiler/lexer.py +16 -5
- package/src/zexus/compiler/parser.py +108 -7
- package/src/zexus/compiler/semantic.py +18 -19
- package/src/zexus/compiler/zexus_ast.py +26 -1
- package/src/zexus/concurrency_system.py +79 -0
- package/src/zexus/config.py +54 -0
- package/src/zexus/crypto_bridge.py +244 -8
- package/src/zexus/dap/__init__.py +10 -0
- package/src/zexus/dap/__main__.py +4 -0
- package/src/zexus/dap/dap_server.py +391 -0
- package/src/zexus/dap/debug_engine.py +298 -0
- package/src/zexus/environment.py +112 -9
- 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__/resource_limiter.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/unified_execution.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/bytecode_compiler.py +457 -37
- package/src/zexus/evaluator/core.py +644 -50
- package/src/zexus/evaluator/expressions.py +358 -62
- package/src/zexus/evaluator/functions.py +458 -20
- package/src/zexus/evaluator/resource_limiter.py +4 -4
- package/src/zexus/evaluator/statements.py +774 -122
- package/src/zexus/evaluator/unified_execution.py +573 -72
- package/src/zexus/evaluator/utils.py +14 -2
- package/src/zexus/evaluator_original.py +1 -1
- package/src/zexus/event_loop.py +186 -0
- package/src/zexus/lexer.py +742 -458
- package/src/zexus/lsp/__init__.py +1 -1
- package/src/zexus/lsp/definition_provider.py +163 -9
- package/src/zexus/lsp/server.py +22 -8
- package/src/zexus/lsp/symbol_provider.py +182 -9
- package/src/zexus/module_cache.py +239 -9
- package/src/zexus/module_manager.py +129 -1
- package/src/zexus/object.py +76 -6
- 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/parser.py +1349 -408
- package/src/zexus/parser/strategy_context.py +755 -58
- package/src/zexus/parser/strategy_structural.py +121 -21
- package/src/zexus/persistence.py +15 -1
- package/src/zexus/renderer/__init__.py +61 -0
- package/src/zexus/renderer/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/backend.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/canvas.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/color_system.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/layout.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/main_renderer.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/painter.cpython-312.pyc +0 -0
- package/src/zexus/renderer/backend.py +261 -0
- package/src/zexus/renderer/canvas.py +78 -0
- package/src/zexus/renderer/color_system.py +201 -0
- package/src/zexus/renderer/graphics.py +31 -0
- package/src/zexus/renderer/layout.py +222 -0
- package/src/zexus/renderer/main_renderer.py +66 -0
- package/src/zexus/renderer/painter.py +30 -0
- package/src/zexus/renderer/tk_backend.py +208 -0
- package/src/zexus/renderer/web_backend.py +260 -0
- package/src/zexus/runtime/__init__.py +10 -2
- package/src/zexus/runtime/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/runtime/__pycache__/async_runtime.cpython-312.pyc +0 -0
- package/src/zexus/runtime/__pycache__/load_manager.cpython-312.pyc +0 -0
- package/src/zexus/runtime/file_flags.py +137 -0
- package/src/zexus/runtime/load_manager.py +368 -0
- package/src/zexus/safety/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/safety/__pycache__/memory_safety.cpython-312.pyc +0 -0
- package/src/zexus/security.py +424 -34
- package/src/zexus/stdlib/fs.py +23 -18
- package/src/zexus/stdlib/http.py +289 -186
- package/src/zexus/stdlib/sockets.py +207 -163
- package/src/zexus/stdlib/websockets.py +282 -0
- package/src/zexus/stdlib_integration.py +369 -2
- package/src/zexus/strategy_recovery.py +6 -3
- package/src/zexus/type_checker.py +423 -0
- package/src/zexus/virtual_filesystem.py +189 -2
- package/src/zexus/vm/__init__.py +113 -3
- 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__/bytecode_converter.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/compiler.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/gas_metering.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/async_optimizer.py +80 -6
- package/src/zexus/vm/binary_bytecode.py +659 -0
- package/src/zexus/vm/bytecode.py +59 -11
- package/src/zexus/vm/bytecode_converter.py +26 -12
- package/src/zexus/vm/cabi.c +1985 -0
- package/src/zexus/vm/cabi.cpython-312-x86_64-linux-gnu.so +0 -0
- package/src/zexus/vm/cabi.h +127 -0
- package/src/zexus/vm/cache.py +561 -17
- package/src/zexus/vm/compiler.py +818 -51
- package/src/zexus/vm/fastops.c +15743 -0
- package/src/zexus/vm/fastops.cpython-312-x86_64-linux-gnu.so +0 -0
- package/src/zexus/vm/fastops.pyx +288 -0
- package/src/zexus/vm/gas_metering.py +50 -9
- package/src/zexus/vm/jit.py +364 -20
- package/src/zexus/vm/native_jit_backend.py +1816 -0
- package/src/zexus/vm/native_runtime.cpp +1388 -0
- package/src/zexus/vm/native_runtime.cpython-312-x86_64-linux-gnu.so +0 -0
- package/src/zexus/vm/optimizer.py +161 -11
- package/src/zexus/vm/parallel_vm.py +140 -45
- package/src/zexus/vm/peephole_optimizer.py +82 -4
- package/src/zexus/vm/profiler.py +38 -18
- package/src/zexus/vm/register_allocator.py +16 -5
- package/src/zexus/vm/register_vm.py +8 -5
- package/src/zexus/vm/vm.py +3581 -531
- package/src/zexus/vm/wasm_compiler.py +658 -0
- package/src/zexus/zexus_ast.py +137 -11
- package/src/zexus/zexus_token.py +16 -5
- package/src/zexus/zpm/installer.py +55 -15
- package/src/zexus/zpm/package_manager.py +1 -1
- package/src/zexus/zpm/registry.py +257 -28
- package/src/zexus.egg-info/PKG-INFO +16 -6
- package/src/zexus.egg-info/SOURCES.txt +129 -17
- package/src/zexus.egg-info/entry_points.txt +1 -0
- package/src/zexus.egg-info/requires.txt +4 -0
package/src/zexus/vm/jit.py
CHANGED
|
@@ -18,6 +18,7 @@ Features:
|
|
|
18
18
|
import hashlib
|
|
19
19
|
import time
|
|
20
20
|
import dis
|
|
21
|
+
import os
|
|
21
22
|
from typing import Dict, Any, Optional, Tuple, Callable, List, Set
|
|
22
23
|
from dataclasses import dataclass, field
|
|
23
24
|
from enum import Enum
|
|
@@ -29,6 +30,19 @@ try:
|
|
|
29
30
|
except ImportError:
|
|
30
31
|
OPTIMIZER_AVAILABLE = False
|
|
31
32
|
|
|
33
|
+
try:
|
|
34
|
+
from .gas_metering import OutOfGasError, OperationLimitExceededError
|
|
35
|
+
except Exception:
|
|
36
|
+
OutOfGasError = None
|
|
37
|
+
OperationLimitExceededError = None
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
from .native_jit_backend import NativeJITBackend
|
|
41
|
+
_NATIVE_JIT_AVAILABLE = True
|
|
42
|
+
except Exception:
|
|
43
|
+
_NATIVE_JIT_AVAILABLE = False
|
|
44
|
+
NativeJITBackend = None
|
|
45
|
+
|
|
32
46
|
|
|
33
47
|
class ExecutionTier(Enum):
|
|
34
48
|
"""Execution tiers for tiered compilation"""
|
|
@@ -128,6 +142,28 @@ class JITCompiler:
|
|
|
128
142
|
'RETURN', 'JUMP', 'JUMP_IF_FALSE',
|
|
129
143
|
}
|
|
130
144
|
|
|
145
|
+
# Native JIT backend (optional)
|
|
146
|
+
self.native_backend = None
|
|
147
|
+
native_flag = os.environ.get("ZEXUS_NATIVE_JIT", "0")
|
|
148
|
+
if native_flag.lower() in ("1", "true", "yes"):
|
|
149
|
+
self.enable_native_backend()
|
|
150
|
+
if os.environ.get("ZEXUS_JIT_TRACE", "0") in ("1", "true", "yes"):
|
|
151
|
+
print(f"[JIT TRACE] native_backend={'on' if self.native_backend else 'off'}")
|
|
152
|
+
|
|
153
|
+
def enable_native_backend(self) -> bool:
|
|
154
|
+
if self.native_backend is not None:
|
|
155
|
+
return True
|
|
156
|
+
if not _NATIVE_JIT_AVAILABLE:
|
|
157
|
+
return False
|
|
158
|
+
try:
|
|
159
|
+
self.native_backend = NativeJITBackend(debug=self.debug)
|
|
160
|
+
if self.debug:
|
|
161
|
+
print("🔧 JIT: Native backend enabled")
|
|
162
|
+
return True
|
|
163
|
+
except Exception:
|
|
164
|
+
self.native_backend = None
|
|
165
|
+
return False
|
|
166
|
+
|
|
131
167
|
def should_compile(self, bytecode_hash: str) -> bool:
|
|
132
168
|
"""
|
|
133
169
|
Determine if bytecode should be JIT compiled
|
|
@@ -217,6 +253,33 @@ class JITCompiler:
|
|
|
217
253
|
|
|
218
254
|
start_time = time.time()
|
|
219
255
|
|
|
256
|
+
# Native JIT path
|
|
257
|
+
if self.native_backend is not None:
|
|
258
|
+
try:
|
|
259
|
+
native_fn = self.native_backend.compile(bytecode)
|
|
260
|
+
if native_fn is not None:
|
|
261
|
+
self.compilation_cache[bytecode_hash] = native_fn
|
|
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
|
+
if bytecode_hash in self.hot_paths:
|
|
271
|
+
info = self.hot_paths[bytecode_hash]
|
|
272
|
+
info.compiled_version = native_fn
|
|
273
|
+
info.compilation_time = compilation_time
|
|
274
|
+
info.tier = ExecutionTier.JIT_NATIVE
|
|
275
|
+
|
|
276
|
+
if self.debug:
|
|
277
|
+
print(f"✅ JIT: Native compiled {bytecode_hash[:8]} in {compilation_time*1000:.2f}ms")
|
|
278
|
+
return native_fn
|
|
279
|
+
except Exception:
|
|
280
|
+
if self.debug:
|
|
281
|
+
print(f"⚠️ JIT: Native backend failed for {bytecode_hash[:8]}, falling back")
|
|
282
|
+
|
|
220
283
|
try:
|
|
221
284
|
# Step 1: Analyze stack behavior
|
|
222
285
|
stack_frames = self._analyze_stack_behavior(bytecode)
|
|
@@ -242,18 +305,27 @@ class JITCompiler:
|
|
|
242
305
|
compiled = compile(python_code, f'<jit:{bytecode_hash[:8]}>', 'exec')
|
|
243
306
|
|
|
244
307
|
# Step 5: Create executable function
|
|
245
|
-
namespace = {
|
|
308
|
+
namespace = {
|
|
309
|
+
'__builtins__': {},
|
|
310
|
+
'OutOfGasError': OutOfGasError,
|
|
311
|
+
'OperationLimitExceededError': OperationLimitExceededError,
|
|
312
|
+
}
|
|
246
313
|
exec(compiled, namespace)
|
|
247
314
|
jit_function = namespace.get('jit_execute')
|
|
248
315
|
|
|
249
316
|
if jit_function:
|
|
250
|
-
# Verify the compiled function works
|
|
251
317
|
verification_result = self._verify_compilation(bytecode, jit_function)
|
|
252
318
|
if not verification_result:
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
319
|
+
fallback_fn = self._build_fallback_executor(optimized_instructions, updated_constants)
|
|
320
|
+
if fallback_fn and self._verify_compilation(bytecode, fallback_fn):
|
|
321
|
+
if self.debug:
|
|
322
|
+
print(f"♻️ JIT: Falling back to compatibility executor for {bytecode_hash[:8]}")
|
|
323
|
+
jit_function = fallback_fn
|
|
324
|
+
else:
|
|
325
|
+
if self.debug:
|
|
326
|
+
print(f"❌ JIT: Verification failed for {bytecode_hash[:8]}")
|
|
327
|
+
self.stats.compilation_failures += 1
|
|
328
|
+
return None
|
|
257
329
|
|
|
258
330
|
# Cache the compiled function
|
|
259
331
|
self.compilation_cache[bytecode_hash] = jit_function
|
|
@@ -372,6 +444,7 @@ class JITCompiler:
|
|
|
372
444
|
instructions = bytecode.instructions if hasattr(bytecode, 'instructions') else bytecode
|
|
373
445
|
|
|
374
446
|
for opcode, _ in instructions:
|
|
447
|
+
opcode = self._normalize_opcode(opcode)
|
|
375
448
|
if opcode not in self.supported_opcodes:
|
|
376
449
|
if self.debug:
|
|
377
450
|
print(f"⚠️ JIT: Unsupported opcode: {opcode}")
|
|
@@ -385,8 +458,12 @@ class JITCompiler:
|
|
|
385
458
|
Returns:
|
|
386
459
|
List of StackFrame objects representing stack state at each instruction
|
|
387
460
|
"""
|
|
388
|
-
|
|
461
|
+
raw_instructions = bytecode.instructions if hasattr(bytecode, 'instructions') else bytecode
|
|
389
462
|
constants = bytecode.constants if hasattr(bytecode, 'constants') else []
|
|
463
|
+
instructions = [
|
|
464
|
+
(self._normalize_opcode(opcode), operand)
|
|
465
|
+
for opcode, operand in raw_instructions
|
|
466
|
+
]
|
|
390
467
|
|
|
391
468
|
frames = []
|
|
392
469
|
current_frame = StackFrame()
|
|
@@ -484,24 +561,32 @@ class JITCompiler:
|
|
|
484
561
|
'OR': 'or',
|
|
485
562
|
}.get(opcode, opcode)
|
|
486
563
|
|
|
564
|
+
def _normalize_opcode(self, opcode) -> str:
|
|
565
|
+
"""Normalize opcode values from enums or raw strings."""
|
|
566
|
+
return opcode.name if hasattr(opcode, 'name') else opcode
|
|
567
|
+
|
|
487
568
|
def _optimize_bytecode(self, bytecode) -> Tuple[List, List]:
|
|
488
569
|
"""
|
|
489
570
|
Apply optimization passes to bytecode
|
|
490
571
|
|
|
491
572
|
Returns: (optimized_instructions, updated_constants)
|
|
492
573
|
"""
|
|
493
|
-
|
|
574
|
+
raw_instructions = list(bytecode.instructions) if hasattr(bytecode, 'instructions') else list(bytecode)
|
|
494
575
|
constants = list(bytecode.constants) if hasattr(bytecode, 'constants') else []
|
|
576
|
+
instructions = [
|
|
577
|
+
(self._normalize_opcode(opcode), operand)
|
|
578
|
+
for opcode, operand in raw_instructions
|
|
579
|
+
]
|
|
495
580
|
|
|
496
581
|
if self.optimizer:
|
|
497
582
|
try:
|
|
498
|
-
optimized
|
|
583
|
+
optimized = self.optimizer.optimize(instructions, constants)
|
|
499
584
|
if self.debug:
|
|
500
585
|
stats = self.optimizer.get_stats()
|
|
501
586
|
if stats['total_optimizations'] > 0:
|
|
502
587
|
print(f"🔧 JIT Optimizer: {stats['original_size']} → {stats['optimized_size']} instructions "
|
|
503
|
-
f"({stats['
|
|
504
|
-
return optimized,
|
|
588
|
+
f"({stats['size_reduction']:.1f}% reduction)")
|
|
589
|
+
return optimized, constants
|
|
505
590
|
except Exception as e:
|
|
506
591
|
if self.debug:
|
|
507
592
|
print(f"⚠️ JIT: Optimizer failed: {e}")
|
|
@@ -538,6 +623,229 @@ class JITCompiler:
|
|
|
538
623
|
|
|
539
624
|
return optimized
|
|
540
625
|
|
|
626
|
+
def _build_fallback_executor(self, instructions, constants):
|
|
627
|
+
"""Construct a conservative executor for instructions when optimized code fails."""
|
|
628
|
+
normalized_instrs = [
|
|
629
|
+
(self._normalize_opcode(op), operand)
|
|
630
|
+
for op, operand in (instructions or [])
|
|
631
|
+
]
|
|
632
|
+
consts = list(constants or [])
|
|
633
|
+
|
|
634
|
+
def _const(idx):
|
|
635
|
+
if isinstance(idx, int) and 0 <= idx < len(consts):
|
|
636
|
+
return consts[idx]
|
|
637
|
+
return idx
|
|
638
|
+
|
|
639
|
+
arithmetic_ops: Dict[str, Callable[[Any, Any], Any]] = {
|
|
640
|
+
'ADD': lambda a, b: a + b,
|
|
641
|
+
'SUB': lambda a, b: a - b,
|
|
642
|
+
'MUL': lambda a, b: a * b,
|
|
643
|
+
'DIV': lambda a, b: a / b if b not in (0, None) else None,
|
|
644
|
+
'MOD': lambda a, b: a % b if b not in (0, None) else None,
|
|
645
|
+
'POW': lambda a, b: a ** b,
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
compare_ops: Dict[str, Callable[[Any, Any], bool]] = {
|
|
649
|
+
'EQ': lambda a, b: a == b,
|
|
650
|
+
'NEQ': lambda a, b: a != b,
|
|
651
|
+
'LT': lambda a, b: a < b,
|
|
652
|
+
'GT': lambda a, b: a > b,
|
|
653
|
+
'LTE': lambda a, b: a <= b,
|
|
654
|
+
'GTE': lambda a, b: a >= b,
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
def jit_execute(vm, stack, env):
|
|
658
|
+
ip = 0
|
|
659
|
+
while ip < len(normalized_instrs):
|
|
660
|
+
op, operand = normalized_instrs[ip]
|
|
661
|
+
|
|
662
|
+
if op == 'LOAD_CONST':
|
|
663
|
+
stack.append(_const(operand))
|
|
664
|
+
|
|
665
|
+
elif op == 'LOAD_NAME':
|
|
666
|
+
name = _const(operand)
|
|
667
|
+
stack.append(env.get(name, None))
|
|
668
|
+
|
|
669
|
+
elif op == 'STORE_NAME':
|
|
670
|
+
name = _const(operand)
|
|
671
|
+
value = stack.pop() if stack else None
|
|
672
|
+
env[name] = value
|
|
673
|
+
|
|
674
|
+
elif op == 'STORE_CONST':
|
|
675
|
+
if isinstance(operand, (tuple, list)) and len(operand) == 2:
|
|
676
|
+
name = _const(operand[0])
|
|
677
|
+
value = _const(operand[1])
|
|
678
|
+
env[name] = value
|
|
679
|
+
|
|
680
|
+
elif op in arithmetic_ops:
|
|
681
|
+
b = stack.pop() if stack else None
|
|
682
|
+
a = stack.pop() if stack else None
|
|
683
|
+
try:
|
|
684
|
+
stack.append(arithmetic_ops[op](a, b))
|
|
685
|
+
except Exception:
|
|
686
|
+
stack.append(None)
|
|
687
|
+
|
|
688
|
+
elif op in compare_ops:
|
|
689
|
+
b = stack.pop() if stack else None
|
|
690
|
+
a = stack.pop() if stack else None
|
|
691
|
+
try:
|
|
692
|
+
stack.append(compare_ops[op](a, b))
|
|
693
|
+
except Exception:
|
|
694
|
+
stack.append(False)
|
|
695
|
+
|
|
696
|
+
elif op == 'NOT':
|
|
697
|
+
value = stack.pop() if stack else None
|
|
698
|
+
stack.append(not value)
|
|
699
|
+
|
|
700
|
+
elif op == 'AND':
|
|
701
|
+
b = stack.pop() if stack else None
|
|
702
|
+
a = stack.pop() if stack else None
|
|
703
|
+
stack.append(bool(a) and bool(b))
|
|
704
|
+
|
|
705
|
+
elif op == 'OR':
|
|
706
|
+
b = stack.pop() if stack else None
|
|
707
|
+
a = stack.pop() if stack else None
|
|
708
|
+
stack.append(bool(a) or bool(b))
|
|
709
|
+
|
|
710
|
+
elif op == 'POP':
|
|
711
|
+
if stack:
|
|
712
|
+
stack.pop()
|
|
713
|
+
|
|
714
|
+
elif op == 'JUMP':
|
|
715
|
+
ip = operand if isinstance(operand, int) else ip + 1
|
|
716
|
+
continue
|
|
717
|
+
|
|
718
|
+
elif op == 'JUMP_IF_FALSE':
|
|
719
|
+
condition = stack.pop() if stack else None
|
|
720
|
+
target = operand if isinstance(operand, int) else None
|
|
721
|
+
if not condition and target is not None:
|
|
722
|
+
ip = target
|
|
723
|
+
continue
|
|
724
|
+
|
|
725
|
+
elif op == 'RETURN':
|
|
726
|
+
return stack[-1] if stack else None
|
|
727
|
+
|
|
728
|
+
else:
|
|
729
|
+
# Unsupported opcode - bail out with None to keep semantics safe
|
|
730
|
+
return stack[-1] if stack else None
|
|
731
|
+
|
|
732
|
+
ip += 1
|
|
733
|
+
|
|
734
|
+
return stack[-1] if stack else None
|
|
735
|
+
|
|
736
|
+
return jit_execute if normalized_instrs else None
|
|
737
|
+
|
|
738
|
+
def _constant_folding(self, instructions, constants=None):
|
|
739
|
+
"""Perform simple constant folding for common arithmetic patterns."""
|
|
740
|
+
instructions = [tuple(inst) for inst in instructions or []]
|
|
741
|
+
constants_list = list(constants) if constants is not None else None
|
|
742
|
+
|
|
743
|
+
if not instructions:
|
|
744
|
+
return []
|
|
745
|
+
|
|
746
|
+
# Without constants we cannot safely fold indexed operands.
|
|
747
|
+
if not constants_list:
|
|
748
|
+
return list(instructions)
|
|
749
|
+
|
|
750
|
+
def _op_name(op):
|
|
751
|
+
return op.name if hasattr(op, 'name') else op
|
|
752
|
+
|
|
753
|
+
result = []
|
|
754
|
+
i = 0
|
|
755
|
+
while i < len(instructions):
|
|
756
|
+
if i + 2 < len(instructions):
|
|
757
|
+
op1, operand1 = instructions[i]
|
|
758
|
+
op2, operand2 = instructions[i + 1]
|
|
759
|
+
op3, _ = instructions[i + 2]
|
|
760
|
+
if (_op_name(op1) == 'LOAD_CONST' and _op_name(op2) == 'LOAD_CONST' and
|
|
761
|
+
isinstance(operand1, int) and isinstance(operand2, int) and
|
|
762
|
+
0 <= operand1 < len(constants_list) and 0 <= operand2 < len(constants_list) and
|
|
763
|
+
_op_name(op3) in {'ADD', 'SUB', 'MUL', 'DIV', 'MOD', 'POW'}):
|
|
764
|
+
a = constants_list[operand1]
|
|
765
|
+
b = constants_list[operand2]
|
|
766
|
+
try:
|
|
767
|
+
op3_name = _op_name(op3)
|
|
768
|
+
if op3_name == 'ADD':
|
|
769
|
+
value = a + b
|
|
770
|
+
elif op3_name == 'SUB':
|
|
771
|
+
value = a - b
|
|
772
|
+
elif op3_name == 'MUL':
|
|
773
|
+
value = a * b
|
|
774
|
+
elif op3_name == 'DIV':
|
|
775
|
+
value = a / b if b != 0 else 0
|
|
776
|
+
elif op3_name == 'MOD':
|
|
777
|
+
value = a % b if b != 0 else 0
|
|
778
|
+
else: # POW
|
|
779
|
+
value = a ** b
|
|
780
|
+
except Exception:
|
|
781
|
+
value = None
|
|
782
|
+
|
|
783
|
+
if value is not None:
|
|
784
|
+
const_idx = len(constants_list)
|
|
785
|
+
constants_list.append(value)
|
|
786
|
+
result.append(('LOAD_CONST', const_idx))
|
|
787
|
+
i += 3
|
|
788
|
+
continue
|
|
789
|
+
result.append(instructions[i])
|
|
790
|
+
i += 1
|
|
791
|
+
return result
|
|
792
|
+
|
|
793
|
+
def _dead_code_elimination(self, instructions):
|
|
794
|
+
"""Remove unreachable instructions after terminal ops."""
|
|
795
|
+
instructions = [tuple(inst) for inst in instructions or []]
|
|
796
|
+
def _op_name(op):
|
|
797
|
+
return op.name if hasattr(op, 'name') else op
|
|
798
|
+
result = []
|
|
799
|
+
dead = False
|
|
800
|
+
for opcode, operand in instructions:
|
|
801
|
+
name = _op_name(opcode)
|
|
802
|
+
if dead and name not in {'LABEL', 'JUMP_TARGET'}:
|
|
803
|
+
continue
|
|
804
|
+
result.append((opcode, operand))
|
|
805
|
+
if name in {'RETURN', 'JUMP'}:
|
|
806
|
+
dead = True
|
|
807
|
+
return result
|
|
808
|
+
|
|
809
|
+
def _peephole_optimization(self, instructions):
|
|
810
|
+
"""Eliminate short redundant instruction patterns."""
|
|
811
|
+
instructions = [tuple(inst) for inst in instructions or []]
|
|
812
|
+
def _op_name(op):
|
|
813
|
+
return op.name if hasattr(op, 'name') else op
|
|
814
|
+
result = []
|
|
815
|
+
i = 0
|
|
816
|
+
while i < len(instructions):
|
|
817
|
+
if i + 1 < len(instructions):
|
|
818
|
+
op1, operand1 = instructions[i]
|
|
819
|
+
op2, _ = instructions[i + 1]
|
|
820
|
+
if _op_name(op1) in {'LOAD_CONST', 'LOAD_NAME'} and _op_name(op2) == 'POP':
|
|
821
|
+
i += 2
|
|
822
|
+
continue
|
|
823
|
+
if _op_name(op1) == 'DUP' and _op_name(op2) == 'POP':
|
|
824
|
+
i += 2
|
|
825
|
+
continue
|
|
826
|
+
result.append(instructions[i])
|
|
827
|
+
i += 1
|
|
828
|
+
return result
|
|
829
|
+
|
|
830
|
+
def _instruction_combining(self, instructions):
|
|
831
|
+
"""Combine simple instruction pairs into compact forms."""
|
|
832
|
+
instructions = [tuple(inst) for inst in instructions or []]
|
|
833
|
+
def _op_name(op):
|
|
834
|
+
return op.name if hasattr(op, 'name') else op
|
|
835
|
+
result = []
|
|
836
|
+
i = 0
|
|
837
|
+
while i < len(instructions):
|
|
838
|
+
if i + 1 < len(instructions):
|
|
839
|
+
(op1, operand1) = instructions[i]
|
|
840
|
+
(op2, operand2) = instructions[i + 1]
|
|
841
|
+
if _op_name(op1) == 'LOAD_CONST' and _op_name(op2) == 'STORE_NAME':
|
|
842
|
+
result.append(('STORE_CONST', (operand2, operand1)))
|
|
843
|
+
i += 2
|
|
844
|
+
continue
|
|
845
|
+
result.append(instructions[i])
|
|
846
|
+
i += 1
|
|
847
|
+
return result
|
|
848
|
+
|
|
541
849
|
def _generate_efficient_python_code(self, instructions: List, constants: List, stack_frames: List[StackFrame]) -> str:
|
|
542
850
|
"""
|
|
543
851
|
Generate efficient Python source code from optimized bytecode
|
|
@@ -546,6 +854,14 @@ class JITCompiler:
|
|
|
546
854
|
lines = [
|
|
547
855
|
"def jit_execute(vm, stack, env):",
|
|
548
856
|
" # JIT-compiled native code",
|
|
857
|
+
" gas = getattr(vm, 'gas_metering', None)",
|
|
858
|
+
" def _gas(op, **kwargs):",
|
|
859
|
+
" if gas is None:",
|
|
860
|
+
" return",
|
|
861
|
+
" if not gas.consume(op, **kwargs):",
|
|
862
|
+
" if gas.operation_count > gas.max_operations:",
|
|
863
|
+
" raise OperationLimitExceededError(gas.operation_count, gas.max_operations)",
|
|
864
|
+
" raise OutOfGasError(gas.gas_used, gas.gas_limit, op)",
|
|
549
865
|
]
|
|
550
866
|
|
|
551
867
|
# Track variable assignments for efficient code generation
|
|
@@ -559,6 +875,7 @@ class JITCompiler:
|
|
|
559
875
|
frame = stack_frames[i]
|
|
560
876
|
|
|
561
877
|
if opcode == 'LOAD_CONST':
|
|
878
|
+
lines.append(" _gas('LOAD_CONST')")
|
|
562
879
|
if operand < len(constants):
|
|
563
880
|
const_val = constants[operand]
|
|
564
881
|
var_name = f"const_{operand}_{i}"
|
|
@@ -572,6 +889,7 @@ class JITCompiler:
|
|
|
572
889
|
stack_height += 1
|
|
573
890
|
|
|
574
891
|
elif opcode == 'LOAD_NAME':
|
|
892
|
+
lines.append(" _gas('LOAD_NAME')")
|
|
575
893
|
if operand < len(constants):
|
|
576
894
|
name = constants[operand]
|
|
577
895
|
var_name = f"var_{operand}_{i}"
|
|
@@ -585,6 +903,7 @@ class JITCompiler:
|
|
|
585
903
|
stack_height += 1
|
|
586
904
|
|
|
587
905
|
elif opcode == 'STORE_NAME':
|
|
906
|
+
lines.append(" _gas('STORE_NAME')")
|
|
588
907
|
if operand < len(constants):
|
|
589
908
|
name = constants[operand]
|
|
590
909
|
if stack_height > 0:
|
|
@@ -592,6 +911,7 @@ class JITCompiler:
|
|
|
592
911
|
stack_height -= 1
|
|
593
912
|
|
|
594
913
|
elif opcode == 'STORE_CONST':
|
|
914
|
+
lines.append(" _gas('STORE_NAME')")
|
|
595
915
|
if isinstance(operand, tuple) and len(operand) == 2:
|
|
596
916
|
name_idx, const_idx = operand
|
|
597
917
|
if name_idx < len(constants) and const_idx < len(constants):
|
|
@@ -600,10 +920,12 @@ class JITCompiler:
|
|
|
600
920
|
lines.append(f" env[{repr(name)}] = {repr(const_val)}")
|
|
601
921
|
|
|
602
922
|
elif opcode in ['ADD', 'SUB', 'MUL', 'DIV', 'MOD', 'POW']:
|
|
923
|
+
lines.append(f" _gas('{opcode}')")
|
|
603
924
|
if stack_height >= 2:
|
|
604
925
|
# Generate efficient arithmetic
|
|
605
926
|
operator = self._opcode_to_operator(opcode)
|
|
606
927
|
result_var = f"result_{i}"
|
|
928
|
+
assigned = False
|
|
607
929
|
|
|
608
930
|
# Try to use pre-computed values from stack analysis
|
|
609
931
|
if i > 0 and i-1 < len(stack_frames):
|
|
@@ -619,28 +941,29 @@ class JITCompiler:
|
|
|
619
941
|
|
|
620
942
|
# Check if we can compute at compile time
|
|
621
943
|
try:
|
|
622
|
-
if (a_expr
|
|
944
|
+
if (isinstance(a_expr, str) and isinstance(b_expr, str) and
|
|
945
|
+
a_expr.startswith('const_') and b_expr.startswith('const_')):
|
|
623
946
|
# Already computed by optimizer
|
|
624
947
|
computed = eval(f"{a_val} {operator} {b_val}")
|
|
625
948
|
lines.append(f" {result_var} = {repr(computed)}")
|
|
626
949
|
else:
|
|
627
950
|
lines.append(f" {result_var} = {a_val} {operator} {b_val}")
|
|
628
|
-
except (TypeError, ValueError, NameError, SyntaxError):
|
|
951
|
+
except (TypeError, ValueError, NameError, SyntaxError, AttributeError):
|
|
629
952
|
lines.append(f" {result_var} = {a_val} {operator} {b_val}")
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
lines.append(f" {result_var} = a {operator} b")
|
|
634
|
-
else:
|
|
953
|
+
assigned = True
|
|
954
|
+
|
|
955
|
+
if not assigned:
|
|
635
956
|
lines.append(f" b = stack.pop()")
|
|
636
957
|
lines.append(f" a = stack.pop()")
|
|
637
958
|
lines.append(f" {result_var} = a {operator} b")
|
|
959
|
+
assigned = True
|
|
638
960
|
|
|
639
961
|
local_vars.add(result_var)
|
|
640
962
|
lines.append(f" stack.append({result_var})")
|
|
641
963
|
stack_height -= 1 # 2 popped, 1 pushed = net -1
|
|
642
964
|
|
|
643
965
|
elif opcode == 'RETURN':
|
|
966
|
+
lines.append(" _gas('RETURN')")
|
|
644
967
|
if stack_height > 0:
|
|
645
968
|
lines.append(" return stack[-1]")
|
|
646
969
|
else:
|
|
@@ -683,13 +1006,34 @@ class JITCompiler:
|
|
|
683
1006
|
vm_bytecode = VM(use_jit=False)
|
|
684
1007
|
vm_bytecode.env = env_dict.copy()
|
|
685
1008
|
vm_bytecode.stack = stack.copy()
|
|
686
|
-
|
|
1009
|
+
bytecode_exc = None
|
|
1010
|
+
try:
|
|
1011
|
+
bytecode_result = vm_bytecode.execute(original_bytecode)
|
|
1012
|
+
except Exception as e: # noqa: BLE001 - intentional verification comparison
|
|
1013
|
+
bytecode_exc = e
|
|
1014
|
+
bytecode_result = None
|
|
687
1015
|
|
|
688
1016
|
# Run JIT version
|
|
689
1017
|
vm_jit = VM(use_jit=False)
|
|
690
1018
|
vm_jit.env = env_dict.copy()
|
|
691
1019
|
vm_jit.stack = stack.copy()
|
|
692
|
-
|
|
1020
|
+
jit_exc = None
|
|
1021
|
+
try:
|
|
1022
|
+
jit_result = jit_function(vm_jit, vm_jit.stack, vm_jit.env)
|
|
1023
|
+
except Exception as e: # noqa: BLE001 - intentional verification comparison
|
|
1024
|
+
jit_exc = e
|
|
1025
|
+
jit_result = None
|
|
1026
|
+
|
|
1027
|
+
# If both threw exceptions, ensure they match in type
|
|
1028
|
+
if bytecode_exc or jit_exc:
|
|
1029
|
+
if type(bytecode_exc) != type(jit_exc):
|
|
1030
|
+
if self.debug:
|
|
1031
|
+
print("❌ JIT Verification mismatch (exceptions):")
|
|
1032
|
+
print(f" Bytecode exception: {bytecode_exc!r}")
|
|
1033
|
+
print(f" JIT exception: {jit_exc!r}")
|
|
1034
|
+
print(f" Environment: {env_dict}")
|
|
1035
|
+
return False
|
|
1036
|
+
continue
|
|
693
1037
|
|
|
694
1038
|
# Compare results
|
|
695
1039
|
if bytecode_result != jit_result:
|