Files
Nim/compiler/ccgliterals.nim
Andreas Rumpf a690a9ac90 YRC: threadsafe cycle collection for Nim (#25495)
First performance numbers:

time tests/arc/torcbench   -- YRC
true peak memory: true

real    0m0,163s
user    0m0,161s
sys     0m0,002s


time tests/arc/torcbench   -- ORC
true peak memory: true

real    0m0,107s
user    0m0,104s
sys     0m0,003s


So it's 1.6x slower. But it's threadsafe and provably correct. (Lean and
model checking via TLA+ used.)

Of course there is always the chance that the implementation is wrong
and doesn't match the model.
2026-02-10 00:04:11 +01:00

153 lines
5.7 KiB
Nim

#
#
# The Nim Compiler
# (c) Copyright 2018 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# included from cgen.nim
## This include file contains the logic to produce constant string
## and seq literals. The code here is responsible that
## ``const x = ["a", "b"]`` works without hidden runtime creation code.
## The price is that seqs and strings are not purely a library
## implementation.
template detectVersion(field, corename) =
if m.g.config.selectedGC in {gcArc, gcOrc, gcYrc, gcAtomicArc, gcHooks}:
result = 2
else:
result = 1
proc detectStrVersion(m: BModule): int =
detectVersion(strVersion, "nimStrVersion")
proc detectSeqVersion(m: BModule): int =
detectVersion(seqVersion, "nimSeqVersion")
# ----- Version 1: GC'ed strings and seqs --------------------------------
proc genStringLiteralDataOnlyV1(m: BModule, s: string; result: var Rope) =
cgsym(m, "TGenericSeq")
let tmp = getTempName(m)
result.add tmp
var res = newBuilder("")
res.addVarWithTypeAndInitializer(AlwaysConst, name = tmp):
res.addSimpleStruct(m, name = "", baseType = ""):
res.addField(name = "Sup", typ = "TGenericSeq")
res.addArrayField(name = "data", elementType = NimChar, len = s.len + 1)
do:
var strInit: StructInitializer
res.addStructInitializer(strInit, kind = siOrderedStruct):
res.addField(strInit, name = "Sup"):
var seqInit: StructInitializer
res.addStructInitializer(seqInit, kind = siOrderedStruct):
res.addField(seqInit, name = "len"):
res.addIntValue(s.len)
res.addField(seqInit, name = "reserved"):
res.add(cCast(NimInt, cOp(BitOr, NimUint, cCast(NimUint, cIntValue(s.len)), NimStrlitFlag)))
res.addField(strInit, name = "data"):
res.add(makeCString(s))
m.s[cfsStrData].add(extract(res))
proc genStringLiteralV1(m: BModule; n: PNode; result: var Builder) =
if s.isNil:
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), NimNil))
else:
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var name: string = ""
if id == m.labels:
# string literal not found in the cache:
genStringLiteralDataOnlyV1(m, n.strVal, name)
else:
name = m.tmpBase & $id
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), cAddr(name)))
# ------ Version 2: destructor based strings and seqs -----------------------
proc genStringLiteralDataOnlyV2(m: BModule, s: string; result: Rope; isConst: bool) =
var res = newBuilder("")
res.addVarWithTypeAndInitializer(
if isConst: AlwaysConst else: Global,
name = result):
res.addSimpleStruct(m, name = "", baseType = ""):
res.addField(name = "cap", typ = NimInt)
res.addArrayField(name = "data", elementType = NimChar, len = s.len + 1)
do:
var structInit: StructInitializer
res.addStructInitializer(structInit, kind = siOrderedStruct):
res.addField(structInit, name = "cap"):
res.add(cOp(BitOr, NimInt, cIntValue(s.len), NimStrlitFlag))
res.addField(structInit, name = "data"):
res.add(makeCString(s))
m.s[cfsStrData].add(extract(res))
proc genStringLiteralV2(m: BModule; n: PNode; isConst: bool; result: var Builder) =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var litName: string
if id == m.labels:
cgsym(m, "NimStrPayload")
cgsym(m, "NimStringV2")
# string literal not found in the cache:
litName = getTempName(m)
genStringLiteralDataOnlyV2(m, n.strVal, litName, isConst)
else:
litName = m.tmpBase & $id
let tmp = getTempName(m)
result.add tmp
var res = newBuilder("")
res.addVarWithInitializer(
if isConst: AlwaysConst else: Global,
name = tmp,
typ = "NimStringV2"):
var strInit: StructInitializer
res.addStructInitializer(strInit, kind = siOrderedStruct):
res.addField(strInit, name = "len"):
res.addIntValue(n.strVal.len)
res.addField(strInit, name = "p"):
res.add(cCast(ptrType("NimStrPayload"), cAddr(litName)))
m.s[cfsStrData].add(extract(res))
proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Builder) =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var pureLit: Rope
if id == m.labels:
pureLit = getTempName(m)
cgsym(m, "NimStrPayload")
cgsym(m, "NimStringV2")
# string literal not found in the cache:
genStringLiteralDataOnlyV2(m, n.strVal, pureLit, isConst)
else:
pureLit = m.tmpBase & rope(id)
var strInit: StructInitializer
result.addStructInitializer(strInit, kind = siOrderedStruct):
result.addField(strInit, name = "len"):
result.addIntValue(n.strVal.len)
result.addField(strInit, name = "p"):
result.add(cCast(ptrType("NimStrPayload"), cAddr(pureLit)))
# ------ Version selector ---------------------------------------------------
proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
isConst: bool; result: var Rope) =
case detectStrVersion(m)
of 0, 1: genStringLiteralDataOnlyV1(m, s, result)
of 2:
let tmp = getTempName(m)
genStringLiteralDataOnlyV2(m, s, tmp, isConst)
result.add tmp
else:
localError(m.config, info, "cannot determine how to produce code for string literal")
proc genNilStringLiteral(m: BModule; info: TLineInfo; result: var Builder) =
result.add(cCast(ptrType(cgsymValue(m, "NimStringDesc")), NimNil))
proc genStringLiteral(m: BModule; n: PNode; result: var Builder) =
case detectStrVersion(m)
of 0, 1: genStringLiteralV1(m, n, result)
of 2: genStringLiteralV2(m, n, isConst = true, result)
else:
localError(m.config, n.info, "cannot determine how to produce code for string literal")