@fraczak/k 6.3.3 → 6.4.0

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 (155) hide show
  1. package/DOCS/CODECS.md +258 -0
  2. package/DOCS/DICTIONARY.md +1172 -0
  3. package/DOCS/KIR_SPECIALIZATION_DESIGN.md +51 -46
  4. package/DOCS/KIR_V1.md +221 -0
  5. package/DOCS/KVM_EXECUTION_MODEL.md +56 -19
  6. package/DOCS/OBJECT_FILE_AND_PATTERN.md +2 -1
  7. package/DOCS/PROFILING_AND_TRACING.md +196 -0
  8. package/DOCS/REPL.md +61 -4
  9. package/DOCS/WEB_REPL_REQUIREMENTS.md +135 -0
  10. package/DOCS/dependency-graph.md +144 -0
  11. package/Examples/arithmetics.k +51 -48
  12. package/Examples/bnat.k +1 -1
  13. package/Examples/buda.k +44 -0
  14. package/Examples/ieee.k +300 -8671
  15. package/Examples/poly.k +67 -0
  16. package/README.md +68 -19
  17. package/augmentation.mjs +9 -7
  18. package/backend-api.mjs +11 -2
  19. package/backends/arm64/README.md +104 -0
  20. package/backends/arm64/bin/k-arm64-compile.mjs +101 -0
  21. package/backends/arm64/bin/k-arm64-run.mjs +58 -0
  22. package/backends/arm64/bin/k-arm64.mjs +88 -0
  23. package/backends/arm64/scripts/run-tests.mjs +41 -0
  24. package/backends/arm64/src/arm64.mjs +229 -0
  25. package/backends/arm64/src/cli.mjs +155 -0
  26. package/backends/arm64/src/kvm2arm64.mjs +906 -0
  27. package/backends/arm64/src/runtime.c +728 -0
  28. package/backends/arm64/tests/integration.sh +112 -0
  29. package/backends/arm64/tests/test-arm64.mjs +240 -0
  30. package/backends/llvm/README.md +135 -0
  31. package/backends/llvm/bin/k-llvm-build.mjs +71 -0
  32. package/backends/llvm/bin/k-llvm-compile.mjs +68 -0
  33. package/backends/llvm/bin/k-llvm-jit.mjs +160 -0
  34. package/backends/llvm/bin/k-llvm-run.mjs +90 -0
  35. package/backends/llvm/runtime/krt.c +1508 -0
  36. package/backends/llvm/runtime/krt.h +109 -0
  37. package/backends/llvm/scripts/conformance.mjs +76 -0
  38. package/backends/llvm/scripts/run-tests.mjs +28 -0
  39. package/backends/llvm/src/executable.mjs +562 -0
  40. package/backends/llvm/src/kvm2llvm.mjs +998 -0
  41. package/backends/llvm/src/llvm.mjs +1092 -0
  42. package/backends/llvm/tests/composition-driver.c +22 -0
  43. package/backends/llvm/tests/identity-driver.c +27 -0
  44. package/backends/llvm/tests/integration.sh +153 -0
  45. package/backends/llvm/tests/perf-support.mjs +735 -0
  46. package/backends/llvm/tests/product-driver.c +23 -0
  47. package/backends/llvm/tests/projection-driver.c +19 -0
  48. package/backends/llvm/tests/relation-driver.c +29 -0
  49. package/backends/llvm/tests/test-llvm.mjs +240 -0
  50. package/backends/llvm/tests/union-driver.c +31 -0
  51. package/backends/llvm/tests/variant-driver.c +19 -0
  52. package/backends/llvm/tests/variant-projection-driver.c +21 -0
  53. package/backends/wasm/DOCS/USE-WEB-ASSEMBLY.md +233 -0
  54. package/backends/wasm/README.md +97 -0
  55. package/backends/wasm/TECHNICAL-DEBT.md +60 -0
  56. package/backends/wasm/bin/k-wasm-compile.mjs +50 -0
  57. package/backends/wasm/bin/k-wasm-run.mjs +140 -0
  58. package/backends/wasm/bin/k-wasm.mjs +49 -0
  59. package/backends/wasm/demo_ieee.mjs +319 -0
  60. package/backends/wasm/runtime.wat +102 -0
  61. package/backends/wasm/scripts/run-tests.mjs +41 -0
  62. package/backends/wasm/src/cli.mjs +133 -0
  63. package/backends/wasm/src/kvm2wasm.mjs +661 -0
  64. package/backends/wasm/src/wasm.mjs +1010 -0
  65. package/backends/wasm/tests/integration.sh +182 -0
  66. package/backends/wasm/tests/perf-support.mjs +336 -0
  67. package/backends/wasm/tests/test-wasm.mjs +617 -0
  68. package/browser/repl-browser.mjs +1584 -0
  69. package/browser/shims/assert.mjs +19 -0
  70. package/browser/shims/buffer.mjs +224 -0
  71. package/browser/shims/crypto.mjs +103 -0
  72. package/browser/shims/fs.mjs +159 -0
  73. package/browser/shims/os.mjs +17 -0
  74. package/browser/shims/path.mjs +54 -0
  75. package/browser/shims/process.mjs +44 -0
  76. package/browser/shims/readline.mjs +11 -0
  77. package/browser/shims/url.mjs +12 -0
  78. package/browser/vfs-data.mjs +19 -0
  79. package/codecs/README.md +3 -0
  80. package/codecs/runtime/show-value.mjs +2 -2
  81. package/conformance/helper-reuse/case.json +8 -0
  82. package/conformance/helper-reuse/expected.kv +1 -0
  83. package/conformance/helper-reuse/input.kv +1 -0
  84. package/conformance/helper-reuse/program.k +2 -0
  85. package/conformance/identity/case.json +8 -0
  86. package/conformance/identity/expected.kv +1 -0
  87. package/conformance/identity/input.kv +1 -0
  88. package/conformance/identity/program.k +1 -0
  89. package/conformance/product-projection/case.json +8 -0
  90. package/conformance/product-projection/expected.kv +1 -0
  91. package/conformance/product-projection/input.kv +1 -0
  92. package/conformance/product-projection/program.k +1 -0
  93. package/conformance/run.mjs +149 -0
  94. package/conformance/variant-construction/case.json +8 -0
  95. package/conformance/variant-construction/expected.kv +1 -0
  96. package/conformance/variant-construction/input.kv +1 -0
  97. package/conformance/variant-construction/program.k +1 -0
  98. package/harness/adapters/arm64.mjs +105 -0
  99. package/harness/adapters/kvm.mjs +144 -0
  100. package/harness/adapters/llvm.mjs +118 -0
  101. package/harness/adapters/native.mjs +77 -0
  102. package/harness/adapters/wasm.mjs +169 -0
  103. package/harness/backend.mjs +95 -0
  104. package/harness/cli.mjs +130 -0
  105. package/harness/format.mjs +95 -0
  106. package/harness/index.mjs +25 -0
  107. package/harness/persistent.mjs +121 -0
  108. package/harness/registry.mjs +44 -0
  109. package/harness/suite.mjs +257 -0
  110. package/harness/suites/poly.mjs +156 -0
  111. package/harness/trace.mjs +50 -0
  112. package/harness/util.mjs +92 -0
  113. package/intrinsics.mjs +41 -0
  114. package/kir.mjs +399 -0
  115. package/kvm.mjs +585 -81
  116. package/objects/README.md +37 -3
  117. package/objects/compile.mjs +15 -22
  118. package/objects/inspect.mjs +96 -0
  119. package/objects/validate.mjs +415 -0
  120. package/package.json +51 -19
  121. package/repl-codecs.mjs +105 -6
  122. package/repl.mjs +335 -49
  123. package/run.mjs +2 -7
  124. package/scripts/benchmark.mjs +406 -22
  125. package/scripts/build-repl-html.mjs +1784 -0
  126. package/scripts/perf-ieee.mjs +586 -0
  127. package/scripts/perf-int.mjs +531 -0
  128. package/scripts/perf-poly.mjs +945 -0
  129. package/scripts/render-benchmark.mjs +12 -8
  130. package/scripts/run-tests.mjs +6 -0
  131. package/tests/integration.sh +19 -2
  132. package/tests/test-arithmetics.mjs +54 -0
  133. package/tests/test-ieee-arithmetic.mjs +4 -0
  134. package/tests/test-kir.mjs +85 -0
  135. package/tests/test-kvm-polymorphic.mjs +278 -0
  136. package/tests/test-kvm.mjs +25 -6
  137. package/tests/test-poly.mjs +129 -0
  138. package/tests/test-repl-html.mjs +303 -0
  139. package/tests/test-repl.mjs +144 -1
  140. package/tests/test-validate-object.mjs +40 -0
  141. package/a.klib +0 -1
  142. package/a.kvm +0 -142676
  143. package/a.wasm +0 -0
  144. package/benchmark-results.html +0 -532
  145. package/benchmark-results.json +0 -480
  146. package/k-vscode/.vscode/launch.json +0 -14
  147. package/k-vscode/README.md +0 -75
  148. package/k-vscode/extension.js +0 -273
  149. package/k-vscode/language-configuration.json +0 -42
  150. package/k-vscode/package.json +0 -79
  151. package/k-vscode/snippets/k.json +0 -92
  152. package/k-vscode/syntaxes/k.tmLanguage.json +0 -599
  153. package/k-vscode/test/background-ranges.test.js +0 -50
  154. package/k-vscode/themes/k-contrast-color-theme.json +0 -104
  155. package/scripts/git-hooks/pre-commit +0 -10
@@ -0,0 +1,728 @@
1
+ #include "krt.h"
2
+ #include <stdio.h>
3
+ #include <stdlib.h>
4
+ #include <stdint.h>
5
+ #include <string.h>
6
+ #include <time.h>
7
+
8
+ #define ARENA_CAPACITY (64 * 1024 * 1024)
9
+
10
+ typedef enum {
11
+ K_VALUE_UNIT,
12
+ K_VALUE_PRODUCT,
13
+ K_VALUE_VARIANT
14
+ } k_val_kind_t;
15
+
16
+ typedef struct {
17
+ char *label;
18
+ size_t label_length;
19
+ k_value *value;
20
+ } k_val_field_t;
21
+
22
+ struct k_value {
23
+ k_val_kind_t kind;
24
+ k_rt *rt;
25
+ union {
26
+ struct {
27
+ size_t count;
28
+ size_t capacity;
29
+ k_val_field_t *fields;
30
+ } product;
31
+ struct {
32
+ char *tag;
33
+ size_t tag_length;
34
+ k_value *payload;
35
+ } variant;
36
+ } as;
37
+ };
38
+
39
+ typedef struct {
40
+ const char *name;
41
+ size_t length;
42
+ uint32_t id;
43
+ } k_arm64_tag_t;
44
+
45
+ typedef struct {
46
+ int32_t status;
47
+ void *val;
48
+ } k_arm64_res_t;
49
+
50
+ // Defined in generated metadata:
51
+ extern const k_arm64_tag_t k_arm64_tags[];
52
+ extern const size_t k_arm64_tag_count;
53
+ extern k_pattern compiled_input_pattern;
54
+ extern k_pattern compiled_output_pattern;
55
+
56
+ typedef struct {
57
+ const char *name;
58
+ uint64_t *counter;
59
+ } k_profile_entry_t;
60
+
61
+ extern const k_profile_entry_t k_profile_entries[];
62
+ extern const size_t k_profile_entry_count;
63
+
64
+ static void dump_profile_counts(void) {
65
+ if (k_profile_entry_count == 0) return;
66
+ fprintf(stderr, "K_PROFILE_BEGIN\n");
67
+ for (size_t i = 0; i < k_profile_entry_count; i++) {
68
+ if (k_profile_entries[i].counter && *k_profile_entries[i].counter > 0) {
69
+ fprintf(stderr, "K_FUNC_CALL name=%s count=%llu\n",
70
+ k_profile_entries[i].name,
71
+ (unsigned long long)(*k_profile_entries[i].counter));
72
+ *k_profile_entries[i].counter = 0;
73
+ }
74
+ }
75
+ fprintf(stderr, "K_PROFILE_END\n");
76
+ fflush(stderr);
77
+ }
78
+
79
+ #ifndef ENTRY_NAME
80
+ #define ENTRY_NAME rel___main__
81
+ #endif
82
+
83
+ extern k_arm64_res_t ENTRY_NAME(void *input);
84
+
85
+ #define MAX_DYNAMIC_TAGS 4096
86
+ static k_arm64_tag_t dynamic_tags[MAX_DYNAMIC_TAGS];
87
+ static size_t dynamic_tag_count = 0;
88
+ static uint32_t next_dynamic_id = 0;
89
+
90
+ static void init_tag_registry(void) {
91
+ uint32_t max_id = 0;
92
+ for (size_t i = 0; i < k_arm64_tag_count; i++) {
93
+ if (k_arm64_tags[i].id > max_id) max_id = k_arm64_tags[i].id;
94
+ }
95
+ next_dynamic_id = max_id + 1;
96
+ }
97
+
98
+ static uint32_t lookup_tag_id(const char *name, size_t len) {
99
+ for (size_t i = 0; i < k_arm64_tag_count; i++) {
100
+ if (k_arm64_tags[i].length == len && memcmp(k_arm64_tags[i].name, name, len) == 0) {
101
+ return k_arm64_tags[i].id;
102
+ }
103
+ }
104
+ for (size_t i = 0; i < dynamic_tag_count; i++) {
105
+ if (dynamic_tags[i].length == len && memcmp(dynamic_tags[i].name, name, len) == 0) {
106
+ return dynamic_tags[i].id;
107
+ }
108
+ }
109
+ if (dynamic_tag_count < MAX_DYNAMIC_TAGS) {
110
+ char *copy = malloc(len + 1);
111
+ if (!copy) return 0;
112
+ memcpy(copy, name, len);
113
+ copy[len] = '\0';
114
+ uint32_t id = next_dynamic_id++;
115
+ dynamic_tags[dynamic_tag_count].name = copy;
116
+ dynamic_tags[dynamic_tag_count].length = len;
117
+ dynamic_tags[dynamic_tag_count].id = id;
118
+ dynamic_tag_count++;
119
+ return id;
120
+ }
121
+ return 0;
122
+ }
123
+
124
+ static const char *lookup_tag_name(uint32_t id, size_t *out_len) {
125
+ for (size_t i = 0; i < k_arm64_tag_count; i++) {
126
+ if (k_arm64_tags[i].id == id) {
127
+ if (out_len) *out_len = k_arm64_tags[i].length;
128
+ return k_arm64_tags[i].name;
129
+ }
130
+ }
131
+ for (size_t i = 0; i < dynamic_tag_count; i++) {
132
+ if (dynamic_tags[i].id == id) {
133
+ if (out_len) *out_len = dynamic_tags[i].length;
134
+ return dynamic_tags[i].name;
135
+ }
136
+ }
137
+ if (out_len) *out_len = 0;
138
+ return "";
139
+ }
140
+
141
+ typedef struct {
142
+ void *flat_ptr;
143
+ k_value *val;
144
+ } k_flat_map_entry;
145
+
146
+ #define MAX_FLAT_MAP 65536
147
+ #define FLAT_MAP_MASK (MAX_FLAT_MAP - 1)
148
+ static k_flat_map_entry flat_map[MAX_FLAT_MAP];
149
+
150
+ static void flat_map_reset(void) {
151
+ memset(flat_map, 0, sizeof(flat_map));
152
+ }
153
+
154
+ static void flat_map_put(void *flat_ptr, k_value *val) {
155
+ if (flat_ptr == NULL) return;
156
+ size_t idx = (((uintptr_t)flat_ptr) >> 4) & FLAT_MAP_MASK;
157
+ for (size_t probe = 0; probe < MAX_FLAT_MAP; probe++) {
158
+ if (flat_map[idx].flat_ptr == NULL || flat_map[idx].flat_ptr == flat_ptr) {
159
+ flat_map[idx].flat_ptr = flat_ptr;
160
+ flat_map[idx].val = val;
161
+ return;
162
+ }
163
+ idx = (idx + 1) & FLAT_MAP_MASK;
164
+ }
165
+ }
166
+
167
+ static k_value *flat_map_get(void *flat_ptr) {
168
+ if (flat_ptr == NULL) return NULL;
169
+ size_t idx = (((uintptr_t)flat_ptr) >> 4) & FLAT_MAP_MASK;
170
+ for (size_t probe = 0; probe < MAX_FLAT_MAP; probe++) {
171
+ if (flat_map[idx].flat_ptr == NULL) {
172
+ return NULL;
173
+ }
174
+ if (flat_map[idx].flat_ptr == flat_ptr) {
175
+ return flat_map[idx].val;
176
+ }
177
+ idx = (idx + 1) & FLAT_MAP_MASK;
178
+ }
179
+ return NULL;
180
+ }
181
+
182
+ static void *alloc_arena(void **bump, size_t size) {
183
+ size_t aligned = (size + 15) & ~15;
184
+ void *ptr = *bump;
185
+ *bump = (char *)*bump + aligned;
186
+ return ptr;
187
+ }
188
+
189
+ static void *k_value_to_flat(k_value *val, void **arena_bump, size_t pattern_node_id, const k_pattern *in_pattern) {
190
+ if (val == NULL) return NULL;
191
+
192
+ if (val->kind == K_VALUE_UNIT) {
193
+ void *flat_prod = alloc_arena(arena_bump, 16);
194
+ *(uint16_t *)((char *)flat_prod + 0) = 16;
195
+ *(uint16_t *)((char *)flat_prod + 2) = 1; // Kind = 1 (Product)
196
+ *(uint32_t *)((char *)flat_prod + 4) = 0; // Count = 0
197
+ *(uint64_t *)((char *)flat_prod + 8) = 0;
198
+ flat_map_put(flat_prod, val);
199
+ return flat_prod;
200
+ }
201
+
202
+ if (val->kind == K_VALUE_PRODUCT) {
203
+ const k_pattern_node *pnode = (in_pattern && pattern_node_id < in_pattern->node_count)
204
+ ? &in_pattern->nodes[pattern_node_id]
205
+ : NULL;
206
+
207
+ if (pnode && (pnode->kind == KP_OPEN_PRODUCT || pnode->kind == KP_CLOSED_PRODUCT) && pnode->edge_count > 0) {
208
+ size_t count = pnode->edge_count;
209
+ size_t total_size = (8 + 8 * count + 15) & ~15;
210
+ void *flat_prod = alloc_arena(arena_bump, total_size);
211
+ *(uint16_t *)((char *)flat_prod + 0) = (uint16_t)total_size;
212
+ *(uint16_t *)((char *)flat_prod + 2) = 1; // Kind = 1 (Product)
213
+ *(uint32_t *)((char *)flat_prod + 4) = (uint32_t)count;
214
+
215
+ for (size_t i = 0; i < count; i++) {
216
+ k_value *child_val = k_product_get_n(val, pnode->edges[i].label, pnode->edges[i].label_length);
217
+ void *child = k_value_to_flat(child_val, arena_bump, pnode->edges[i].target, in_pattern);
218
+ *(uint64_t *)((char *)flat_prod + 8 + 8 * i) = (uint64_t)child;
219
+ }
220
+ flat_map_put(flat_prod, val);
221
+ return flat_prod;
222
+ }
223
+
224
+ size_t count = val->as.product.count;
225
+ size_t total_size = (8 + 8 * count + 15) & ~15;
226
+ void *flat_prod = alloc_arena(arena_bump, total_size);
227
+ *(uint16_t *)((char *)flat_prod + 0) = (uint16_t)total_size;
228
+ *(uint16_t *)((char *)flat_prod + 2) = 1; // Kind = 1 (Product)
229
+ *(uint32_t *)((char *)flat_prod + 4) = (uint32_t)count;
230
+
231
+ for (size_t i = 0; i < count; i++) {
232
+ void *child = k_value_to_flat(val->as.product.fields[i].value, arena_bump, 0, NULL);
233
+ *(uint64_t *)((char *)flat_prod + 8 + 8 * i) = (uint64_t)child;
234
+ }
235
+ flat_map_put(flat_prod, val);
236
+ return flat_prod;
237
+ }
238
+
239
+ if (val->kind == K_VALUE_VARIANT) {
240
+ uint32_t tag_id = lookup_tag_id(val->as.variant.tag, val->as.variant.tag_length);
241
+
242
+ const k_pattern_node *pnode = (in_pattern && pattern_node_id < in_pattern->node_count)
243
+ ? &in_pattern->nodes[pattern_node_id]
244
+ : NULL;
245
+
246
+ size_t target_node = 0;
247
+ const k_pattern *next_pat = NULL;
248
+ if (pnode && (pnode->kind == KP_OPEN_UNION || pnode->kind == KP_CLOSED_UNION)) {
249
+ for (size_t j = 0; j < pnode->edge_count; j++) {
250
+ if (pnode->edges[j].label_length == val->as.variant.tag_length &&
251
+ memcmp(pnode->edges[j].label, val->as.variant.tag, val->as.variant.tag_length) == 0) {
252
+ target_node = pnode->edges[j].target;
253
+ next_pat = in_pattern;
254
+ break;
255
+ }
256
+ }
257
+ }
258
+
259
+ void *payload = k_value_to_flat(val->as.variant.payload, arena_bump, target_node, next_pat);
260
+
261
+ void *flat_var = alloc_arena(arena_bump, 16);
262
+ *(uint16_t *)((char *)flat_var + 0) = 16;
263
+ *(uint16_t *)((char *)flat_var + 2) = 2; // Kind = 2 (Variant)
264
+ *(uint32_t *)((char *)flat_var + 4) = tag_id;
265
+ *(uint64_t *)((char *)flat_var + 8) = (uint64_t)payload;
266
+ flat_map_put(flat_var, val);
267
+ return flat_var;
268
+ }
269
+
270
+ return NULL;
271
+ }
272
+
273
+ static k_value *flat_to_k_value(k_rt *rt, void *flat_ptr, size_t pattern_node_id, const k_pattern *out_pattern) {
274
+ if (flat_ptr == NULL) return NULL;
275
+
276
+ k_value *mapped = flat_map_get(flat_ptr);
277
+ if (mapped != NULL) return mapped;
278
+
279
+ uint16_t kind = *(uint16_t *)((char *)flat_ptr + 2);
280
+
281
+ if (kind == 1) {
282
+ // Product
283
+ uint32_t count = *(uint32_t *)((char *)flat_ptr + 4);
284
+ k_value *prod = k_product(rt, count);
285
+
286
+ const k_pattern_node *pnode = (out_pattern && pattern_node_id < out_pattern->node_count)
287
+ ? &out_pattern->nodes[pattern_node_id]
288
+ : NULL;
289
+
290
+ for (size_t i = 0; i < count; i++) {
291
+ const char *label = "";
292
+ size_t label_len = 0;
293
+ size_t target_node = 0;
294
+
295
+ if (pnode && i < pnode->edge_count) {
296
+ label = pnode->edges[i].label;
297
+ label_len = pnode->edges[i].label_length;
298
+ target_node = pnode->edges[i].target;
299
+ } else {
300
+ char buf[32];
301
+ snprintf(buf, sizeof(buf), "%zu", i);
302
+ label = buf;
303
+ label_len = strlen(buf);
304
+ }
305
+
306
+ void *child_flat = (void *)(*(uint64_t *)((char *)flat_ptr + 8 + 8 * i));
307
+ k_value *child_val = flat_to_k_value(rt, child_flat, target_node, out_pattern);
308
+ k_product_set_n(prod, label, label_len, child_val);
309
+ }
310
+ return prod;
311
+ }
312
+
313
+ if (kind == 2) {
314
+ // Variant
315
+ uint32_t tag_id = *(uint32_t *)((char *)flat_ptr + 4);
316
+ size_t tag_len = 0;
317
+ const char *tag_name = lookup_tag_name(tag_id, &tag_len);
318
+
319
+ const k_pattern_node *pnode = (out_pattern && pattern_node_id < out_pattern->node_count)
320
+ ? &out_pattern->nodes[pattern_node_id]
321
+ : NULL;
322
+
323
+ size_t target_node = 0;
324
+ if (pnode) {
325
+ for (size_t j = 0; j < pnode->edge_count; j++) {
326
+ if (pnode->edges[j].label_length == tag_len &&
327
+ memcmp(pnode->edges[j].label, tag_name, tag_len) == 0) {
328
+ target_node = pnode->edges[j].target;
329
+ break;
330
+ }
331
+ }
332
+ }
333
+
334
+ void *payload_flat = (void *)(*(uint64_t *)((char *)flat_ptr + 8));
335
+ k_value *payload_val = flat_to_k_value(rt, payload_flat, target_node, out_pattern);
336
+ return k_variant_n(rt, tag_name, tag_len, payload_val);
337
+ }
338
+
339
+ return NULL;
340
+ }
341
+
342
+ #define STR(s) #s
343
+ #define XSTR(s) STR(s)
344
+
345
+ static inline k_arm64_res_t invoke_entry(void *flat_in, void **arena_ptr) {
346
+ register void *arg0 __asm__("x0") = flat_in;
347
+ register void *r_arena __asm__("x19") = *arena_ptr;
348
+ register uint64_t ret_status __asm__("x0");
349
+ register void *ret_val __asm__("x1");
350
+
351
+ __asm__ __volatile__(
352
+ "bl " XSTR(ENTRY_NAME) "\n\t"
353
+ : "=r"(ret_status), "=r"(ret_val), "+r"(r_arena)
354
+ : "r"(arg0)
355
+ : "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12",
356
+ "x13", "x14", "x15", "x16", "x17", "x20", "x21", "x22", "x23", "x24",
357
+ "x25", "x26", "x27", "x28", "x30", "memory"
358
+ );
359
+
360
+ *arena_ptr = r_arena;
361
+ k_arm64_res_t res;
362
+ res.status = (int32_t)ret_status;
363
+ res.val = ret_val;
364
+ return res;
365
+ }
366
+
367
+ static int pattern_has_any(const k_pattern *pattern) {
368
+ if (!pattern || pattern->node_count == 0) return 1;
369
+ for (size_t i = 0; i < pattern->node_count; i++) {
370
+ if (pattern->nodes[i].kind == KP_ANY) return 1;
371
+ }
372
+ return 0;
373
+ }
374
+
375
+ static int read_exact(FILE *fp, unsigned char *buf, size_t count) {
376
+ size_t offset = 0;
377
+ while (offset < count) {
378
+ size_t n = fread(buf + offset, 1, count - offset, fp);
379
+ if (n == 0) {
380
+ if (feof(fp) && offset == 0) return 0;
381
+ return -1;
382
+ }
383
+ offset += n;
384
+ }
385
+ return 1;
386
+ }
387
+
388
+ static uint64_t monotonic_ns(void) {
389
+ struct timespec ts;
390
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) return 0;
391
+ return ((uint64_t)ts.tv_sec * 1000000000ull) + (uint64_t)ts.tv_nsec;
392
+ }
393
+
394
+ static int is_trace_enabled(void) {
395
+ static int cached = -1;
396
+ if (cached < 0) {
397
+ const char *e1 = getenv("K_TRACE");
398
+ const char *e2 = getenv("TRACE");
399
+ cached = ((e1 && *e1 && strcmp(e1, "0") != 0) || (e2 && *e2 && strcmp(e2, "0") != 0)) ? 1 : 0;
400
+ }
401
+ return cached;
402
+ }
403
+
404
+ static int write_frame(k_wire_prefix *prefix, const k_pattern *pattern, k_value *value) {
405
+ if (!value) return 0;
406
+ size_t length = 0;
407
+ unsigned char *payload = k_encode_wire_as_with_prefix(prefix, (k_pattern *)pattern, value, &length);
408
+ if (!payload || length > UINT32_MAX) {
409
+ free(payload);
410
+ return 0;
411
+ }
412
+ unsigned char header[4] = {
413
+ (unsigned char)((length >> 24) & 0xff),
414
+ (unsigned char)((length >> 16) & 0xff),
415
+ (unsigned char)((length >> 8) & 0xff),
416
+ (unsigned char)(length & 0xff)
417
+ };
418
+ int ok = (fwrite(header, 1, 4, stdout) == 4 && fwrite(payload, 1, length, stdout) == length && fflush(stdout) == 0);
419
+ free(payload);
420
+ return ok;
421
+ }
422
+
423
+ static int run_server(void *arena_mem) {
424
+ k_rt *rt = k_rt_new();
425
+ if (!rt) return 1;
426
+ k_wire_prefix input_prefix = k_wire_prefix_for_pattern(&compiled_input_pattern);
427
+ k_wire_prefix output_prefix = k_wire_prefix_for_pattern(&compiled_output_pattern);
428
+ if (!input_prefix.ok || !output_prefix.ok) {
429
+ k_wire_prefix_free(input_prefix);
430
+ k_wire_prefix_free(output_prefix);
431
+ k_rt_free(rt);
432
+ return 8;
433
+ }
434
+ for (;;) {
435
+ uint64_t t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0;
436
+ int tracing = is_trace_enabled();
437
+ if (tracing) t0 = monotonic_ns();
438
+
439
+ unsigned char header[4];
440
+ int header_status = read_exact(stdin, header, 4);
441
+ if (header_status == 0) {
442
+ k_wire_prefix_free(input_prefix);
443
+ k_wire_prefix_free(output_prefix);
444
+ k_rt_free(rt);
445
+ return 0;
446
+ }
447
+ if (header_status < 0) {
448
+ k_wire_prefix_free(input_prefix);
449
+ k_wire_prefix_free(output_prefix);
450
+ k_rt_free(rt);
451
+ return 6;
452
+ }
453
+ uint32_t length = ((uint32_t)header[0] << 24) | ((uint32_t)header[1] << 16) | ((uint32_t)header[2] << 8) | (uint32_t)header[3];
454
+ unsigned char *payload = malloc(length == 0 ? 1 : length);
455
+ if (!payload) {
456
+ k_wire_prefix_free(input_prefix);
457
+ k_wire_prefix_free(output_prefix);
458
+ k_rt_free(rt);
459
+ return 7;
460
+ }
461
+ int payload_status = read_exact(stdin, payload, length);
462
+ if (payload_status != 1) {
463
+ free(payload);
464
+ k_wire_prefix_free(input_prefix);
465
+ k_wire_prefix_free(output_prefix);
466
+ k_rt_free(rt);
467
+ return 6;
468
+ }
469
+ if (tracing) t1 = monotonic_ns();
470
+
471
+ flat_map_reset();
472
+ void *arena_bump = arena_mem;
473
+ k_value *in_val = k_decode_wire_value_with_prefix(payload, length, &input_prefix, &compiled_input_pattern, rt);
474
+ if (!in_val) {
475
+ k_wire_input envelope = k_decode_wire_envelope(payload, length, rt);
476
+ if (envelope.value) {
477
+ in_val = envelope.value;
478
+ }
479
+ }
480
+ free(payload);
481
+ if (!in_val) {
482
+ k_rt_reset(rt);
483
+ k_wire_prefix_free(input_prefix);
484
+ k_wire_prefix_free(output_prefix);
485
+ k_rt_free(rt);
486
+ return 2;
487
+ }
488
+ if (tracing) t2 = monotonic_ns();
489
+
490
+ void *flat_in = k_value_to_flat(in_val, &arena_bump, 0, &compiled_input_pattern);
491
+ if (tracing) t3 = monotonic_ns();
492
+
493
+ k_arm64_res_t res = invoke_entry(flat_in, &arena_bump);
494
+ if (tracing) t4 = monotonic_ns();
495
+ if (res.status != 0) {
496
+ k_rt_reset(rt);
497
+ k_wire_prefix_free(input_prefix);
498
+ k_wire_prefix_free(output_prefix);
499
+ k_rt_free(rt);
500
+ return 3;
501
+ }
502
+
503
+ k_value *out_val = flat_to_k_value(rt, res.val, 0, &compiled_output_pattern);
504
+ if (tracing) t5 = monotonic_ns();
505
+
506
+ size_t out_len = 0;
507
+ unsigned char *out_payload = k_encode_wire_as_with_prefix(&output_prefix, (k_pattern *)&compiled_output_pattern, out_val, &out_len);
508
+ if (tracing) t6 = monotonic_ns();
509
+
510
+ int ok = 0;
511
+ uint64_t write_start = t6;
512
+ if (out_payload && out_len <= UINT32_MAX) {
513
+ unsigned char out_header[4] = {
514
+ (unsigned char)((out_len >> 24) & 0xff),
515
+ (unsigned char)((out_len >> 16) & 0xff),
516
+ (unsigned char)((out_len >> 8) & 0xff),
517
+ (unsigned char)(out_len & 0xff)
518
+ };
519
+ ok = (fwrite(out_header, 1, 4, stdout) == 4 && fwrite(out_payload, 1, out_len, stdout) == out_len && fflush(stdout) == 0);
520
+ }
521
+ free(out_payload);
522
+ if (tracing) {
523
+ t7 = monotonic_ns();
524
+ dump_profile_counts();
525
+ fprintf(stderr, "K_TRACE_PHASES backend=arm64 ipc_read_ns=%llu decode_ns=%llu flat_in_ns=%llu eval_ns=%llu flat_out_ns=%llu encode_ns=%llu ipc_write_ns=%llu total_ns=%llu\n",
526
+ (unsigned long long)(t1 >= t0 ? t1 - t0 : 0),
527
+ (unsigned long long)(t2 >= t1 ? t2 - t1 : 0),
528
+ (unsigned long long)(t3 >= t2 ? t3 - t2 : 0),
529
+ (unsigned long long)(t4 >= t3 ? t4 - t3 : 0),
530
+ (unsigned long long)(t5 >= t4 ? t5 - t4 : 0),
531
+ (unsigned long long)(t6 >= t5 ? t6 - t5 : 0),
532
+ (unsigned long long)(t7 >= write_start ? t7 - write_start : 0),
533
+ (unsigned long long)(t7 >= t0 ? t7 - t0 : 0));
534
+ fflush(stderr);
535
+ } else {
536
+ dump_profile_counts();
537
+ }
538
+ k_rt_reset(rt);
539
+ if (!ok) {
540
+ k_wire_prefix_free(input_prefix);
541
+ k_wire_prefix_free(output_prefix);
542
+ k_rt_free(rt);
543
+ return 4;
544
+ }
545
+ }
546
+ }
547
+
548
+ static int parse_size_arg(const char *text, size_t *out) {
549
+ if (text == NULL || *text == 0) return 0;
550
+ size_t value = 0;
551
+ for (const char *p = text; *p != 0; p++) {
552
+ if (*p < '0' || *p > '9') return 0;
553
+ size_t digit = (size_t)(*p - '0');
554
+ if (value > (((size_t)-1) - digit) / 10) return 0;
555
+ value = value * 10 + digit;
556
+ }
557
+ if (value == 0) return 0;
558
+ *out = value;
559
+ return 1;
560
+ }
561
+
562
+ static int run_bench_main(void *arena_mem, const char *count_text) {
563
+ size_t count = 0;
564
+ if (!parse_size_arg(count_text, &count)) return 9;
565
+ k_rt *rt = k_rt_new();
566
+ if (!rt) return 1;
567
+ k_wire_input input = k_read_wire_envelope(stdin, rt);
568
+ if (!input.value || !input.pattern) {
569
+ k_wire_input_free(input);
570
+ k_rt_free(rt);
571
+ return 2;
572
+ }
573
+ if (!k_pattern_equal(input.pattern, &compiled_input_pattern)) {
574
+ k_wire_input_free(input);
575
+ k_rt_free(rt);
576
+ return 5;
577
+ }
578
+ void *arena_bump = arena_mem;
579
+ void *flat_in = k_value_to_flat(input.value, &arena_bump, 0, &compiled_input_pattern);
580
+ void *arena_mark = arena_bump;
581
+
582
+ uint64_t started_at = monotonic_ns();
583
+ for (size_t i = 0; i < count; i++) {
584
+ arena_bump = arena_mark;
585
+ k_arm64_res_t result = invoke_entry(flat_in, &arena_bump);
586
+ if (result.status != 0) {
587
+ k_wire_input_free(input);
588
+ k_rt_free(rt);
589
+ return 3;
590
+ }
591
+ }
592
+ uint64_t ended_at = monotonic_ns();
593
+ uint64_t elapsed = ended_at >= started_at ? ended_at - started_at : 0;
594
+ fprintf(stderr, "K_ARM64_BENCH_MAIN calls=%zu total_ns=%llu per_call_ns=%.2f\n",
595
+ count, (unsigned long long)elapsed, count == 0 ? 0.0 : (double)elapsed / (double)count);
596
+ k_wire_input_free(input);
597
+ k_rt_free(rt);
598
+ return 0;
599
+ }
600
+
601
+ int main(int argc, char **argv) {
602
+ init_tag_registry();
603
+
604
+ if (argc == 2 && strcmp(argv[1], "--server") == 0) {
605
+ void *arena_mem = malloc(ARENA_CAPACITY);
606
+ if (!arena_mem) return 1;
607
+ int rc = run_server(arena_mem);
608
+ free(arena_mem);
609
+ return rc;
610
+ }
611
+
612
+ if (argc == 3 && strcmp(argv[1], "--bench-main") == 0) {
613
+ void *arena_mem = malloc(ARENA_CAPACITY);
614
+ if (!arena_mem) return 1;
615
+ int rc = run_bench_main(arena_mem, argv[2]);
616
+ free(arena_mem);
617
+ return rc;
618
+ }
619
+
620
+ int json_mode = 0;
621
+ const char *input_file = NULL;
622
+
623
+ for (int i = 1; i < argc; i++) {
624
+ if (strcmp(argv[i], "--json") == 0) {
625
+ json_mode = 1;
626
+ } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
627
+ fprintf(stderr, "Usage: %s [--json] [input-file]\n", argv[0]);
628
+ fprintf(stderr, "Execute compiled k relation on ARM64 Linux.\n\n");
629
+ fprintf(stderr, "Options:\n");
630
+ fprintf(stderr, " --json Output result as JSON instead of binary wire format\n");
631
+ fprintf(stderr, " -h, --help Show this help\n");
632
+ return 0;
633
+ } else if (argv[i][0] != '-') {
634
+ input_file = argv[i];
635
+ } else {
636
+ fprintf(stderr, "Unknown option: %s\n", argv[i]);
637
+ return 1;
638
+ }
639
+ }
640
+
641
+ FILE *in_fp = stdin;
642
+ if (input_file) {
643
+ in_fp = fopen(input_file, "rb");
644
+ if (!in_fp) {
645
+ perror("Failed to open input file");
646
+ return 1;
647
+ }
648
+ }
649
+
650
+ void *arena_mem = malloc(ARENA_CAPACITY);
651
+ if (!arena_mem) {
652
+ if (in_fp != stdin) fclose(in_fp);
653
+ return 1;
654
+ }
655
+ void *arena_bump = arena_mem;
656
+
657
+ k_rt *rt = k_rt_new();
658
+ if (!rt) {
659
+ if (in_fp != stdin) fclose(in_fp);
660
+ free(arena_mem);
661
+ return 1;
662
+ }
663
+
664
+ uint64_t t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0;
665
+ int tracing = is_trace_enabled();
666
+ if (tracing) t0 = monotonic_ns();
667
+
668
+ k_wire_input input = k_read_wire_envelope(in_fp, rt);
669
+ if (in_fp != stdin) fclose(in_fp);
670
+ if (!input.value) {
671
+ k_rt_free(rt);
672
+ free(arena_mem);
673
+ return 2;
674
+ }
675
+ if (tracing) t1 = monotonic_ns();
676
+
677
+ void *flat_in = k_value_to_flat(input.value, &arena_bump, 0, &compiled_input_pattern);
678
+ if (tracing) t2 = monotonic_ns();
679
+
680
+ k_arm64_res_t res = invoke_entry(flat_in, &arena_bump);
681
+ if (tracing) t3 = monotonic_ns();
682
+ if (res.status != 0) {
683
+ // Partial failure
684
+ k_wire_input_free(input);
685
+ k_rt_free(rt);
686
+ free(arena_mem);
687
+ return 1;
688
+ }
689
+
690
+ k_value *out_val = flat_to_k_value(rt, res.val, 0, &compiled_output_pattern);
691
+ if (tracing) t4 = monotonic_ns();
692
+ if (!out_val) {
693
+ k_wire_input_free(input);
694
+ k_rt_free(rt);
695
+ free(arena_mem);
696
+ return 3;
697
+ }
698
+
699
+ if (json_mode) {
700
+ k_print_json(stdout, out_val);
701
+ printf("\n");
702
+ } else if (!pattern_has_any(&compiled_output_pattern)) {
703
+ k_write_wire_as(stdout, &compiled_output_pattern, out_val);
704
+ } else {
705
+ k_write_wire(stdout, out_val);
706
+ }
707
+ fflush(stdout);
708
+
709
+ if (tracing) {
710
+ t5 = monotonic_ns();
711
+ dump_profile_counts();
712
+ fprintf(stderr, "K_TRACE_PHASES backend=arm64 ipc_read_ns=%llu decode_ns=0 flat_in_ns=%llu eval_ns=%llu flat_out_ns=%llu encode_ns=%llu ipc_write_ns=0 total_ns=%llu\n",
713
+ (unsigned long long)(t1 >= t0 ? t1 - t0 : 0),
714
+ (unsigned long long)(t2 >= t1 ? t2 - t1 : 0),
715
+ (unsigned long long)(t3 >= t2 ? t3 - t2 : 0),
716
+ (unsigned long long)(t4 >= t3 ? t4 - t3 : 0),
717
+ (unsigned long long)(t5 >= t4 ? t5 - t4 : 0),
718
+ (unsigned long long)(t5 >= t0 ? t5 - t0 : 0));
719
+ fflush(stderr);
720
+ } else {
721
+ dump_profile_counts();
722
+ }
723
+
724
+ k_wire_input_free(input);
725
+ k_rt_free(rt);
726
+ free(arena_mem);
727
+ return 0;
728
+ }