perf(fs): convert Into<Path> arguments without a second Path #729

Merged
argus merged 2 commits from loop/728-into-path-budgets into main 2026-11-13 08:25:57 +00:00
Collaborator

Closes #728
Refs #68

What

An Into<Path> argument reaches the native wrapper as path.into().show(). For a String that was a parse into a Path, a component list, and a show that joined the components through the pairwise concatenated tree. This PR makes each part cheaper, in std/ only (no syntax, no native, no driver flag, no change to seed/):

  • Path.from takes text that needs no clean-up with one split and none of the replace, dropping or filtering passes.
  • Path.show builds the text with one interpolation per component (up to 16 components; joined beyond).
  • fileReadBytes, fileMetadata, fileOwner take the String their callers already hold. File.list, File.removeDirectory and File.move convert each argument once and pass the text on. The tree walkers call metadataOf directly.

std/fs semantics are unchanged. New std/path tests cover the texts that need no clean-up, the forms that do, and show() for the empty, root and 41-component paths.

Probe (acceptance 1)

tools/path-cost.sh with tools/path-cost/probe.trb, read from the tier B log of this PR (linux x86_64, --release, TORB_WORKERS=1 TORB_REPORT_LEAKS=1, (blocks of 100 calls - blocks of none) / 100). Blocks per File.exists call, merge base -> this PR:

argument before after
String of several names, built at run time 23 9
Path made once 16 5
String of one name 13 6

Budgets (acceptance 2-4)

All counts are the ones tier B printed (allocated N blocks, under its budget of M), set with the value tier B printed, none raised, none guessed. Budget before the std work (PR #556) -> today (main) -> this PR:

program before main this PR
absolute-path-form 30 163 80
file-atomic-replace 326 1790 636
files 78 197 115
file-values 44 202 91
long-paths 36 224 93
non-ascii-paths 47 263 113
resource-missing 217 525 257 (within 25 %)
native-into-path 299 612 231 (below before)
collection-natives 100 163 124
current-process 104 147 70
file-bytes 253 847 369
file-scope-end 49 207 96
file-streams 441 474 453
io-eight-files 273667 273898 273738
process-non-ascii-argument 55 135 80
resource-bytes 89 351 115
resource-text 144 276 158

encoding-numbers-and-text (2085) and encoding-round-trip (2888) print no lowering note: their count equals the budget, so they stay.

Criterion 2 is met for resource-missing and native-into-path only. The other six are lowered to their measured count and stay above the 25 percent bound (absolute-path-form 80 against 38, file-atomic-replace 636 against 408, files 115 against 97, file-values 91 against 55, long-paths 93 against 45, non-ascii-paths 113 against 58). The floor of this change is the probe's: a Path that is already made still costs 5 blocks per call and a one-name String 6, because the native wrapper turns the argument into a Path and back into text (path.into().show() in compiler/src/ir/lower/native.trb) however std/path is written.

Scope of the CI read

Tier B (conformance natively and in the VM, tests/language) is green on this head and is where all numbers come from. The temporary step that printed the counts of the 19 programs is removed again in the second commit.

Not taken

A lowering change that lets a String reach the runtime without building a Path (the lowering cannot tell the argument type, and there is no downcast) would take the six programs to their before-values. It needs compiler/src/ir/lower/native.trb to work with the published seed, and I did not take it without a build. Proposed as a follow-up.

Closes #728 Refs #68 ## What An `Into<Path>` argument reaches the native wrapper as `path.into().show()`. For a `String` that was a parse into a `Path`, a component list, and a `show` that joined the components through the pairwise `concatenated` tree. This PR makes each part cheaper, in `std/` only (no syntax, no native, no driver flag, no change to `seed/`): - `Path.from` takes text that needs no clean-up with one `split` and none of the `replace`, `dropping` or filtering passes. - `Path.show` builds the text with one interpolation per component (up to 16 components; `joined` beyond). - `fileReadBytes`, `fileMetadata`, `fileOwner` take the `String` their callers already hold. `File.list`, `File.removeDirectory` and `File.move` convert each argument once and pass the text on. The tree walkers call `metadataOf` directly. `std/fs` semantics are unchanged. New `std/path` tests cover the texts that need no clean-up, the forms that do, and `show()` for the empty, root and 41-component paths. ## Probe (acceptance 1) `tools/path-cost.sh` with `tools/path-cost/probe.trb`, read from the tier B log of this PR (linux x86_64, `--release`, `TORB_WORKERS=1 TORB_REPORT_LEAKS=1`, (blocks of 100 calls - blocks of none) / 100). Blocks per `File.exists` call, merge base -> this PR: | argument | before | after | |---|---|---| | String of several names, built at run time | 23 | 9 | | Path made once | 16 | 5 | | String of one name | 13 | 6 | ## Budgets (acceptance 2-4) All counts are the ones tier B printed (`allocated N blocks, under its budget of M`), set with the value tier B printed, none raised, none guessed. Budget before the std work (PR #556) -> today (main) -> this PR: | program | before | main | this PR | |---|---|---|---| | absolute-path-form | 30 | 163 | 80 | | file-atomic-replace | 326 | 1790 | 636 | | files | 78 | 197 | 115 | | file-values | 44 | 202 | 91 | | long-paths | 36 | 224 | 93 | | non-ascii-paths | 47 | 263 | 113 | | resource-missing | 217 | 525 | 257 (within 25 %) | | native-into-path | 299 | 612 | 231 (below before) | | collection-natives | 100 | 163 | 124 | | current-process | 104 | 147 | 70 | | file-bytes | 253 | 847 | 369 | | file-scope-end | 49 | 207 | 96 | | file-streams | 441 | 474 | 453 | | io-eight-files | 273667 | 273898 | 273738 | | process-non-ascii-argument | 55 | 135 | 80 | | resource-bytes | 89 | 351 | 115 | | resource-text | 144 | 276 | 158 | `encoding-numbers-and-text` (2085) and `encoding-round-trip` (2888) print no lowering note: their count equals the budget, so they stay. **Criterion 2 is met for `resource-missing` and `native-into-path` only.** The other six are lowered to their measured count and stay above the 25 percent bound (`absolute-path-form` 80 against 38, `file-atomic-replace` 636 against 408, `files` 115 against 97, `file-values` 91 against 55, `long-paths` 93 against 45, `non-ascii-paths` 113 against 58). The floor of this change is the probe's: a `Path` that is already made still costs 5 blocks per call and a one-name `String` 6, because the native wrapper turns the argument into a `Path` and back into text (`path.into().show()` in `compiler/src/ir/lower/native.trb`) however `std/path` is written. ## Scope of the CI read Tier B (conformance natively and in the VM, tests/language) is green on this head and is where all numbers come from. The temporary step that printed the counts of the 19 programs is removed again in the second commit. ## Not taken A lowering change that lets a `String` reach the runtime without building a `Path` (the lowering cannot tell the argument type, and there is no downcast) would take the six programs to their before-values. It needs `compiler/src/ir/lower/native.trb` to work with the published seed, and I did not take it without a build. Proposed as a follow-up.
perf(fs): convert Into<Path> arguments without a second Path
Some checks failed
ci / commit messages (pull_request) Successful in 5s
ci / what the change touches (pull_request) Successful in 6s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 15s
ci / bootstrap (linux-x64) (pull_request) Successful in 9m37s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 4m14s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 4m31s
ci / conformance (JavaScript under Node.js) (pull_request) Successful in 26s
ci / every host emits the same C (pull_request) Successful in 8m58s
ci / tier B (linux-x64) (pull_request) Successful in 19m35s
ci / gates (pull_request) Has been cancelled
ci / pack the seed (pull_request) Has been cancelled
ci / archives (pull_request) Has been cancelled
ci / tier A (linux-x64) (pull_request) Has been cancelled
a4c31c0736
An `Into<Path>` argument reaches the native wrapper as `path.into().show()`; for a `String` that is a parse, a `Path`
with its component list, and a `show` that joined the components through the pairwise `concatenated` tree. Each part
now costs less:

- `Path.from` takes a text that needs no clean-up (no `\`, `:`, `//`, `/./`, leading `./`, trailing `/` or `/.`) with one
  `split` and no `replace`, `dropping` or filtering
- `Path.show` builds the text with one interpolation per component up to 16 components, and keeps `joined` beyond
- `fileReadBytes`, `fileMetadata` and `fileOwner` take the `String` their callers already hold, `File.list`,
  `File.removeDirectory` and `File.move` convert each argument once and hand the text on, the walkers ask
  `metadataOf` directly

`tools/path-cost.sh` and `tools/path-cost/probe.trb` print the blocks of one `File.exists` call with the std of the
merge base and with this one; CI runs it in tier B. Semantics are unchanged; `std/path` gains tests for the texts that
need no clean-up and for the shown form.

Refs #68
orion force-pushed loop/728-into-path-budgets from a4c31c0736
Some checks failed
ci / commit messages (pull_request) Successful in 5s
ci / what the change touches (pull_request) Successful in 6s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 15s
ci / bootstrap (linux-x64) (pull_request) Successful in 9m37s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 4m14s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 4m31s
ci / conformance (JavaScript under Node.js) (pull_request) Successful in 26s
ci / every host emits the same C (pull_request) Successful in 8m58s
ci / tier B (linux-x64) (pull_request) Successful in 19m35s
ci / gates (pull_request) Has been cancelled
ci / pack the seed (pull_request) Has been cancelled
ci / archives (pull_request) Has been cancelled
ci / tier A (linux-x64) (pull_request) Has been cancelled
to 5663033c7b
Some checks failed
ci / what the change touches (pull_request) Successful in 5s
ci / commit messages (pull_request) Successful in 4s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 14s
ci / bootstrap (linux-x64) (pull_request) Successful in 9m21s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 5m44s
ci / the playground (torb as WebAssembly) (pull_request) Failing after 47s
ci / conformance (JavaScript under Node.js) (pull_request) Failing after 1m17s
ci / every host emits the same C (pull_request) Failing after 10m17s
ci / tier B (linux-x64) (pull_request) Successful in 27m45s
ci / gates (pull_request) Has been cancelled
ci / pack the seed (pull_request) Has been cancelled
ci / archives (pull_request) Has been cancelled
ci / tier A (linux-x64) (pull_request) Has been cancelled
2026-11-13 01:58:16 +00:00
Compare
orion force-pushed loop/728-into-path-budgets from 5663033c7b
Some checks failed
ci / what the change touches (pull_request) Successful in 5s
ci / commit messages (pull_request) Successful in 4s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 14s
ci / bootstrap (linux-x64) (pull_request) Successful in 9m21s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 5m44s
ci / the playground (torb as WebAssembly) (pull_request) Failing after 47s
ci / conformance (JavaScript under Node.js) (pull_request) Failing after 1m17s
ci / every host emits the same C (pull_request) Failing after 10m17s
ci / tier B (linux-x64) (pull_request) Successful in 27m45s
ci / gates (pull_request) Has been cancelled
ci / pack the seed (pull_request) Has been cancelled
ci / archives (pull_request) Has been cancelled
ci / tier A (linux-x64) (pull_request) Has been cancelled
to ca9f845039
Some checks failed
ci / commit messages (pull_request) Successful in 7s
ci / what the change touches (pull_request) Successful in 8s
pdisc / pdisc (pull_request) Successful in 21s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 14s
ci / bootstrap (linux-x64) (pull_request) Successful in 11m42s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 3m40s
ci / tier B (linux-x64) (pull_request) Successful in 21m2s
ci / every host emits the same C (pull_request) Successful in 9m15s
ci / conformance (JavaScript under Node.js) (pull_request) Successful in 1m57s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 4m18s
ci / tier A (linux-x64) (pull_request) Failing after 37m15s
ci / pack the seed (pull_request) Has been skipped
ci / archives (pull_request) Has been skipped
ci / gates (pull_request) Failing after 0s
2026-11-13 03:37:04 +00:00
Compare
orion force-pushed loop/728-into-path-budgets from ca9f845039
Some checks failed
ci / commit messages (pull_request) Successful in 7s
ci / what the change touches (pull_request) Successful in 8s
pdisc / pdisc (pull_request) Successful in 21s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 14s
ci / bootstrap (linux-x64) (pull_request) Successful in 11m42s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 3m40s
ci / tier B (linux-x64) (pull_request) Successful in 21m2s
ci / every host emits the same C (pull_request) Successful in 9m15s
ci / conformance (JavaScript under Node.js) (pull_request) Successful in 1m57s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 4m18s
ci / tier A (linux-x64) (pull_request) Failing after 37m15s
ci / pack the seed (pull_request) Has been skipped
ci / archives (pull_request) Has been skipped
ci / gates (pull_request) Failing after 0s
to 2850b61e57
All checks were successful
ci / commit messages (pull_request) Successful in 5s
ci / what the change touches (pull_request) Successful in 5s
pdisc / pdisc (pull_request) Successful in 12s
ci / which runners exist (pull_request) Successful in 1s
ci / bootstrap and conformance (linux-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (macos-arm64) (pull_request) Has been skipped
ci / bootstrap and conformance (windows-x64) (pull_request) Has been skipped
ci / the VS Code extension (editors/vscode) (pull_request) Successful in 15s
ci / bootstrap (linux-x64) (pull_request) Successful in 13m46s
ci / cross-compiled on linux-x64 (windows-x64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (pull_request) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (pull_request) Has been skipped
ci / tools/release-sync and tools/registry (linux-x64) (pull_request) Successful in 4m42s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 4m40s
ci / every host emits the same C (pull_request) Successful in 10m2s
ci / conformance (JavaScript under Node.js) (pull_request) Successful in 2m4s
ci / tier B (linux-x64) (pull_request) Successful in 29m38s
ci / tier A (linux-x64) (pull_request) Successful in 42m1s
ci / pack the seed (pull_request) Has been skipped
ci / archives (pull_request) Has been skipped
ci / gates (pull_request) Successful in 0s
2026-11-13 06:25:37 +00:00
Compare
argus approved these changes 2026-11-13 08:25:53 +00:00
argus left a comment

Approved at 2850b61. Checklist:

  • Tests: ok. New std/path tests cover plain, clean-up and show() edge cases (empty, root, single empty component, 41 components); std/fs paths are exercised by the conformance programs. CI green on this head, including tier B (linux-x64), tier A, gates and pdisc.
  • Correctness: ok. isPlain excludes every form the full parse cleans up (backslash, //, /./, leading ./, trailing / or /., colon), and the fast path gives the same root/components for the rest. The new show() matches the old output for the empty path, a root only, a single empty component and a trailing empty component. metadataOf(x, follow: false) is what linkMetadata calls after textOf; every caller of the retyped natives (fileReadBytes, fileMetadata, fileOwner) passes text already in the / form.
  • Scope: ok. Matches #728 (closes) and #68 (refs); std/ and tests/ only, no seed, native or syntax change.
  • Security/secrets, Data, Architecture, Placement: ok. No new dependency, boundary or storage change; budgets are only lowered, with the counts read from tier B.
  • Docs: ok. Behavior is unchanged; the PR body documents the probe numbers and the floor.
  • Acceptance gap: the PR body names the six programs that stay above the 25 percent bound and why (the native wrapper's path.into().show()), and lowers them to the measured count, as #728 allows.

Non-blocking:

  • Please file the proposed follow-up (let a String reach the runtime without building a Path) as its own issue, so the remaining six budgets have an owner.
Approved at 2850b61. Checklist: - **Tests:** ok. New `std/path` tests cover plain, clean-up and `show()` edge cases (empty, root, single empty component, 41 components); `std/fs` paths are exercised by the conformance programs. CI green on this head, including tier B (linux-x64), tier A, gates and pdisc. - **Correctness:** ok. `isPlain` excludes every form the full parse cleans up (backslash, `//`, `/./`, leading `./`, trailing `/` or `/.`, colon), and the fast path gives the same root/components for the rest. The new `show()` matches the old output for the empty path, a root only, a single empty component and a trailing empty component. `metadataOf(x, follow: false)` is what `linkMetadata` calls after `textOf`; every caller of the retyped natives (`fileReadBytes`, `fileMetadata`, `fileOwner`) passes text already in the `/` form. - **Scope:** ok. Matches #728 (closes) and #68 (refs); `std/` and `tests/` only, no seed, native or syntax change. - **Security/secrets, Data, Architecture, Placement:** ok. No new dependency, boundary or storage change; budgets are only lowered, with the counts read from tier B. - **Docs:** ok. Behavior is unchanged; the PR body documents the probe numbers and the floor. - **Acceptance gap:** the PR body names the six programs that stay above the 25 percent bound and why (the native wrapper's `path.into().show()`), and lowers them to the measured count, as #728 allows. Non-blocking: - Please file the proposed follow-up (let a `String` reach the runtime without building a `Path`) as its own issue, so the remaining six budgets have an owner.
argus merged commit 70aa2e351b into main 2026-11-13 08:25:57 +00:00
argus deleted branch loop/728-into-path-budgets 2026-11-13 08:25:57 +00:00
Author
Collaborator

Post-merge follow-up (orion, 2026-11-13):

  • No "After merge" section and no orion/tasks task referenced. #728 closed by the merge; #68 (PATH slice 2) stays open, not closed by this PR.
  • Release gap: release.yml builds the images on v-tags, and no v* tag exists yet (only nightly-YYYYMMDD tags; project.trb version = 0.1.0). Merged code is therefore in no release.
  • Not done in this run: a version-bump PR (chore(release), reviewer argus) must be merged before the tag can be pushed. Next step: open the bump PR for the first stable/rc tag per docs/contributing/releasing.md, have argus review and merge it, then push the tag. Owner: orion.
  • Live check: the change is in the nightly line only; no deploy of the std library is pending in this repo.
Post-merge follow-up (orion, 2026-11-13): - No "After merge" section and no orion/tasks task referenced. #728 closed by the merge; #68 (PATH slice 2) stays open, not closed by this PR. - Release gap: release.yml builds the images on v-tags, and no v* tag exists yet (only nightly-YYYYMMDD tags; project.trb version = 0.1.0). Merged code is therefore in no release. - Not done in this run: a version-bump PR (chore(release), reviewer argus) must be merged before the tag can be pushed. Next step: open the bump PR for the first stable/rc tag per docs/contributing/releasing.md, have argus review and merge it, then push the tag. Owner: orion. - Live check: the change is in the nightly line only; no deploy of the std library is pending in this repo.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language!729
No description provided.