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.
Files changed (159) hide show
  1. package/README.md +3 -3
  2. package/package.json +1 -1
  3. package/src/__init__.py +7 -0
  4. package/src/zexus/__init__.py +1 -1
  5. package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
  6. package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
  7. package/src/zexus/__pycache__/debug_sanitizer.cpython-312.pyc +0 -0
  8. package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
  9. package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
  10. package/src/zexus/__pycache__/input_validation.cpython-312.pyc +0 -0
  11. package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
  12. package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
  13. package/src/zexus/__pycache__/module_manager.cpython-312.pyc +0 -0
  14. package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
  15. package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
  16. package/src/zexus/__pycache__/security_enforcement.cpython-312.pyc +0 -0
  17. package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
  18. package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  19. package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
  20. package/src/zexus/access_control_system/__pycache__/__init__.cpython-312.pyc +0 -0
  21. package/src/zexus/access_control_system/__pycache__/access_control.cpython-312.pyc +0 -0
  22. package/src/zexus/advanced_types.py +17 -2
  23. package/src/zexus/blockchain/__init__.py +411 -0
  24. package/src/zexus/blockchain/accelerator.py +1160 -0
  25. package/src/zexus/blockchain/chain.py +660 -0
  26. package/src/zexus/blockchain/consensus.py +821 -0
  27. package/src/zexus/blockchain/contract_vm.py +1019 -0
  28. package/src/zexus/blockchain/crypto.py +79 -14
  29. package/src/zexus/blockchain/events.py +526 -0
  30. package/src/zexus/blockchain/loadtest.py +721 -0
  31. package/src/zexus/blockchain/monitoring.py +350 -0
  32. package/src/zexus/blockchain/mpt.py +716 -0
  33. package/src/zexus/blockchain/multichain.py +951 -0
  34. package/src/zexus/blockchain/multiprocess_executor.py +338 -0
  35. package/src/zexus/blockchain/network.py +886 -0
  36. package/src/zexus/blockchain/node.py +666 -0
  37. package/src/zexus/blockchain/rpc.py +1203 -0
  38. package/src/zexus/blockchain/rust_bridge.py +421 -0
  39. package/src/zexus/blockchain/storage.py +423 -0
  40. package/src/zexus/blockchain/tokens.py +750 -0
  41. package/src/zexus/blockchain/upgradeable.py +1004 -0
  42. package/src/zexus/blockchain/verification.py +1602 -0
  43. package/src/zexus/blockchain/wallet.py +621 -0
  44. package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
  45. package/src/zexus/cli/main.py +300 -20
  46. package/src/zexus/cli/zpm.py +1 -1
  47. package/src/zexus/compiler/__pycache__/bytecode.cpython-312.pyc +0 -0
  48. package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
  49. package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
  50. package/src/zexus/compiler/__pycache__/semantic.cpython-312.pyc +0 -0
  51. package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  52. package/src/zexus/compiler/lexer.py +10 -5
  53. package/src/zexus/concurrency_system.py +79 -0
  54. package/src/zexus/config.py +54 -0
  55. package/src/zexus/crypto_bridge.py +244 -8
  56. package/src/zexus/dap/__init__.py +10 -0
  57. package/src/zexus/dap/__main__.py +4 -0
  58. package/src/zexus/dap/dap_server.py +391 -0
  59. package/src/zexus/dap/debug_engine.py +298 -0
  60. package/src/zexus/environment.py +10 -1
  61. package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
  62. package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
  63. package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
  64. package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
  65. package/src/zexus/evaluator/__pycache__/resource_limiter.cpython-312.pyc +0 -0
  66. package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
  67. package/src/zexus/evaluator/__pycache__/unified_execution.cpython-312.pyc +0 -0
  68. package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
  69. package/src/zexus/evaluator/bytecode_compiler.py +441 -37
  70. package/src/zexus/evaluator/core.py +560 -49
  71. package/src/zexus/evaluator/expressions.py +122 -49
  72. package/src/zexus/evaluator/functions.py +417 -16
  73. package/src/zexus/evaluator/statements.py +521 -118
  74. package/src/zexus/evaluator/unified_execution.py +573 -72
  75. package/src/zexus/evaluator/utils.py +14 -2
  76. package/src/zexus/event_loop.py +186 -0
  77. package/src/zexus/lexer.py +742 -486
  78. package/src/zexus/lsp/__init__.py +1 -1
  79. package/src/zexus/lsp/definition_provider.py +163 -9
  80. package/src/zexus/lsp/server.py +22 -8
  81. package/src/zexus/lsp/symbol_provider.py +182 -9
  82. package/src/zexus/module_cache.py +237 -9
  83. package/src/zexus/object.py +64 -6
  84. package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
  85. package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
  86. package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
  87. package/src/zexus/parser/parser.py +786 -285
  88. package/src/zexus/parser/strategy_context.py +407 -66
  89. package/src/zexus/parser/strategy_structural.py +117 -19
  90. package/src/zexus/persistence.py +15 -1
  91. package/src/zexus/renderer/__init__.py +15 -0
  92. package/src/zexus/renderer/__pycache__/__init__.cpython-312.pyc +0 -0
  93. package/src/zexus/renderer/__pycache__/backend.cpython-312.pyc +0 -0
  94. package/src/zexus/renderer/__pycache__/canvas.cpython-312.pyc +0 -0
  95. package/src/zexus/renderer/__pycache__/color_system.cpython-312.pyc +0 -0
  96. package/src/zexus/renderer/__pycache__/layout.cpython-312.pyc +0 -0
  97. package/src/zexus/renderer/__pycache__/main_renderer.cpython-312.pyc +0 -0
  98. package/src/zexus/renderer/__pycache__/painter.cpython-312.pyc +0 -0
  99. package/src/zexus/renderer/tk_backend.py +208 -0
  100. package/src/zexus/renderer/web_backend.py +260 -0
  101. package/src/zexus/runtime/__pycache__/__init__.cpython-312.pyc +0 -0
  102. package/src/zexus/runtime/__pycache__/async_runtime.cpython-312.pyc +0 -0
  103. package/src/zexus/runtime/__pycache__/load_manager.cpython-312.pyc +0 -0
  104. package/src/zexus/runtime/file_flags.py +137 -0
  105. package/src/zexus/safety/__pycache__/__init__.cpython-312.pyc +0 -0
  106. package/src/zexus/safety/__pycache__/memory_safety.cpython-312.pyc +0 -0
  107. package/src/zexus/security.py +424 -34
  108. package/src/zexus/stdlib/fs.py +23 -18
  109. package/src/zexus/stdlib/http.py +289 -186
  110. package/src/zexus/stdlib/sockets.py +207 -163
  111. package/src/zexus/stdlib/websockets.py +282 -0
  112. package/src/zexus/stdlib_integration.py +369 -2
  113. package/src/zexus/strategy_recovery.py +6 -3
  114. package/src/zexus/type_checker.py +423 -0
  115. package/src/zexus/virtual_filesystem.py +189 -2
  116. package/src/zexus/vm/__init__.py +113 -3
  117. package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
  118. package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
  119. package/src/zexus/vm/__pycache__/bytecode_converter.cpython-312.pyc +0 -0
  120. package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
  121. package/src/zexus/vm/__pycache__/compiler.cpython-312.pyc +0 -0
  122. package/src/zexus/vm/__pycache__/gas_metering.cpython-312.pyc +0 -0
  123. package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
  124. package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
  125. package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
  126. package/src/zexus/vm/async_optimizer.py +14 -1
  127. package/src/zexus/vm/binary_bytecode.py +659 -0
  128. package/src/zexus/vm/bytecode.py +28 -1
  129. package/src/zexus/vm/bytecode_converter.py +26 -12
  130. package/src/zexus/vm/cabi.c +1985 -0
  131. package/src/zexus/vm/cabi.cpython-312-x86_64-linux-gnu.so +0 -0
  132. package/src/zexus/vm/cabi.h +127 -0
  133. package/src/zexus/vm/cache.py +557 -17
  134. package/src/zexus/vm/compiler.py +703 -5
  135. package/src/zexus/vm/fastops.c +15743 -0
  136. package/src/zexus/vm/fastops.cpython-312-x86_64-linux-gnu.so +0 -0
  137. package/src/zexus/vm/fastops.pyx +288 -0
  138. package/src/zexus/vm/gas_metering.py +50 -9
  139. package/src/zexus/vm/jit.py +83 -2
  140. package/src/zexus/vm/native_jit_backend.py +1816 -0
  141. package/src/zexus/vm/native_runtime.cpp +1388 -0
  142. package/src/zexus/vm/native_runtime.cpython-312-x86_64-linux-gnu.so +0 -0
  143. package/src/zexus/vm/optimizer.py +161 -11
  144. package/src/zexus/vm/parallel_vm.py +118 -42
  145. package/src/zexus/vm/peephole_optimizer.py +82 -4
  146. package/src/zexus/vm/profiler.py +38 -18
  147. package/src/zexus/vm/register_allocator.py +16 -5
  148. package/src/zexus/vm/register_vm.py +8 -5
  149. package/src/zexus/vm/vm.py +3411 -573
  150. package/src/zexus/vm/wasm_compiler.py +658 -0
  151. package/src/zexus/zexus_ast.py +63 -11
  152. package/src/zexus/zexus_token.py +13 -5
  153. package/src/zexus/zpm/installer.py +55 -15
  154. package/src/zexus/zpm/package_manager.py +1 -1
  155. package/src/zexus/zpm/registry.py +257 -28
  156. package/src/zexus.egg-info/PKG-INFO +7 -4
  157. package/src/zexus.egg-info/SOURCES.txt +116 -9
  158. package/src/zexus.egg-info/entry_points.txt +1 -0
  159. package/src/zexus.egg-info/requires.txt +4 -0
@@ -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 1_000_000
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 = 1_000_000 # Safety limit for operations with generous default
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[operation] = self.gas_by_operation.get(operation, 0) + cost
131
- self.operation_counts[operation] = self.operation_counts.get(operation, 0) + 1
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
- # Check operation count limit (prevents infinite loops even with high gas)
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:
@@ -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 = {'__builtins__': {}}
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['size_reduction_pct']:.1f}% reduction)")
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: