@amritk/nish-x86_64-linux 0.18.0 → 0.21.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.
- package/INSTALL.md +58 -28
- package/bin/nish +0 -0
- package/docs/AI.md +2759 -0
- package/package.json +3 -2
- package/runtime/browser.d.ts +14 -0
- package/runtime/browser.mjs +88 -0
- package/runtime/core/arrays.d.ts +18 -0
- package/runtime/core/arrays.mjs +125 -0
- package/runtime/core/checks.mjs +20 -0
- package/runtime/core/host.d.ts +70 -0
- package/runtime/core/host.mjs +311 -0
- package/runtime/core/numbers.d.ts +53 -0
- package/runtime/core/numbers.mjs +316 -0
- package/runtime/core/result.d.ts +41 -0
- package/runtime/core/result.mjs +127 -0
- package/runtime/core/strings.d.ts +14 -0
- package/runtime/core/strings.mjs +169 -0
- package/runtime/core.d.ts +9 -0
- package/runtime/core.mjs +55 -0
- package/runtime/host.d.ts +6 -0
- package/runtime/nish.d.ts +99 -5
- package/runtime/nish.h +289 -19
- package/runtime/nish.mjs +39 -3
- package/runtime/node.mjs +383 -0
- package/runtime/runtime-aes.c +490 -0
- package/runtime/runtime-bytes.c +401 -0
- package/runtime/runtime-cross.c +366 -0
- package/runtime/runtime-host.c +8 -7
- package/runtime/runtime-net.c +93 -34
- package/runtime/runtime-os.c +214 -16
- package/runtime/runtime-parallel.c +590 -107
- package/runtime/runtime-simd.c +235 -11
- package/runtime/runtime-term.c +504 -0
- package/runtime/runtime-wasm.c +5 -14
- package/runtime/runtime.c +257 -17
- package/runtime/shim.mjs +6 -915
- package/runtime/sqlite/LICENSE.md +85 -0
- package/runtime/sqlite/README.md +45 -0
- package/runtime/sqlite/nish-sqlite.c +359 -0
- package/runtime/sqlite/sqlite3.c +271131 -0
- package/runtime/sqlite/sqlite3.h +14447 -0
- package/scripts/build.sh +437 -28
- package/std/LICENSE-fast-float +23 -0
- package/std/LICENSE-fdlibm +8 -0
- package/std/README.md +108 -58
- package/std/base64.ts +116 -0
- package/std/bytes.ts +419 -0
- package/std/cli.ts +328 -0
- package/std/collections.ts +6 -5
- package/std/crypto/LICENSE-crypt_blowfish +26 -0
- package/std/crypto/LICENSE-libsecp256k1 +19 -0
- package/std/crypto/aes.ts +238 -76
- package/std/crypto/base64url.ts +125 -0
- package/std/crypto/bcrypt.ts +760 -0
- package/std/crypto/chacha20poly1305.ts +43 -9
- package/std/crypto/ed25519.ts +840 -0
- package/std/crypto/hkdf.ts +304 -12
- package/std/crypto/hmac.ts +382 -54
- package/std/crypto/p256.ts +932 -61
- package/std/crypto/x25519.ts +55 -37
- package/std/crypto/x509-random.ts +71 -0
- package/std/crypto/x509.ts +20 -131
- package/std/json-tokenizer.ts +4237 -0
- package/std/json-typed.ts +1014 -0
- package/std/json-value.ts +1182 -0
- package/std/json.ts +1202 -34
- package/std/math.ts +608 -0
- package/std/net/buffer-pool.ts +151 -0
- package/std/net/hpack.ts +416 -112
- package/std/net/http-fields.ts +93 -0
- package/std/net/http1-server.ts +501 -62
- package/std/net/http1.ts +31 -6
- package/std/net/http2-tls.ts +112 -24
- package/std/net/http2.ts +333 -75
- package/std/net/http3-server.ts +261 -43
- package/std/net/http3.ts +187 -28
- package/std/net/postgres.ts +1875 -0
- package/std/net/prefork.ts +412 -0
- package/std/net/quic-listener.ts +108 -11
- package/std/net/quic-packet.ts +243 -82
- package/std/net/quic-recovery.ts +361 -30
- package/std/net/quic-stream.ts +424 -24
- package/std/net/quic.ts +519 -167
- package/std/net/router.ts +676 -0
- package/std/net/tls/codec.ts +426 -27
- package/std/net/tls/record-server.ts +478 -132
- package/std/net/tls/record.ts +133 -42
- package/std/net/tls/schedule.ts +464 -55
- package/std/net/tls/ticket.ts +610 -0
- package/std/net/tls-tcp.ts +196 -53
- package/std/net/tls.ts +1018 -260
- package/std/net/url.ts +571 -0
- package/std/random.ts +94 -0
- package/std/regex.ts +4274 -0
- package/std/sqlite.ts +391 -0
- package/std/term-io.ts +978 -0
- package/std/term-pixels.ts +874 -0
- package/std/term-probe.ts +459 -0
- package/std/term-rate.ts +993 -0
- package/std/term.ts +2453 -0
- package/std/text.ts +90 -7
- package/std/threads.ts +438 -14
- package/std/yaml-lines.ts +141 -0
- package/std/yaml.ts +4675 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/* Nish runtime, the byte-class half: the runs `nish/bytes` steps over -- JSON's
|
|
2
|
+
* blanks, the digits, the bytes a JSON string holds as themselves, and the bytes
|
|
3
|
+
* a JSON writer copies without an escape -- read
|
|
4
|
+
* sixteen or thirty-two bytes at a time (WP38 S6a, docs/wp38-simd.md §3.1).
|
|
5
|
+
*
|
|
6
|
+
* A translation unit of its own for the reason runtime-aes.c is one: each file
|
|
7
|
+
* carries its own measured `.text*` ceiling in tests/runtime-budgets.js, and
|
|
8
|
+
* these kernels would not fit in what runtime-simd.c has left
|
|
9
|
+
* (RUNTIME_BYTES_TEXT_BUDGET says how much they need). Section GC means a
|
|
10
|
+
* program that never calls a kernel links none of this file.
|
|
11
|
+
*
|
|
12
|
+
* The paths and their choice are runtime-simd.c's: a scalar path that runs
|
|
13
|
+
* anywhere, a base path on the vectors every machine of the target has, an
|
|
14
|
+
* AVX2 path compiled for that extension alone, and a choice made on the first
|
|
15
|
+
* call and pinned by `NISH_SIMD` the same way. The one difference is a
|
|
16
|
+
* freestanding wasm32 build, which has no libc to read `NISH_SIMD` with: there
|
|
17
|
+
* the kernels call the base path directly, and the base path is the scalar one
|
|
18
|
+
* unless the build adds `-msimd128`.
|
|
19
|
+
*/
|
|
20
|
+
#include <stdint.h>
|
|
21
|
+
|
|
22
|
+
#include "nish.h"
|
|
23
|
+
|
|
24
|
+
#if defined(__x86_64__) || defined(__i386__)
|
|
25
|
+
#if defined(__SSE2__)
|
|
26
|
+
#include <cpuid.h>
|
|
27
|
+
#include <immintrin.h>
|
|
28
|
+
#define NISH_SIMD_SSE2 1
|
|
29
|
+
#endif
|
|
30
|
+
#elif defined(__ARM_NEON)
|
|
31
|
+
#include <arm_neon.h>
|
|
32
|
+
#define NISH_SIMD_NEON 1
|
|
33
|
+
#elif defined(__wasm_simd128__)
|
|
34
|
+
#include <wasm_simd128.h>
|
|
35
|
+
#define NISH_SIMD_WASM 1
|
|
36
|
+
#endif
|
|
37
|
+
|
|
38
|
+
/* Whether `NISH_SIMD` can be read: everywhere but a freestanding wasm32 build. */
|
|
39
|
+
#if !defined(__wasm__) || defined(__wasi__)
|
|
40
|
+
#include <stdlib.h>
|
|
41
|
+
#include <string.h>
|
|
42
|
+
#define NISH_RUN_CHOOSES 1
|
|
43
|
+
#endif
|
|
44
|
+
|
|
45
|
+
#if defined(NISH_SIMD_SSE2)
|
|
46
|
+
/* runtime-simd.c's `nish_cpu_has_avx2`, which says why it asks `cpuid.h`
|
|
47
|
+
rather than `__builtin_cpu_supports`. A copy rather than a shared symbol, as
|
|
48
|
+
runtime-aes.c keeps its own question, so that each unit links alone. */
|
|
49
|
+
static int nish_cpu_has_avx2(void) {
|
|
50
|
+
unsigned a, b, c, d;
|
|
51
|
+
if (!__get_cpuid(1, &a, &b, &c, &d) || !(c & bit_OSXSAVE) || !(c & bit_AVX)) return 0;
|
|
52
|
+
unsigned lo, hi;
|
|
53
|
+
__asm__("xgetbv" : "=a"(lo), "=d"(hi) : "c"(0));
|
|
54
|
+
if ((lo & 6) != 6) return 0;
|
|
55
|
+
return __get_cpuid_count(7, 0, &a, &b, &c, &d) && (b & bit_AVX2);
|
|
56
|
+
}
|
|
57
|
+
#endif
|
|
58
|
+
|
|
59
|
+
/* The byte-class runs of `nish/bytes` -- `skipBlank`, `skipDigits`,
|
|
60
|
+
`skipJsonText` and `skipJsonPlain` -- which answer the first index in
|
|
61
|
+
[from, to) whose byte is outside a class, or `to`. The contracts are in
|
|
62
|
+
nish.h. The first three share one resolver and one chooser, because they
|
|
63
|
+
are one question asked of three classes: a path is one function taking the
|
|
64
|
+
class, and each exported kernel calls it with its own constant. The fourth
|
|
65
|
+
has paths and a pointer of its own, the same shape, which the one resolver
|
|
66
|
+
sets beside the first's.
|
|
67
|
+
|
|
68
|
+
The JSON text class is the bytes a string's scan steps over without a
|
|
69
|
+
second look: printable ASCII other than `"` and `\`, and every complete,
|
|
70
|
+
well-formed UTF-8 sequence that ends at or before `to` (RFC 3629 §4, the
|
|
71
|
+
ranges `jsonTokUtf8Length` in std/json-tokenizer.ts checks). A block of
|
|
72
|
+
ASCII is classified sixteen or thirty-two bytes at a time; a byte with its
|
|
73
|
+
top bit set stops the block, and the sequence it leads is checked one byte
|
|
74
|
+
at a time, as is every sequence after it until the next ASCII byte, so a
|
|
75
|
+
run of CJK text costs one block load per run rather than one per
|
|
76
|
+
character. A sequence that is malformed, or cut short by `to`, ends the
|
|
77
|
+
run at its lead, where the caller's own checks judge it.
|
|
78
|
+
|
|
79
|
+
The JSON plain class is the bytes a writer copies into a string as they
|
|
80
|
+
are: every byte from 0x20 up other than `"` and `\`. It is the text class
|
|
81
|
+
with no UTF-8 check -- a writer passes what it is given through, and the
|
|
82
|
+
reader that checks it is on the other side -- so its vector stops are the
|
|
83
|
+
text class's without the high bytes, and nothing in it resumes. It is kept
|
|
84
|
+
out of the class paths because a fourth class there costs the other three:
|
|
85
|
+
choosing its stops inside the shared block loop is a branch on the class in
|
|
86
|
+
every block of the text loop JsonTokenizer runs, and a test on entry costs
|
|
87
|
+
each path its loop unswitching at -O3 and a prologue's worth of bytes at
|
|
88
|
+
-Oz. Its base path is the 16-byte one on every machine, AVX2 or not: a
|
|
89
|
+
writer's strings are short, and a 32-byte copy would not fit the file's
|
|
90
|
+
ceiling. */
|
|
91
|
+
enum { NISH_RUN_BLANK = 0, NISH_RUN_DIGIT = 1, NISH_RUN_TEXT = 2, NISH_RUN_PLAIN = 3 };
|
|
92
|
+
|
|
93
|
+
/* One path of a run kernel: the class, then the nish.h contract. The plain
|
|
94
|
+
kernel's paths take the class too and ignore it, so one resolver serves
|
|
95
|
+
both pointers. */
|
|
96
|
+
typedef int64_t (*nish_run_path)(int cls, const uint8_t *p, int64_t from, int64_t to);
|
|
97
|
+
|
|
98
|
+
/* The length of the well-formed UTF-8 sequence whose lead is at `p[i]` and
|
|
99
|
+
that ends at or before `to`, or 0. */
|
|
100
|
+
static inline int64_t nish_run_utf8(const uint8_t *p, int64_t i, int64_t to) {
|
|
101
|
+
uint8_t lead = p[i];
|
|
102
|
+
uint8_t low = 0x80, high = 0xbf;
|
|
103
|
+
int64_t n;
|
|
104
|
+
if (lead >= 0xc2 && lead <= 0xdf) {
|
|
105
|
+
n = 2;
|
|
106
|
+
} else if (lead >= 0xe0 && lead <= 0xef) {
|
|
107
|
+
n = 3;
|
|
108
|
+
if (lead == 0xe0) low = 0xa0;
|
|
109
|
+
if (lead == 0xed) high = 0x9f;
|
|
110
|
+
} else if (lead >= 0xf0 && lead <= 0xf4) {
|
|
111
|
+
n = 4;
|
|
112
|
+
if (lead == 0xf0) low = 0x90;
|
|
113
|
+
if (lead == 0xf4) high = 0x8f;
|
|
114
|
+
} else {
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
if (to - i < n) return 0;
|
|
118
|
+
if (p[i + 1] < low || p[i + 1] > high) return 0;
|
|
119
|
+
for (int64_t k = 2; k < n; k++) {
|
|
120
|
+
if (p[i + k] < 0x80 || p[i + k] > 0xbf) return 0;
|
|
121
|
+
}
|
|
122
|
+
return n;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* Whether ASCII-range byte `b` is in the class; for the text class a byte
|
|
126
|
+
with its top bit set answers no here and is taken by `nish_run_utf8`. */
|
|
127
|
+
static inline int nish_run_in(int cls, uint8_t b) {
|
|
128
|
+
if (cls == NISH_RUN_BLANK) return b == 0x20 || b == 0x0a || b == 0x0d || b == 0x09;
|
|
129
|
+
if (cls == NISH_RUN_DIGIT) return (uint8_t)(b - 0x30) < 10;
|
|
130
|
+
return b >= 0x20 && b < 0x80 && b != 0x22 && b != 0x5c;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* Steps `i` over the run of UTF-8 sequences that starts there, stopping at
|
|
134
|
+
the first ASCII byte, the first malformed sequence or `to`. */
|
|
135
|
+
static inline int64_t nish_run_wide(const uint8_t *p, int64_t i, int64_t to) {
|
|
136
|
+
while (i < to && p[i] >= 0x80) {
|
|
137
|
+
int64_t n = nish_run_utf8(p, i, to);
|
|
138
|
+
if (n == 0) return i;
|
|
139
|
+
i += n;
|
|
140
|
+
}
|
|
141
|
+
return i;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* The plain class's scalar path, and the tail of its vector ones. */
|
|
145
|
+
static int64_t nish_plain_scalar(int cls, const uint8_t *p, int64_t i, int64_t to) {
|
|
146
|
+
(void)cls;
|
|
147
|
+
while (i < to && p[i] >= 0x20 && p[i] != 0x22 && p[i] != 0x5c) i++;
|
|
148
|
+
return i;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* The scalar path, and the tail of the vector ones. */
|
|
152
|
+
static int64_t nish_run_scalar(int cls, const uint8_t *p, int64_t from, int64_t to) {
|
|
153
|
+
int64_t i = from;
|
|
154
|
+
while (i < to) {
|
|
155
|
+
uint8_t b = p[i];
|
|
156
|
+
if (nish_run_in(cls, b)) {
|
|
157
|
+
i++;
|
|
158
|
+
} else if (cls == NISH_RUN_TEXT && b >= 0x80) {
|
|
159
|
+
int64_t j = nish_run_wide(p, i, to);
|
|
160
|
+
if (j == i) return i;
|
|
161
|
+
i = j;
|
|
162
|
+
} else {
|
|
163
|
+
return i;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return to;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
#if defined(NISH_SIMD_SSE2) || defined(NISH_SIMD_NEON) || defined(NISH_SIMD_WASM)
|
|
170
|
+
/* A vector path's step past a block's first stop at `i`: `i` again when the
|
|
171
|
+
stop ends the run, else where the run resumes. Only a text run resumes,
|
|
172
|
+
and only past UTF-8. */
|
|
173
|
+
static inline int64_t nish_run_resume(int cls, const uint8_t *p, int64_t i, int64_t to) {
|
|
174
|
+
if (cls != NISH_RUN_TEXT || p[i] < 0x80) return i;
|
|
175
|
+
return nish_run_wide(p, i, to);
|
|
176
|
+
}
|
|
177
|
+
#endif
|
|
178
|
+
|
|
179
|
+
/* Each vector path computes a mask of the block's stops -- the bytes outside
|
|
180
|
+
the class, where for text every byte with its top bit set counts as a stop
|
|
181
|
+
-- and either moves on a whole block or jumps to the first stop. */
|
|
182
|
+
#if defined(NISH_SIMD_SSE2)
|
|
183
|
+
static inline unsigned nish_run_stops_sse2(int cls, __m128i v) {
|
|
184
|
+
if (cls == NISH_RUN_BLANK) {
|
|
185
|
+
__m128i in = _mm_or_si128(_mm_or_si128(_mm_cmpeq_epi8(v, _mm_set1_epi8(0x20)), _mm_cmpeq_epi8(v, _mm_set1_epi8(0x0a))),
|
|
186
|
+
_mm_or_si128(_mm_cmpeq_epi8(v, _mm_set1_epi8(0x0d)), _mm_cmpeq_epi8(v, _mm_set1_epi8(0x09))));
|
|
187
|
+
return ~(unsigned)_mm_movemask_epi8(in) & 0xffffu;
|
|
188
|
+
}
|
|
189
|
+
if (cls == NISH_RUN_DIGIT) {
|
|
190
|
+
__m128i x = _mm_sub_epi8(v, _mm_set1_epi8(0x30));
|
|
191
|
+
__m128i in = _mm_cmpeq_epi8(_mm_min_epu8(x, _mm_set1_epi8(9)), x);
|
|
192
|
+
return ~(unsigned)_mm_movemask_epi8(in) & 0xffffu;
|
|
193
|
+
}
|
|
194
|
+
/* A control byte is one that `min(v, 0x1f)` leaves alone; a high byte is
|
|
195
|
+
its own sign bit, which movemask reads straight off `v`. */
|
|
196
|
+
__m128i stop = _mm_or_si128(_mm_or_si128(_mm_cmpeq_epi8(v, _mm_set1_epi8(0x22)), _mm_cmpeq_epi8(v, _mm_set1_epi8(0x5c))),
|
|
197
|
+
_mm_cmpeq_epi8(_mm_min_epu8(v, _mm_set1_epi8(0x1f)), v));
|
|
198
|
+
return (unsigned)_mm_movemask_epi8(_mm_or_si128(stop, v));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
static int64_t nish_plain_base(int cls, const uint8_t *p, int64_t i, int64_t to) {
|
|
202
|
+
for (; to - i >= 16; i += 16) {
|
|
203
|
+
__m128i v = _mm_loadu_si128((const __m128i *)(p + i));
|
|
204
|
+
__m128i stop = _mm_or_si128(_mm_or_si128(_mm_cmpeq_epi8(v, _mm_set1_epi8(0x22)), _mm_cmpeq_epi8(v, _mm_set1_epi8(0x5c))),
|
|
205
|
+
_mm_cmpeq_epi8(_mm_min_epu8(v, _mm_set1_epi8(0x1f)), v));
|
|
206
|
+
unsigned m = (unsigned)_mm_movemask_epi8(stop);
|
|
207
|
+
if (m != 0) return i + __builtin_ctz(m);
|
|
208
|
+
}
|
|
209
|
+
return nish_plain_scalar(cls, p, i, to);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
static int64_t nish_run_base(int cls, const uint8_t *p, int64_t from, int64_t to) {
|
|
213
|
+
int64_t i = from;
|
|
214
|
+
while (to - i >= 16) {
|
|
215
|
+
unsigned m = nish_run_stops_sse2(cls, _mm_loadu_si128((const __m128i *)(p + i)));
|
|
216
|
+
if (m == 0) {
|
|
217
|
+
i += 16;
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
int64_t at = i + __builtin_ctz(m);
|
|
221
|
+
i = nish_run_resume(cls, p, at, to);
|
|
222
|
+
if (i == at) return at;
|
|
223
|
+
}
|
|
224
|
+
return nish_run_scalar(cls, p, i, to);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
__attribute__((target("avx2"))) static inline unsigned nish_run_stops_avx2(int cls, __m256i v) {
|
|
228
|
+
if (cls == NISH_RUN_BLANK) {
|
|
229
|
+
__m256i in = _mm256_or_si256(
|
|
230
|
+
_mm256_or_si256(_mm256_cmpeq_epi8(v, _mm256_set1_epi8(0x20)), _mm256_cmpeq_epi8(v, _mm256_set1_epi8(0x0a))),
|
|
231
|
+
_mm256_or_si256(_mm256_cmpeq_epi8(v, _mm256_set1_epi8(0x0d)), _mm256_cmpeq_epi8(v, _mm256_set1_epi8(0x09))));
|
|
232
|
+
return ~(unsigned)_mm256_movemask_epi8(in);
|
|
233
|
+
}
|
|
234
|
+
if (cls == NISH_RUN_DIGIT) {
|
|
235
|
+
__m256i x = _mm256_sub_epi8(v, _mm256_set1_epi8(0x30));
|
|
236
|
+
__m256i in = _mm256_cmpeq_epi8(_mm256_min_epu8(x, _mm256_set1_epi8(9)), x);
|
|
237
|
+
return ~(unsigned)_mm256_movemask_epi8(in);
|
|
238
|
+
}
|
|
239
|
+
__m256i stop = _mm256_or_si256(
|
|
240
|
+
_mm256_or_si256(_mm256_cmpeq_epi8(v, _mm256_set1_epi8(0x22)), _mm256_cmpeq_epi8(v, _mm256_set1_epi8(0x5c))),
|
|
241
|
+
_mm256_cmpeq_epi8(_mm256_min_epu8(v, _mm256_set1_epi8(0x1f)), v));
|
|
242
|
+
return (unsigned)_mm256_movemask_epi8(_mm256_or_si256(stop, v));
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/* Thirty-two bytes a block, then the base path for what is left. */
|
|
246
|
+
__attribute__((target("avx2"))) static int64_t nish_run_avx2(int cls, const uint8_t *p, int64_t from, int64_t to) {
|
|
247
|
+
int64_t i = from;
|
|
248
|
+
while (to - i >= 32) {
|
|
249
|
+
unsigned m = nish_run_stops_avx2(cls, _mm256_loadu_si256((const __m256i *)(p + i)));
|
|
250
|
+
if (m == 0) {
|
|
251
|
+
i += 32;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
int64_t at = i + __builtin_ctz(m);
|
|
255
|
+
i = nish_run_resume(cls, p, at, to);
|
|
256
|
+
if (i == at) return at;
|
|
257
|
+
}
|
|
258
|
+
return nish_run_base(cls, p, i, to);
|
|
259
|
+
}
|
|
260
|
+
#elif defined(NISH_SIMD_NEON)
|
|
261
|
+
static inline uint64_t nish_run_stops_neon(int cls, uint8x16_t v) {
|
|
262
|
+
uint8x16_t stop;
|
|
263
|
+
if (cls == NISH_RUN_BLANK) {
|
|
264
|
+
stop = vmvnq_u8(vorrq_u8(vorrq_u8(vceqq_u8(v, vdupq_n_u8(0x20)), vceqq_u8(v, vdupq_n_u8(0x0a))),
|
|
265
|
+
vorrq_u8(vceqq_u8(v, vdupq_n_u8(0x0d)), vceqq_u8(v, vdupq_n_u8(0x09)))));
|
|
266
|
+
} else if (cls == NISH_RUN_DIGIT) {
|
|
267
|
+
stop = vcgtq_u8(vsubq_u8(v, vdupq_n_u8(0x30)), vdupq_n_u8(9));
|
|
268
|
+
} else {
|
|
269
|
+
stop = vorrq_u8(vorrq_u8(vceqq_u8(v, vdupq_n_u8(0x22)), vceqq_u8(v, vdupq_n_u8(0x5c))),
|
|
270
|
+
vorrq_u8(vcleq_u8(v, vdupq_n_u8(0x1f)), vcgeq_u8(v, vdupq_n_u8(0x80))));
|
|
271
|
+
}
|
|
272
|
+
/* runtime-simd.c's NEON movemask: four bits a byte, in order. */
|
|
273
|
+
return vget_lane_u64(vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(stop), 4)), 0);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
static int64_t nish_plain_base(int cls, const uint8_t *p, int64_t i, int64_t to) {
|
|
277
|
+
for (; to - i >= 16; i += 16) {
|
|
278
|
+
uint8x16_t v = vld1q_u8(p + i);
|
|
279
|
+
uint8x16_t stop = vorrq_u8(vorrq_u8(vceqq_u8(v, vdupq_n_u8(0x22)), vceqq_u8(v, vdupq_n_u8(0x5c))), vcleq_u8(v, vdupq_n_u8(0x1f)));
|
|
280
|
+
uint64_t m = vget_lane_u64(vreinterpret_u64_u8(vshrn_n_u16(vreinterpretq_u16_u8(stop), 4)), 0);
|
|
281
|
+
if (m != 0) return i + (int64_t)(__builtin_ctzll(m) >> 2);
|
|
282
|
+
}
|
|
283
|
+
return nish_plain_scalar(cls, p, i, to);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
static int64_t nish_run_base(int cls, const uint8_t *p, int64_t from, int64_t to) {
|
|
287
|
+
int64_t i = from;
|
|
288
|
+
while (to - i >= 16) {
|
|
289
|
+
uint64_t m = nish_run_stops_neon(cls, vld1q_u8(p + i));
|
|
290
|
+
if (m == 0) {
|
|
291
|
+
i += 16;
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
int64_t at = i + (int64_t)(__builtin_ctzll(m) >> 2);
|
|
295
|
+
i = nish_run_resume(cls, p, at, to);
|
|
296
|
+
if (i == at) return at;
|
|
297
|
+
}
|
|
298
|
+
return nish_run_scalar(cls, p, i, to);
|
|
299
|
+
}
|
|
300
|
+
#elif defined(NISH_SIMD_WASM)
|
|
301
|
+
static inline uint32_t nish_run_stops_wasm(int cls, v128_t v) {
|
|
302
|
+
v128_t stop;
|
|
303
|
+
if (cls == NISH_RUN_BLANK) {
|
|
304
|
+
stop = wasm_v128_not(wasm_v128_or(wasm_v128_or(wasm_i8x16_eq(v, wasm_i8x16_splat(0x20)), wasm_i8x16_eq(v, wasm_i8x16_splat(0x0a))),
|
|
305
|
+
wasm_v128_or(wasm_i8x16_eq(v, wasm_i8x16_splat(0x0d)), wasm_i8x16_eq(v, wasm_i8x16_splat(0x09)))));
|
|
306
|
+
} else if (cls == NISH_RUN_DIGIT) {
|
|
307
|
+
stop = wasm_u8x16_gt(wasm_i8x16_sub(v, wasm_i8x16_splat(0x30)), wasm_i8x16_splat(9));
|
|
308
|
+
} else {
|
|
309
|
+
stop = wasm_v128_or(wasm_v128_or(wasm_i8x16_eq(v, wasm_i8x16_splat(0x22)), wasm_i8x16_eq(v, wasm_i8x16_splat(0x5c))),
|
|
310
|
+
wasm_v128_or(wasm_u8x16_le(v, wasm_i8x16_splat(0x1f)), v));
|
|
311
|
+
}
|
|
312
|
+
return wasm_i8x16_bitmask(stop);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
static int64_t nish_plain_base(int cls, const uint8_t *p, int64_t i, int64_t to) {
|
|
316
|
+
for (; to - i >= 16; i += 16) {
|
|
317
|
+
v128_t v = wasm_v128_load(p + i);
|
|
318
|
+
v128_t stop = wasm_v128_or(wasm_v128_or(wasm_i8x16_eq(v, wasm_i8x16_splat(0x22)), wasm_i8x16_eq(v, wasm_i8x16_splat(0x5c))),
|
|
319
|
+
wasm_u8x16_le(v, wasm_i8x16_splat(0x1f)));
|
|
320
|
+
uint32_t m = wasm_i8x16_bitmask(stop);
|
|
321
|
+
if (m != 0) return i + __builtin_ctz(m);
|
|
322
|
+
}
|
|
323
|
+
return nish_plain_scalar(cls, p, i, to);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
static int64_t nish_run_base(int cls, const uint8_t *p, int64_t from, int64_t to) {
|
|
327
|
+
int64_t i = from;
|
|
328
|
+
while (to - i >= 16) {
|
|
329
|
+
uint32_t m = nish_run_stops_wasm(cls, wasm_v128_load(p + i));
|
|
330
|
+
if (m == 0) {
|
|
331
|
+
i += 16;
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
int64_t at = i + __builtin_ctz(m);
|
|
335
|
+
i = nish_run_resume(cls, p, at, to);
|
|
336
|
+
if (i == at) return at;
|
|
337
|
+
}
|
|
338
|
+
return nish_run_scalar(cls, p, i, to);
|
|
339
|
+
}
|
|
340
|
+
#else
|
|
341
|
+
#define nish_run_base nish_run_scalar
|
|
342
|
+
#define nish_plain_base nish_plain_scalar
|
|
343
|
+
#endif
|
|
344
|
+
|
|
345
|
+
#if defined(NISH_RUN_CHOOSES)
|
|
346
|
+
/* Which path `NISH_SIMD` and this machine pick: runtime-simd.c's
|
|
347
|
+
`nish_any_choose`, for the run kernels. */
|
|
348
|
+
static nish_run_path nish_run_choose(void) {
|
|
349
|
+
const char *pin = getenv("NISH_SIMD");
|
|
350
|
+
if (pin != NULL && strcmp(pin, "scalar") == 0) return nish_run_scalar;
|
|
351
|
+
if (pin != NULL && strcmp(pin, "base") == 0) return nish_run_base;
|
|
352
|
+
#if defined(NISH_SIMD_SSE2)
|
|
353
|
+
if (nish_cpu_has_avx2()) return nish_run_avx2;
|
|
354
|
+
#endif
|
|
355
|
+
return nish_run_base;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
static int64_t nish_run_resolve(int cls, const uint8_t *p, int64_t from, int64_t to);
|
|
359
|
+
|
|
360
|
+
/* runtime-simd.c's `nish_any`, for the run kernels: a pointer that starts at
|
|
361
|
+
the resolver, read and written with relaxed atomics, plain moves, because
|
|
362
|
+
under `--threads` two workers may make the first call at once and both
|
|
363
|
+
store the same path. The plain kernel has a pointer of its own. */
|
|
364
|
+
static nish_run_path nish_run = nish_run_resolve;
|
|
365
|
+
static nish_run_path nish_plain = nish_run_resolve;
|
|
366
|
+
|
|
367
|
+
/* Asks the chooser once and sets both pointers: the plain kernel takes its
|
|
368
|
+
scalar path when the chooser picks the scalar one, else its base path. */
|
|
369
|
+
static void nish_run_settle(void) {
|
|
370
|
+
nish_run_path path = nish_run_choose();
|
|
371
|
+
__atomic_store_n(&nish_run, path, __ATOMIC_RELAXED);
|
|
372
|
+
__atomic_store_n(&nish_plain, path == nish_run_scalar ? nish_plain_scalar : nish_plain_base, __ATOMIC_RELAXED);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
#define NISH_RUN_PATH __atomic_load_n(&nish_run, __ATOMIC_RELAXED)
|
|
376
|
+
#define NISH_PLAIN_PATH __atomic_load_n(&nish_plain, __ATOMIC_RELAXED)
|
|
377
|
+
|
|
378
|
+
static int64_t nish_run_resolve(int cls, const uint8_t *p, int64_t from, int64_t to) {
|
|
379
|
+
nish_run_settle();
|
|
380
|
+
return (cls == NISH_RUN_PLAIN ? NISH_PLAIN_PATH : NISH_RUN_PATH)(cls, p, from, to);
|
|
381
|
+
}
|
|
382
|
+
#else
|
|
383
|
+
#define NISH_RUN_PATH nish_run_base
|
|
384
|
+
#define NISH_PLAIN_PATH nish_plain_base
|
|
385
|
+
#endif
|
|
386
|
+
|
|
387
|
+
int64_t nish_bytes_skip_blank(const uint8_t *p, int64_t from, int64_t to) {
|
|
388
|
+
return NISH_RUN_PATH(NISH_RUN_BLANK, p, from, to);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
int64_t nish_bytes_skip_digits(const uint8_t *p, int64_t from, int64_t to) {
|
|
392
|
+
return NISH_RUN_PATH(NISH_RUN_DIGIT, p, from, to);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
int64_t nish_bytes_skip_json_text(const uint8_t *p, int64_t from, int64_t to) {
|
|
396
|
+
return NISH_RUN_PATH(NISH_RUN_TEXT, p, from, to);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
int64_t nish_bytes_skip_json_plain(const uint8_t *p, int64_t from, int64_t to) {
|
|
400
|
+
return NISH_PLAIN_PATH(NISH_RUN_PLAIN, p, from, to);
|
|
401
|
+
}
|