Skip to content

Commit

Permalink
forward type alignment information to seqs (#12430)
Browse files Browse the repository at this point in the history
  • Loading branch information
krux02 authored Apr 19, 2020
1 parent a8f030f commit 4005f0d
Show file tree
Hide file tree
Showing 25 changed files with 152 additions and 114 deletions.
20 changes: 10 additions & 10 deletions compiler/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1301,9 +1301,10 @@ proc genNewSeq(p: BProc, e: PNode) =
initLocExpr(p, e[2], b)
if optSeqDestructors in p.config.globalOptions:
let seqtype = skipTypes(e[1].typ, abstractVarRange)
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
[a.rdLoc, b.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype)])
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
[a.rdLoc, b.rdLoc,
getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype)])
else:
let lenIsZero = optNilSeqs notin p.options and
e[2].kind == nkIntLit and e[2].intVal == 0
Expand All @@ -1316,9 +1317,10 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
initLocExpr(p, e[1], a)
if optSeqDestructors in p.config.globalOptions:
if d.k == locNone: getTemp(p, e.typ, d, needsInit=false)
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
[d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype)])
getSeqPayloadType(p.module, seqtype),
])
else:
putIntoDest(p, d, e, ropecg(p.module,
"($1)#nimNewSeqOfCap($2, $3)", [
Expand Down Expand Up @@ -1425,7 +1427,7 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
let l = intLiteral(n.len)
if optSeqDestructors in p.config.globalOptions:
let seqtype = n.typ
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
[rdLoc dest[], l, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype)])
else:
Expand Down Expand Up @@ -1456,7 +1458,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
let L = toInt(lengthOrd(p.config, n[1].typ))
if optSeqDestructors in p.config.globalOptions:
let seqtype = n.typ
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
[rdLoc d, L, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype)])
else:
Expand Down Expand Up @@ -2224,9 +2226,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)])
of mAlignOf:
let t = e[1].typ.skipTypes({tyTypeDesc})
if not p.module.compileToCpp:
p.module.includeHeader("<stdalign.h>")
putIntoDest(p, d, e, "((NI)alignof($1))" % [getTypeDesc(p.module, t)])
putIntoDest(p, d, e, "((NI)NIM_ALIGNOF($1))" % [getTypeDesc(p.module, t)])
of mOffsetOf:
var dotExpr: PNode
block findDotExpr:
Expand Down
16 changes: 8 additions & 8 deletions compiler/ccgtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -999,11 +999,14 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
let nameHcr = tiNameForHcr(m, name)

var size: Rope
if tfIncompleteStruct in typ.flags: size = rope"void*"
else: size = getTypeDesc(m, origType)
if tfIncompleteStruct in typ.flags:
size = rope"void*"
else:
size = getTypeDesc(m, origType)
m.s[cfsTypeInit3].addf(
"$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
[nameHcr, size, rope(nimtypeKind), base])
"$1.size = sizeof($2);$n$1.align = NIM_ALIGNOF($2);$n$1.kind = $3;$n$1.base = $4;$n",
[nameHcr, size, rope(nimtypeKind), base]
)
# compute type flags for GC optimization
var flags = 0
if not containsGarbageCollectedRef(typ): flags = flags or 1
Expand Down Expand Up @@ -1313,10 +1316,7 @@ proc genTypeInfoV2(m: BModule, t, origType: PType, name: Rope; info: TLineInfo)
let traceImpl = genHook(m, t, info, attachedTrace)
let disposeImpl = genHook(m, t, info, attachedDispose)

m.s[cfsTypeInit3].addf("$1.destructor = (void*)$2; $1.size = sizeof($3);$n" &
"$1.name = $4;$n" &
"$1.traceImpl = (void*)$5;$n" &
"$1.disposeImpl = (void*)$6;$n", [
addf(m.s[cfsTypeInit3], "$1.destructor = (void*)$2; $1.size = sizeof($3); $1.align = NIM_ALIGNOF($3); $1.name = $4;$n; $1.traceImpl = (void*)$5; $1.disposeImpl = (void*)$6;", [
name, destroyImpl, getTypeDesc(m, t), typeName,
traceImpl, disposeImpl])

Expand Down
1 change: 1 addition & 0 deletions compiler/condsyms.nim
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimnomagic64")
defineSymbol("nimNewShiftOps")
defineSymbol("nimHasCursor")
defineSymbol("nimAlignPragma")
defineSymbol("nimHasExceptionsQuery")
defineSymbol("nimHasIsNamedTuple")
defineSymbol("nimHashOrdinalFixed")
Expand Down
17 changes: 10 additions & 7 deletions lib/core/typeinfo.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@
## what this module allows you to do.
##
## Note that even though ``Any`` and its operations hide the nasty low level
## details from its clients, it remains inherently unsafe! Also, Nim's
## details from its clients, it remains inherently unsafe! Also, Nim's
## runtime type information will evolve and may eventually be deprecated.
## As an alternative approach to programmatically understanding and
## manipulating types, consider using the `macros <macros.html>`_ package to
## work with the types' AST representation at compile time. See, for example,
## the `getTypeImpl proc<macros.html#getTypeImpl,NimNode>`_. As an alternative
## the `getTypeImpl proc<macros.html#getTypeImpl,NimNode>`_. As an alternative
## approach to storing arbitrary types at runtime, consider using generics.
##
##
##

{.push hints: off.}

Expand Down Expand Up @@ -98,7 +98,7 @@ else:
proc genericAssign(dest, src: pointer, mt: PNimType) {.importCompilerProc.}
proc genericShallowAssign(dest, src: pointer, mt: PNimType) {.
importCompilerProc.}
proc incrSeq(seq: PGenSeq, elemSize: int): PGenSeq {.importCompilerProc.}
proc incrSeq(seq: PGenSeq, elemSize, elemAlign: int): PGenSeq {.importCompilerProc.}
proc newObj(typ: PNimType, size: int): pointer {.importCompilerProc.}
proc newSeq(typ: PNimType, len: int): pointer {.importCompilerProc.}
proc objectInit(dest: pointer, typ: PNimType) {.importCompilerProc.}
Expand Down Expand Up @@ -180,7 +180,7 @@ proc extendSeq*(x: Any) =
## performs ``setLen(x, x.len+1)``. `x` needs to represent a ``seq``.
assert x.rawType.kind == tySequence
var y = cast[ptr PGenSeq](x.value)[]
var z = incrSeq(y, x.rawType.base.size)
var z = incrSeq(y, x.rawType.base.size, x.rawType.base.align)
# 'incrSeq' already freed the memory for us and copied over the RC!
# So we simply copy the raw pointer into 'x.value':
cast[ppointer](x.value)[] = z
Expand All @@ -195,6 +195,9 @@ proc skipRange(x: PNimType): PNimType {.inline.} =
result = x
if result.kind == tyRange: result = result.base

proc align(address, alignment: int): int =
result = (address + (alignment - 1)) and not (alignment - 1)

proc `[]`*(x: Any, i: int): Any =
## accessor for an any `x` that represents an array or a sequence.
case x.rawType.kind
Expand All @@ -209,7 +212,7 @@ proc `[]`*(x: Any, i: int): Any =
var bs = x.rawType.base.size
if i >=% cast[PGenSeq](s).len:
raise newException(IndexError, formatErrorIndexBound(i, cast[PGenSeq](s).len-1))
return newAny(s +!! (GenericSeqSize+i*bs), x.rawType.base)
return newAny(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), x.rawType.base)
else: assert false

proc `[]=`*(x: Any, i: int, y: Any) =
Expand All @@ -228,7 +231,7 @@ proc `[]=`*(x: Any, i: int, y: Any) =
if i >=% cast[PGenSeq](s).len:
raise newException(IndexError, formatErrorIndexBound(i, cast[PGenSeq](s).len-1))
assert y.rawType == x.rawType.base
genericAssign(s +!! (GenericSeqSize+i*bs), y.value, y.rawType)
genericAssign(s +!! (align(GenericSeqSize, x.rawType.base.align)+i*bs), y.value, y.rawType)
else: assert false

proc len*(x: Any): int =
Expand Down
3 changes: 2 additions & 1 deletion lib/nimbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,6 @@ typedef char* NCSTRING;
#define ALLOC_0(size) calloc(1, size)
#define DL_ALLOC_0(size) dlcalloc(1, size)

#define GenericSeqSize sizeof(TGenericSeq)
#define paramCount() cmdCount

// NAN definition copied from math.h included in the Windows SDK version 10.0.14393.0
Expand Down Expand Up @@ -546,8 +545,10 @@ NIM_STATIC_ASSERT(sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8, ""

#if defined(_MSC_VER)
# define NIM_ALIGN(x) __declspec(align(x))
# define NIM_ALIGNOF(x) __alignof(x)
#else
# define NIM_ALIGN(x) __attribute__((aligned(x)))
# define NIM_ALIGNOF(x) __alignof__(x)
#endif

/* ---------------- platform specific includes ----------------------- */
Expand Down
3 changes: 1 addition & 2 deletions lib/pure/includes/osenv.nim
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ else:
when useNSGetEnviron:
var gEnv = NSGetEnviron()[]
var i = 0
while true:
if gEnv[i] == nil: break
while gEnv[i] != nil:
add environment, $gEnv[i]
inc(i)
envComputed = true
Expand Down
12 changes: 10 additions & 2 deletions lib/system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ when not defined(js) and not defined(nimSeqsV2):
len, reserved: int
when defined(gogc):
elemSize: int
elemAlign: int
PGenericSeq {.exportc.} = ptr TGenericSeq
# len and space without counting the terminating zero:
NimStringDesc {.compilerproc, final.} = object of TGenericSeq
Expand Down Expand Up @@ -1123,6 +1124,13 @@ elif hostOS != "standalone":
var programResult* {.compilerproc, exportc: "nim_program_result".}: int
## deprecated, prefer ``quit``

proc align(address, alignment: int): int =
if alignment == 0: # Actually, this is illegal. This branch exists to actively
# hide problems.
result = address
else:
result = (address + (alignment - 1)) and not (alignment - 1)

when defined(nimdoc):
proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.}
## Stops the program immediately with an exit code.
Expand Down Expand Up @@ -1698,6 +1706,7 @@ when not defined(js) and defined(nimV2):
TNimType {.compilerproc.} = object
destructor: pointer
size: int
align: int
name: cstring
traceImpl: pointer
disposeImpl: pointer
Expand All @@ -1709,7 +1718,6 @@ when notJSnotNims and defined(nimSeqsV2):

{.pop.}


when notJSnotNims:
proc writeStackTrace*() {.tags: [], gcsafe, raises: [].}
## Writes the current stack trace to ``stderr``. This is only works
Expand Down Expand Up @@ -1988,8 +1996,8 @@ proc abs*(x: int64): int64 {.magic: "AbsI", noSideEffect.} =
result = if x < 0: -x else: x
{.pop.}


when not defined(js):

proc likelyProc(val: bool): bool {.importc: "NIM_LIKELY", nodecl, noSideEffect.}
proc unlikelyProc(val: bool): bool {.importc: "NIM_UNLIKELY", nodecl, noSideEffect.}

Expand Down
17 changes: 10 additions & 7 deletions lib/system/alloc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ type
data: TrunkBuckets

type
AlignType = BiggestFloat
FreeCell {.final, pure.} = object
next: ptr FreeCell # next free cell in chunk (overlaid with refcount)
when not defined(gcDestructors):
Expand All @@ -68,16 +67,20 @@ type
freeList: ptr FreeCell
free: int # how many bytes remain
acc: int # accumulator for small object allocation
when defined(cpu32):
align: int
data: AlignType # start of usable memory
when defined(nimAlignPragma):
data {.align: MemAlign.}: UncheckedArray[byte] # start of usable memory
else:
data: UncheckedArray[byte]

BigChunk = object of BaseChunk # not necessarily > PageSize!
next, prev: PBigChunk # chunks of the same (or bigger) size
data: AlignType # start of usable memory
when defined(nimAlignPragma):
data {.align: MemAlign.}: UncheckedArray[byte] # start of usable memory
else:
data: UncheckedArray[byte]

template smallChunkOverhead(): untyped = sizeof(SmallChunk)-sizeof(AlignType)
template bigChunkOverhead(): untyped = sizeof(BigChunk)-sizeof(AlignType)
template smallChunkOverhead(): untyped = sizeof(SmallChunk)
template bigChunkOverhead(): untyped = sizeof(BigChunk)

# ------------- chunk table ---------------------------------------------------
# We use a PtrSet of chunk starts and a table[Page, chunksize] for chunk
Expand Down
11 changes: 5 additions & 6 deletions lib/system/assign.nim
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,16 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
cast[PGenericSeq](ss).len = seq.len
unsureAsgnRef(x, ss)
var dst = cast[ByteAddress](cast[PPointer](dest)[])
copyMem(cast[pointer](dst +% GenericSeqSize),
cast[pointer](cast[ByteAddress](s2) +% GenericSeqSize),
seq.len * mt.base.size)
copyMem(cast[pointer](dst +% align(GenericSeqSize, mt.base.align)),
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align)),
seq.len *% mt.base.size)
else:
unsureAsgnRef(x, newSeq(mt, seq.len))
var dst = cast[ByteAddress](cast[PPointer](dest)[])
for i in 0..seq.len-1:
genericAssignAux(
cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize),
cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
GenericSeqSize),
cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ),
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size ),
mt.base, shallow)
of tyObject:
var it = mt.base
Expand Down
11 changes: 5 additions & 6 deletions lib/system/channels.nim
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ when not usesDestructors:
x[] = nil
else:
var ss = cast[NimString](s2)
var ns = cast[NimString](alloc(t.region, ss.len+1 + GenericSeqSize))
var ns = cast[NimString](alloc(t.region, GenericSeqSize + ss.len+1))
copyMem(ns, ss, ss.len+1 + GenericSeqSize)
x[] = ns
else:
Expand All @@ -239,7 +239,7 @@ when not usesDestructors:
else:
sysAssert(dest != nil, "dest == nil")
if mode == mStore:
x[] = alloc0(t.region, seq.len *% mt.base.size +% GenericSeqSize)
x[] = alloc0(t.region, align(GenericSeqSize, mt.base.align) +% seq.len *% mt.base.size)
else:
unsureAsgnRef(x, newSeq(mt, seq.len))
var dst = cast[ByteAddress](cast[PPointer](dest)[])
Expand All @@ -248,9 +248,9 @@ when not usesDestructors:
dstseq.reserved = seq.len
for i in 0..seq.len-1:
storeAux(
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
GenericSeqSize),
cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i*% mt.base.size),
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +%
i *% mt.base.size),
mt.base, t, mode)
if mode != mStore: dealloc(t.region, s2)
of tyObject:
Expand Down Expand Up @@ -452,4 +452,3 @@ proc ready*[TMsg](c: var Channel[TMsg]): bool =
## new messages.
var q = cast[PRawChannel](addr(c))
result = q.ready

5 changes: 2 additions & 3 deletions lib/system/deepcopy.nim
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,8 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
var dst = cast[ByteAddress](cast[PPointer](dest)[])
for i in 0..seq.len-1:
genericDeepCopyAux(
cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize),
cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
GenericSeqSize),
cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size),
cast[pointer](cast[ByteAddress](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size),
mt.base, tab)
of tyObject:
# we need to copy m_type field for tyObject, as it could be empty for
Expand Down
15 changes: 8 additions & 7 deletions lib/system/gc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,7 @@ proc forAllChildren(cell: PCell, op: WalkOp) =
var s = cast[PGenericSeq](d)
if s != nil:
for i in 0..s.len-1:
forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
GenericSeqSize), cell.typ.base, op)
forAllChildrenAux(cast[pointer](d +% align(GenericSeqSize, cell.typ.base.align) +% i *% cell.typ.base.size), cell.typ.base, op)
else: discard

proc addNewObjToZCT(res: PCell, gch: var GcHeap) {.inline.} =
Expand Down Expand Up @@ -444,7 +443,7 @@ proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
{.push overflowChecks: on.}
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
# `newObj` already uses locks, so no need for them here.
let size = len * typ.base.size + GenericSeqSize
let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size
result = newObj(typ, size)
cast[PGenericSeq](result).len = len
cast[PGenericSeq](result).reserved = len
Expand Down Expand Up @@ -480,7 +479,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =

{.push overflowChecks: on.}
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
let size = len * typ.base.size + GenericSeqSize
let size = align(GenericSeqSize, typ.base.align) + len * typ.base.size
result = newObjRC1(typ, size)
cast[PGenericSeq](result).len = len
cast[PGenericSeq](result).reserved = len
Expand All @@ -495,11 +494,13 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
sysAssert(allocInv(gch.region), "growObj begin")

var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
var elemSize = 1
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
var elemSize,elemAlign = 1
if ol.typ.kind != tyString:
elemSize = ol.typ.base.size
elemAlign = ol.typ.base.align
incTypeSize ol.typ, newsize

var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
var oldsize = align(GenericSeqSize, elemAlign) + cast[PGenericSeq](old).len * elemSize
copyMem(res, ol, oldsize + sizeof(Cell))
zeroMem(cast[pointer](cast[ByteAddress](res) +% oldsize +% sizeof(Cell)),
newsize-oldsize)
Expand Down
Loading

0 comments on commit 4005f0d

Please sign in to comment.