a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
47 lines
1.8 KiB
Go
47 lines
1.8 KiB
Go
// Hot-path workaround: the upstream tree-sitter/go-tree-sitter
|
||
// (v0.25.0) registers a Go-routed allocator at package init —
|
||
// `ts_set_allocator(c_malloc_fn, …)` — and `c_malloc_fn` calls back
|
||
// into Go (`go_malloc`), which then calls `C.malloc`. Every internal
|
||
// allocation inside the parser therefore round-trips C → Go → C
|
||
// instead of going straight to libc. On large repos that round-trip
|
||
// dominated the cgo cost: `_cgoexp_…go_malloc` showed up at ~35% of
|
||
// total CPU in our indexer profile, and indexing the gortex repo
|
||
// itself ran 3× slower than the smacker baseline.
|
||
//
|
||
// We undo that by re-calling `ts_set_allocator(NULL, …, NULL)` from
|
||
// our own init, which the C library treats as "use libc directly."
|
||
// The symbol `ts_set_allocator` is exported from the upstream
|
||
// package's CGO archive, so we declare it `extern` and link against
|
||
// the same archive.
|
||
//
|
||
// Init ordering: Go runs init() functions in import-graph order, and
|
||
// this file is in the `tsitter` package which depends on the upstream
|
||
// `tree_sitter` package — so the upstream init (which registers the
|
||
// indirection) runs first, ours runs after, and our reset wins.
|
||
//
|
||
// Tree-sitter's docs warn that switching allocators after objects
|
||
// have been created is unsafe unless those objects are freed first
|
||
// or the new allocator shares state with the old. Both go-routed and
|
||
// libc allocators ultimately call `C.malloc`/`C.free`, so they share
|
||
// state — the round-trip layer drops away cleanly.
|
||
|
||
package tsitter
|
||
|
||
/*
|
||
extern void ts_set_allocator(
|
||
void *(*new_malloc)(unsigned long),
|
||
void *(*new_calloc)(unsigned long, unsigned long),
|
||
void *(*new_realloc)(void *, unsigned long),
|
||
void (*new_free)(void *)
|
||
);
|
||
|
||
static void gortex_use_libc_allocator(void) {
|
||
ts_set_allocator(0, 0, 0, 0);
|
||
}
|
||
*/
|
||
import "C"
|
||
|
||
func init() {
|
||
C.gortex_use_libc_allocator()
|
||
}
|