diff --git a/compiler/deps.nim b/compiler/deps.nim index 3e09a5e40f..f46a7f01da 100644 --- a/compiler/deps.nim +++ b/compiler/deps.nim @@ -1249,15 +1249,21 @@ proc commandIc*(conf: ConfigRef) = let nifmake = findNifmake() # Build the per-module rules concurrently: nifmake fans out all commands at # each DAG depth via execProcesses (defaults to all cores). Cold builds are - # otherwise serial (one child at a time) and leave the machine idle. Opt out - # with `-d:icNoParallel` (e.g. for readable, non-interleaved child output - # when debugging a build), or cap the concurrency with `-d:icJobs:N` — an - # uncapped fan-out across many cores can exhaust RAM on a large project - # (each `nim m`/`cg` child holds its own module graph), which nifmake's own - # `-j:N` exists to bound. + # otherwise serial (one child at a time) and leave the machine idle. An + # uncapped fan-out across many cores can exhaust RAM on a large project (each + # `nim m`/`cg` child holds its own module graph), which nifmake's own `-j:N` + # exists to bound. Concurrency is chosen (highest precedence first): + # * `-d:icNoParallel` -> serial (readable, non-interleaved child output) + # * `-d:icJobs:N` -> cap at N (legacy IC-tuning define) + # * `--parallelBuild:N` -> cap at N (the standard Nim build-parallelism + # flag; a no-op for `nim c` under IC, so we give + # it meaning here — lets Nimbus devs pick their + # own value without a `-d:` define) + # * otherwise -> uncapped (all cores) let parallel = if isDefined(conf, "icNoParallel"): "" elif isDefined(conf, "icJobs"): " --parallel:" & conf.symbols["icJobs"] + elif conf.numberOfProcessors > 0: " --parallel:" & $conf.numberOfProcessors else: " --parallel" # Phase 1 — frontend (nifler + `nim m`), run to a discovery fixpoint. diff --git a/compiler/icnifcore.nim b/compiler/icnifcore.nim index b0cdbdf745..b4ed9d064f 100644 --- a/compiler/icnifcore.nim +++ b/compiler/icnifcore.nim @@ -219,8 +219,18 @@ proc collectBifStrLits*(path: string): seq[string] = ## string literal it holds, in order — the binary analogue of the old nifstreams ## scan that collected `StrLit`s. Keeps nifcore types out of `deps.nim`, which ## only needs the recorded string list. + ## + ## Uses `loadFromFile` (a full read into owned memory) rather than the mmap-backed + ## `bif.load`, then CLOSES the handle. `bif.load` intentionally leaves the mapping + ## resident for the process lifetime; for the `nim ic` driver that reads these + ## sidecars while `nim m` children rewrite them, a lingering read mapping is a + ## Windows sharing violation: the child's `open(path, fmWrite)` fails with + ## `IOError: cannot open`. These sidecars are tiny, so the zero-copy mmap buys + ## nothing here anyway. result = @[] - var m = bif.load(path) + var f = open(path, fmRead) + var m = bif.loadFromFile(f) + close(f) var c = m.buf.beginRead() while c.hasMore: if c.kind == StrLit: result.add strVal(c) diff --git a/compiler/typekeys.nim b/compiler/typekeys.nim index 54092eb055..6c7ca51d7b 100644 --- a/compiler/typekeys.nim +++ b/compiler/typekeys.nim @@ -47,6 +47,11 @@ type CoConsiderOwned CoDistinct CoHashTypeInsideNode + CoPrecise # produce a FRONTEND-faithful, unique key (for the + # stable NIF *name*, not hook dedup): keep distinctions + # sem makes that the backend identity collapses — e.g. + # an `int literal(x)` type carries its value so it does + # not merge with `int`. See `getTypeKey`/`typeKeyHook`. TypeLoader* = proc (t: PType) {.nimcall.} SymLoader* = proc (s: PSym) {.nimcall.} @@ -139,6 +144,20 @@ proc maybeImported(c: var Context; s: PSym; conf: ConfigRef) {.inline.} = if s != nil and {sfImportc, sfExportc} * s.flagsImpl != {}: c.symKey(s, conf) +proc emitPreciseFlags(c: var Context; t: PType; flags: set[ConsiderFlag]) {.inline.} = + ## Under CoPrecise the NIF *name* must be as fine as `types.sameType`, which + ## compares `eqTypeFlags * flags` (see `sameFlags`). Without this a + ## `proc() {.gcsafe.}` keyed identically to `proc()`, and a `ref X not nil` + ## identically to `ref X` — the loader would then merge two frontend-distinct + ## types onto one NIF name. Emitted only for the naming path (CoPrecise); the + ## `setAttachedOp` hook key (no CoPrecise) is unaffected, so its byte layout is + ## unchanged. + if CoPrecise in flags: + let ef = eqTypeFlags * t.flagsImpl + if ef != {}: + withTree c.m, "´tflags": + for f in ef: c.m.addIntLit ord(f) + proc backendTypeName(t: PType; conf: ConfigRef): string = ## Stable cross-module identity of a backend-minted (lower-stage) type: its ## serialized `@bk` NIF name (mirrors ast2nif.nifTypeName). A closure-env @@ -229,6 +248,10 @@ proc typeKey(c: var Context; t: PType; flags: set[ConsiderFlag]; conf: ConfigRef of tyInt: withTree c.m, "i": c.m.addIntLit -1 + # An `int literal(x)` type (nImpl holds the value) must stay distinct from + # plain `int` for the NIF name, else overload resolution breaks on reload. + if CoPrecise in flags and t.nImpl != nil: + c.m.addIntLit t.nImpl.intVal maybeImported(c, t.symImpl, conf) of tyInt8: withTree c.m, "i": @@ -266,6 +289,14 @@ proc typeKey(c: var Context; t: PType; flags: set[ConsiderFlag]; conf: ConfigRef withTree c.m, "u": c.m.addIntLit 64 maybeImported(c, t.symImpl, conf) + of tyFloat: + withTree c.m, "f": + c.m.addIntLit -1 + # A `float literal(x)` type (nImpl = nkFloatLit) must stay distinct from + # plain `float`, just like the `int literal(x)` case above. + if CoPrecise in flags and t.nImpl != nil and t.nImpl.kind in {nkFloatLit..nkFloat64Lit}: + c.m.addFloatLit t.nImpl.floatVal + maybeImported(c, t.symImpl, conf) of tyObject, tyEnum: if t.typeInstImpl != nil: # prevent against infinite recursions here, see bug #8883: @@ -381,6 +412,9 @@ proc typeKey(c: var Context; t: PType; flags: set[ConsiderFlag]; conf: ConfigRef c.m.addIdent toNifTag(t.callConvImpl) if tfVarargs in t.flagsImpl: c.m.addIdent "´varargs" + # `.gcsafe`/`.noSideEffect` (in eqTypeFlags) distinguish proc types under + # sameType, so they must distinguish the NIF name too. + emitPreciseFlags(c, t, flags) of tyArray: withTree c.m, toNifTag(t.kind): if t.sonsImpl.len == 0: @@ -395,6 +429,9 @@ proc typeKey(c: var Context; t: PType; flags: set[ConsiderFlag]; conf: ConfigRef c.typeKey t.sonsImpl[i], flags, conf if tfNotNil in t.flagsImpl and CoType notin flags: c.m.addIdent "´notnil" + # tfNotNil/tfVarIsPtr/tfIsOutParam (eqTypeFlags) part of sameType identity + # for ref/ptr/var/lent/sink; the hook path (no CoPrecise) keeps its layout. + emitPreciseFlags(c, t, flags) proc typeKey*(t: PType; conf: ConfigRef; tl: TypeLoader; sl: SymLoader): string = var c: Context = Context(m: createMangler(30, -1), tl: tl, sl: sl, diff --git a/koch.nim b/koch.nim index fe75164526..4a3f4ae9ae 100644 --- a/koch.nim +++ b/koch.nim @@ -16,11 +16,11 @@ const ChecksumsStableCommit = "5c132cd332cce5d64a0da9ac3e4c9664313dccb4" # 0.2.2 SatStableCommit = "9d52513b3c68bfb929dbd687d4fb2836cfee6936" - NimonyStableCommit = "557b865192e25e8e76ce4ccc81c6ea71676e92e7" # unversioned \ + NimonyStableCommit = "6f9ac6655dc6724ae4e5ccb93b8123c18d54391a" # unversioned \ # Note that Nimony uses Nim as a git submodule but we don't want to install # Nimony's dependency to Nim as we are Nim. So a `git clone` without --recursive # is **required** here. - # Commit from 2026-07-01 -- contains a critical feature addition from nifmake for us + # Commit from 2026-07-03 -- .bif files are memory mapped too # examples of possible values for fusion: #head, #ea82b54, 1.2.3 FusionStableHash = "#562467452b32cb7a97410ea177f083e6d8405734"