Commit Graph
2 Commits
Author SHA1 Message Date
Chris Tateandmmamedel 9080986166 Add sparse UTF-16 indexing for large strings (#275)
* fix: index large unicode strings sparsely

Co-authored-by: mmamedel <23098414+mmamedel@users.noreply.github.com>

* fix: retain sparse anchors for long ascii prefixes

Co-authored-by: mmamedel <23098414+mmamedel@users.noreply.github.com>

* fix: skip sparse index for proven ASCII strings

Co-authored-by: mmamedel <23098414+mmamedel@users.noreply.github.com>

* fix: complete sparse UTF-16 string indexing

Co-authored-by: mmamedel <23098414+mmamedel@users.noreply.github.com>

* test: rebase static size contracts for sparse index

Co-authored-by: mmamedel <23098414+mmamedel@users.noreply.github.com>

* test: retain sparse checkpoints through ASCII prefix end

Co-authored-by: mmamedel <23098414+mmamedel@users.noreply.github.com>

* fix: retain sparse anchors across threshold append

Co-authored-by: mmamedel <23098414+mmamedel@users.noreply.github.com>

* fix: retain sparse indexes beyond cursor cache

Co-authored-by: mmamedel <23098414+mmamedel@users.noreply.github.com>

* fix: bound sparse string index residency

Co-authored-by: mmamedel <23098414+mmamedel@users.noreply.github.com>

* fix: isolate sparse string index residency

Co-authored-by: mmamedel <23098414+mmamedel@users.noreply.github.com>

* test: restore parseInt oracle outputs

* test: verify committed string oracle

- Regenerate the string case oracle with the active Node executable.\n- Compare the checked-in fixture byte-for-byte before native runtime checks.\n- Keep the Linux parseInt ULP allowance scoped to native output.

---------

Co-authored-by: mmamedel <23098414+mmamedel@users.noreply.github.com>
2026-08-31 17:12:52 -05:00
Chris Tate 6f7a1a08fe feat: support thread-instanced library state (#137)
* feat: support thread-instanced library state

- Add the abi.instance_per_thread profile field: the archive's TUs compile
  with -DSCR_THREAD_INSTANCES, and the SCR_TL qualifier in scr_runtime.h
  moves every runtime unit's mutable statics into thread-local storage;
  both backends emit the program TU's module globals, run-once guards, and
  lazily-compiled regex literal caches thread-local to match
- ONE linked archive then serves one independent instance per embedder
  thread through the unchanged entry family: a thread registers its sink
  and calls the init entry, and owns its own collector, result arena,
  poison flag, and program state — a trap poisons only the instance it
  fired in while sibling threads' instances keep answering
- Document the contract beside the profile spec: one instance per thread,
  selected implicitly by the calling thread; instance lifetime is the
  thread's lifetime; the never-entered-from-two-threads rule is unchanged;
  independent of and composable with abi.localize_runtime
- Immutable interned data (string literals, unit arms, template arrays,
  vtables) stays shared — Darwin ASan's image-registration common
  included, keeping the one-registration-per-image discipline; the
  exception cell's current pointer resolves a NULL sentinel in this mode
  because a thread-local address is not a constant initializer
- Add the four-thread acceptance probe (distinct per-thread workloads,
  concurrent instance-local inits, per-instance collects, a trap delivered
  to its own thread's sink exactly once), the composition probe pairing a
  thread-instanced localized archive with a second different-prefix
  localized archive, an explicit ASan rerun beside the suite-flavor
  sanitized builds, and profile-shape coverage; schedule the new lane
  contracts beside M1/M2
- Non-opted builds are byte-for-byte unchanged: the qualifier expands to
  nothing outside -DSCR_LIB -DSCR_THREAD_INSTANCES (verified object-level
  over every touched runtime TU in both default and library flavors)

* fix: keep sanitized runtime-localized archives linkable on ELF

ASan's instrumented globals ride ELF section groups; archives built from
shared runtime objects carry groups with REPEATED signatures, so a process
linking two runtime-localized sanitized archives kept one archive's group
and discarded the other's — whose now-local references then dangled at the
embedder's link. Resolving the groups into the combined relocatable member
(ld -r --force-group-allocation) keeps every archive's copies; the
localization step then demotes them per archive exactly like unsanitized
state. Plain builds carry no section groups, so the flag is inert there.

With the groups resolved, ELF surfaces the same deliberate exception
Mach-O already documented: the image-wide registration guard COMMON stays
shared so the final image registers its ASan globals exactly once — M1/M7
now pin that spelling on both platforms. The explicit ASan pairing (M8)
additionally points Linux LSan away from contractually thread-lifetime
instance state, exactly as the sanitized suite lanes do.

* fix: isolate inspect state per thread

* fix(runtime): share uptime anchor across threads
2026-08-12 09:49:43 -05:00