zexus 1.7.1 → 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 +3 -3
- 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/cli/__pycache__/main.cpython-312.pyc +0 -0
- package/src/zexus/cli/main.py +300 -20
- 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/lexer.py +10 -5
- 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 +10 -1
- 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 +441 -37
- package/src/zexus/evaluator/core.py +560 -49
- package/src/zexus/evaluator/expressions.py +122 -49
- package/src/zexus/evaluator/functions.py +417 -16
- package/src/zexus/evaluator/statements.py +521 -118
- package/src/zexus/evaluator/unified_execution.py +573 -72
- package/src/zexus/evaluator/utils.py +14 -2
- package/src/zexus/event_loop.py +186 -0
- package/src/zexus/lexer.py +742 -486
- 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 +237 -9
- package/src/zexus/object.py +64 -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 +786 -285
- package/src/zexus/parser/strategy_context.py +407 -66
- package/src/zexus/parser/strategy_structural.py +117 -19
- package/src/zexus/persistence.py +15 -1
- package/src/zexus/renderer/__init__.py +15 -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/tk_backend.py +208 -0
- package/src/zexus/renderer/web_backend.py +260 -0
- 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/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 +14 -1
- package/src/zexus/vm/binary_bytecode.py +659 -0
- package/src/zexus/vm/bytecode.py +28 -1
- 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 +557 -17
- package/src/zexus/vm/compiler.py +703 -5
- 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 +83 -2
- 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 +118 -42
- 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 +3411 -573
- package/src/zexus/vm/wasm_compiler.py +658 -0
- package/src/zexus/zexus_ast.py +63 -11
- package/src/zexus/zexus_token.py +13 -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 +7 -4
- package/src/zexus.egg-info/SOURCES.txt +116 -9
- package/src/zexus.egg-info/entry_points.txt +1 -0
- package/src/zexus.egg-info/requires.txt +4 -0
|
Binary file
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# cython: language_level=3
|
|
2
|
+
# cython: boundscheck=False
|
|
3
|
+
# cython: wraparound=False
|
|
4
|
+
# cython: cdivision=True
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
Cython-accelerated hot-path VM execution.
|
|
8
|
+
|
|
9
|
+
Implements a fast dispatch loop for common bytecode ops used in benchmarks.
|
|
10
|
+
Falls back to Python execution for unsupported ops by raising NotImplementedError.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from zexus.object import List as ZList
|
|
14
|
+
from zexus.object import Map as ZMap
|
|
15
|
+
from zexus.object import String as ZString
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _resolve(name, dict env, dict closure_cells):
|
|
19
|
+
if name in env:
|
|
20
|
+
val = env[name]
|
|
21
|
+
if hasattr(val, "value"):
|
|
22
|
+
return val.value
|
|
23
|
+
return val
|
|
24
|
+
if closure_cells is not None and name in closure_cells:
|
|
25
|
+
cell = closure_cells[name]
|
|
26
|
+
if hasattr(cell, "value"):
|
|
27
|
+
return cell.value
|
|
28
|
+
return cell
|
|
29
|
+
return None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _store(name, value, dict env, dict closure_cells):
|
|
33
|
+
if name in env:
|
|
34
|
+
current = env[name]
|
|
35
|
+
if hasattr(current, "value"):
|
|
36
|
+
current.value = value
|
|
37
|
+
return
|
|
38
|
+
env[name] = value
|
|
39
|
+
return
|
|
40
|
+
if closure_cells is not None and name in closure_cells:
|
|
41
|
+
cell = closure_cells[name]
|
|
42
|
+
if hasattr(cell, "value"):
|
|
43
|
+
cell.value = value
|
|
44
|
+
return
|
|
45
|
+
closure_cells[name] = value
|
|
46
|
+
return
|
|
47
|
+
env[name] = value
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _call_method(target, method_name, args):
|
|
51
|
+
if target is None:
|
|
52
|
+
return None
|
|
53
|
+
try:
|
|
54
|
+
if method_name == "set":
|
|
55
|
+
if isinstance(target, ZMap) and len(args) >= 2:
|
|
56
|
+
key = args[0]
|
|
57
|
+
if isinstance(key, str):
|
|
58
|
+
key = ZString(key)
|
|
59
|
+
return target.set(key, args[1])
|
|
60
|
+
if isinstance(target, ZList) and len(args) >= 2:
|
|
61
|
+
return target.set(args[0], args[1])
|
|
62
|
+
if isinstance(target, (dict, list)) and len(args) >= 2:
|
|
63
|
+
target[args[0]] = args[1]
|
|
64
|
+
return args[1]
|
|
65
|
+
if hasattr(target, "call_method"):
|
|
66
|
+
return target.call_method(method_name, args)
|
|
67
|
+
attr = getattr(target, method_name, None)
|
|
68
|
+
if callable(attr):
|
|
69
|
+
return attr(*args)
|
|
70
|
+
if isinstance(target, dict) and method_name in target:
|
|
71
|
+
candidate = target[method_name]
|
|
72
|
+
return candidate(*args) if callable(candidate) else candidate
|
|
73
|
+
return attr
|
|
74
|
+
except Exception:
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _call_top(fn_obj, args):
|
|
79
|
+
if fn_obj is None:
|
|
80
|
+
return None
|
|
81
|
+
if isinstance(fn_obj, dict) and "bytecode" in fn_obj:
|
|
82
|
+
raise NotImplementedError("CALL_TOP requires VM execution")
|
|
83
|
+
try:
|
|
84
|
+
if callable(fn_obj):
|
|
85
|
+
return fn_obj(*args)
|
|
86
|
+
return None
|
|
87
|
+
except Exception:
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def execute(list instrs, list consts, dict env, dict builtins, dict closure_cells=None):
|
|
92
|
+
cdef Py_ssize_t ip = 0
|
|
93
|
+
cdef Py_ssize_t instr_count = len(instrs)
|
|
94
|
+
cdef list stack = []
|
|
95
|
+
cdef object op_name
|
|
96
|
+
cdef object operand
|
|
97
|
+
|
|
98
|
+
while ip < instr_count:
|
|
99
|
+
op_name, operand = instrs[ip]
|
|
100
|
+
ip += 1
|
|
101
|
+
|
|
102
|
+
if op_name == "LOAD_CONST":
|
|
103
|
+
if isinstance(operand, int) and 0 <= operand < len(consts):
|
|
104
|
+
stack.append(consts[operand])
|
|
105
|
+
else:
|
|
106
|
+
stack.append(operand)
|
|
107
|
+
elif op_name == "LOAD_NAME":
|
|
108
|
+
name = consts[operand] if isinstance(operand, int) and 0 <= operand < len(consts) else operand
|
|
109
|
+
stack.append(_resolve(name, env, closure_cells))
|
|
110
|
+
elif op_name == "STORE_NAME":
|
|
111
|
+
name = consts[operand] if isinstance(operand, int) and 0 <= operand < len(consts) else operand
|
|
112
|
+
val = stack.pop() if stack else None
|
|
113
|
+
_store(name, val, env, closure_cells)
|
|
114
|
+
elif op_name == "POP":
|
|
115
|
+
if stack:
|
|
116
|
+
stack.pop()
|
|
117
|
+
elif op_name == "DUP":
|
|
118
|
+
if stack:
|
|
119
|
+
stack.append(stack[-1])
|
|
120
|
+
elif op_name == "ADD":
|
|
121
|
+
b = stack.pop() if stack else 0
|
|
122
|
+
a = stack.pop() if stack else 0
|
|
123
|
+
if hasattr(a, "value"):
|
|
124
|
+
a = a.value
|
|
125
|
+
if hasattr(b, "value"):
|
|
126
|
+
b = b.value
|
|
127
|
+
stack.append(a + b)
|
|
128
|
+
elif op_name == "SUB":
|
|
129
|
+
b = stack.pop() if stack else 0
|
|
130
|
+
a = stack.pop() if stack else 0
|
|
131
|
+
if hasattr(a, "value"):
|
|
132
|
+
a = a.value
|
|
133
|
+
if hasattr(b, "value"):
|
|
134
|
+
b = b.value
|
|
135
|
+
stack.append(a - b)
|
|
136
|
+
elif op_name == "MUL":
|
|
137
|
+
b = stack.pop() if stack else 0
|
|
138
|
+
a = stack.pop() if stack else 0
|
|
139
|
+
if hasattr(a, "value"):
|
|
140
|
+
a = a.value
|
|
141
|
+
if hasattr(b, "value"):
|
|
142
|
+
b = b.value
|
|
143
|
+
stack.append(a * b)
|
|
144
|
+
elif op_name == "DIV":
|
|
145
|
+
b = stack.pop() if stack else 1
|
|
146
|
+
a = stack.pop() if stack else 0
|
|
147
|
+
if hasattr(a, "value"):
|
|
148
|
+
a = a.value
|
|
149
|
+
if hasattr(b, "value"):
|
|
150
|
+
b = b.value
|
|
151
|
+
stack.append(a / b if b != 0 else 0)
|
|
152
|
+
elif op_name == "MOD":
|
|
153
|
+
b = stack.pop() if stack else 1
|
|
154
|
+
a = stack.pop() if stack else 0
|
|
155
|
+
stack.append(a % b if b != 0 else 0)
|
|
156
|
+
elif op_name == "EQ":
|
|
157
|
+
b = stack.pop() if stack else None
|
|
158
|
+
a = stack.pop() if stack else None
|
|
159
|
+
stack.append(a == b)
|
|
160
|
+
elif op_name == "NEQ":
|
|
161
|
+
b = stack.pop() if stack else None
|
|
162
|
+
a = stack.pop() if stack else None
|
|
163
|
+
stack.append(a != b)
|
|
164
|
+
elif op_name == "LT":
|
|
165
|
+
b = stack.pop() if stack else 0
|
|
166
|
+
a = stack.pop() if stack else 0
|
|
167
|
+
stack.append(a < b)
|
|
168
|
+
elif op_name == "GT":
|
|
169
|
+
b = stack.pop() if stack else 0
|
|
170
|
+
a = stack.pop() if stack else 0
|
|
171
|
+
stack.append(a > b)
|
|
172
|
+
elif op_name == "LTE":
|
|
173
|
+
b = stack.pop() if stack else 0
|
|
174
|
+
a = stack.pop() if stack else 0
|
|
175
|
+
stack.append(a <= b)
|
|
176
|
+
elif op_name == "GTE":
|
|
177
|
+
b = stack.pop() if stack else 0
|
|
178
|
+
a = stack.pop() if stack else 0
|
|
179
|
+
stack.append(a >= b)
|
|
180
|
+
elif op_name == "NOT":
|
|
181
|
+
a = stack.pop() if stack else False
|
|
182
|
+
stack.append(not a)
|
|
183
|
+
elif op_name == "NEG":
|
|
184
|
+
a = stack.pop() if stack else 0
|
|
185
|
+
stack.append(-a)
|
|
186
|
+
elif op_name == "JUMP":
|
|
187
|
+
ip = operand
|
|
188
|
+
elif op_name == "JUMP_IF_FALSE":
|
|
189
|
+
cond = stack.pop() if stack else None
|
|
190
|
+
if not cond:
|
|
191
|
+
ip = operand
|
|
192
|
+
elif op_name == "RETURN":
|
|
193
|
+
return stack.pop() if stack else None
|
|
194
|
+
elif op_name == "BUILD_LIST":
|
|
195
|
+
count = operand if operand is not None else 0
|
|
196
|
+
elements = [stack.pop() for _ in range(count)][::-1]
|
|
197
|
+
stack.append(elements)
|
|
198
|
+
elif op_name == "BUILD_MAP":
|
|
199
|
+
count = operand if operand is not None else 0
|
|
200
|
+
result = {}
|
|
201
|
+
for _ in range(count):
|
|
202
|
+
val = stack.pop(); key = stack.pop()
|
|
203
|
+
result[key] = val
|
|
204
|
+
stack.append(result)
|
|
205
|
+
elif op_name == "BUILD_SET":
|
|
206
|
+
count = operand if operand is not None else 0
|
|
207
|
+
elements = [stack.pop() for _ in range(count)][::-1]
|
|
208
|
+
stack.append(set(elements))
|
|
209
|
+
elif op_name == "INDEX":
|
|
210
|
+
idx = stack.pop()
|
|
211
|
+
obj = stack.pop()
|
|
212
|
+
try:
|
|
213
|
+
if isinstance(obj, ZList):
|
|
214
|
+
stack.append(obj.get(idx))
|
|
215
|
+
elif isinstance(obj, ZMap):
|
|
216
|
+
stack.append(obj.get(idx))
|
|
217
|
+
else:
|
|
218
|
+
stack.append(obj[idx] if obj is not None else None)
|
|
219
|
+
except Exception:
|
|
220
|
+
stack.append(None)
|
|
221
|
+
elif op_name == "SLICE":
|
|
222
|
+
end = stack.pop() if stack else None
|
|
223
|
+
start = stack.pop() if stack else None
|
|
224
|
+
obj = stack.pop() if stack else None
|
|
225
|
+
if hasattr(start, "value"):
|
|
226
|
+
start = start.value
|
|
227
|
+
if hasattr(end, "value"):
|
|
228
|
+
end = end.value
|
|
229
|
+
try:
|
|
230
|
+
if isinstance(obj, ZList):
|
|
231
|
+
stack.append(ZList(obj.elements[start:end]))
|
|
232
|
+
elif isinstance(obj, ZString):
|
|
233
|
+
stack.append(ZString(obj.value[start:end]))
|
|
234
|
+
else:
|
|
235
|
+
stack.append(obj[start:end] if obj is not None else None)
|
|
236
|
+
except Exception:
|
|
237
|
+
stack.append(None)
|
|
238
|
+
elif op_name == "GET_LENGTH":
|
|
239
|
+
obj = stack.pop() if stack else None
|
|
240
|
+
try:
|
|
241
|
+
if obj is None:
|
|
242
|
+
stack.append(0)
|
|
243
|
+
elif isinstance(obj, ZList):
|
|
244
|
+
stack.append(len(obj.elements))
|
|
245
|
+
elif isinstance(obj, ZMap):
|
|
246
|
+
stack.append(len(obj.pairs))
|
|
247
|
+
elif isinstance(obj, ZString):
|
|
248
|
+
stack.append(len(obj.value))
|
|
249
|
+
else:
|
|
250
|
+
stack.append(len(obj))
|
|
251
|
+
except Exception:
|
|
252
|
+
stack.append(0)
|
|
253
|
+
elif op_name == "CALL_NAME":
|
|
254
|
+
name_idx, arg_count = operand
|
|
255
|
+
func_name = consts[name_idx] if isinstance(name_idx, int) and 0 <= name_idx < len(consts) else name_idx
|
|
256
|
+
args = [stack.pop() for _ in range(arg_count)][::-1] if arg_count else []
|
|
257
|
+
fn = _resolve(func_name, env, closure_cells) or builtins.get(func_name)
|
|
258
|
+
if fn is None:
|
|
259
|
+
stack.append(None)
|
|
260
|
+
else:
|
|
261
|
+
stack.append(fn(*args))
|
|
262
|
+
elif op_name == "CALL_BUILTIN":
|
|
263
|
+
name_idx, arg_count = operand
|
|
264
|
+
func_name = consts[name_idx] if isinstance(name_idx, int) and 0 <= name_idx < len(consts) else name_idx
|
|
265
|
+
args = [stack.pop() for _ in range(arg_count)][::-1] if arg_count else []
|
|
266
|
+
fn = builtins.get(func_name)
|
|
267
|
+
if fn is None:
|
|
268
|
+
stack.append(None)
|
|
269
|
+
else:
|
|
270
|
+
try:
|
|
271
|
+
stack.append(fn(*args))
|
|
272
|
+
except Exception:
|
|
273
|
+
stack.append(None)
|
|
274
|
+
elif op_name == "CALL_METHOD":
|
|
275
|
+
method_idx, arg_count = operand
|
|
276
|
+
args = [stack.pop() for _ in range(arg_count)][::-1] if arg_count else []
|
|
277
|
+
target = stack.pop() if stack else None
|
|
278
|
+
method_name = consts[method_idx] if isinstance(method_idx, int) and 0 <= method_idx < len(consts) else method_idx
|
|
279
|
+
stack.append(_call_method(target, method_name, args))
|
|
280
|
+
elif op_name == "CALL_TOP":
|
|
281
|
+
arg_count = operand
|
|
282
|
+
args = [stack.pop() for _ in range(arg_count)][::-1] if arg_count else []
|
|
283
|
+
fn_obj = stack.pop() if stack else None
|
|
284
|
+
stack.append(_call_top(fn_obj, args))
|
|
285
|
+
else:
|
|
286
|
+
raise NotImplementedError(f"opcode not supported: {op_name}")
|
|
287
|
+
|
|
288
|
+
return stack.pop() if stack else None
|
|
@@ -57,6 +57,8 @@ class GasCost(IntEnum):
|
|
|
57
57
|
# Function operations
|
|
58
58
|
CALL_NAME = 10 # Base cost for function call
|
|
59
59
|
CALL_TOP = 10
|
|
60
|
+
CALL_METHOD = 10
|
|
61
|
+
CALL_BUILTIN = 8
|
|
60
62
|
STORE_FUNC = 5
|
|
61
63
|
BUILD_LAMBDA = 5
|
|
62
64
|
|
|
@@ -74,6 +76,22 @@ class GasCost(IntEnum):
|
|
|
74
76
|
TX_COMMIT = 30
|
|
75
77
|
TX_REVERT = 20
|
|
76
78
|
LEDGER_APPEND = 40
|
|
79
|
+
GAS_CHARGE = 2 # Overhead of the charge itself
|
|
80
|
+
REQUIRE = 5
|
|
81
|
+
AUDIT_LOG = 15
|
|
82
|
+
RESTRICT_ACCESS = 5
|
|
83
|
+
DEFINE_CONTRACT = 50
|
|
84
|
+
EMIT_EVENT = 10
|
|
85
|
+
|
|
86
|
+
# Error handling
|
|
87
|
+
SETUP_TRY = 3
|
|
88
|
+
POP_TRY = 2
|
|
89
|
+
THROW = 5
|
|
90
|
+
ENABLE_ERROR_MODE = 2
|
|
91
|
+
|
|
92
|
+
# Parallel operations
|
|
93
|
+
PARALLEL_START = 15
|
|
94
|
+
PARALLEL_END = 10
|
|
77
95
|
|
|
78
96
|
# I/O operations
|
|
79
97
|
PRINT = 10
|
|
@@ -90,16 +108,19 @@ class GasMetering:
|
|
|
90
108
|
gas_limit: Maximum gas allowed (None = unlimited)
|
|
91
109
|
enable_timeout: Enable execution timeout mechanism
|
|
92
110
|
"""
|
|
93
|
-
self.gas_limit = gas_limit if gas_limit is not None else
|
|
111
|
+
self.gas_limit = gas_limit if gas_limit is not None else 100_000_000
|
|
94
112
|
self.gas_used = 0
|
|
95
113
|
self.enable_timeout = enable_timeout
|
|
96
114
|
self.operation_count = 0
|
|
97
|
-
self.max_operations =
|
|
115
|
+
self.max_operations = 100_000_000 # Safety limit for operations with generous default
|
|
98
116
|
|
|
99
117
|
# Track gas usage by operation type for profiling
|
|
100
118
|
self.gas_by_operation: Dict[str, int] = {}
|
|
101
119
|
self.operation_counts: Dict[str, int] = {}
|
|
102
120
|
|
|
121
|
+
# OPTIMIZATION: Cache for operation costs to avoid repeated enum lookups
|
|
122
|
+
self._cost_cache: Dict[str, int] = {}
|
|
123
|
+
|
|
103
124
|
def consume(self, operation: str, amount: Optional[int] = None, **kwargs) -> bool:
|
|
104
125
|
"""
|
|
105
126
|
Consume gas for an operation
|
|
@@ -112,6 +133,11 @@ class GasMetering:
|
|
|
112
133
|
Returns:
|
|
113
134
|
True if enough gas available, False if out of gas
|
|
114
135
|
"""
|
|
136
|
+
# OPTIMIZATION: Fast path for operation count check (most common failure)
|
|
137
|
+
self.operation_count += 1
|
|
138
|
+
if self.operation_count > self.max_operations:
|
|
139
|
+
return False
|
|
140
|
+
|
|
115
141
|
# Calculate gas cost
|
|
116
142
|
if amount is not None:
|
|
117
143
|
cost = amount
|
|
@@ -124,16 +150,23 @@ class GasMetering:
|
|
|
124
150
|
|
|
125
151
|
# Consume gas
|
|
126
152
|
self.gas_used += cost
|
|
127
|
-
self.operation_count += 1
|
|
128
153
|
|
|
129
|
-
# Track for profiling
|
|
130
|
-
self.gas_by_operation
|
|
131
|
-
|
|
154
|
+
# Track for profiling (only if needed)
|
|
155
|
+
if self.gas_by_operation is not None: # Allow disabling profiling
|
|
156
|
+
self.gas_by_operation[operation] = self.gas_by_operation.get(operation, 0) + cost
|
|
157
|
+
self.operation_counts[operation] = self.operation_counts.get(operation, 0) + 1
|
|
132
158
|
|
|
133
|
-
|
|
159
|
+
return True
|
|
160
|
+
|
|
161
|
+
def consume_light(self, amount: int = 1) -> bool:
|
|
162
|
+
"""Lightweight gas accounting: only counts operations with a fixed cost."""
|
|
163
|
+
self.operation_count += 1
|
|
134
164
|
if self.operation_count > self.max_operations:
|
|
135
165
|
return False
|
|
136
|
-
|
|
166
|
+
if self.gas_limit is not None:
|
|
167
|
+
self.gas_used += amount
|
|
168
|
+
if self.gas_used > self.gas_limit:
|
|
169
|
+
return False
|
|
137
170
|
return True
|
|
138
171
|
|
|
139
172
|
def _get_operation_cost(self, operation: str, **kwargs) -> int:
|
|
@@ -147,6 +180,10 @@ class GasMetering:
|
|
|
147
180
|
Returns:
|
|
148
181
|
Gas cost for the operation
|
|
149
182
|
"""
|
|
183
|
+
# OPTIMIZATION: Check cache first for static costs (no kwargs)
|
|
184
|
+
if not kwargs and operation in self._cost_cache:
|
|
185
|
+
return self._cost_cache[operation]
|
|
186
|
+
|
|
150
187
|
# Try to get cost from GasCost enum
|
|
151
188
|
try:
|
|
152
189
|
base_cost = GasCost[operation].value
|
|
@@ -170,11 +207,15 @@ class GasMetering:
|
|
|
170
207
|
leaf_count = kwargs.get('leaf_count', 0)
|
|
171
208
|
return base_cost + (leaf_count * 5)
|
|
172
209
|
|
|
173
|
-
elif operation in ("CALL_NAME", "CALL_TOP"):
|
|
210
|
+
elif operation in ("CALL_NAME", "CALL_TOP", "CALL_METHOD", "CALL_BUILTIN"):
|
|
174
211
|
# Cost scales with number of arguments
|
|
175
212
|
arg_count = kwargs.get('arg_count', 0)
|
|
176
213
|
return base_cost + (arg_count * 2)
|
|
177
214
|
|
|
215
|
+
# Cache static costs
|
|
216
|
+
if not kwargs:
|
|
217
|
+
self._cost_cache[operation] = base_cost
|
|
218
|
+
|
|
178
219
|
return base_cost
|
|
179
220
|
|
|
180
221
|
def check_limit(self) -> bool:
|
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,7 +305,11 @@ 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
|
|
|
@@ -518,7 +585,7 @@ class JITCompiler:
|
|
|
518
585
|
stats = self.optimizer.get_stats()
|
|
519
586
|
if stats['total_optimizations'] > 0:
|
|
520
587
|
print(f"🔧 JIT Optimizer: {stats['original_size']} → {stats['optimized_size']} instructions "
|
|
521
|
-
f"({stats['
|
|
588
|
+
f"({stats['size_reduction']:.1f}% reduction)")
|
|
522
589
|
return optimized, constants
|
|
523
590
|
except Exception as e:
|
|
524
591
|
if self.debug:
|
|
@@ -787,6 +854,14 @@ class JITCompiler:
|
|
|
787
854
|
lines = [
|
|
788
855
|
"def jit_execute(vm, stack, env):",
|
|
789
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)",
|
|
790
865
|
]
|
|
791
866
|
|
|
792
867
|
# Track variable assignments for efficient code generation
|
|
@@ -800,6 +875,7 @@ class JITCompiler:
|
|
|
800
875
|
frame = stack_frames[i]
|
|
801
876
|
|
|
802
877
|
if opcode == 'LOAD_CONST':
|
|
878
|
+
lines.append(" _gas('LOAD_CONST')")
|
|
803
879
|
if operand < len(constants):
|
|
804
880
|
const_val = constants[operand]
|
|
805
881
|
var_name = f"const_{operand}_{i}"
|
|
@@ -813,6 +889,7 @@ class JITCompiler:
|
|
|
813
889
|
stack_height += 1
|
|
814
890
|
|
|
815
891
|
elif opcode == 'LOAD_NAME':
|
|
892
|
+
lines.append(" _gas('LOAD_NAME')")
|
|
816
893
|
if operand < len(constants):
|
|
817
894
|
name = constants[operand]
|
|
818
895
|
var_name = f"var_{operand}_{i}"
|
|
@@ -826,6 +903,7 @@ class JITCompiler:
|
|
|
826
903
|
stack_height += 1
|
|
827
904
|
|
|
828
905
|
elif opcode == 'STORE_NAME':
|
|
906
|
+
lines.append(" _gas('STORE_NAME')")
|
|
829
907
|
if operand < len(constants):
|
|
830
908
|
name = constants[operand]
|
|
831
909
|
if stack_height > 0:
|
|
@@ -833,6 +911,7 @@ class JITCompiler:
|
|
|
833
911
|
stack_height -= 1
|
|
834
912
|
|
|
835
913
|
elif opcode == 'STORE_CONST':
|
|
914
|
+
lines.append(" _gas('STORE_NAME')")
|
|
836
915
|
if isinstance(operand, tuple) and len(operand) == 2:
|
|
837
916
|
name_idx, const_idx = operand
|
|
838
917
|
if name_idx < len(constants) and const_idx < len(constants):
|
|
@@ -841,6 +920,7 @@ class JITCompiler:
|
|
|
841
920
|
lines.append(f" env[{repr(name)}] = {repr(const_val)}")
|
|
842
921
|
|
|
843
922
|
elif opcode in ['ADD', 'SUB', 'MUL', 'DIV', 'MOD', 'POW']:
|
|
923
|
+
lines.append(f" _gas('{opcode}')")
|
|
844
924
|
if stack_height >= 2:
|
|
845
925
|
# Generate efficient arithmetic
|
|
846
926
|
operator = self._opcode_to_operator(opcode)
|
|
@@ -883,6 +963,7 @@ class JITCompiler:
|
|
|
883
963
|
stack_height -= 1 # 2 popped, 1 pushed = net -1
|
|
884
964
|
|
|
885
965
|
elif opcode == 'RETURN':
|
|
966
|
+
lines.append(" _gas('RETURN')")
|
|
886
967
|
if stack_height > 0:
|
|
887
968
|
lines.append(" return stack[-1]")
|
|
888
969
|
else:
|