From 2ba7427e91a2b3b8ced1adb51f30c8309c5fccdc Mon Sep 17 00:00:00 2001 From: araq Date: Fri, 14 Nov 2025 08:57:15 +0100 Subject: [PATCH 01/28] bugfix: produce the required nimcache subdir --- compiler/ast2nif.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/ast2nif.nim b/compiler/ast2nif.nim index af4955d94739..5ca1f5f14171 100644 --- a/compiler/ast2nif.nim +++ b/compiler/ast2nif.nim @@ -463,7 +463,8 @@ proc writeNifModule*(config: ConfigRef; thisModule: int32; n: PNode) = inner.addParRi() let m = modname(w.moduleToNifSuffix, w.currentModule, w.infos.config) - let d = toGeneratedFile(config, AbsoluteFile(m), ".nif").string + let nifFilename = AbsoluteFile(m).changeFileExt(".nif") + let d = completeGeneratedFilePath(config, nifFilename).string var dest = createTokenBuf(600) dest.addParLe pool.tags.getOrIncl(toNifTag(nkStmtList)), rootInfo From bc26f70ca85955bfb82d80813ba6a86a3e188f26 Mon Sep 17 00:00:00 2001 From: araq Date: Fri, 14 Nov 2025 13:40:31 +0100 Subject: [PATCH 02/28] progress --- compiler/ast2nif.nim | 96 ++++++++++++++++++++++--------------------- compiler/ccgexprs.nim | 12 +++--- compiler/cgen.nim | 6 +++ compiler/cgendata.nim | 4 ++ compiler/msgs.nim | 10 +++++ 5 files changed, 76 insertions(+), 52 deletions(-) diff --git a/compiler/ast2nif.nim b/compiler/ast2nif.nim index 5ca1f5f14171..1528b9d11220 100644 --- a/compiler/ast2nif.nim +++ b/compiler/ast2nif.nim @@ -13,7 +13,7 @@ import std / [assertions, tables, sets] from std / strutils import startsWith import astdef, idents, msgs, options import lineinfos as astli -import pathutils +import pathutils #, modulegraphs import "../dist/nimony/src/lib" / [bitabs, nifstreams, nifcursors, lineinfos, nifindexes, nifreader] import "../dist/nimony/src/gear2" / modnames @@ -258,6 +258,10 @@ proc writeLib(w: var Writer; dest: var TokenBuf; lib: PLib) = proc writeSymDef(w: var Writer; dest: var TokenBuf; sym: PSym) = dest.addParLe sdefTag, trLineInfo(w, sym.infoImpl) dest.addSymDef pool.syms.getOrIncl(w.toNifSymName(sym)), NoLineInfo + if sfExported in sym.flagsImpl: + dest.addIdent "x" + else: + dest.addDotToken if sym.magicImpl == mNone: dest.addDotToken else: @@ -537,48 +541,37 @@ type DecodeContext* = object infos: LineInfoWriter - moduleIds: Table[string, int32] + #moduleIds: Table[string, int32] types: Table[ItemId, (PType, NifIndexEntry)] syms: Table[ItemId, (PSym, NifIndexEntry)] mods: seq[NifModule] cache: IdentCache - moduleToNifSuffix: Table[FileIndex, string] + #moduleToNifSuffix: Table[FileIndex, string] proc createDecodeContext*(config: ConfigRef; cache: IdentCache): DecodeContext = ## Supposed to be a global variable result = DecodeContext(infos: LineInfoWriter(config: config), cache: cache) -proc idToIdx(x: int32): int {.inline.} = - assert x <= -2'i32 - result = -(x+2) - -proc cursorFromIndexEntry(c: var DecodeContext; module: int32; entry: NifIndexEntry; +proc cursorFromIndexEntry(c: var DecodeContext; module: FileIndex; entry: NifIndexEntry; buf: var TokenBuf): Cursor = - let m = idToIdx(module) - let s = addr c.mods[m].stream + let s = addr c.mods[module.int32].stream s.r.jumpTo entry.offset var buf = createTokenBuf(30) nifcursors.parse(s[], buf, entry.info) result = cursorAt(buf, 0) -proc moduleId(c: var DecodeContext; suffix: string): int32 = - # We don't know the "real" FileIndex due to our mapping to a short "Module suffix" - # This is not a problem, we use negative `ItemId.module` values here and then - # there is no interference with in-memory-modules. Modulegraphs.nim already uses -1 - # so we start at -2 here. - result = c.moduleIds.getOrDefault(suffix) - if result == 0: - result = -int32(c.moduleIds.len + 2) # negative index! +proc moduleId(c: var DecodeContext; suffix: string): FileIndex = + var isKnownFile = false + result = c.infos.config.registerNifSuffix(suffix, isKnownFile) + if not isKnownFile: let modFile = (getNimcacheDir(c.infos.config) / RelativeFile(suffix & ".nif")).string let idxFile = (getNimcacheDir(c.infos.config) / RelativeFile(suffix & ".idx.nif")).string - c.moduleIds[suffix] = result - c.mods.add NifModule(stream: nifstreams.open(modFile), index: readIndex(idxFile)) - assert c.mods.len-1 == idToIdx(result) - -proc getOffset(c: var DecodeContext; module: int32; nifName: string): NifIndexEntry = - assert module < 0'i32 - let index = idToIdx(module) - let ii = addr c.mods[index].index + if result.int >= c.mods.len: + c.mods.setLen(result.int + 1) + c.mods[result.int] = NifModule(stream: nifstreams.open(modFile), index: readIndex(idxFile)) + +proc getOffset(c: var DecodeContext; module: FileIndex; nifName: string): NifIndexEntry = + let ii = addr c.mods[module.int32].index result = ii.public.getOrDefault(nifName) if result.offset == 0: result = ii.private.getOrDefault(nifName) @@ -602,10 +595,10 @@ proc loadTypeStub(c: var DecodeContext; t: SymId): PType = inc i if i < name.len and name[i] == '.': inc i let suffix = name.substr(i) - let id = ItemId(module: moduleId(c, suffix), item: itemId) + let id = ItemId(module: moduleId(c, suffix).int32, item: itemId) result = c.types.getOrDefault(id)[0] if result == nil: - let offs = c.getOffset(id.module, name) + let offs = c.getOffset(id.module.FileIndex, name) result = PType(itemId: id, uniqueId: id, kind: TTypeKind(k), state: Partial) c.types[id] = (result, offs) @@ -628,10 +621,10 @@ proc loadSymStub(c: var DecodeContext; t: SymId): PSym = let symAsStr = pool.syms[t] let sn = parseSymName(symAsStr) let module = moduleId(c, sn.module) - let val = addr c.mods[idToIdx(module)].symCounter + let val = addr c.mods[module.int32].symCounter inc val[] - let id = ItemId(module: module, item: val[]) + let id = ItemId(module: module.int32, item: val[]) result = c.syms.getOrDefault(id)[0] if result == nil: let offs = c.getOffset(module, symAsStr) @@ -697,7 +690,7 @@ proc loadType*(c: var DecodeContext; t: PType) = if t.state != Partial: return t.state = Sealed var buf = createTokenBuf(30) - var n = cursorFromIndexEntry(c, t.itemId.module, c.types[t.itemId][1], buf) + var n = cursorFromIndexEntry(c, t.itemId.module.FileIndex, c.types[t.itemId][1], buf) expect n, ParLe if n.tagId != tdefTag: @@ -746,7 +739,7 @@ proc loadSym*(c: var DecodeContext; s: PSym) = if s.state != Partial: return s.state = Sealed var buf = createTokenBuf(30) - var n = cursorFromIndexEntry(c, s.itemId.module, c.syms[s.itemId][1], buf) + var n = cursorFromIndexEntry(c, s.itemId.module.FileIndex, c.syms[s.itemId][1], buf) expect n, ParLe if n.tagId != sdefTag: @@ -755,6 +748,17 @@ proc loadSym*(c: var DecodeContext; s: PSym) = expect n, SymbolDef # ignore the symbol's name, we have already used it to create this PSym instance! inc n + if n.kind == Ident: + if pool.strings[n.litId] == "x": + s.flagsImpl.incl sfExported + inc n + else: + raiseAssert "expected `x` as the export marker" + elif n.kind == DotToken: + inc n + else: + raiseAssert "expected `x` or '.' but got " & $n.kind + loadField s.magicImpl loadField s.flagsImpl loadField s.optionsImpl @@ -895,20 +899,20 @@ proc loadNode(c: var DecodeContext; n: var Cursor): PNode = else: raiseAssert "Not yet implemented " & $n.kind - -proc loadNifModule*(c: var DecodeContext; f: FileIndex): PNode = - let moduleSuffix = modname(c.moduleToNifSuffix, f.int, c.infos.config) - let modFile = toGeneratedFile(c.infos.config, AbsoluteFile(moduleSuffix), ".nif").string - - var buf = createTokenBuf(300) - var s = nifstreams.open(modFile) - # XXX We can optimize this here and only load the top level entries! - try: - nifcursors.parse(s, buf, NoLineInfo) - finally: - nifstreams.close(s) - var n = cursorAt(buf, 0) - result = loadNode(c, n) +when false: + proc loadNifModule*(c: var DecodeContext; f: FileIndex): PNode = + let moduleSuffix = moduleSuffix(c.infos.config, f) + let modFile = toGeneratedFile(c.infos.config, AbsoluteFile(moduleSuffix), ".nif").string + + var buf = createTokenBuf(300) + var s = nifstreams.open(modFile) + # XXX We can optimize this here and only load the top level entries! + try: + nifcursors.parse(s, buf, NoLineInfo) + finally: + nifstreams.close(s) + var n = cursorAt(buf, 0) + result = loadNode(c, n) when isMainModule: import std / syncio diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 5859abd8b42c..27c8f607e745 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -3435,7 +3435,7 @@ proc genConstDefinition(q: BModule; p: BProc; sym: PSym) = proc genConstStmt(p: BProc, n: PNode) = # This code is only used in the new DCE implementation. - assert useAliveDataFromDce in p.module.flags + assert delayedCodegen(p.module) let m = p.module for it in n: if it[0].kind == nkSym: @@ -3453,7 +3453,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = var sym = n.sym case sym.kind of skMethod: - if useAliveDataFromDce in p.module.flags or {sfDispatcher, sfForward} * sym.flags != {}: + if delayedCodegen(p.module) or {sfDispatcher, sfForward} * sym.flags != {}: # we cannot produce code for the dispatcher yet: fillProcLoc(p.module, n) genProcPrototype(p.module, sym) @@ -3466,7 +3466,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = if sfCompileTime in sym.flags: localError(p.config, n.info, "request to generate code for .compileTime proc: " & sym.name.s) - if useAliveDataFromDce in p.module.flags and sym.typ.callConv != ccInline: + if delayedCodegen(p.module) and sym.typ.callConv != ccInline: fillProcLoc(p.module, n) genProcPrototype(p.module, sym) else: @@ -3479,7 +3479,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = var lit = newBuilder("") genLiteral(p, sym.astdef, sym.typ, lit) putIntoDest(p, d, n, extract(lit), OnStatic) - elif useAliveDataFromDce in p.module.flags: + elif delayedCodegen(p.module): genConstHeader(p.module, p.module, p, sym) assert((sym.loc.snippet != "") and (sym.loc.t != nil)) putLocIntoDest(p, d, sym.loc) @@ -3611,7 +3611,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkWhileStmt: genWhileStmt(p, n) of nkVarSection, nkLetSection: genVarStmt(p, n) of nkConstSection: - if useAliveDataFromDce in p.module.flags: + if delayedCodegen(p.module): genConstStmt(p, n) else: # enforce addressable consts for exportc let m = p.module @@ -3677,7 +3677,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef: if n[genericParamsPos].kind == nkEmpty: var prc = n[namePos].sym - if useAliveDataFromDce in p.module.flags: + if delayedCodegen(p.module): if p.module.alive.contains(prc.itemId.item) and prc.magic in generatedMagics: genProc(p.module, prc) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 518613c1bdfd..5a0c793fe226 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1445,6 +1445,7 @@ proc genProcPrototype(m: BModule, sym: PSym) = getModuleDllPath(m, sym), '"' & name & '"') elif not containsOrIncl(m.declaredProtos, sym.id): + m.queue.add(sym) let asPtr = isReloadable(m, sym) var header = newBuilder("") var visibility: DeclVisibility = None @@ -2506,6 +2507,11 @@ proc writeModule(m: BModule, pending: bool) = let cfile = getCFile(m) if moduleHasChanged(m.g.graph, m.module): genInitCode(m) + + while m.queue.len > 0: + let sym = m.queue.pop() + genProcAux(m, sym) + finishTypeDescriptions(m) if sfMainModule in m.module.flags: # generate main file: diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index f9ed9c6fdae9..b82962898f83 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -155,6 +155,7 @@ type forwTypeCache*: TypeCache # cache for forward declarations of types declaredThings*: IntSet # things we have declared in this .c file declaredProtos*: IntSet # prototypes we have declared in this .c file + queue*: seq[PSym] # queue of procs to generate alive*: IntSet # symbol IDs of alive data as computed by `dce.nim` headerFiles*: seq[string] # needed headers to include typeInfoMarker*: TypeCache # needed for generating type information @@ -178,6 +179,9 @@ template config*(m: BModule): ConfigRef = m.g.config template config*(p: BProc): ConfigRef = p.module.g.config template vccAndC*(p: BProc): bool = p.module.config.cCompiler == ccVcc and p.module.config.backend == backendC +proc delayedCodegen*(m: BModule): bool {.inline.} = + useAliveDataFromDce in m.flags or m.config.globalOptions.contains(optCompress) + proc includeHeader*(this: BModule; header: string) = if not this.headerFiles.contains header: this.headerFiles.add header diff --git a/compiler/msgs.nim b/compiler/msgs.nim index c49ca8c9b128..f0e7419f6873 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -133,6 +133,16 @@ proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile): FileIndex = var dummy: bool = false fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy) +proc registerNifSuffix*(conf: ConfigRef; suffix: string; isKnownFile: var bool): FileIndex = + result = conf.m.filenameToIndexTbl.getOrDefault(suffix, InvalidFileIdx) + if result == InvalidFileIdx: + isKnownFile = false + result = conf.m.fileInfos.len.FileIndex + conf.m.fileInfos.add(newFileInfo(AbsoluteFile suffix, RelativeFile suffix)) + conf.m.filenameToIndexTbl[suffix] = result + else: + isKnownFile = true + proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo = result = TLineInfo(fileIndex: fileInfoIdx) if line < int high(uint16): From 94e94c9458d7c19e746a841f7d0b3b0d25f8468a Mon Sep 17 00:00:00 2001 From: araq Date: Fri, 14 Nov 2025 16:20:43 +0100 Subject: [PATCH 03/28] fixes regression --- compiler/cgen.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 5a0c793fe226..7d0733d90f24 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -506,7 +506,7 @@ include ccgreset proc resetLoc(p: BProc, loc: var TLoc) = let containsGcRef = optSeqDestructors notin p.config.globalOptions and containsGarbageCollectedRef(loc.t) let typ = skipTypes(loc.t, abstractVarRange) - if isImportedCppType(typ): + if isImportedCppType(typ): var didGenTemp = false let rl = rdLoc(loc) let init = genCppInitializer(p.module, p, typ, didGenTemp) @@ -1445,7 +1445,8 @@ proc genProcPrototype(m: BModule, sym: PSym) = getModuleDllPath(m, sym), '"' & name & '"') elif not containsOrIncl(m.declaredProtos, sym.id): - m.queue.add(sym) + if delayedCodegen(m): + m.queue.add(sym) let asPtr = isReloadable(m, sym) var header = newBuilder("") var visibility: DeclVisibility = None From f5f6e6744a1d36295767ba0913afc0e6449cbee9 Mon Sep 17 00:00:00 2001 From: araq Date: Fri, 14 Nov 2025 20:53:09 +0100 Subject: [PATCH 04/28] progress --- compiler/sempass2.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index b0463e76c391..dfb76983a04a 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -372,9 +372,9 @@ proc useVarNoInitCheck(a: PEffects; n: PNode; s: PSym) = proc useVar(a: PEffects, n: PNode) = let s = n.sym - if a.inExceptOrFinallyStmt > 0: - incl s, sfUsedInFinallyOrExcept if isLocalSym(a, s): + if a.inExceptOrFinallyStmt > 0: + incl s, sfUsedInFinallyOrExcept if sfNoInit in s.flags: # If the variable is explicitly marked as .noinit. do not emit any error a.init.add s.id From 89a706fb3c23289d336d5feddaf64f1a797ef7e9 Mon Sep 17 00:00:00 2001 From: araq Date: Sun, 16 Nov 2025 10:00:28 +0100 Subject: [PATCH 05/28] progress --- compiler/ast2nif.nim | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/ast2nif.nim b/compiler/ast2nif.nim index 1528b9d11220..499db5e41df4 100644 --- a/compiler/ast2nif.nim +++ b/compiler/ast2nif.nim @@ -356,14 +356,14 @@ proc trInclude(w: var Writer; n: PNode) = w.deps.addParRi proc trImport(w: var Writer; n: PNode) = - w.deps.addParLe pool.tags.getOrIncl(toNifTag(n.kind)), trLineInfo(w, n.info) for child in n: - assert child.kind == nkSym - let s = child.sym - assert s.kindImpl == skModule - let fp = toFullPath(w.infos.config, s.positionImpl.FileIndex) - w.deps.addStrLit fp - w.deps.addParRi + if child.kind == nkSym: + w.deps.addParLe pool.tags.getOrIncl(toNifTag(n.kind)), trLineInfo(w, n.info) + let s = child.sym + assert s.kindImpl == skModule + let fp = toFullPath(w.infos.config, s.positionImpl.FileIndex) + w.deps.addStrLit fp + w.deps.addParRi proc writeNode(w: var Writer; dest: var TokenBuf; n: PNode) = if n == nil: From ad66f76774c466080e86581a2e972f6e7329b9e3 Mon Sep 17 00:00:00 2001 From: araq Date: Sun, 16 Nov 2025 16:43:28 +0100 Subject: [PATCH 06/28] progress --- compiler/ast2nif.nim | 1 + compiler/ccgtypes.nim | 4 ++-- compiler/cgen.nim | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/ast2nif.nim b/compiler/ast2nif.nim index 499db5e41df4..c99ef3cee462 100644 --- a/compiler/ast2nif.nim +++ b/compiler/ast2nif.nim @@ -425,6 +425,7 @@ proc writeNode(w: var Writer; dest: var TokenBuf; n: PNode) = var ast = n if n[namePos].kind == nkSym: ast = n[namePos].sym.astImpl + if ast == nil: ast = n w.withNode dest, ast: # Process body and other parts for i in 0 ..< ast.len: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index eb81c4e56286..e58c1439b5ed 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -715,7 +715,7 @@ proc genRecordFieldsAux(m: BModule; n: PNode, if field.typ.kind == tyVoid: return #assert(field.ast == nil) let sname = mangleRecFieldName(m, field) - ensureMutable field + #ensureMutable field fillLoc(field.locImpl, locField, n, unionPrefix & sname, OnUnknown) # for importcpp'ed objects, we only need to set field.loc, but don't # have to recurse via 'getTypeDescAux'. And not doing so prevents problems @@ -1212,7 +1212,7 @@ proc genProcHeader(m: BModule; prc: PSym; result: var Builder; visibility: var D # using static is needed for inline procs var check = initIntSet() fillBackendName(m, prc) - ensureMutable prc + #ensureMutable prc fillLoc(prc.locImpl, locProc, prc.ast[namePos], OnUnknown) var rettype: Snippet = "" var desc = newBuilder("") diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 7d0733d90f24..f9737ce3625b 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -63,7 +63,7 @@ proc addForwardedProc(m: BModule, prc: PSym) = proc findPendingModule(m: BModule, s: PSym): BModule = # TODO fixme - if m.config.symbolFiles == v2Sf: + if m.config.symbolFiles == v2Sf or optCompress in m.config.globalOptions: let ms = s.itemId.module #getModule(s) result = m.g.modules[ms] else: @@ -785,7 +785,7 @@ proc fillProcLoc(m: BModule; n: PNode) = let sym = n.sym if sym.loc.k == locNone: fillBackendName(m, sym) - ensureMutable sym + #ensureMutable sym fillLoc(sym.locImpl, locProc, n, OnStack) proc getLabel(p: BProc): TLabel = From a65945cedc6b24b2d65758dfd412036494a7196a Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 16 Nov 2025 20:33:26 +0100 Subject: [PATCH 07/28] progress --- compiler/ast2nif.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/ast2nif.nim b/compiler/ast2nif.nim index c99ef3cee462..dbf388e9d6a8 100644 --- a/compiler/ast2nif.nim +++ b/compiler/ast2nif.nim @@ -478,7 +478,8 @@ proc writeNifModule*(config: ConfigRef; thisModule: int32; n: PNode) = dest.add inner dest.addParRi() - writeFileAndIndex d, dest + writeFile(dest, d) + createIndex(d, false, dest[0].info) # --------------------------- Loader (lazy!) ----------------------------------------------- From 8ad86b00f158ab42f2231e27030f5344967836fb Mon Sep 17 00:00:00 2001 From: araq Date: Mon, 17 Nov 2025 18:38:07 +0100 Subject: [PATCH 08/28] progress --- compiler/ccgexprs.nim | 5 +++- compiler/ccgtypes.nim | 2 +- compiler/cgendata.nim | 2 +- lib/std/private/digitsutils.nim | 4 +++ lib/system/chcks.nim | 47 ++++++++++++++++++++------------- lib/system/dollars.nim | 9 ------- lib/system/memory.nim | 10 +++---- 7 files changed, 44 insertions(+), 35 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 27c8f607e745..1a73f8fbb92f 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -3677,7 +3677,10 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef: if n[genericParamsPos].kind == nkEmpty: var prc = n[namePos].sym - if delayedCodegen(p.module): + if optCompress in p.config.globalOptions: + if prc.magic in generatedMagics: + genProc(p.module, prc) + elif delayedCodegen(p.module): if p.module.alive.contains(prc.itemId.item) and prc.magic in generatedMagics: genProc(p.module, prc) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index e58c1439b5ed..a7b29b9c87cb 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -608,7 +608,7 @@ proc genProcParams(m: BModule; t: PType, rettype: var Rope, params: var Builder, else: descKind = dkRefParam if isCompileTimeOnly(param.typ): continue - ensureMutable param + #ensureMutable param fillParamName(m, param) fillLoc(param.locImpl, locParam, t.n[i], param.paramStorageLoc) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index b82962898f83..479babb0b969 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -119,7 +119,7 @@ type mapping*: Rope # the generated mapping file (if requested) modules*: seq[BModule] # list of all compiled modules modulesClosed*: seq[BModule] # list of the same compiled modules, but in the order they were closed - forwardedProcs*: seq[PSym] # proc:s that did not yet have a body + forwardedProcs*: seq[PSym] # procs that did not yet have a body generatedHeader*: BModule typeInfoMarker*: TypeCacheWithOwner typeInfoMarkerV2*: TypeCacheWithOwner diff --git a/lib/std/private/digitsutils.nim b/lib/std/private/digitsutils.nim index f2d0d25cba55..989a04996700 100644 --- a/lib/std/private/digitsutils.nim +++ b/lib/std/private/digitsutils.nim @@ -29,6 +29,8 @@ const # doAssert res == digits100 # ``` +{.push checks: off, stackTrace: off.} + proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} = buf[pos] = digits100[2 * digits] buf[pos+1] = digits100[2 * digits + 1] @@ -114,3 +116,5 @@ proc addInt*(result: var string; x: int64) {.enforceNoRaises.} = proc addInt*(result: var string; x: int) {.inline, enforceNoRaises.} = addInt(result, int64(x)) + +{.pop.} diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index 1a7d7f0a9038..1653e824ca88 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -9,8 +9,6 @@ # Implementation of some runtime checks. include system/indexerrors -when defined(nimPreviewSlimSystem): - import std/formatfloat proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} = when hostOS == "standalone": @@ -53,12 +51,6 @@ proc raiseRangeErrorI(i, a, b: BiggestInt) {.compilerproc, noinline.} = else: sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b) -proc raiseRangeErrorF(i, a, b: float) {.compilerproc, noinline.} = - when defined(standalone): - sysFatal(RangeDefect, "value out of range") - else: - sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b) - proc raiseRangeErrorU(i, a, b: uint64) {.compilerproc, noinline.} = # todo: better error reporting sysFatal(RangeDefect, "value out of range") @@ -97,16 +89,6 @@ proc chckRangeU(i, a, b: uint64): uint64 {.compilerproc.} = result = 0 sysFatal(RangeDefect, "value out of range") -proc chckRangeF(x, a, b: float): float = - if x >= a and x <= b: - return x - else: - result = 0.0 - when hostOS == "standalone": - sysFatal(RangeDefect, "value out of range") - else: - sysFatal(RangeDefect, "value out of range: ", $x) - proc chckNil(p: pointer) = if p == nil: sysFatal(NilAccessDefect, "attempt to write to a nil address") @@ -164,3 +146,32 @@ when not defined(nimV2): when defined(nimV2): proc raiseObjectCaseTransition() {.compilerproc.} = sysFatal(FieldDefect, "assignment to discriminant changes object branch") + +when defined(nimPreviewSlimSystem): + import std/formatfloat + +when not defined(nimPreviewSlimSystem): + import std/formatfloat + export addFloat + + func `$`*(x: float | float32): string = + ## Outplace version of `addFloat`. + result = "" + result.addFloat(x) + + +proc raiseRangeErrorF(i, a, b: float) {.compilerproc, noinline.} = + when defined(standalone): + sysFatal(RangeDefect, "value out of range") + else: + sysFatal(RangeDefect, "value out of range: " & $i & " notin " & $a & " .. " & $b) + +proc chckRangeF(x, a, b: float): float = + if x >= a and x <= b: + return x + else: + result = 0.0 + when hostOS == "standalone": + sysFatal(RangeDefect, "value out of range") + else: + sysFatal(RangeDefect, "value out of range: ", $x) diff --git a/lib/system/dollars.nim b/lib/system/dollars.nim index e33d6bbc8a02..2025d42964a3 100644 --- a/lib/system/dollars.nim +++ b/lib/system/dollars.nim @@ -5,15 +5,6 @@ runnableExamples: import std/private/[digitsutils, miscdollars] -when not defined(nimPreviewSlimSystem): - import std/formatfloat - export addFloat - - func `$`*(x: float | float32): string = - ## Outplace version of `addFloat`. - result = "" - result.addFloat(x) - template addIntAlias(T: typedesc) = proc `$`*(x: T): string {.raises: [].} = ## Outplace version of `addInt`. diff --git a/lib/system/memory.nim b/lib/system/memory.nim index 156773c4843f..c6c3cb3ab01f 100644 --- a/lib/system/memory.nim +++ b/lib/system/memory.nim @@ -5,7 +5,7 @@ const useLibC = not defined(nimNoLibc) when useLibC: import ansi_c -proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compilerproc, inline.} = +proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compilerproc, inline, enforceNoRaises.} = when useLibC: c_memcpy(dest, source, cast[csize_t](size)) else: @@ -16,7 +16,7 @@ proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compiler d[i] = s[i] inc i -proc nimSetMem*(a: pointer, v: cint, size: Natural) {.nonReloadable, inline.} = +proc nimSetMem*(a: pointer, v: cint, size: Natural) {.nonReloadable, inline, enforceNoRaises.} = when useLibC: c_memset(a, v, cast[csize_t](size)) else: @@ -27,10 +27,10 @@ proc nimSetMem*(a: pointer, v: cint, size: Natural) {.nonReloadable, inline.} = a[i] = v inc i -proc nimZeroMem*(p: pointer, size: Natural) {.compilerproc, nonReloadable, inline.} = +proc nimZeroMem*(p: pointer, size: Natural) {.compilerproc, nonReloadable, inline, enforceNoRaises.} = nimSetMem(p, 0, size) -proc nimCmpMem*(a, b: pointer, size: Natural): cint {.compilerproc, nonReloadable, inline.} = +proc nimCmpMem*(a, b: pointer, size: Natural): cint {.compilerproc, nonReloadable, inline, enforceNoRaises.} = when useLibC: c_memcmp(a, b, cast[csize_t](size)) else: @@ -42,7 +42,7 @@ proc nimCmpMem*(a, b: pointer, size: Natural): cint {.compilerproc, nonReloadabl if d != 0: return d inc i -proc nimCStrLen*(a: cstring): int {.compilerproc, nonReloadable, inline.} = +proc nimCStrLen*(a: cstring): int {.compilerproc, nonReloadable, inline, enforceNoRaises.} = if a.isNil: return 0 when useLibC: cast[int](c_strlen(a)) From d848c7df764475196eb5d21fe1675c0a2d978dad Mon Sep 17 00:00:00 2001 From: araq Date: Tue, 18 Nov 2025 17:04:37 +0100 Subject: [PATCH 09/28] progress --- compiler/cgen.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index f9737ce3625b..af4677e4718a 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1362,7 +1362,8 @@ proc genProcAux*(m: BModule, prc: PSym) = closureSetup(p, prc) genProcBody(p, procBody) - prc.info = tmpInfo + # IC: spurious write, seems fine for now: + prc.infoImpl = tmpInfo var generatedProc = newBuilder("") generatedProc.genCLineDir prc.info, m.config From c308363015daaf134b34dfc94b5b5f079638d824 Mon Sep 17 00:00:00 2001 From: araq Date: Tue, 18 Nov 2025 17:05:48 +0100 Subject: [PATCH 10/28] fixed merge conflict --- lib/std/private/digitsutils.nim | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/std/private/digitsutils.nim b/lib/std/private/digitsutils.nim index f2d0d25cba55..b6d2d10b97a9 100644 --- a/lib/std/private/digitsutils.nim +++ b/lib/std/private/digitsutils.nim @@ -29,18 +29,23 @@ const # doAssert res == digits100 # ``` -proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline.} = +{.push checks: off, stackTrace: off.} + +when not defined(nimHasEnforceNoRaises): + {.pragma: enforceNoRaises.} + +proc utoa2Digits*(buf: var openArray[char]; pos: int; digits: uint32) {.inline, enforceNoRaises.} = buf[pos] = digits100[2 * digits] buf[pos+1] = digits100[2 * digits + 1] #copyMem(buf, unsafeAddr(digits100[2 * digits]), 2 * sizeof((char))) -proc trailingZeros2Digits*(digits: uint32): int {.inline.} = +proc trailingZeros2Digits*(digits: uint32): int {.inline, enforceNoRaises.} = trailingZeros100[digits] when defined(js): proc numToString(a: SomeInteger): cstring {.importjs: "((#) + \"\")".} -func addChars[T](result: var string, x: T, start: int, n: int) {.inline.} = +func addChars[T](result: var string, x: T, start: int, n: int) {.inline, enforceNoRaises.} = let old = result.len result.setLen old + n template impl = @@ -52,10 +57,10 @@ func addChars[T](result: var string, x: T, start: int, n: int) {.inline.} = {.noSideEffect.}: copyMem result[old].addr, x[start].unsafeAddr, n -func addChars[T](result: var string, x: T) {.inline.} = +func addChars[T](result: var string, x: T) {.inline, enforceNoRaises.} = addChars(result, x, 0, x.len) -func addIntImpl(result: var string, x: uint64) {.inline.} = +func addIntImpl(result: var string, x: uint64) {.inline, enforceNoRaises.} = var tmp {.noinit.}: array[24, char] var num = x var next = tmp.len - 1 @@ -79,8 +84,6 @@ func addIntImpl(result: var string, x: uint64) {.inline.} = dec next addChars(result, tmp, next, tmp.len - next) -when not defined(nimHasEnforceNoRaises): - {.pragma: enforceNoRaises.} func addInt*(result: var string, x: uint64) {.enforceNoRaises.} = when nimvm: addIntImpl(result, x) From fff0201c5fe95715f40c5cbda1972b1e43d35d45 Mon Sep 17 00:00:00 2001 From: araq Date: Tue, 18 Nov 2025 17:06:52 +0100 Subject: [PATCH 11/28] system.nim: refactoring that removes cyclic dependencies in prep for IC --- lib/std/assertions.nim | 4 + lib/std/private/miscdollars.nim | 8 +- lib/system.nim | 230 +++++++++++++++++--------------- lib/system/excpt.nim | 56 ++++++-- lib/system/gc_interface.nim | 2 - lib/system/memalloc.nim | 10 +- lib/system/strs_v2.nim | 4 + 7 files changed, 183 insertions(+), 131 deletions(-) diff --git a/lib/std/assertions.nim b/lib/std/assertions.nim index 56c37d205725..f31a8465afb9 100644 --- a/lib/std/assertions.nim +++ b/lib/std/assertions.nim @@ -19,12 +19,16 @@ import std/private/miscdollars type InstantiationInfo = tuple[filename: string, line: int, column: int] +{.push overflowChecks: off, rangeChecks: off.} + proc `$`(info: InstantiationInfo): string = # The +1 is needed here # instead of overriding `$` (and changing its meaning), consider explicit name. result = "" result.toLocation(info.filename, info.line, info.column + 1) +{.pop.} + # --------------------------------------------------------------------------- diff --git a/lib/std/private/miscdollars.nim b/lib/std/private/miscdollars.nim index 06fda6fa1a0f..77ba158b0ca6 100644 --- a/lib/std/private/miscdollars.nim +++ b/lib/std/private/miscdollars.nim @@ -4,7 +4,13 @@ template toLocation*(result: var string, file: string | cstring, line: int, col: ## avoids spurious allocations # Hopefully this can be re-used everywhere so that if a user needs to customize, # it can be done in a single place. - result.add file + when file is cstring: + var i = 0 + while file[i] != '\0': + add(result, file[i]) + inc i + else: + result.add file if line > 0: result.add "(" addInt(result, line) diff --git a/lib/system.nim b/lib/system.nim index fece232b34d7..e6d0bd0bed88 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1766,6 +1766,111 @@ template newException*(exceptn: typedesc, message: string; ## to `message`. Returns the new exception object. (ref exceptn)(msg: message, parent: parentException) +# we have to compute this here before turning it off in except.nim anyway ... +const NimStackTrace = compileOption("stacktrace") +const + usesDestructors = defined(gcDestructors) or defined(gcHooks) + +when notJSnotNims: + proc setControlCHook*(hook: proc () {.noconv.}) {.raises: [], gcsafe.} + ## Allows you to override the behaviour of your application when CTRL+C + ## is pressed. Only one such hook is supported. + ## + ## The handler runs inside a C signal handler and comes with similar + ## limitations. + ## + ## Allocating memory and interacting with most system calls, including using + ## `echo`, `string`, `seq`, raising or catching exceptions etc is undefined + ## behavior and will likely lead to application crashes. + ## + ## The OS may call the ctrl-c handler from any thread, including threads + ## that were not created by Nim, such as happens on Windows. + ## + ## ## Example: + ## + ## ```nim + ## var stop: Atomic[bool] + ## proc ctrlc() {.noconv.} = + ## # Using atomics types is safe! + ## stop.store(true) + ## + ## setControlCHook(ctrlc) + ## + ## while not stop.load(): + ## echo "Still running.." + ## sleep(1000) + ## ``` + + when not defined(noSignalHandler) and not defined(useNimRtl): + proc unsetControlCHook*() + ## Reverts a call to setControlCHook. + + when hostOS != "standalone": + proc getStackTrace*(): string {.gcsafe.} + ## Gets the current stack trace. This only works for debug builds. + + proc getStackTrace*(e: ref Exception): string {.gcsafe.} + ## Gets the stack trace associated with `e`, which is the stack that + ## lead to the `raise` statement. This only works for debug builds. + + var + globalRaiseHook*: proc (e: ref Exception): bool {.nimcall, benign.} + ## With this hook you can influence exception handling on a global level. + ## If not nil, every 'raise' statement ends up calling this hook. + ## + ## .. warning:: Ordinary application code should never set this hook! You better know what you do when setting this. + ## + ## If `globalRaiseHook` returns false, the exception is caught and does + ## not propagate further through the call stack. + + localRaiseHook* {.threadvar.}: proc (e: ref Exception): bool {.nimcall, benign.} + ## With this hook you can influence exception handling on a + ## thread local level. + ## If not nil, every 'raise' statement ends up calling this hook. + ## + ## .. warning:: Ordinary application code should never set this hook! You better know what you do when setting this. + ## + ## If `localRaiseHook` returns false, the exception + ## is caught and does not propagate further through the call stack. + + outOfMemHook*: proc () {.nimcall, tags: [], benign, raises: [].} + ## Set this variable to provide a procedure that should be called + ## in case of an `out of memory`:idx: event. The standard handler + ## writes an error message and terminates the program. + ## + ## `outOfMemHook` can be used to raise an exception in case of OOM like so: + ## + ## ```nim + ## var gOutOfMem: ref EOutOfMemory + ## new(gOutOfMem) # need to be allocated *before* OOM really happened! + ## gOutOfMem.msg = "out of memory" + ## + ## proc handleOOM() = + ## raise gOutOfMem + ## + ## system.outOfMemHook = handleOOM + ## ``` + ## + ## If the handler does not raise an exception, ordinary control flow + ## continues and the program is terminated. + + unhandledExceptionHook*: proc (e: ref Exception) {.nimcall, tags: [], benign, raises: [].} + ## Set this variable to provide a procedure that should be called + ## in case of an `unhandle exception` event. The standard handler + ## writes an error message and terminates the program, except when + ## using `--os:any` + + {.push stackTrace: off, profiler: off.} + when defined(memtracker): + include "system/memtracker" + + when hostOS == "standalone": + include "system/embedded" + else: + include "system/excpt" + {.pop.} + + when not defined(nimPreviewSlimSystem): import std/assertions export assertions @@ -1844,9 +1949,6 @@ proc `<`*[T: tuple](x, y: T): bool = include "system/gc_interface" -# we have to compute this here before turning it off in except.nim anyway ... -const NimStackTrace = compileOption("stacktrace") - import system/coro_detection {.push checks: off.} @@ -1855,53 +1957,6 @@ import system/coro_detection # however, stack-traces are available for most parts # of the code -when notJSnotNims: - var - globalRaiseHook*: proc (e: ref Exception): bool {.nimcall, benign.} - ## With this hook you can influence exception handling on a global level. - ## If not nil, every 'raise' statement ends up calling this hook. - ## - ## .. warning:: Ordinary application code should never set this hook! You better know what you do when setting this. - ## - ## If `globalRaiseHook` returns false, the exception is caught and does - ## not propagate further through the call stack. - - localRaiseHook* {.threadvar.}: proc (e: ref Exception): bool {.nimcall, benign.} - ## With this hook you can influence exception handling on a - ## thread local level. - ## If not nil, every 'raise' statement ends up calling this hook. - ## - ## .. warning:: Ordinary application code should never set this hook! You better know what you do when setting this. - ## - ## If `localRaiseHook` returns false, the exception - ## is caught and does not propagate further through the call stack. - - outOfMemHook*: proc () {.nimcall, tags: [], benign, raises: [].} - ## Set this variable to provide a procedure that should be called - ## in case of an `out of memory`:idx: event. The standard handler - ## writes an error message and terminates the program. - ## - ## `outOfMemHook` can be used to raise an exception in case of OOM like so: - ## - ## ```nim - ## var gOutOfMem: ref EOutOfMemory - ## new(gOutOfMem) # need to be allocated *before* OOM really happened! - ## gOutOfMem.msg = "out of memory" - ## - ## proc handleOOM() = - ## raise gOutOfMem - ## - ## system.outOfMemHook = handleOOM - ## ``` - ## - ## If the handler does not raise an exception, ordinary control flow - ## continues and the program is terminated. - unhandledExceptionHook*: proc (e: ref Exception) {.nimcall, tags: [], benign, raises: [].} - ## Set this variable to provide a procedure that should be called - ## in case of an `unhandle exception` event. The standard handler - ## writes an error message and terminates the program, except when - ## using `--os:any` - when defined(js) or defined(nimdoc): proc add*(x: var string, y: cstring) {.asmNoStackFrame.} = ## Appends `y` to `x` in place. @@ -2028,6 +2083,16 @@ template unlikely*(val: bool): bool = import system/dollars export dollars +when notJSnotNims: + {.push stackTrace: off, profiler: off.} + + include "system/chcks" + + # we cannot compile this with stack tracing on + # as it would recurse endlessly! + include "system/integerops" + {.pop.} + when defined(nimAuditDelete): {.pragma: auditDelete, deprecated: "review this call for out of bounds behavior".} else: @@ -2110,17 +2175,17 @@ when notJSnotNims: nimZeroMem(p, size) when declared(memTrackerOp): memTrackerOp("zeroMem", p, size) - proc copyMem(dest, source: pointer, size: Natural) = + proc copyMem(dest, source: pointer, size: Natural) {.enforceNoRaises.} = nimCopyMem(dest, source, size) when declared(memTrackerOp): memTrackerOp("copyMem", dest, size) - proc moveMem(dest, source: pointer, size: Natural) = + proc moveMem(dest, source: pointer, size: Natural) {.enforceNoRaises.} = c_memmove(dest, source, csize_t(size)) when declared(memTrackerOp): memTrackerOp("moveMem", dest, size) - proc equalMem(a, b: pointer, size: Natural): bool = + proc equalMem(a, b: pointer, size: Natural): bool {.enforceNoRaises.} = nimCmpMem(a, b, size) == 0 - proc cmpMem(a, b: pointer, size: Natural): int = + proc cmpMem(a, b: pointer, size: Natural): int {.enforceNoRaises.} = nimCmpMem(a, b, size).int when not defined(js) or defined(nimscript): @@ -2194,63 +2259,6 @@ when not defined(js): when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom() when declared(initGC): initGC() -when notJSnotNims: - proc setControlCHook*(hook: proc () {.noconv.}) {.raises: [], gcsafe.} - ## Allows you to override the behaviour of your application when CTRL+C - ## is pressed. Only one such hook is supported. - ## - ## The handler runs inside a C signal handler and comes with similar - ## limitations. - ## - ## Allocating memory and interacting with most system calls, including using - ## `echo`, `string`, `seq`, raising or catching exceptions etc is undefined - ## behavior and will likely lead to application crashes. - ## - ## The OS may call the ctrl-c handler from any thread, including threads - ## that were not created by Nim, such as happens on Windows. - ## - ## ## Example: - ## - ## ```nim - ## var stop: Atomic[bool] - ## proc ctrlc() {.noconv.} = - ## # Using atomics types is safe! - ## stop.store(true) - ## - ## setControlCHook(ctrlc) - ## - ## while not stop.load(): - ## echo "Still running.." - ## sleep(1000) - ## ``` - - when not defined(noSignalHandler) and not defined(useNimRtl): - proc unsetControlCHook*() - ## Reverts a call to setControlCHook. - - when hostOS != "standalone": - proc getStackTrace*(): string {.gcsafe.} - ## Gets the current stack trace. This only works for debug builds. - - proc getStackTrace*(e: ref Exception): string {.gcsafe.} - ## Gets the stack trace associated with `e`, which is the stack that - ## lead to the `raise` statement. This only works for debug builds. - - {.push stackTrace: off, profiler: off.} - when defined(memtracker): - include "system/memtracker" - - when hostOS == "standalone": - include "system/embedded" - else: - include "system/excpt" - include "system/chcks" - - # we cannot compile this with stack tracing on - # as it would recurse endlessly! - include "system/integerops" - {.pop.} - when not defined(js): # this is a hack: without this when statement, you would get: diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 511839914f0f..18ebc1c609b8 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -42,11 +42,13 @@ proc writeToStdErr(msg: string) {.inline.} = # fix bug #13115: handles correctly '\0' unlike default implicit conversion to cstring writeToStdErr(msg.cstring, msg.len) +proc cstrToStrBuiltin(x: cstring): string {.magic: "CStrToStr", noSideEffect.} + proc showErrorMessage(data: cstring, length: int) {.gcsafe, raises: [].} = var toWrite = true if errorMessageWriter != nil: try: - errorMessageWriter($data) + errorMessageWriter(cstrToStrBuiltin data) toWrite = false except: discard @@ -261,7 +263,10 @@ template addFrameEntry(s: var string, f: StackTraceEntry|PFrame) = var oldLen = s.len s.toLocation(f.filename, f.line, 0) for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ') - add(s, f.procname) + var i = 0 + while f.procname[i] != '\0': + add(s, f.procname[i]) + inc i when NimStackTraceMsgs: when typeof(f) is StackTraceEntry: add(s, f.frameMsg) @@ -283,8 +288,34 @@ proc `$`(stackTraceEntries: seq[StackTraceEntry]): string = else: addFrameEntry(result, s[i]) when hasSomeStackTrace: - - proc auxWriteStackTrace(f: PFrame, s: var string) = + const + Ten = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] + + proc i2s(x: int64): string = + # quick reimplementation; optimized for code size, no dependencies + if x < 0: + if x == -9223372036854775808: + result = "-9223372036854775808" + else: + result = "-" & i2s(0-x) + elif x < 10: + result = Ten[int x] # saves allocations + else: + var y = x + while true: + result.add char((y mod 10) + int('0')) + y = y div 10 + if y == 0: break + let last = result.len-1 + var i = 0 + let b = result.len div 2 + while i < b: + let ch = result[i] + result[i] = result[last-i] + result[last-i] = ch + inc i + + proc auxWriteStackTrace(f: PFrame, s: var string) {.raises: [].} = when hasThreadSupport: var tempFrames: array[maxStackTraceLines, PFrame] # but better than a threadvar @@ -322,14 +353,14 @@ when hasSomeStackTrace: for j in countdown(i-1, 0): if tempFrames[j] == nil: add(s, "(") - add(s, $skipped) + s.add(i2s(skipped)) add(s, " calls omitted) ...\n") else: addFrameEntry(s, tempFrames[j]) proc stackTraceAvailable*(): bool - proc rawWriteStackTrace(s: var string) = + proc rawWriteStackTrace(s: var string) {.raises: [].} = when defined(nimStackTraceOverride): add(s, "Traceback (most recent call last, using override)\n") auxWriteStackTraceWithOverride(s) @@ -388,7 +419,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy, gcsafe.} = add(buf, "Error: unhandled exception: ") add(buf, e.msg) add(buf, " [") - add(buf, $e.name) + add(buf, cstrToStrBuiltin(e.name)) add(buf, "]\n") if onUnhandledException != nil: @@ -408,7 +439,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy, gcsafe.} = var buf: array[0..2000, char] var L = 0 if e.trace.len != 0: - var trace = $e.trace + var trace = cstrToStrBuiltin(e.trace) add(buf, trace) {.gcsafe.}: `=destroy`(trace) @@ -559,10 +590,11 @@ const nimCallDepthLimit {.intdefine.} = 2000 proc callDepthLimitReached() {.noinline.} = writeStackTrace() - let msg = "Error: call depth limit reached in a debug build (" & - $nimCallDepthLimit & " function calls). You can change it with " & - "-d:nimCallDepthLimit= but really try to avoid deep " & - "recursions instead.\n" + var msg = "Error: call depth limit reached in a debug build (" + msg.add(i2s(nimCallDepthLimit)) + msg.add(" function calls). You can change it with " & + "-d:nimCallDepthLimit= but really try to avoid deep " & + "recursions instead.\n") showErrorMessage2(msg) rawQuit(1) diff --git a/lib/system/gc_interface.nim b/lib/system/gc_interface.nim index 4540db21f21d..b34ce4a566d8 100644 --- a/lib/system/gc_interface.nim +++ b/lib/system/gc_interface.nim @@ -1,6 +1,4 @@ # ----------------- GC interface --------------------------------------------- -const - usesDestructors = defined(gcDestructors) or defined(gcHooks) when not usesDestructors: {.pragma: nodestroy.} diff --git a/lib/system/memalloc.nim b/lib/system/memalloc.nim index 63473573476e..b26f3af24d11 100644 --- a/lib/system/memalloc.nim +++ b/lib/system/memalloc.nim @@ -1,13 +1,13 @@ when notJSnotNims: proc zeroMem*(p: pointer, size: Natural) {.inline, noSideEffect, - tags: [], raises: [].} + tags: [], raises: [], enforceNoRaises.} ## Overwrites the contents of the memory at `p` with the value 0. ## ## Exactly `size` bytes will be overwritten. Like any procedure ## dealing with raw memory this is **unsafe**. proc copyMem*(dest, source: pointer, size: Natural) {.inline, benign, - tags: [], raises: [].} + tags: [], raises: [], enforceNoRaises.} ## Copies the contents from the memory at `source` to the memory ## at `dest`. ## Exactly `size` bytes will be copied. The memory @@ -15,7 +15,7 @@ when notJSnotNims: ## memory this is **unsafe**. proc moveMem*(dest, source: pointer, size: Natural) {.inline, benign, - tags: [], raises: [].} + tags: [], raises: [], enforceNoRaises.} ## Copies the contents from the memory at `source` to the memory ## at `dest`. ## @@ -25,7 +25,7 @@ when notJSnotNims: ## dealing with raw memory this is still **unsafe**, though. proc equalMem*(a, b: pointer, size: Natural): bool {.inline, noSideEffect, - tags: [], raises: [].} + tags: [], raises: [], enforceNoRaises.} ## Compares the memory blocks `a` and `b`. `size` bytes will ## be compared. ## @@ -34,7 +34,7 @@ when notJSnotNims: ## **unsafe**. proc cmpMem*(a, b: pointer, size: Natural): int {.inline, noSideEffect, - tags: [], raises: [].} + tags: [], raises: [], enforceNoRaises.} ## Compares the memory blocks `a` and `b`. `size` bytes will ## be compared. ## diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim index 1b44e9123cfa..1bc8fb7d789c 100644 --- a/lib/system/strs_v2.nim +++ b/lib/system/strs_v2.nim @@ -23,6 +23,8 @@ type const nimStrVersion {.core.} = 2 +{.push overflowChecks: off, rangeChecks: off.} + template isLiteral(s): bool = (s.p == nil) or (s.p.cap and strlitFlag) == strlitFlag template contentSize(cap): int = cap + 1 + sizeof(NimStrPayloadBase) @@ -227,3 +229,5 @@ func capacity*(self: string): int {.inline.} = let str = cast[ptr NimStringV2](unsafeAddr self) result = if str.p != nil: str.p.cap and not strlitFlag else: 0 + +{.pop.} From 62943390eb8d7756320c6018e272310f06052e5f Mon Sep 17 00:00:00 2001 From: araq Date: Tue, 18 Nov 2025 17:12:53 +0100 Subject: [PATCH 12/28] progress --- lib/system/excpt.nim | 59 +++++++++++++++++++-------------------- lib/system/threadimpl.nim | 2 +- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 18ebc1c609b8..f9e6ec9a85f5 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -287,34 +287,34 @@ proc `$`(stackTraceEntries: seq[StackTraceEntry]): string = elif s[i].line == reraisedFromEnd: result.add "]]\n" else: addFrameEntry(result, s[i]) -when hasSomeStackTrace: - const - Ten = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] - - proc i2s(x: int64): string = - # quick reimplementation; optimized for code size, no dependencies - if x < 0: - if x == -9223372036854775808: - result = "-9223372036854775808" - else: - result = "-" & i2s(0-x) - elif x < 10: - result = Ten[int x] # saves allocations +const + Ten = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] + +proc i2s(x: int64): string = + # quick reimplementation; optimized for code size, no dependencies + if x < 0: + if x == -9223372036854775808: + result = "-9223372036854775808" else: - var y = x - while true: - result.add char((y mod 10) + int('0')) - y = y div 10 - if y == 0: break - let last = result.len-1 - var i = 0 - let b = result.len div 2 - while i < b: - let ch = result[i] - result[i] = result[last-i] - result[last-i] = ch - inc i + result = "-" & i2s(0-x) + elif x < 10: + result = Ten[int x] # saves allocations + else: + var y = x + while true: + result.add char((y mod 10) + int('0')) + y = y div 10 + if y == 0: break + let last = result.len-1 + var i = 0 + let b = result.len div 2 + while i < b: + let ch = result[i] + result[i] = result[last-i] + result[last-i] = ch + inc i +when hasSomeStackTrace: proc auxWriteStackTrace(f: PFrame, s: var string) {.raises: [].} = when hasThreadSupport: var @@ -439,7 +439,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy, gcsafe.} = var buf: array[0..2000, char] var L = 0 if e.trace.len != 0: - var trace = cstrToStrBuiltin(e.trace) + var trace = $e.trace add(buf, trace) {.gcsafe.}: `=destroy`(trace) @@ -449,7 +449,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy, gcsafe.} = xadd(buf, e.name, e.name.len) add(buf, "]\n") if onUnhandledException != nil: - onUnhandledException($cast[cstring](buf.addr)) + onUnhandledException(cstrToStrBuiltin(cast[cstring](buf.addr))) else: showErrorMessage(cast[cstring](buf.addr), L) @@ -546,8 +546,7 @@ proc reraiseException() {.compilerRtl.} = else: raiseExceptionAux(currException) -proc threadTrouble() = - # also forward declared, it is 'raises: []' hence the try-except. +proc threadTrouble() {.raises: [], gcsafe.} = try: if currException != nil: reportUnhandledError(currException) except: diff --git a/lib/system/threadimpl.nim b/lib/system/threadimpl.nim index 093a920a1d53..dcd1b267a03b 100644 --- a/lib/system/threadimpl.nim +++ b/lib/system/threadimpl.nim @@ -2,7 +2,7 @@ var nimThreadDestructionHandlers* {.rtlThreadVar.}: seq[proc () {.closure, gcsafe, raises: [].}] when not defined(boehmgc) and not hasSharedHeap and not defined(gogc) and not defined(gcRegions): proc deallocOsPages() {.rtl, raises: [].} -proc threadTrouble() {.raises: [], gcsafe.} + # create for the main thread. Note: do not insert this data into the list # of all threads; it's not to be stopped etc. when not defined(useNimRtl): From c82697251e802afea3f82bf7794897e6e1aae4ba Mon Sep 17 00:00:00 2001 From: araq Date: Tue, 18 Nov 2025 17:41:26 +0100 Subject: [PATCH 13/28] and again --- lib/system.nim | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index e6d0bd0bed88..b1774b965f65 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1754,6 +1754,15 @@ type when NimStackTraceMsgs: frameMsgLen*: int ## end position in frameMsgBuf for this frame. +when notJSnotNims and not gotoBasedExceptions: + type + PSafePoint = ptr TSafePoint + TSafePoint {.compilerproc, final.} = object + prev: PSafePoint # points to next safe point ON THE STACK + status: int + context: C_JmpBuf + SafePoint = TSafePoint + when defined(nimV2): var framePtr {.threadvar.}: PFrame @@ -2238,15 +2247,6 @@ when not defined(js) and declared(alloc0) and declared(dealloc): inc(i) dealloc(a) -when notJSnotNims and not gotoBasedExceptions: - type - PSafePoint = ptr TSafePoint - TSafePoint {.compilerproc, final.} = object - prev: PSafePoint # points to next safe point ON THE STACK - status: int - context: C_JmpBuf - SafePoint = TSafePoint - when not defined(js): when hasThreadSupport: when hostOS != "standalone": From 76a2b884f7f40723d3a2fd54879ca1d7308869c2 Mon Sep 17 00:00:00 2001 From: araq Date: Tue, 18 Nov 2025 18:35:43 +0100 Subject: [PATCH 14/28] and again --- lib/system/excpt.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index f9e6ec9a85f5..ea0eb13c8134 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -632,7 +632,7 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and {.emit: "#endif".} except Exception: msg = currException.getStackTrace() & "Error: unhandled exception: " & - currException.msg & " [" & $currException.name & "]" + currException.msg & " [" & cstrToStrBuiltin(currException.name) & "]" except StdException as e: msg = "Error: unhandled cpp exception: " & $e.what() except: From 6de6de980a136a124d9408ac97af5418b45a9bb8 Mon Sep 17 00:00:00 2001 From: araq Date: Tue, 18 Nov 2025 18:39:13 +0100 Subject: [PATCH 15/28] progress --- lib/system/memory.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/system/memory.nim b/lib/system/memory.nim index 156773c4843f..c6c3cb3ab01f 100644 --- a/lib/system/memory.nim +++ b/lib/system/memory.nim @@ -5,7 +5,7 @@ const useLibC = not defined(nimNoLibc) when useLibC: import ansi_c -proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compilerproc, inline.} = +proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compilerproc, inline, enforceNoRaises.} = when useLibC: c_memcpy(dest, source, cast[csize_t](size)) else: @@ -16,7 +16,7 @@ proc nimCopyMem*(dest, source: pointer, size: Natural) {.nonReloadable, compiler d[i] = s[i] inc i -proc nimSetMem*(a: pointer, v: cint, size: Natural) {.nonReloadable, inline.} = +proc nimSetMem*(a: pointer, v: cint, size: Natural) {.nonReloadable, inline, enforceNoRaises.} = when useLibC: c_memset(a, v, cast[csize_t](size)) else: @@ -27,10 +27,10 @@ proc nimSetMem*(a: pointer, v: cint, size: Natural) {.nonReloadable, inline.} = a[i] = v inc i -proc nimZeroMem*(p: pointer, size: Natural) {.compilerproc, nonReloadable, inline.} = +proc nimZeroMem*(p: pointer, size: Natural) {.compilerproc, nonReloadable, inline, enforceNoRaises.} = nimSetMem(p, 0, size) -proc nimCmpMem*(a, b: pointer, size: Natural): cint {.compilerproc, nonReloadable, inline.} = +proc nimCmpMem*(a, b: pointer, size: Natural): cint {.compilerproc, nonReloadable, inline, enforceNoRaises.} = when useLibC: c_memcmp(a, b, cast[csize_t](size)) else: @@ -42,7 +42,7 @@ proc nimCmpMem*(a, b: pointer, size: Natural): cint {.compilerproc, nonReloadabl if d != 0: return d inc i -proc nimCStrLen*(a: cstring): int {.compilerproc, nonReloadable, inline.} = +proc nimCStrLen*(a: cstring): int {.compilerproc, nonReloadable, inline, enforceNoRaises.} = if a.isNil: return 0 when useLibC: cast[int](c_strlen(a)) From 855e60651f2e62963e60f8dfdc4ef336cabdf0e1 Mon Sep 17 00:00:00 2001 From: araq Date: Tue, 18 Nov 2025 20:33:18 +0100 Subject: [PATCH 16/28] progress --- lib/system/excpt.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index ea0eb13c8134..719224f16b3b 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -597,6 +597,8 @@ proc callDepthLimitReached() {.noinline.} = showErrorMessage2(msg) rawQuit(1) +{.push overflowChecks: off.} + proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} = if framePtr == nil: s.calldepth = 0 @@ -608,6 +610,8 @@ proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} = framePtr = s if s.calldepth == nimCallDepthLimit: callDepthLimitReached() +{.pop.} + when defined(cpp) and appType != "lib" and not gotoBasedExceptions and not defined(js) and not defined(nimscript) and hostOS != "standalone" and hostOS != "any" and not defined(noCppExceptions) and From 843bb14807b9d5402ec5ca22f5f782fbd59ee349 Mon Sep 17 00:00:00 2001 From: araq Date: Tue, 18 Nov 2025 20:34:41 +0100 Subject: [PATCH 17/28] progress --- lib/system/excpt.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index ea0eb13c8134..c5d82a27883d 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -597,6 +597,8 @@ proc callDepthLimitReached() {.noinline.} = showErrorMessage2(msg) rawQuit(1) +{.push overflowChecks: off.} + proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} = if framePtr == nil: s.calldepth = 0 @@ -608,6 +610,8 @@ proc nimFrame(s: PFrame) {.compilerRtl, inl, raises: [].} = framePtr = s if s.calldepth == nimCallDepthLimit: callDepthLimitReached() +{.pop.} + when defined(cpp) and appType != "lib" and not gotoBasedExceptions and not defined(js) and not defined(nimscript) and hostOS != "standalone" and hostOS != "any" and not defined(noCppExceptions) and @@ -634,7 +638,7 @@ when defined(cpp) and appType != "lib" and not gotoBasedExceptions and msg = currException.getStackTrace() & "Error: unhandled exception: " & currException.msg & " [" & cstrToStrBuiltin(currException.name) & "]" except StdException as e: - msg = "Error: unhandled cpp exception: " & $e.what() + msg = "Error: unhandled cpp exception: " & cstrToStrBuiltin(e.what()) except: msg = "Error: unhandled unknown cpp exception" From 51028a828d01e6a40a882e02e3b5792f0cae827a Mon Sep 17 00:00:00 2001 From: araq Date: Tue, 18 Nov 2025 21:25:35 +0100 Subject: [PATCH 18/28] yay --- lib/system.nim | 43 ++++++++++++++++++++++--------------------- lib/system/excpt.nim | 4 +++- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index b1774b965f65..5813651869cb 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1740,6 +1740,28 @@ when not defined(nimscript): when not declared(sysFatal): include "system/fatal" +proc echo*(x: varargs[typed, `$`]) {.magic: "Echo", benign, sideEffect.} + ## Writes and flushes the parameters to the standard output. + ## + ## Special built-in that takes a variable number of arguments. Each argument + ## is converted to a string via `$`, so it works for user-defined + ## types that have an overloaded `$` operator. + ## It is roughly equivalent to `writeLine(stdout, x); flushFile(stdout)`, but + ## available for the JavaScript target too. + ## + ## Unlike other IO operations this is guaranteed to be thread-safe as + ## `echo` is very often used for debugging convenience. If you want to use + ## `echo` inside a `proc without side effects + ## `_ you can use `debugEcho + ## <#debugEcho,varargs[typed,]>`_ instead. + +proc debugEcho*(x: varargs[typed, `$`]) {.magic: "Echo", noSideEffect, + tags: [], raises: [].} + ## Same as `echo <#echo,varargs[typed,]>`_, but as a special semantic rule, + ## `debugEcho` pretends to be free of side effects, so that it can be used + ## for debugging routines marked as `noSideEffect + ## `_. + type PFrame* = ptr TFrame ## Represents a runtime frame of the call stack; ## part of the debugger API. @@ -2002,27 +2024,6 @@ elif hasAlloc: inc(i) {.pop.} -proc echo*(x: varargs[typed, `$`]) {.magic: "Echo", benign, sideEffect.} - ## Writes and flushes the parameters to the standard output. - ## - ## Special built-in that takes a variable number of arguments. Each argument - ## is converted to a string via `$`, so it works for user-defined - ## types that have an overloaded `$` operator. - ## It is roughly equivalent to `writeLine(stdout, x); flushFile(stdout)`, but - ## available for the JavaScript target too. - ## - ## Unlike other IO operations this is guaranteed to be thread-safe as - ## `echo` is very often used for debugging convenience. If you want to use - ## `echo` inside a `proc without side effects - ## `_ you can use `debugEcho - ## <#debugEcho,varargs[typed,]>`_ instead. - -proc debugEcho*(x: varargs[typed, `$`]) {.magic: "Echo", noSideEffect, - tags: [], raises: [].} - ## Same as `echo <#echo,varargs[typed,]>`_, but as a special semantic rule, - ## `debugEcho` pretends to be free of side effects, so that it can be used - ## for debugging routines marked as `noSideEffect - ## `_. when hostOS == "standalone" and defined(nogc): proc nimToCStringConv(s: NimString): cstring {.compilerproc, inline.} = diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index c5d82a27883d..2fb958999f0e 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -43,6 +43,8 @@ proc writeToStdErr(msg: string) {.inline.} = writeToStdErr(msg.cstring, msg.len) proc cstrToStrBuiltin(x: cstring): string {.magic: "CStrToStr", noSideEffect.} +when defined(genode): + template `$`(s: string): string = s proc showErrorMessage(data: cstring, length: int) {.gcsafe, raises: [].} = var toWrite = true @@ -55,7 +57,7 @@ proc showErrorMessage(data: cstring, length: int) {.gcsafe, raises: [].} = if toWrite: when defined(genode): # stderr not available by default, use the LOG session - echo data + echo cstrToStrBuiltin(data) else: writeToStdErr(data, length) From 3bf692b3559f19ab6ebc0f168e6e3e27e42a9e05 Mon Sep 17 00:00:00 2001 From: araq Date: Wed, 19 Nov 2025 11:25:14 +0100 Subject: [PATCH 19/28] progress --- compiler/ccgtypes.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index a7b29b9c87cb..d5745c6983e6 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -158,8 +158,8 @@ proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope = else: break let typ = if typ.kind in {tyAlias, tySink, tyOwned}: typ.elementType else: typ - ensureMutable typ if typ.loc.snippet == "": + ensureMutable typ typ.typeName(typ.locImpl.snippet) typ.locImpl.snippet.add $sig else: From 65e0c9abc32196af820ceca7422094360c622b1c Mon Sep 17 00:00:00 2001 From: araq Date: Wed, 19 Nov 2025 11:33:36 +0100 Subject: [PATCH 20/28] no regrets --- lib/system.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/system.nim b/lib/system.nim index 5813651869cb..9ef8128c2d46 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1802,6 +1802,8 @@ const NimStackTrace = compileOption("stacktrace") const usesDestructors = defined(gcDestructors) or defined(gcHooks) +include "system/gc_interface" + when notJSnotNims: proc setControlCHook*(hook: proc () {.noconv.}) {.raises: [], gcsafe.} ## Allows you to override the behaviour of your application when CTRL+C @@ -1978,8 +1980,6 @@ proc `<`*[T: tuple](x, y: T): bool = return false -include "system/gc_interface" - import system/coro_detection {.push checks: off.} From e13291f80584fe8c46a27e330f2130cce38f8f40 Mon Sep 17 00:00:00 2001 From: araq Date: Wed, 19 Nov 2025 17:51:39 +0100 Subject: [PATCH 21/28] progress --- compiler/ccgtypes.nim | 3 ++- lib/system.nim | 22 +++++++++++++++++++--- lib/system/strs_v2.nim | 14 -------------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index d5745c6983e6..019307fcc7c0 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -2056,6 +2056,7 @@ proc genTypeInfo*(config: ConfigRef, m: BModule; t: PType; info: TLineInfo): Rop proc genTypeSection(m: BModule, n: PNode) = var intSet = initIntSet() + let compress = optCompress in m.config.globalOptions for i in 0.. Date: Wed, 19 Nov 2025 20:35:44 +0100 Subject: [PATCH 22/28] merge conflict problem --- lib/system/strs_v2.nim | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/system/strs_v2.nim b/lib/system/strs_v2.nim index df5f481a8c78..9861c9ae4e43 100644 --- a/lib/system/strs_v2.nim +++ b/lib/system/strs_v2.nim @@ -11,8 +11,6 @@ {.push overflowChecks: off, rangeChecks: off.} -{.push overflowChecks: off, rangeChecks: off.} - template isLiteral(s): bool = (s.p == nil) or (s.p.cap and strlitFlag) == strlitFlag template contentSize(cap): int = cap + 1 + sizeof(NimStrPayloadBase) From 15124f05b6d9d67292653382187f1cd6b977cbf0 Mon Sep 17 00:00:00 2001 From: Araq Date: Wed, 19 Nov 2025 22:47:44 +0100 Subject: [PATCH 23/28] progress --- compiler/ccgexprs.nim | 6 +++--- lib/system/arc.nim | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 68d2871bf722..b5ece69ae643 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -170,7 +170,7 @@ proc canMove(p: BProc, n: PNode; dest: TLoc): bool = template simpleAsgn(builder: var Builder, dest, src: TLoc) = let rd = rdLoc(dest) let rs = rdLoc(src) - builder.addAssignment(rd, rs) + builder.addAssignment(rd, rs) proc genRefAssign(p: BProc, dest, src: TLoc) = if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config): @@ -675,7 +675,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = if e[2].kind in {nkIntLit..nkInt64Lit}: needsOverflowCheck = e[2].intVal == -1 if canBeZero: - # remove extra paren from `==` op here to avoid Wparentheses-equality: + # remove extra paren from `==` op here to avoid Wparentheses-equality: p.s(cpsStmts).addSingleIfStmt(removeSinglePar(cOp(Equal, rdLoc(b), cIntValue(0)))): p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "raiseDivByZero")) raiseInstr(p, p.s(cpsStmts)) @@ -696,7 +696,7 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = let ra = rdLoc(a) if optOverflowCheck in p.options: let first = cIntLiteral(firstOrd(p.config, t)) - # remove extra paren from `==` op here to avoid Wparentheses-equality: + # remove extra paren from `==` op here to avoid Wparentheses-equality: p.s(cpsStmts).addSingleIfStmt(removeSinglePar(cOp(Equal, ra, first))): p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "raiseOverflow")) raiseInstr(p, p.s(cpsStmts)) diff --git a/lib/system/arc.nim b/lib/system/arc.nim index 5677013013d0..14da1531c28b 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -14,7 +14,7 @@ at offset 0 then. The ``ref`` object header is independent from the runtime type and only contains a reference count. ]# -{.push raises: [].} +{.push raises: [], rangeChecks: off.} when defined(gcOrc): const From 9d7007a2a743f1f83b3d9dac5e7ead698143da2c Mon Sep 17 00:00:00 2001 From: araq Date: Thu, 20 Nov 2025 13:25:37 +0100 Subject: [PATCH 24/28] progress --- compiler/cgen.nim | 28 +++++++++------ compiler/inliner.nim | 81 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 compiler/inliner.nim diff --git a/compiler/cgen.nim b/compiler/cgen.nim index b39e5ffedc58..598b77ecdb09 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1467,6 +1467,8 @@ proc genProcPrototype(m: BModule, sym: PSym) = m.s[cfsProcHeaders].add(extract(header)) m.s[cfsProcHeaders].finishProcHeaderAsProto() +include inliner + # TODO: figure out how to rename this - it DOES generate a forward declaration proc genProcNoForward(m: BModule, prc: PSym) = if lfImportCompilerProc in prc.loc.flags: @@ -1505,16 +1507,22 @@ proc genProcNoForward(m: BModule, prc: PSym) = #if prc.loc.k == locNone: # mangle the inline proc based on the module where it is defined - # not on the first module that uses it - let m2 = if m.config.symbolFiles != disabledSf: m - else: findPendingModule(m, prc) - fillProcLoc(m2, prc.ast[namePos]) - #elif {sfExportc, sfImportc} * prc.flags == {}: - # # reset name to restore consistency in case of hashing collisions: - # echo "resetting ", prc.id, " by ", m.module.name.s - # prc.loc.snippet = nil - # prc.loc.snippet = mangleName(m, prc) - genProcPrototype(m, prc) - genProcAux(m, prc) + if optCompress in m.config.globalOptions: + let prcCopy = copyInlineProc(prc, m.idgen) + fillProcLoc(m, prcCopy.ast[namePos]) + genProcPrototype(m, prcCopy) + genProcAux(m, prcCopy) + else: + let m2 = if m.config.symbolFiles != disabledSf: m + else: findPendingModule(m, prc) + fillProcLoc(m2, prc.ast[namePos]) + #elif {sfExportc, sfImportc} * prc.flags == {}: + # # reset name to restore consistency in case of hashing collisions: + # echo "resetting ", prc.id, " by ", m.module.name.s + # prc.loc.snippet = nil + # prc.loc.snippet = mangleName(m, prc) + genProcPrototype(m, prc) + genProcAux(m, prc) elif sfImportc notin prc.flags: var q = findPendingModule(m, prc) fillProcLoc(q, prc.ast[namePos]) diff --git a/compiler/inliner.nim b/compiler/inliner.nim new file mode 100644 index 000000000000..31620ae99e5a --- /dev/null +++ b/compiler/inliner.nim @@ -0,0 +1,81 @@ + + +proc copyInlineProcBody(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerator): PNode = + case n.kind + of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: + result = n + of nkSym: + let sym = locals.getOrDefault(n.sym.id) + if sym != nil: + result = newSymNode(sym, n.info) + else: + result = n + of nkLetSection, nkVarSection, nkConstSection: + result = shallowCopy(n) + for i in 0.. Date: Thu, 20 Nov 2025 18:13:15 +0100 Subject: [PATCH 25/28] progress --- compiler/inliner.nim | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/compiler/inliner.nim b/compiler/inliner.nim index 31620ae99e5a..7f7a68d8da8f 100644 --- a/compiler/inliner.nim +++ b/compiler/inliner.nim @@ -1,6 +1,6 @@ -proc copyInlineProcBody(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerator): PNode = +proc copyInlineProcBody(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerator; owner: PSym): PNode = case n.kind of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: result = n @@ -20,11 +20,12 @@ proc copyInlineProcBody(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerat if it[0].kind == nkSym: let oldSym = it[0].sym let newSym = copySym(oldSym, idgen) + setOwner(newSym, owner) locals[oldSym.id] = newSym result[i] = shallowCopy(it) result[i][0] = newSymNode(newSym, oldSym.info) for j in 1.. 0: + result.typ.n.add copyNode(prc.typ.n[0]) + for i in 0.. Date: Thu, 20 Nov 2025 18:58:24 +0100 Subject: [PATCH 26/28] progress --- compiler/inliner.nim | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/inliner.nim b/compiler/inliner.nim index 7f7a68d8da8f..becf88007ab6 100644 --- a/compiler/inliner.nim +++ b/compiler/inliner.nim @@ -47,22 +47,23 @@ proc copyInlineProcBody(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerat result = shallowCopy(n) for i in 0.. Date: Fri, 21 Nov 2025 15:09:09 +0100 Subject: [PATCH 27/28] progress --- compiler/cgen.nim | 2 +- compiler/inliner.nim | 59 +++++++++++++++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 598b77ecdb09..b1893cabfbf9 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1507,7 +1507,7 @@ proc genProcNoForward(m: BModule, prc: PSym) = #if prc.loc.k == locNone: # mangle the inline proc based on the module where it is defined - # not on the first module that uses it - if optCompress in m.config.globalOptions: + if m.module.itemId.module != prc.itemId.module and optCompress in m.config.globalOptions: let prcCopy = copyInlineProc(prc, m.idgen) fillProcLoc(m, prcCopy.ast[namePos]) genProcPrototype(m, prcCopy) diff --git a/compiler/inliner.nim b/compiler/inliner.nim index becf88007ab6..a8f032bccc4f 100644 --- a/compiler/inliner.nim +++ b/compiler/inliner.nim @@ -1,4 +1,18 @@ +proc copySymdef(n: PNode; locals: var Table[int, PSym]; idgen: IdGenerator; owner: PSym): PNode = + case n.kind + of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit: + result = n + of nkSym: + let oldSym = n.sym + let newSym = copySym(oldSym, idgen) + setOwner(newSym, owner) + locals[oldSym.id] = newSym + result = newSymNode(newSym, oldSym.info) + else: + result = shallowCopy(n) + for i in 0.. 0: result.typ.n.add copyNode(prc.typ.n[0]) + for i in 1.. Date: Fri, 21 Nov 2025 21:22:58 +0100 Subject: [PATCH 28/28] progress --- compiler/ccgtypes.nim | 27 ++++++++++--------- lib/system.nim | 62 +++++++++++++++++++++---------------------- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 019307fcc7c0..ce49d4de41fc 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -2054,18 +2054,21 @@ proc genTypeInfo*(config: ConfigRef, m: BModule; t: PType; info: TLineInfo): Rop else: result = genTypeInfoV1(m, t, info) +proc retrieveSym(n: PNode): PSym = + case n.kind + of nkPostfix: result = retrieveSym(n[1]) + of nkPragmaExpr, nkTypeDef: result = retrieveSym(n[0]) + of nkSym: result = n.sym + else: result = nil + proc genTypeSection(m: BModule, n: PNode) = var intSet = initIntSet() let compress = optCompress in m.config.globalOptions - for i in 0..