more checking for --gc:arc, no need for valgrind (#14467)
* sigmatch: removed dead code
This commit is contained in:
parent
4c08e64e98
commit
e31ac81899
12 changed files with 159 additions and 73 deletions
|
|
@ -2067,7 +2067,8 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||||
let disp = generateMethodDispatchers(graph)
|
let disp = generateMethodDispatchers(graph)
|
||||||
for x in disp: genProcAux(m, x.sym)
|
for x in disp: genProcAux(m, x.sym)
|
||||||
|
|
||||||
m.g.modulesClosed.add m
|
let mm = m
|
||||||
|
m.g.modulesClosed.add mm
|
||||||
|
|
||||||
proc genForwardedProcs(g: BModuleList) =
|
proc genForwardedProcs(g: BModuleList) =
|
||||||
# Forward declared proc:s lack bodies when first encountered, so they're given
|
# Forward declared proc:s lack bodies when first encountered, so they're given
|
||||||
|
|
|
||||||
|
|
@ -809,4 +809,7 @@ proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph =
|
||||||
withBlock(s):
|
withBlock(s):
|
||||||
gen(c, body)
|
gen(c, body)
|
||||||
genImplicitReturn(c)
|
genImplicitReturn(c)
|
||||||
|
when defined(gcArc) or defined(gcOrc):
|
||||||
|
result = c.code # will move
|
||||||
|
else:
|
||||||
shallowCopy(result, c.code)
|
shallowCopy(result, c.code)
|
||||||
|
|
|
||||||
|
|
@ -354,6 +354,8 @@ proc genWasMoved(n: PNode; c: var Con): PNode =
|
||||||
result = newNodeI(nkCall, n.info)
|
result = newNodeI(nkCall, n.info)
|
||||||
result.add(newSymNode(createMagic(c.graph, "wasMoved", mWasMoved)))
|
result.add(newSymNode(createMagic(c.graph, "wasMoved", mWasMoved)))
|
||||||
result.add copyTree(n) #mWasMoved does not take the address
|
result.add copyTree(n) #mWasMoved does not take the address
|
||||||
|
#if n.kind != nkSym:
|
||||||
|
# message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")")
|
||||||
|
|
||||||
proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
|
proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
|
||||||
result = newNodeI(nkCall, info)
|
result = newNodeI(nkCall, info)
|
||||||
|
|
|
||||||
|
|
@ -993,6 +993,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
result = isNone
|
result = isNone
|
||||||
assert(f != nil)
|
assert(f != nil)
|
||||||
|
|
||||||
|
when declared(deallocatedRefId):
|
||||||
|
let corrupt = deallocatedRefId(cast[pointer](f))
|
||||||
|
if corrupt != 0:
|
||||||
|
quit "it's corrupt " & $corrupt
|
||||||
|
|
||||||
if f.kind == tyUntyped:
|
if f.kind == tyUntyped:
|
||||||
if aOrig != nil: put(c, f, aOrig)
|
if aOrig != nil: put(c, f, aOrig)
|
||||||
return isGeneric
|
return isGeneric
|
||||||
|
|
@ -1409,7 +1414,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||||
let roota = a.skipGenericAlias
|
let roota = a.skipGenericAlias
|
||||||
let rootf = f.skipGenericAlias
|
let rootf = f.skipGenericAlias
|
||||||
|
|
||||||
var m = c
|
|
||||||
if a.kind == tyGenericInst:
|
if a.kind == tyGenericInst:
|
||||||
if roota.base == rootf.base:
|
if roota.base == rootf.base:
|
||||||
let nextFlags = flags + {trNoCovariance}
|
let nextFlags = flags + {trNoCovariance}
|
||||||
|
|
|
||||||
30
lib/system/bitmasks.nim
Normal file
30
lib/system/bitmasks.nim
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nim's Runtime Library
|
||||||
|
# (c) Copyright 2015 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Page size of the system; in most cases 4096 bytes. For exotic OS or
|
||||||
|
# CPU this needs to be changed:
|
||||||
|
const
|
||||||
|
PageShift = when defined(cpu16): 8 else: 12 # \
|
||||||
|
# my tests showed no improvements for using larger page sizes.
|
||||||
|
PageSize = 1 shl PageShift
|
||||||
|
PageMask = PageSize-1
|
||||||
|
|
||||||
|
MemAlign = 16 # also minimal allocatable memory block
|
||||||
|
|
||||||
|
BitsPerPage = PageSize div MemAlign
|
||||||
|
UnitsPerPage = BitsPerPage div (sizeof(int)*8)
|
||||||
|
# how many ints do we need to describe a page:
|
||||||
|
# on 32 bit systems this is only 16 (!)
|
||||||
|
|
||||||
|
TrunkShift = 9
|
||||||
|
BitsPerTrunk = 1 shl TrunkShift # needs to be power of 2 and divisible by 64
|
||||||
|
TrunkMask = BitsPerTrunk - 1
|
||||||
|
IntsPerTrunk = BitsPerTrunk div (sizeof(int)*8)
|
||||||
|
IntShift = 5 + ord(sizeof(int) == 8) # 5 or 6, depending on int width
|
||||||
|
IntMask = 1 shl IntShift - 1
|
||||||
43
lib/system/cellseqs_v1.nim
Normal file
43
lib/system/cellseqs_v1.nim
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nim's Runtime Library
|
||||||
|
# (c) Copyright 2019 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
# ------------------- cell seq handling ---------------------------------------
|
||||||
|
|
||||||
|
type
|
||||||
|
PCellArray = ptr UncheckedArray[PCell]
|
||||||
|
CellSeq {.final, pure.} = object
|
||||||
|
len, cap: int
|
||||||
|
d: PCellArray
|
||||||
|
|
||||||
|
proc contains(s: CellSeq, c: PCell): bool {.inline.} =
|
||||||
|
for i in 0 .. s.len-1:
|
||||||
|
if s.d[i] == c: return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
proc add(s: var CellSeq, c: PCell) {.inline.} =
|
||||||
|
if s.len >= s.cap:
|
||||||
|
s.cap = s.cap * 3 div 2
|
||||||
|
var d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
|
||||||
|
copyMem(d, s.d, s.len * sizeof(PCell))
|
||||||
|
dealloc(s.d)
|
||||||
|
s.d = d
|
||||||
|
# XXX: realloc?
|
||||||
|
s.d[s.len] = c
|
||||||
|
inc(s.len)
|
||||||
|
|
||||||
|
proc init(s: var CellSeq, cap: int = 1024) =
|
||||||
|
s.len = 0
|
||||||
|
s.cap = cap
|
||||||
|
s.d = cast[PCellArray](alloc0(cap * sizeof(PCell)))
|
||||||
|
|
||||||
|
proc deinit(s: var CellSeq) =
|
||||||
|
dealloc(s.d)
|
||||||
|
s.d = nil
|
||||||
|
s.len = 0
|
||||||
|
s.cap = 0
|
||||||
|
|
@ -9,6 +9,13 @@
|
||||||
|
|
||||||
# Efficient set of pointers for the GC (and repr)
|
# Efficient set of pointers for the GC (and repr)
|
||||||
|
|
||||||
|
when defined(gcOrc) or defined(gcArc):
|
||||||
|
type
|
||||||
|
PCell = Cell
|
||||||
|
|
||||||
|
include bitmasks
|
||||||
|
|
||||||
|
else:
|
||||||
type
|
type
|
||||||
RefCount = int
|
RefCount = int
|
||||||
|
|
||||||
|
|
@ -23,6 +30,7 @@ type
|
||||||
|
|
||||||
PCell = ptr Cell
|
PCell = ptr Cell
|
||||||
|
|
||||||
|
type
|
||||||
PPageDesc = ptr PageDesc
|
PPageDesc = ptr PageDesc
|
||||||
BitIndex = range[0..UnitsPerPage-1]
|
BitIndex = range[0..UnitsPerPage-1]
|
||||||
PageDesc {.final, pure.} = object
|
PageDesc {.final, pure.} = object
|
||||||
|
|
@ -35,39 +43,11 @@ type
|
||||||
counter, max: int
|
counter, max: int
|
||||||
head: PPageDesc
|
head: PPageDesc
|
||||||
data: PPageDescArray
|
data: PPageDescArray
|
||||||
PCellArray = ptr UncheckedArray[PCell]
|
|
||||||
CellSeq {.final, pure.} = object
|
|
||||||
len, cap: int
|
|
||||||
d: PCellArray
|
|
||||||
|
|
||||||
# ------------------- cell seq handling ---------------------------------------
|
when defined(gcOrc) or defined(gcArc):
|
||||||
|
discard
|
||||||
proc contains(s: CellSeq, c: PCell): bool {.inline.} =
|
else:
|
||||||
for i in 0 .. s.len-1:
|
include cellseqs_v1
|
||||||
if s.d[i] == c: return true
|
|
||||||
return false
|
|
||||||
|
|
||||||
proc add(s: var CellSeq, c: PCell) {.inline.} =
|
|
||||||
if s.len >= s.cap:
|
|
||||||
s.cap = s.cap * 3 div 2
|
|
||||||
var d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
|
|
||||||
copyMem(d, s.d, s.len * sizeof(PCell))
|
|
||||||
dealloc(s.d)
|
|
||||||
s.d = d
|
|
||||||
# XXX: realloc?
|
|
||||||
s.d[s.len] = c
|
|
||||||
inc(s.len)
|
|
||||||
|
|
||||||
proc init(s: var CellSeq, cap: int = 1024) =
|
|
||||||
s.len = 0
|
|
||||||
s.cap = cap
|
|
||||||
s.d = cast[PCellArray](alloc0(cap * sizeof(PCell)))
|
|
||||||
|
|
||||||
proc deinit(s: var CellSeq) =
|
|
||||||
dealloc(s.d)
|
|
||||||
s.d = nil
|
|
||||||
s.len = 0
|
|
||||||
s.cap = 0
|
|
||||||
|
|
||||||
# ------------------- cell set handling ---------------------------------------
|
# ------------------- cell set handling ---------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,6 @@ const
|
||||||
colGreen = 0b000
|
colGreen = 0b000
|
||||||
colYellow = 0b001
|
colYellow = 0b001
|
||||||
colRed = 0b010
|
colRed = 0b010
|
||||||
rcShift = 3 # shift by rcShift to get the reference counter
|
|
||||||
colorMask = 0b011
|
colorMask = 0b011
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ const
|
||||||
colPurple = 0b011
|
colPurple = 0b011
|
||||||
isCycleCandidate = 0b100 # cell is marked as a cycle candidate
|
isCycleCandidate = 0b100 # cell is marked as a cycle candidate
|
||||||
jumpStackFlag = 0b1000
|
jumpStackFlag = 0b1000
|
||||||
rcShift = 4 # shift by rcShift to get the reference counter
|
|
||||||
colorMask = 0b011
|
colorMask = 0b011
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
|
||||||
|
|
@ -38,27 +38,10 @@ type
|
||||||
PByte = ptr ByteArray
|
PByte = ptr ByteArray
|
||||||
PString = ptr string
|
PString = ptr string
|
||||||
|
|
||||||
# Page size of the system; in most cases 4096 bytes. For exotic OS or
|
when declared(IntsPerTrunk):
|
||||||
# CPU this needs to be changed:
|
discard
|
||||||
const
|
else:
|
||||||
PageShift = when defined(cpu16): 8 else: 12 # \
|
include bitmasks
|
||||||
# my tests showed no improvements for using larger page sizes.
|
|
||||||
PageSize = 1 shl PageShift
|
|
||||||
PageMask = PageSize-1
|
|
||||||
|
|
||||||
MemAlign = 16 # also minimal allocatable memory block
|
|
||||||
|
|
||||||
BitsPerPage = PageSize div MemAlign
|
|
||||||
UnitsPerPage = BitsPerPage div (sizeof(int)*8)
|
|
||||||
# how many ints do we need to describe a page:
|
|
||||||
# on 32 bit systems this is only 16 (!)
|
|
||||||
|
|
||||||
TrunkShift = 9
|
|
||||||
BitsPerTrunk = 1 shl TrunkShift # needs to be power of 2 and divisible by 64
|
|
||||||
TrunkMask = BitsPerTrunk - 1
|
|
||||||
IntsPerTrunk = BitsPerTrunk div (sizeof(int)*8)
|
|
||||||
IntShift = 5 + ord(sizeof(int) == 8) # 5 or 6, depending on int width
|
|
||||||
IntMask = 1 shl IntShift - 1
|
|
||||||
|
|
||||||
proc raiseOutOfMem() {.noinline.} =
|
proc raiseOutOfMem() {.noinline.} =
|
||||||
if outOfMemHook != nil: outOfMemHook()
|
if outOfMemHook != nil: outOfMemHook()
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,13 @@ when defined(gcOrc):
|
||||||
const
|
const
|
||||||
rcIncrement = 0b10000 # so that lowest 4 bits are not touched
|
rcIncrement = 0b10000 # so that lowest 4 bits are not touched
|
||||||
rcMask = 0b1111
|
rcMask = 0b1111
|
||||||
|
rcShift = 4 # shift by rcShift to get the reference counter
|
||||||
|
|
||||||
else:
|
else:
|
||||||
const
|
const
|
||||||
rcIncrement = 0b1000 # so that lowest 3 bits are not touched
|
rcIncrement = 0b1000 # so that lowest 3 bits are not touched
|
||||||
rcMask = 0b111
|
rcMask = 0b111
|
||||||
|
rcShift = 3 # shift by rcShift to get the reference counter
|
||||||
|
|
||||||
type
|
type
|
||||||
RefHeader = object
|
RefHeader = object
|
||||||
|
|
@ -52,6 +54,8 @@ type
|
||||||
when defined(gcOrc):
|
when defined(gcOrc):
|
||||||
rootIdx: int # thanks to this we can delete potential cycle roots
|
rootIdx: int # thanks to this we can delete potential cycle roots
|
||||||
# in O(1) without doubly linked lists
|
# in O(1) without doubly linked lists
|
||||||
|
when defined(nimArcDebug):
|
||||||
|
refId: int
|
||||||
|
|
||||||
Cell = ptr RefHeader
|
Cell = ptr RefHeader
|
||||||
|
|
||||||
|
|
@ -67,6 +71,14 @@ template head(p: pointer): Cell =
|
||||||
const
|
const
|
||||||
traceCollector = defined(traceArc)
|
traceCollector = defined(traceArc)
|
||||||
|
|
||||||
|
when defined(nimArcDebug):
|
||||||
|
include cellsets
|
||||||
|
|
||||||
|
const traceId = 7739 # 1037
|
||||||
|
|
||||||
|
var gRefId: int
|
||||||
|
var freedCells: CellSet
|
||||||
|
|
||||||
proc nimNewObj(size: int): pointer {.compilerRtl.} =
|
proc nimNewObj(size: int): pointer {.compilerRtl.} =
|
||||||
let s = size + sizeof(RefHeader)
|
let s = size + sizeof(RefHeader)
|
||||||
when defined(nimscript):
|
when defined(nimscript):
|
||||||
|
|
@ -79,6 +91,9 @@ proc nimNewObj(size: int): pointer {.compilerRtl.} =
|
||||||
result = allocShared0(s) +! sizeof(RefHeader)
|
result = allocShared0(s) +! sizeof(RefHeader)
|
||||||
else:
|
else:
|
||||||
result = alloc0(s) +! sizeof(RefHeader)
|
result = alloc0(s) +! sizeof(RefHeader)
|
||||||
|
when defined(nimArcDebug):
|
||||||
|
head(result).refId = gRefId
|
||||||
|
atomicInc gRefId
|
||||||
when traceCollector:
|
when traceCollector:
|
||||||
cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result)
|
cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result)
|
||||||
|
|
||||||
|
|
@ -98,6 +113,9 @@ proc nimNewObjUninit(size: int): pointer {.compilerRtl.} =
|
||||||
when defined(gcOrc):
|
when defined(gcOrc):
|
||||||
orig.rootIdx = 0
|
orig.rootIdx = 0
|
||||||
result = orig +! sizeof(RefHeader)
|
result = orig +! sizeof(RefHeader)
|
||||||
|
when defined(nimArcDebug):
|
||||||
|
head(result).refId = gRefId
|
||||||
|
atomicInc gRefId
|
||||||
when traceCollector:
|
when traceCollector:
|
||||||
cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result)
|
cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result)
|
||||||
|
|
||||||
|
|
@ -105,10 +123,25 @@ proc nimDecWeakRef(p: pointer) {.compilerRtl, inl.} =
|
||||||
dec head(p).rc, rcIncrement
|
dec head(p).rc, rcIncrement
|
||||||
|
|
||||||
proc nimIncRef(p: pointer) {.compilerRtl, inl.} =
|
proc nimIncRef(p: pointer) {.compilerRtl, inl.} =
|
||||||
|
when defined(nimArcDebug):
|
||||||
|
if head(p).refId == traceId:
|
||||||
|
writeStackTrace()
|
||||||
|
cfprintf(cstderr, "[IncRef] %p %ld\n", p, head(p).rc shr rcShift)
|
||||||
|
|
||||||
inc head(p).rc, rcIncrement
|
inc head(p).rc, rcIncrement
|
||||||
when traceCollector:
|
when traceCollector:
|
||||||
cprintf("[INCREF] %p\n", head(p))
|
cprintf("[INCREF] %p\n", head(p))
|
||||||
|
|
||||||
|
when not defined(nimscript) and defined(nimArcDebug):
|
||||||
|
proc deallocatedRefId*(p: pointer): int =
|
||||||
|
## Returns the ref's ID if the ref was already deallocated. This
|
||||||
|
## is a memory corruption check. Returns 0 if there is no error.
|
||||||
|
let c = head(p)
|
||||||
|
if freedCells.data != nil and freedCells.contains(c):
|
||||||
|
result = c.refId
|
||||||
|
else:
|
||||||
|
result = 0
|
||||||
|
|
||||||
proc nimRawDispose(p: pointer) {.compilerRtl.} =
|
proc nimRawDispose(p: pointer) {.compilerRtl.} =
|
||||||
when not defined(nimscript):
|
when not defined(nimscript):
|
||||||
when traceCollector:
|
when traceCollector:
|
||||||
|
|
@ -117,7 +150,11 @@ proc nimRawDispose(p: pointer) {.compilerRtl.} =
|
||||||
if head(p).rc >= rcIncrement:
|
if head(p).rc >= rcIncrement:
|
||||||
cstderr.rawWrite "[FATAL] dangling references exist\n"
|
cstderr.rawWrite "[FATAL] dangling references exist\n"
|
||||||
quit 1
|
quit 1
|
||||||
when defined(useMalloc):
|
when defined(nimArcDebug):
|
||||||
|
# we do NOT really free the memory here in order to reliably detect use-after-frees
|
||||||
|
if freedCells.data == nil: init(freedCells)
|
||||||
|
freedCells.incl head(p)
|
||||||
|
elif defined(useMalloc):
|
||||||
c_free(p -! sizeof(RefHeader))
|
c_free(p -! sizeof(RefHeader))
|
||||||
elif compileOption("threads"):
|
elif compileOption("threads"):
|
||||||
deallocShared(p -! sizeof(RefHeader))
|
deallocShared(p -! sizeof(RefHeader))
|
||||||
|
|
@ -150,6 +187,12 @@ when defined(gcOrc):
|
||||||
proc nimDecRefIsLast(p: pointer): bool {.compilerRtl, inl.} =
|
proc nimDecRefIsLast(p: pointer): bool {.compilerRtl, inl.} =
|
||||||
if p != nil:
|
if p != nil:
|
||||||
var cell = head(p)
|
var cell = head(p)
|
||||||
|
|
||||||
|
when defined(nimArcDebug):
|
||||||
|
if cell.refId == traceId:
|
||||||
|
writeStackTrace()
|
||||||
|
cfprintf(cstderr, "[DecRef] %p %ld\n", p, cell.rc shr rcShift)
|
||||||
|
|
||||||
if (cell.rc and not rcMask) == 0:
|
if (cell.rc and not rcMask) == 0:
|
||||||
result = true
|
result = true
|
||||||
when traceCollector:
|
when traceCollector:
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ proc supportsCopyMem(t: typedesc): bool {.magic: "TypeTrait".}
|
||||||
|
|
||||||
## Default seq implementation used by Nim's core.
|
## Default seq implementation used by Nim's core.
|
||||||
type
|
type
|
||||||
|
|
||||||
NimSeqPayloadBase = object
|
NimSeqPayloadBase = object
|
||||||
cap: int
|
cap: int
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue