mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-01 03:13:41 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
063b03e0ed | ||
|
|
a6222bb2a6 | ||
|
|
8785e64efc | ||
|
|
63f2cd33f8 |
@@ -216,10 +216,6 @@ proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
|
||||
result[0] = le
|
||||
result[1] = ri
|
||||
|
||||
proc markInjectDestructors(s: PSym) {.inline.} =
|
||||
backendEnsureMutable s
|
||||
s.flagsImpl.incl sfInjectDestructors
|
||||
|
||||
proc makeClosure*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; env: PNode; info: TLineInfo): PNode =
|
||||
result = newNodeIT(nkClosure, info, prc.typ)
|
||||
result.add(newSymNode(prc))
|
||||
@@ -232,7 +228,7 @@ proc makeClosure*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; env: PNode; inf
|
||||
#if isClosureIterator(result.typ):
|
||||
createTypeBoundOps(g, nil, result.typ, info, idgen)
|
||||
if tfHasAsgn in result.typ.flags or optSeqDestructors in g.config.globalOptions:
|
||||
markInjectDestructors(prc)
|
||||
prc.incl sfInjectDestructors
|
||||
|
||||
template liftingHarmful(conf: ConfigRef; owner: PSym): bool =
|
||||
## lambda lifting can be harmful for JS-like code generators.
|
||||
@@ -244,7 +240,7 @@ proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; idgen
|
||||
createTypeBoundOps(g, nil, refType.elementType, info, idgen)
|
||||
createTypeBoundOps(g, nil, refType, info, idgen)
|
||||
if tfHasAsgn in refType.flags or optSeqDestructors in g.config.globalOptions:
|
||||
markInjectDestructors(owner)
|
||||
owner.incl sfInjectDestructors
|
||||
|
||||
proc genCreateEnv(env: PNode): PNode =
|
||||
var c = newNodeIT(nkObjConstr, env.info, env.typ)
|
||||
@@ -640,7 +636,7 @@ proc rawClosureCreation(owner: PSym;
|
||||
if owner.kind != skMacro:
|
||||
createTypeBoundOps(d.graph, nil, fieldAccess.typ, env.info, d.idgen)
|
||||
if tfHasAsgn in fieldAccess.typ.flags or optSeqDestructors in d.graph.config.globalOptions:
|
||||
markInjectDestructors(owner)
|
||||
owner.incl sfInjectDestructors
|
||||
|
||||
let upField = lookupInRecord(env.typ.skipTypes({tyOwned, tyRef, tyPtr}).n, getIdent(d.graph.cache, upName))
|
||||
if upField != nil:
|
||||
|
||||
@@ -741,7 +741,7 @@ proc replaceHookMagic*(c: PContext, n: PNode, kind: TTypeAttachedOp): PNode =
|
||||
case kind
|
||||
of attachedDestructor:
|
||||
result = n
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar, tySink})
|
||||
let t = n[1].typ.skipTypes(abstractVar)
|
||||
let op = getAttachedOp(c.graph, t, attachedDestructor)
|
||||
if op != nil:
|
||||
result[0] = newSymNode(op)
|
||||
@@ -753,13 +753,13 @@ proc replaceHookMagic*(c: PContext, n: PNode, kind: TTypeAttachedOp): PNode =
|
||||
result[1] = skipAddr(n[1])
|
||||
of attachedTrace:
|
||||
result = n
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar, tySink})
|
||||
let t = n[1].typ.skipTypes(abstractVar)
|
||||
let op = getAttachedOp(c.graph, t, attachedTrace)
|
||||
if op != nil:
|
||||
result[0] = newSymNode(op)
|
||||
of attachedDup:
|
||||
result = n
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar, tySink})
|
||||
let t = n[1].typ.skipTypes(abstractVar)
|
||||
let op = getAttachedOp(c.graph, t, attachedDup)
|
||||
if op != nil:
|
||||
result[0] = newSymNode(op)
|
||||
@@ -769,7 +769,7 @@ proc replaceHookMagic*(c: PContext, n: PNode, kind: TTypeAttachedOp): PNode =
|
||||
result.add boolLit
|
||||
of attachedWasMoved:
|
||||
result = n
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar, tySink})
|
||||
let t = n[1].typ.skipTypes(abstractVar)
|
||||
let op = getAttachedOp(c.graph, t, attachedWasMoved)
|
||||
if op != nil:
|
||||
result[0] = newSymNode(op)
|
||||
@@ -780,7 +780,7 @@ proc replaceHookMagic*(c: PContext, n: PNode, kind: TTypeAttachedOp): PNode =
|
||||
result = c.semAsgnOpr(c, n, nkAsgn)
|
||||
of attachedDeepCopy:
|
||||
result = n
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar, tySink})
|
||||
let t = n[1].typ.skipTypes(abstractVar)
|
||||
let op = getAttachedOp(c.graph, t, kind)
|
||||
if op != nil:
|
||||
result[0] = newSymNode(op)
|
||||
|
||||
@@ -35,9 +35,7 @@ proc semAddr(c: PContext; n: PNode): PNode =
|
||||
let x = semExprWithType(c, n)
|
||||
if x.kind == nkSym:
|
||||
x.sym.flagsImpl.incl(sfAddrTaken)
|
||||
let aa = isAssignable(c, x)
|
||||
if aa notin {arLValue, arLocalLValue, arAddressableConst, arLentValue} and
|
||||
(aa != arDiscriminant or c.inUncheckedAssignSection <= 0):
|
||||
if isAssignable(c, x) notin {arLValue, arLocalLValue, arAddressableConst, arLentValue}:
|
||||
localError(c.config, n.info, errExprHasNoAddress)
|
||||
result.add x
|
||||
result.typ = makePtrType(c, x.typ.skipTypes({tySink}))
|
||||
|
||||
@@ -1164,7 +1164,7 @@ proc trackCall(tracked: PEffects; n: PNode) =
|
||||
var (isHook, opKind) = findHookKind(a.sym.name.s)
|
||||
if isHook:
|
||||
# rebind type bounds operations after createTypeBoundOps call
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar, tySink})
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar})
|
||||
if a.sym != getAttachedOp(tracked.graph, t, opKind):
|
||||
createTypeBoundOps(tracked, t, n.info, explicit = true)
|
||||
# replace builtin hooks with lifted ones
|
||||
|
||||
@@ -118,6 +118,21 @@ proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PNode; isFirstWrite
|
||||
le.flags.incl nfFirstWrite
|
||||
result[1] = ri
|
||||
|
||||
proc resolveBorrowedRoutineSym(c: PTransf; s: PSym; info: TLineInfo): PSym =
|
||||
# Follow borrow aliases to the underlying implementation symbol.
|
||||
result = nil
|
||||
var s = s
|
||||
while true:
|
||||
# Skips over all borrowed procs getting the last proc symbol without an implementation.
|
||||
let body = getBody(c.graph, s)
|
||||
if body.kind == nkSym and sfBorrow in body.sym.flags and getBody(c.graph, body.sym).kind == nkSym:
|
||||
s = body.sym
|
||||
else:
|
||||
if body.kind != nkSym:
|
||||
internalError(c.graph.config, info, "wrong AST for borrowed symbol")
|
||||
return body.sym
|
||||
internalError(c.graph.config, info, "wrong AST for borrowed symbol")
|
||||
|
||||
proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||
let s = n.sym
|
||||
if s.typ != nil and s.typ.callConv == ccClosure:
|
||||
@@ -136,17 +151,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||
var tc = c.transCon
|
||||
if sfBorrow in s.flags and s.kind in routineKinds:
|
||||
# simply exchange the symbol:
|
||||
var s = s
|
||||
while true:
|
||||
# Skips over all borrowed procs getting the last proc symbol without an implementation
|
||||
let body = getBody(c.graph, s)
|
||||
if body.kind == nkSym and sfBorrow in body.sym.flags and getBody(c.graph, body.sym).kind == nkSym:
|
||||
s = body.sym
|
||||
else:
|
||||
break
|
||||
b = getBody(c.graph, s)
|
||||
if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol")
|
||||
b = newSymNode(b.sym, n.info)
|
||||
b = newSymNode(resolveBorrowedRoutineSym(c, s, n.info), n.info)
|
||||
elif c.inlining > 0:
|
||||
# see bug #13596: we use ref-based equality in the DFA for destruction
|
||||
# injections so we need to ensure unique nodes after iterator inlining
|
||||
@@ -785,7 +790,9 @@ proc transformFor(c: PTransf, n: PNode): PNode =
|
||||
|
||||
discard c.breakSyms.pop
|
||||
|
||||
let iter = call[0].sym
|
||||
var iter = call[0].sym
|
||||
if sfBorrow in iter.flags and iter.kind in routineKinds:
|
||||
iter = resolveBorrowedRoutineSym(c, iter, n.info)
|
||||
|
||||
var v = newNodeI(nkVarSection, n.info)
|
||||
for i in 0..<n.len - 2:
|
||||
|
||||
@@ -127,12 +127,11 @@ type
|
||||
# reaches dealloc while the source chunk is active.
|
||||
# Instead, the receiving chunk gains the capacity and thus reserves space in the foreign chunk.
|
||||
acc: uint32 # Offset from data, used when there are no free cells available but the chunk is considered free.
|
||||
foreignCells: int32 # When a free cell is given to a chunk that is not its origin,
|
||||
foreignCells: int # When a free cell is given to a chunk that is not its origin,
|
||||
# both the cell and the source chunk are considered foreign.
|
||||
# Receiving a foreign cell can happen both when deallocating from another thread or when
|
||||
# the active chunk in `a.freeSmallChunks` is not the current chunk.
|
||||
# Freeing a chunk while `foreignCells > 0` leaks memory as all references to it become lost.
|
||||
chunkAlignOff: int32 # Byte offset from `data` where cells begin. Non-zero for alignment > MemAlign.
|
||||
data {.align: MemAlign.}: UncheckedArray[byte] # start of usable memory
|
||||
|
||||
BigChunk = object of BaseChunk # not necessarily > PageSize!
|
||||
@@ -473,8 +472,8 @@ iterator allObjects(m: var MemRegion): pointer {.inline.} =
|
||||
var c = cast[PSmallChunk](c)
|
||||
|
||||
let size = c.size
|
||||
var a = cast[int](addr(c.data)) + c.chunkAlignOff.int
|
||||
let limit = cast[int](addr(c.data)) + c.acc.int
|
||||
var a = cast[int](addr(c.data))
|
||||
let limit = a + c.acc.int
|
||||
while a <% limit:
|
||||
yield cast[pointer](a)
|
||||
a = a +% size
|
||||
@@ -852,15 +851,6 @@ when defined(heaptrack):
|
||||
proc heaptrack_malloc(a: pointer, size: int) {.cdecl, importc, dynlib: heaptrackLib.}
|
||||
proc heaptrack_free(a: pointer) {.cdecl, importc, dynlib: heaptrackLib.}
|
||||
|
||||
proc smallChunkAlignOffset(alignment: int): int {.inline.} =
|
||||
## Compute the initial data offset so that data + result + sizeof(FreeCell)
|
||||
## is alignment-aligned within a page-aligned small chunk.
|
||||
if alignment <= MemAlign:
|
||||
result = 0
|
||||
else:
|
||||
result = align(smallChunkOverhead() + sizeof(FreeCell), alignment) -
|
||||
smallChunkOverhead() - sizeof(FreeCell)
|
||||
|
||||
proc bigChunkAlignOffset(alignment: int): int {.inline.} =
|
||||
## Compute the alignment offset for big chunk data.
|
||||
if alignment == 0:
|
||||
@@ -873,13 +863,14 @@ proc rawAlloc(a: var MemRegion, requestedSize: int, alignment: int = 0): pointer
|
||||
inc(a.allocCounter)
|
||||
sysAssert(allocInv(a), "rawAlloc: begin")
|
||||
sysAssert(roundup(65, 8) == 72, "rawAlloc: roundup broken")
|
||||
var size = roundup(requestedSize, max(MemAlign, alignment))
|
||||
let alignOff = smallChunkAlignOffset(alignment)
|
||||
var size = roundup(requestedSize, MemAlign)
|
||||
sysAssert(size >= sizeof(FreeCell), "rawAlloc: requested size too small")
|
||||
sysAssert(size >= requestedSize, "insufficient allocated size!")
|
||||
#c_fprintf(stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
|
||||
|
||||
if size + alignOff <= SmallChunkSize-smallChunkOverhead():
|
||||
# For custom alignments > MemAlign, force big chunk allocation
|
||||
# Small chunks cannot handle arbitrary alignments due to fixed cell boundaries
|
||||
if size <= SmallChunkSize-smallChunkOverhead() and alignment == 0:
|
||||
template fetchSharedCells(tc: PSmallChunk) =
|
||||
# Consumes cells from (potentially) foreign threads from `a.sharedFreeLists[s]`
|
||||
when defined(gcDestructors):
|
||||
@@ -897,19 +888,16 @@ proc rawAlloc(a: var MemRegion, requestedSize: int, alignment: int = 0): pointer
|
||||
# allocate a small block: for small chunks, we use only its next pointer
|
||||
let s = size div MemAlign
|
||||
var c = a.freeSmallChunks[s]
|
||||
if c != nil and c.chunkAlignOff != alignOff.int32:
|
||||
c = nil
|
||||
if c == nil:
|
||||
# There is no free chunk of the requested size available, we need a new one.
|
||||
c = getSmallChunk(a)
|
||||
# init all fields in case memory didn't get zeroed
|
||||
c.freeList = nil
|
||||
c.foreignCells = 0
|
||||
c.chunkAlignOff = alignOff.int32
|
||||
sysAssert c.size == PageSize, "rawAlloc 3"
|
||||
c.size = size
|
||||
c.acc = (alignOff + size).uint32
|
||||
c.free = SmallChunkSize - smallChunkOverhead() - alignOff.int32 - size.int32
|
||||
c.acc = size.uint32
|
||||
c.free = SmallChunkSize - smallChunkOverhead() - size.int32
|
||||
sysAssert c.owner == addr(a), "rawAlloc: No owner set!"
|
||||
c.next = nil
|
||||
c.prev = nil
|
||||
@@ -920,7 +908,7 @@ proc rawAlloc(a: var MemRegion, requestedSize: int, alignment: int = 0): pointer
|
||||
# Because removals from `a.freeSmallChunks[s]` only happen in the other alloc branch and during dealloc,
|
||||
# we must not add it to the list if it cannot be used the next time a pointer of `size` bytes is needed.
|
||||
listAdd(a.freeSmallChunks[s], c)
|
||||
result = addr(c.data) +! alignOff
|
||||
result = addr(c.data)
|
||||
sysAssert((cast[int](result) and (MemAlign-1)) == 0, "rawAlloc 4")
|
||||
else:
|
||||
# There is a free chunk of the requested size available, use it.
|
||||
@@ -962,7 +950,7 @@ proc rawAlloc(a: var MemRegion, requestedSize: int, alignment: int = 0): pointer
|
||||
sysAssert(allocInv(a), "rawAlloc: before listRemove test")
|
||||
listRemove(a.freeSmallChunks[s], c)
|
||||
sysAssert(allocInv(a), "rawAlloc: end listRemove test")
|
||||
sysAssert(((cast[int](result) and PageMask) - smallChunkOverhead() - c.chunkAlignOff) %%
|
||||
sysAssert(((cast[int](result) and PageMask) - smallChunkOverhead()) %%
|
||||
size == 0, "rawAlloc 21")
|
||||
sysAssert(allocInv(a), "rawAlloc: end small size")
|
||||
inc a.occ, size
|
||||
@@ -1030,7 +1018,7 @@ proc rawDealloc(a: var MemRegion, p: pointer) =
|
||||
dec a.occ, s
|
||||
untrackSize(s)
|
||||
sysAssert a.occ >= 0, "rawDealloc: negative occupied memory (case A)"
|
||||
sysAssert(((cast[int](p) and PageMask) - smallChunkOverhead() - c.chunkAlignOff) %%
|
||||
sysAssert(((cast[int](p) and PageMask) - smallChunkOverhead()) %%
|
||||
s == 0, "rawDealloc 3")
|
||||
when not defined(gcDestructors):
|
||||
#echo("setting to nil: ", $cast[int](addr(f.zeroField)))
|
||||
@@ -1041,8 +1029,7 @@ proc rawDealloc(a: var MemRegion, p: pointer) =
|
||||
nimSetMem(cast[pointer](cast[int](p) +% sizeof(FreeCell)), -1'i32,
|
||||
s -% sizeof(FreeCell))
|
||||
let activeChunk = a.freeSmallChunks[s div MemAlign]
|
||||
if activeChunk != nil and c != activeChunk and
|
||||
activeChunk.chunkAlignOff == c.chunkAlignOff:
|
||||
if activeChunk != nil and c != activeChunk:
|
||||
# This pointer is not part of the active chunk, lend it out
|
||||
# and do not adjust the current chunk (same logic as compensateCounters.)
|
||||
# Put the cell into the active chunk,
|
||||
@@ -1089,7 +1076,7 @@ proc rawDealloc(a: var MemRegion, p: pointer) =
|
||||
|
||||
when defined(gcDestructors):
|
||||
addToSharedFreeList(c, f, s div MemAlign)
|
||||
sysAssert(((cast[int](p) and PageMask) - smallChunkOverhead() - c.chunkAlignOff) %%
|
||||
sysAssert(((cast[int](p) and PageMask) - smallChunkOverhead()) %%
|
||||
s == 0, "rawDealloc 2")
|
||||
else:
|
||||
# set to 0xff to check for usage after free bugs:
|
||||
@@ -1115,11 +1102,8 @@ when not defined(gcDestructors):
|
||||
var c = cast[PSmallChunk](c)
|
||||
var offset = (cast[int](p) and (PageSize-1)) -%
|
||||
smallChunkOverhead()
|
||||
if c.acc.int >% offset:
|
||||
let ao = c.chunkAlignOff.int
|
||||
result = (offset >= ao) and
|
||||
((offset -% ao) %% c.size == 0) and
|
||||
(cast[ptr FreeCell](p).zeroField >% 1)
|
||||
result = (c.acc.int >% offset) and (offset %% c.size == 0) and
|
||||
(cast[ptr FreeCell](p).zeroField >% 1)
|
||||
else:
|
||||
var c = cast[PBigChunk](c)
|
||||
# prev stores the aligned data pointer set during rawAlloc
|
||||
@@ -1138,12 +1122,11 @@ when not defined(gcDestructors):
|
||||
var c = cast[PSmallChunk](c)
|
||||
var offset = (cast[int](p) and (PageSize-1)) -%
|
||||
smallChunkOverhead()
|
||||
let ao = c.chunkAlignOff.int
|
||||
if c.acc.int >% offset and offset >= ao:
|
||||
if c.acc.int >% offset:
|
||||
sysAssert(cast[int](addr(c.data)) +% offset ==
|
||||
cast[int](p), "offset is not what you think it is")
|
||||
var d = cast[ptr FreeCell](cast[int](addr(c.data)) +%
|
||||
ao +% ((offset -% ao) -% ((offset -% ao) %% c.size)))
|
||||
offset -% (offset %% c.size))
|
||||
if d.zeroField >% 1:
|
||||
result = d
|
||||
sysAssert isAllocatedPtr(a, result), " result wrong pointer!"
|
||||
@@ -1274,20 +1257,6 @@ template instantiateForRegion(allocator: untyped) {.dirty.} =
|
||||
proc alloc0Impl(size: Natural): pointer =
|
||||
result = alloc0(allocator, size)
|
||||
|
||||
when defined(gcOrc) or defined(gcYrc):
|
||||
proc nimAlignedAlloc0(size: Natural, alignment: int): pointer =
|
||||
incStat(allocCount)
|
||||
result = rawAlloc(allocator, size, alignment)
|
||||
zeroMem(result, size)
|
||||
|
||||
proc nimAlignedAlloc(size: Natural, alignment: int): pointer =
|
||||
incStat(allocCount)
|
||||
result = rawAlloc(allocator, size, alignment)
|
||||
|
||||
proc nimAlignedDealloc(p: pointer) =
|
||||
incStat(deallocCount)
|
||||
rawDealloc(allocator, p)
|
||||
|
||||
proc deallocImpl(p: pointer) =
|
||||
dealloc(allocator, p)
|
||||
|
||||
|
||||
@@ -92,27 +92,12 @@ else:
|
||||
when not defined(nimHasQuirky):
|
||||
{.pragma: quirky.}
|
||||
|
||||
# Forward declarations for native allocator alignment (implemented in alloc.nim).
|
||||
# rawAlloc's contract: result + sizeof(FreeCell) is alignment-aligned.
|
||||
# For ORC/YRC, sizeof(FreeCell) == sizeof(RefHeader).
|
||||
const useNativeAlignedAlloc = (defined(gcOrc) or defined(gcYrc)) and
|
||||
not defined(useMalloc) and not defined(nimscript) and
|
||||
not defined(nimdoc) and not defined(useNimRtl)
|
||||
|
||||
when useNativeAlignedAlloc:
|
||||
proc nimAlignedAlloc0(size: Natural, alignment: int): pointer {.gcsafe, raises: [].}
|
||||
proc nimAlignedAlloc(size: Natural, alignment: int): pointer {.gcsafe, raises: [].}
|
||||
proc nimAlignedDealloc(p: pointer) {.gcsafe, raises: [].}
|
||||
|
||||
proc nimNewObj(size, alignment: int): pointer {.compilerRtl.} =
|
||||
when defined(nimscript) or defined(nimdoc):
|
||||
let hdrSize = align(sizeof(RefHeader), alignment)
|
||||
let s = size +% hdrSize
|
||||
when defined(nimscript):
|
||||
discard
|
||||
elif useNativeAlignedAlloc:
|
||||
let s = size +% sizeof(RefHeader)
|
||||
result = nimAlignedAlloc0(s, alignment) +! sizeof(RefHeader)
|
||||
else:
|
||||
let hdrSize = align(sizeof(RefHeader), alignment)
|
||||
let s = size +% hdrSize
|
||||
result = alignedAlloc0(s, alignment) +! hdrSize
|
||||
when defined(nimArcDebug) or defined(nimArcIds):
|
||||
head(result).refId = gRefId
|
||||
@@ -126,14 +111,12 @@ proc nimNewObj(size, alignment: int): pointer {.compilerRtl.} =
|
||||
|
||||
proc nimNewObjUninit(size, alignment: int): pointer {.compilerRtl.} =
|
||||
# Same as 'newNewObj' but do not initialize the memory to zero.
|
||||
when defined(nimscript) or defined(nimdoc):
|
||||
# The codegen proved for us that this is not necessary.
|
||||
let hdrSize = align(sizeof(RefHeader), alignment)
|
||||
let s = size + hdrSize
|
||||
when defined(nimscript):
|
||||
discard
|
||||
elif useNativeAlignedAlloc:
|
||||
let s = size + sizeof(RefHeader)
|
||||
result = cast[ptr RefHeader](nimAlignedAlloc(s, alignment) +! sizeof(RefHeader))
|
||||
else:
|
||||
let hdrSize = align(sizeof(RefHeader), alignment)
|
||||
let s = size + hdrSize
|
||||
result = cast[ptr RefHeader](alignedAlloc(s, alignment) +! hdrSize)
|
||||
head(result).rc = 0
|
||||
when defined(gcOrc) or defined(gcYrc):
|
||||
@@ -206,11 +189,8 @@ proc nimRawDispose(p: pointer, alignment: int) {.compilerRtl.} =
|
||||
if freedCells.data == nil: init(freedCells)
|
||||
freedCells.incl head(p)
|
||||
else:
|
||||
when useNativeAlignedAlloc:
|
||||
nimAlignedDealloc(p -! sizeof(RefHeader))
|
||||
else:
|
||||
let hdrSize = align(sizeof(RefHeader), alignment)
|
||||
alignedDealloc(p -! hdrSize, alignment)
|
||||
let hdrSize = align(sizeof(RefHeader), alignment)
|
||||
alignedDealloc(p -! hdrSize, alignment)
|
||||
|
||||
template `=dispose`*[T](x: owned(ref T)) = nimRawDispose(cast[pointer](x), T.alignOf)
|
||||
#proc dispose*(x: pointer) = nimRawDispose(x)
|
||||
|
||||
@@ -262,11 +262,8 @@ proc setLen[T](s: var seq[T], newlen: Natural) {.nodestroy.} =
|
||||
if xu.p == nil or (xu.p.cap and not strlitFlag) < newlen:
|
||||
xu.p = cast[typeof(xu.p)](prepareSeqAddUninit(oldLen, xu.p, newlen - oldLen, sizeof(T), alignof(T)))
|
||||
xu.len = newlen
|
||||
|
||||
{.push overflowChecks: off.}
|
||||
for i in oldLen..<newlen:
|
||||
xu.p.data[i] = default(T)
|
||||
{.pop.}
|
||||
|
||||
proc newSeq[T](s: var seq[T], len: Natural) =
|
||||
shrink(s, 0)
|
||||
|
||||
@@ -1042,7 +1042,7 @@ proc iterateOutlineNodes(graph: ModuleGraph, n: PNode, infoPairs: SuggestFileSym
|
||||
if symData != nil and symData.sym.kind == skEnumField and symData.info.exactEquals(symData.sym.info):
|
||||
let sym = symData.sym
|
||||
graph.suggestResult(sym, sym.info, ideOutline, n.endInfo.line, n.endInfo.col)
|
||||
elif (n.kind in {nkFuncDef, nkProcDef, nkMethodDef, nkIteratorDef, nkTypeDef, nkMacroDef, nkTemplateDef, nkConverterDef, nkEnumFieldDef, nkConstDef}):
|
||||
elif (n.kind in {nkFuncDef, nkProcDef, nkTypeDef, nkMacroDef, nkTemplateDef, nkConverterDef, nkEnumFieldDef, nkConstDef}):
|
||||
matched = handleIdentOrSym(graph, n, n.endInfo, infoPairs)
|
||||
else:
|
||||
matched = false
|
||||
|
||||
@@ -36,9 +36,7 @@ outline skType tv3_outline.FooPrivate FooPrivate $file 7 2 "" 100 8 22
|
||||
outline skMacro tv3_outline.m macro (arg: untyped): untyped{.noSideEffect, gcsafe, raises: <inferred> [].} $file 10 6 "" 100 10 40
|
||||
outline skTemplate tv3_outline.t template (arg: untyped): untyped $file 11 9 "" 100 11 43
|
||||
outline skProc tv3_outline.p proc (){.noSideEffect, gcsafe, raises: <inferred> [].} $file 12 5 "" 100 12 24
|
||||
outline skIterator tv3_outline.i iterator (): int{.inline, noSideEffect, gcsafe, raises: <inferred> [].} $file 13 9 "" 100 13 27
|
||||
outline skConverter tv3_outline.c converter (s: string): int{.noSideEffect, gcsafe, raises: <inferred> [].} $file 14 10 "" 100 14 37
|
||||
outline skMethod tv3_outline.m proc (f: Foo){.noSideEffect, gcsafe, raises: <inferred> [].} $file 15 7 "" 100 15 32
|
||||
outline skFunc tv3_outline.f proc (){.noSideEffect, gcsafe, raises: <inferred> [].} $file 16 5 "" 100 16 24
|
||||
outline skConst tv3_outline.con int literal(2) $file 20 6 "" 100 20 13
|
||||
outline skProc tv3_outline.outer proc (){.noSideEffect, gcsafe, raises: <inferred> [].} $file 22 5 "" 100 23 24
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
discard """
|
||||
matrix: "--mm:refc; --mm:orc; --mm:arc"
|
||||
targets: "c cpp"
|
||||
output: "ok"
|
||||
"""
|
||||
|
||||
# Test that heap-allocated objects with .align use small chunks,
|
||||
# not a big chunk per object (regression test for #25577).
|
||||
type U = object
|
||||
d {.align: 32.}: int8
|
||||
|
||||
var e: seq[ref U]
|
||||
for _ in 0 ..< 10000: e.add(new U)
|
||||
|
||||
# Without small-chunk alignment, each object gets its own page (~46 MB).
|
||||
# With the fix, 10000 objects fit in ~1-3 MB depending on the GC.
|
||||
doAssert getTotalMem() < 8 * 1024 * 1024, "align:32 heap objects use too much memory"
|
||||
|
||||
# Verify alignment is actually correct
|
||||
for i in 0 ..< e.len:
|
||||
doAssert (cast[int](addr e[i].d) and 31) == 0, "field not 32-byte aligned"
|
||||
|
||||
echo "ok"
|
||||
@@ -130,3 +130,14 @@ block: # issue #22646
|
||||
var x: Vec[3, float]
|
||||
let y = Color(x)
|
||||
doAssert Vec3[float](y) == x
|
||||
|
||||
block: # bug #25697
|
||||
type MyList = distinct seq[int]
|
||||
|
||||
iterator items(x: MyList): lent int {.borrow.}
|
||||
|
||||
let s = MyList(@[1, 2, 3])
|
||||
var count = 0
|
||||
for item in s:
|
||||
count += 1
|
||||
doAssert count == 3, "Expected 3 items, got " & $count
|
||||
|
||||
@@ -27,11 +27,9 @@ t.curr = TokenObject(kind: Token.foo, foo: "foo")
|
||||
echo "SUCCESS"
|
||||
|
||||
proc passToVar(x: var Token) = discard
|
||||
proc passToPtr(x: ptr Token) = discard
|
||||
|
||||
{.cast(uncheckedAssign).}:
|
||||
passToVar(t.curr.kind)
|
||||
passToPtr(addr t.curr.kind)
|
||||
|
||||
t.curr = TokenObject(kind: t.curr.kind, foo: "abc")
|
||||
|
||||
|
||||
6
tests/types/t22842.nim
Normal file
6
tests/types/t22842.nim
Normal file
@@ -0,0 +1,6 @@
|
||||
## Regression test for issue 22842 - auto in proc type
|
||||
## The example should compile and run without internal compiler error.
|
||||
|
||||
proc register(cb: proc (e: auto): void) = discard
|
||||
|
||||
register(proc (e: int) = echo e)
|
||||
Reference in New Issue
Block a user