liftdestructors.nim 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module implements lifting for type-bound operations
  10. ## (`=sink`, `=copy`, `=destroy`, `=deepCopy`, `=wasMoved`, `=dup`).
  11. import modulegraphs, lineinfos, idents, ast, renderer, semdata,
  12. sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils
  13. from trees import isCaseObj
  14. when defined(nimPreviewSlimSystem):
  15. import std/assertions
  16. type
  17. TLiftCtx = object
  18. g: ModuleGraph
  19. info: TLineInfo # for construction
  20. kind: TTypeAttachedOp
  21. fn: PSym
  22. asgnForType: PType
  23. recurse: bool
  24. addMemReset: bool # add wasMoved() call after destructor call
  25. canRaise: bool
  26. filterDiscriminator: PSym # we generating destructor for case branch
  27. c: PContext # c can be nil, then we are called from lambdalifting!
  28. idgen: IdGenerator
  29. template destructor*(t: PType): PSym = getAttachedOp(c.g, t, attachedDestructor)
  30. template assignment*(t: PType): PSym = getAttachedOp(c.g, t, attachedAsgn)
  31. template dup*(t: PType): PSym = getAttachedOp(c.g, t, attachedDup)
  32. template asink*(t: PType): PSym = getAttachedOp(c.g, t, attachedSink)
  33. proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode)
  34. proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
  35. info: TLineInfo; idgen: IdGenerator): PSym
  36. proc createTypeBoundOps*(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo;
  37. idgen: IdGenerator)
  38. proc at(a, i: PNode, elemType: PType): PNode =
  39. result = newNodeI(nkBracketExpr, a.info, 2)
  40. result[0] = a
  41. result[1] = i
  42. result.typ = elemType
  43. proc destructorOverridden(g: ModuleGraph; t: PType): bool =
  44. let op = getAttachedOp(g, t, attachedDestructor)
  45. op != nil and sfOverridden in op.flags
  46. proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
  47. for i in 0..<t.len:
  48. let lit = lowerings.newIntLit(c.g, x.info, i)
  49. let b = if c.kind == attachedTrace: y else: y.at(lit, t[i])
  50. fillBody(c, t[i], body, x.at(lit, t[i]), b)
  51. proc dotField(x: PNode, f: PSym): PNode =
  52. result = newNodeI(nkDotExpr, x.info, 2)
  53. if x.typ.skipTypes(abstractInst).kind == tyVar:
  54. result[0] = x.newDeref
  55. else:
  56. result[0] = x
  57. result[1] = newSymNode(f, x.info)
  58. result.typ = f.typ
  59. proc newAsgnStmt(le, ri: PNode): PNode =
  60. result = newNodeI(nkAsgn, le.info, 2)
  61. result[0] = le
  62. result[1] = ri
  63. proc genBuiltin*(g: ModuleGraph; idgen: IdGenerator; magic: TMagic; name: string; i: PNode): PNode =
  64. result = newNodeI(nkCall, i.info)
  65. result.add createMagic(g, idgen, name, magic).newSymNode
  66. result.add i
  67. proc genBuiltin(c: var TLiftCtx; magic: TMagic; name: string; i: PNode): PNode =
  68. result = genBuiltin(c.g, c.idgen, magic, name, i)
  69. proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
  70. if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink, attachedDup}:
  71. body.add newAsgnStmt(x, y)
  72. elif c.kind == attachedDestructor and c.addMemReset:
  73. let call = genBuiltin(c, mDefault, "default", x)
  74. call.typ = t
  75. body.add newAsgnStmt(x, call)
  76. elif c.kind == attachedWasMoved:
  77. body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
  78. proc genAddr(c: var TLiftCtx; x: PNode): PNode =
  79. if x.kind == nkHiddenDeref:
  80. checkSonsLen(x, 1, c.g.config)
  81. result = x[0]
  82. else:
  83. result = newNodeIT(nkHiddenAddr, x.info, makeVarType(x.typ.owner, x.typ, c.idgen))
  84. result.add x
  85. proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
  86. result = newNodeI(nkWhileStmt, c.info, 2)
  87. let cmp = genBuiltin(c, mLtI, "<", i)
  88. cmp.add genLen(c.g, dest)
  89. cmp.typ = getSysType(c.g, c.info, tyBool)
  90. result[0] = cmp
  91. result[1] = newNodeI(nkStmtList, c.info)
  92. proc genIf(c: var TLiftCtx; cond, action: PNode): PNode =
  93. result = newTree(nkIfStmt, newTree(nkElifBranch, cond, action))
  94. proc genContainerOf(c: var TLiftCtx; objType: PType, field, x: PSym): PNode =
  95. # generate: cast[ptr ObjType](cast[int](addr(x)) - offsetOf(objType.field))
  96. let intType = getSysType(c.g, unknownLineInfo, tyInt)
  97. let addrOf = newNodeIT(nkAddr, c.info, makePtrType(x.owner, x.typ, c.idgen))
  98. addrOf.add newDeref(newSymNode(x))
  99. let castExpr1 = newNodeIT(nkCast, c.info, intType)
  100. castExpr1.add newNodeIT(nkType, c.info, intType)
  101. castExpr1.add addrOf
  102. let dotExpr = newNodeIT(nkDotExpr, c.info, x.typ)
  103. dotExpr.add newNodeIT(nkType, c.info, objType)
  104. dotExpr.add newSymNode(field)
  105. let offsetOf = genBuiltin(c, mOffsetOf, "offsetof", dotExpr)
  106. offsetOf.typ = intType
  107. let minusExpr = genBuiltin(c, mSubI, "-", castExpr1)
  108. minusExpr.typ = intType
  109. minusExpr.add offsetOf
  110. let objPtr = makePtrType(objType.owner, objType, c.idgen)
  111. result = newNodeIT(nkCast, c.info, objPtr)
  112. result.add newNodeIT(nkType, c.info, objPtr)
  113. result.add minusExpr
  114. proc destructorCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
  115. var destroy = newNodeIT(nkCall, x.info, op.typ[0])
  116. destroy.add(newSymNode(op))
  117. if op.typ[1].kind != tyVar:
  118. destroy.add x
  119. else:
  120. destroy.add genAddr(c, x)
  121. if sfNeverRaises notin op.flags:
  122. c.canRaise = true
  123. if c.addMemReset:
  124. result = newTree(nkStmtList, destroy, genBuiltin(c, mWasMoved, "`=wasMoved`", x))
  125. else:
  126. result = destroy
  127. proc genWasMovedCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
  128. result = newNodeIT(nkCall, x.info, op.typ[0])
  129. result.add(newSymNode(op))
  130. result.add genAddr(c, x)
  131. proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) =
  132. case n.kind
  133. of nkSym:
  134. if c.filterDiscriminator != nil: return
  135. let f = n.sym
  136. let b = if c.kind == attachedTrace: y else: y.dotField(f)
  137. if (sfCursor in f.flags and f.typ.skipTypes(abstractInst).kind in {tyRef, tyProc} and
  138. c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or
  139. enforceDefaultOp:
  140. defaultOp(c, f.typ, body, x.dotField(f), b)
  141. else:
  142. fillBody(c, f.typ, body, x.dotField(f), b)
  143. of nkNilLit: discard
  144. of nkRecCase:
  145. # XXX This is only correct for 'attachedSink'!
  146. var localEnforceDefaultOp = enforceDefaultOp
  147. if c.kind == attachedSink:
  148. # the value needs to be destroyed before we assign the selector
  149. # or the value is lost
  150. let prevKind = c.kind
  151. let prevAddMemReset = c.addMemReset
  152. c.kind = attachedDestructor
  153. c.addMemReset = true
  154. fillBodyObj(c, n, body, x, y, enforceDefaultOp = false)
  155. c.kind = prevKind
  156. c.addMemReset = prevAddMemReset
  157. localEnforceDefaultOp = true
  158. if c.kind != attachedDestructor:
  159. # copy the selector before case stmt, but destroy after case stmt
  160. fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false)
  161. let oldfilterDiscriminator = c.filterDiscriminator
  162. if c.filterDiscriminator == n[0].sym:
  163. c.filterDiscriminator = nil # we have found the case part, proceed as normal
  164. # we need to generate a case statement:
  165. var caseStmt = newNodeI(nkCaseStmt, c.info)
  166. # XXX generate 'if' that checks same branches
  167. # generate selector:
  168. var access = dotField(x, n[0].sym)
  169. caseStmt.add(access)
  170. var emptyBranches = 0
  171. # copy the branches over, but replace the fields with the for loop body:
  172. for i in 1..<n.len:
  173. var branch = copyTree(n[i])
  174. branch[^1] = newNodeI(nkStmtList, c.info)
  175. fillBodyObj(c, n[i].lastSon, branch[^1], x, y,
  176. enforceDefaultOp = localEnforceDefaultOp)
  177. if branch[^1].len == 0: inc emptyBranches
  178. caseStmt.add(branch)
  179. if emptyBranches != n.len-1:
  180. body.add(caseStmt)
  181. if c.kind == attachedDestructor:
  182. # destructor for selector is done after case stmt
  183. fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false)
  184. c.filterDiscriminator = oldfilterDiscriminator
  185. of nkRecList:
  186. for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp)
  187. else:
  188. illFormedAstLocal(n, c.g.config)
  189. proc fillBodyObjTImpl(c: var TLiftCtx; t: PType, body, x, y: PNode) =
  190. if t.len > 0 and t[0] != nil:
  191. fillBody(c, skipTypes(t[0], abstractPtrs), body, x, y)
  192. fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false)
  193. proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
  194. var hasCase = isCaseObj(t.n)
  195. var obj = t
  196. while obj.len > 0 and obj[0] != nil:
  197. obj = skipTypes(obj[0], abstractPtrs)
  198. hasCase = hasCase or isCaseObj(obj.n)
  199. if hasCase and c.kind in {attachedAsgn, attachedDeepCopy}:
  200. # assignment for case objects is complex, we do:
  201. # =destroy(dest)
  202. # wasMoved(dest)
  203. # for every field:
  204. # `=` dest.field, src.field
  205. # ^ this is what we used to do, but for 'result = result.sons[0]' it
  206. # destroys 'result' too early.
  207. # So this is what we really need to do:
  208. # let blob {.cursor.} = dest # remembers the old dest.kind
  209. # wasMoved(dest)
  210. # dest.kind = src.kind
  211. # for every field (dependent on dest.kind):
  212. # `=` dest.field, src.field
  213. # =destroy(blob)
  214. var dummy = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
  215. dummy.typ = y.typ
  216. if ccgIntroducedPtr(c.g.config, dummy, y.typ):
  217. # Because of potential aliasing when the src param is passed by ref, we need to check for equality here,
  218. # because the wasMoved(dest) call would zero out src, if dest aliases src.
  219. var cond = newTree(nkCall, newSymNode(c.g.getSysMagic(c.info, "==", mEqRef)),
  220. newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x), newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y))
  221. cond.typ = getSysType(c.g, x.info, tyBool)
  222. body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
  223. var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
  224. temp.typ = x.typ
  225. incl(temp.flags, sfFromGeneric)
  226. var v = newNodeI(nkVarSection, c.info)
  227. let blob = newSymNode(temp)
  228. v.addVar(blob, x)
  229. body.add v
  230. #body.add newAsgnStmt(blob, x)
  231. var wasMovedCall = newNodeI(nkCall, c.info)
  232. wasMovedCall.add(newSymNode(createMagic(c.g, c.idgen, "`=wasMoved`", mWasMoved)))
  233. wasMovedCall.add x # mWasMoved does not take the address
  234. body.add wasMovedCall
  235. fillBodyObjTImpl(c, t, body, x, y)
  236. when false:
  237. # does not work yet due to phase-ordering problems:
  238. assert t.destructor != nil
  239. body.add destructorCall(c.g, t.destructor, blob)
  240. let prevKind = c.kind
  241. c.kind = attachedDestructor
  242. fillBodyObjTImpl(c, t, body, blob, y)
  243. c.kind = prevKind
  244. else:
  245. fillBodyObjTImpl(c, t, body, x, y)
  246. proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
  247. result = newIntLit(g, info, ord value)
  248. result.typ = getSysType(g, info, tyBool)
  249. proc getCycleParam(c: TLiftCtx): PNode =
  250. assert c.kind in {attachedAsgn, attachedDup}
  251. if c.fn.typ.len == 4:
  252. result = c.fn.typ.n.lastSon
  253. assert result.kind == nkSym
  254. assert result.sym.name.s == "cyclic"
  255. else:
  256. result = boolLit(c.g, c.info, true)
  257. proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
  258. #if sfError in op.flags:
  259. # localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s)
  260. result = newNodeI(nkCall, x.info)
  261. result.add newSymNode(op)
  262. if sfNeverRaises notin op.flags:
  263. c.canRaise = true
  264. if op.typ[1].kind == tyVar:
  265. result.add genAddr(c, x)
  266. else:
  267. result.add x
  268. if y != nil:
  269. result.add y
  270. if op.typ.len == 4:
  271. assert y != nil
  272. if c.fn.typ.len == 4:
  273. result.add getCycleParam(c)
  274. else:
  275. # assume the worst: A cycle is created:
  276. result.add boolLit(c.g, y.info, true)
  277. proc newOpCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
  278. result = newNodeIT(nkCall, x.info, op.typ[0])
  279. result.add(newSymNode(op))
  280. result.add x
  281. if sfNeverRaises notin op.flags:
  282. c.canRaise = true
  283. proc newDeepCopyCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
  284. result = newAsgnStmt(x, newOpCall(c, op, y))
  285. proc newDupCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
  286. result = newAsgnStmt(x, newOpCall(c, op, y))
  287. proc usesBuiltinArc(t: PType): bool =
  288. proc wrap(t: PType): bool {.nimcall.} = ast.isGCedMem(t)
  289. result = types.searchTypeFor(t, wrap)
  290. proc useNoGc(c: TLiftCtx; t: PType): bool {.inline.} =
  291. result = optSeqDestructors in c.g.config.globalOptions and
  292. ({tfHasGCedMem, tfHasOwned} * t.flags != {} or usesBuiltinArc(t))
  293. proc requiresDestructor(c: TLiftCtx; t: PType): bool {.inline.} =
  294. result = optSeqDestructors in c.g.config.globalOptions and
  295. containsGarbageCollectedRef(t)
  296. proc instantiateGeneric(c: var TLiftCtx; op: PSym; t, typeInst: PType): PSym =
  297. if c.c != nil and typeInst != nil:
  298. result = c.c.instTypeBoundOp(c.c, op, typeInst, c.info, attachedAsgn, 1)
  299. else:
  300. localError(c.g.config, c.info,
  301. "cannot generate destructor for generic type: " & typeToString(t))
  302. result = nil
  303. proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
  304. field: var PSym): bool =
  305. if optSeqDestructors in c.g.config.globalOptions:
  306. var op = field
  307. let destructorOverridden = destructorOverridden(c.g, t)
  308. if op != nil and op != c.fn and
  309. (sfOverridden in op.flags or destructorOverridden):
  310. if sfError in op.flags:
  311. incl c.fn.flags, sfError
  312. #else:
  313. # markUsed(c.g.config, c.info, op, c.g.usageSym)
  314. onUse(c.info, op)
  315. body.add newHookCall(c, op, x, y)
  316. result = true
  317. elif op == nil and destructorOverridden:
  318. op = produceSym(c.g, c.c, t, c.kind, c.info, c.idgen)
  319. body.add newHookCall(c, op, x, y)
  320. result = true
  321. else:
  322. result = false
  323. elif tfHasAsgn in t.flags:
  324. var op: PSym
  325. if sameType(t, c.asgnForType):
  326. # generate recursive call:
  327. if c.recurse:
  328. op = c.fn
  329. else:
  330. c.recurse = true
  331. return false
  332. else:
  333. op = field
  334. if op == nil:
  335. op = produceSym(c.g, c.c, t, c.kind, c.info, c.idgen)
  336. if sfError in op.flags:
  337. incl c.fn.flags, sfError
  338. #else:
  339. # markUsed(c.g.config, c.info, op, c.g.usageSym)
  340. onUse(c.info, op)
  341. # We also now do generic instantiations in the destructor lifting pass:
  342. if op.ast.isGenericRoutine:
  343. op = instantiateGeneric(c, op, t, t.typeInst)
  344. field = op
  345. #echo "trying to use ", op.ast
  346. #echo "for ", op.name.s, " "
  347. #debug(t)
  348. #return false
  349. assert op.ast[genericParamsPos].kind == nkEmpty
  350. body.add newHookCall(c, op, x, y)
  351. result = true
  352. else:
  353. result = false
  354. proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
  355. let t = orig.skipTypes(abstractInst - {tyDistinct})
  356. var op = t.destructor
  357. if op != nil and sfOverridden in op.flags:
  358. if op.ast.isGenericRoutine:
  359. # patch generic destructor:
  360. op = instantiateGeneric(c, op, t, t.typeInst)
  361. setAttachedOp(c.g, c.idgen.module, t, attachedDestructor, op)
  362. if op == nil and (useNoGc(c, t) or requiresDestructor(c, t)):
  363. op = produceSym(c.g, c.c, t, attachedDestructor, c.info, c.idgen)
  364. doAssert op != nil
  365. doAssert op == t.destructor
  366. if op != nil:
  367. #markUsed(c.g.config, c.info, op, c.g.usageSym)
  368. onUse(c.info, op)
  369. body.add destructorCall(c, op, x)
  370. elif useNoGc(c, t):
  371. internalError(c.g.config, c.info,
  372. "type-bound operator could not be resolved")
  373. proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
  374. case c.kind
  375. of attachedDestructor:
  376. var op = t.destructor
  377. if op != nil and sfOverridden in op.flags:
  378. if op.ast.isGenericRoutine:
  379. # patch generic destructor:
  380. op = instantiateGeneric(c, op, t, t.typeInst)
  381. setAttachedOp(c.g, c.idgen.module, t, attachedDestructor, op)
  382. #markUsed(c.g.config, c.info, op, c.g.usageSym)
  383. onUse(c.info, op)
  384. body.add destructorCall(c, op, x)
  385. result = true
  386. else:
  387. result = false
  388. #result = addDestructorCall(c, t, body, x)
  389. of attachedAsgn, attachedSink, attachedTrace:
  390. var op = getAttachedOp(c.g, t, c.kind)
  391. if op != nil and sfOverridden in op.flags:
  392. if op.ast.isGenericRoutine:
  393. # patch generic =trace:
  394. op = instantiateGeneric(c, op, t, t.typeInst)
  395. setAttachedOp(c.g, c.idgen.module, t, c.kind, op)
  396. result = considerAsgnOrSink(c, t, body, x, y, op)
  397. if op != nil:
  398. setAttachedOp(c.g, c.idgen.module, t, c.kind, op)
  399. of attachedDeepCopy:
  400. let op = getAttachedOp(c.g, t, attachedDeepCopy)
  401. if op != nil:
  402. #markUsed(c.g.config, c.info, op, c.g.usageSym)
  403. onUse(c.info, op)
  404. body.add newDeepCopyCall(c, op, x, y)
  405. result = true
  406. else:
  407. result = false
  408. of attachedWasMoved:
  409. var op = getAttachedOp(c.g, t, attachedWasMoved)
  410. if op != nil and sfOverridden in op.flags:
  411. if op.ast.isGenericRoutine:
  412. # patch generic destructor:
  413. op = instantiateGeneric(c, op, t, t.typeInst)
  414. setAttachedOp(c.g, c.idgen.module, t, attachedWasMoved, op)
  415. #markUsed(c.g.config, c.info, op, c.g.usageSym)
  416. onUse(c.info, op)
  417. body.add genWasMovedCall(c, op, x)
  418. result = true
  419. else:
  420. result = false
  421. of attachedDup:
  422. var op = getAttachedOp(c.g, t, attachedDup)
  423. if op != nil and sfOverridden in op.flags:
  424. if op.ast.isGenericRoutine:
  425. # patch generic destructor:
  426. op = instantiateGeneric(c, op, t, t.typeInst)
  427. setAttachedOp(c.g, c.idgen.module, t, attachedDup, op)
  428. #markUsed(c.g.config, c.info, op, c.g.usageSym)
  429. onUse(c.info, op)
  430. body.add newDupCall(c, op, x, y)
  431. result = true
  432. else:
  433. result = false
  434. proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
  435. var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
  436. temp.typ = getSysType(c.g, body.info, tyInt)
  437. incl(temp.flags, sfFromGeneric)
  438. var v = newNodeI(nkVarSection, c.info)
  439. result = newSymNode(temp)
  440. v.addVar(result, lowerings.newIntLit(c.g, body.info, first))
  441. body.add v
  442. proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode =
  443. var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
  444. temp.typ = value.typ
  445. incl(temp.flags, sfFromGeneric)
  446. var v = newNodeI(nkVarSection, c.info)
  447. result = newSymNode(temp)
  448. v.addVar(result, value)
  449. body.add v
  450. proc addIncStmt(c: var TLiftCtx; body, i: PNode) =
  451. let incCall = genBuiltin(c, mInc, "inc", i)
  452. incCall.add lowerings.newIntLit(c.g, c.info, 1)
  453. body.add incCall
  454. proc newSeqCall(c: var TLiftCtx; x, y: PNode): PNode =
  455. # don't call genAddr(c, x) here:
  456. result = genBuiltin(c, mNewSeq, "newSeq", x)
  457. let lenCall = genBuiltin(c, mLengthSeq, "len", y)
  458. lenCall.typ = getSysType(c.g, x.info, tyInt)
  459. result.add lenCall
  460. proc setLenStrCall(c: var TLiftCtx; x, y: PNode): PNode =
  461. let lenCall = genBuiltin(c, mLengthStr, "len", y)
  462. lenCall.typ = getSysType(c.g, x.info, tyInt)
  463. result = genBuiltin(c, mSetLengthStr, "setLen", x) # genAddr(g, x))
  464. result.add lenCall
  465. proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode =
  466. let lenCall = genBuiltin(c, mLengthSeq, "len", y)
  467. lenCall.typ = getSysType(c.g, x.info, tyInt)
  468. var op = getSysMagic(c.g, x.info, "setLen", mSetLengthSeq)
  469. op = instantiateGeneric(c, op, t, t)
  470. result = newTree(nkCall, newSymNode(op, x.info), x, lenCall)
  471. proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
  472. let counterIdx = body.len
  473. let i = declareCounter(c, body, toInt64(firstOrd(c.g.config, t)))
  474. let whileLoop = genWhileLoop(c, i, x)
  475. let elemType = t.lastSon
  476. let b = if c.kind == attachedTrace: y else: y.at(i, elemType)
  477. fillBody(c, elemType, whileLoop[1], x.at(i, elemType), b)
  478. if whileLoop[1].len > 0:
  479. addIncStmt(c, whileLoop[1], i)
  480. body.add whileLoop
  481. else:
  482. body.sons.setLen counterIdx
  483. proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
  484. case c.kind
  485. of attachedDup:
  486. body.add setLenSeqCall(c, t, x, y)
  487. forallElements(c, t, body, x, y)
  488. of attachedAsgn, attachedDeepCopy:
  489. # we generate:
  490. # setLen(dest, y.len)
  491. # var i = 0
  492. # while i < y.len: dest[i] = y[i]; inc(i)
  493. # This is usually more efficient than a destroy/create pair.
  494. body.add setLenSeqCall(c, t, x, y)
  495. forallElements(c, t, body, x, y)
  496. of attachedSink:
  497. let moveCall = genBuiltin(c, mMove, "move", x)
  498. moveCall.add y
  499. doAssert t.destructor != nil
  500. moveCall.add destructorCall(c, t.destructor, x)
  501. body.add moveCall
  502. of attachedDestructor:
  503. # destroy all elements:
  504. forallElements(c, t, body, x, y)
  505. body.add genBuiltin(c, mDestroy, "destroy", x)
  506. of attachedTrace:
  507. if canFormAcycle(c.g, t.elemType):
  508. # follow all elements:
  509. forallElements(c, t, body, x, y)
  510. of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
  511. proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
  512. createTypeBoundOps(c.g, c.c, t, body.info, c.idgen)
  513. # recursions are tricky, so we might need to forward the generated
  514. # operation here:
  515. var t = t
  516. if t.assignment == nil or t.destructor == nil or t.dup == nil:
  517. let h = sighashes.hashType(t,c.g.config, {CoType, CoConsiderOwned, CoDistinct})
  518. let canon = c.g.canonTypes.getOrDefault(h)
  519. if canon != nil: t = canon
  520. case c.kind
  521. of attachedAsgn, attachedDeepCopy:
  522. # XXX: replace these with assertions.
  523. if t.assignment == nil:
  524. return # protect from recursion
  525. body.add newHookCall(c, t.assignment, x, y)
  526. of attachedSink:
  527. # we always inline the move for better performance:
  528. let moveCall = genBuiltin(c, mMove, "move", x)
  529. moveCall.add y
  530. doAssert t.destructor != nil
  531. moveCall.add destructorCall(c, t.destructor, x)
  532. body.add moveCall
  533. # alternatively we could do this:
  534. when false:
  535. doAssert t.asink != nil
  536. body.add newHookCall(c, t.asink, x, y)
  537. of attachedDestructor:
  538. doAssert t.destructor != nil
  539. body.add destructorCall(c, t.destructor, x)
  540. of attachedTrace:
  541. if t.kind != tyString and canFormAcycle(c.g, t.elemType):
  542. let op = getAttachedOp(c.g, t, c.kind)
  543. if op == nil:
  544. return # protect from recursion
  545. body.add newHookCall(c, op, x, y)
  546. of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
  547. of attachedDup:
  548. # XXX: replace these with assertions.
  549. let op = getAttachedOp(c.g, t, c.kind)
  550. if op == nil:
  551. return # protect from recursion
  552. body.add newDupCall(c, op, x, y)
  553. proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
  554. case c.kind
  555. of attachedAsgn, attachedDeepCopy, attachedDup:
  556. body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c, x), y)
  557. of attachedSink:
  558. let moveCall = genBuiltin(c, mMove, "move", x)
  559. moveCall.add y
  560. doAssert t.destructor != nil
  561. moveCall.add destructorCall(c, t.destructor, x)
  562. body.add moveCall
  563. of attachedDestructor:
  564. body.add genBuiltin(c, mDestroy, "destroy", x)
  565. of attachedTrace:
  566. discard "strings are atomic and have no inner elements that are to trace"
  567. of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
  568. proc cyclicType*(g: ModuleGraph, t: PType): bool =
  569. case t.kind
  570. of tyRef: result = types.canFormAcycle(g, t.lastSon)
  571. of tyProc: result = t.callConv == ccClosure
  572. else: result = false
  573. proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
  574. #[ bug #15753 is really subtle. Usually the classical write barrier for reference
  575. counting looks like this::
  576. incRef source # increment first; this takes care of self-assignments1
  577. decRef dest
  578. dest[] = source
  579. However, 'decRef dest' might trigger a cycle collection and then the collector
  580. traverses the graph. It is crucial that when it follows the pointers the assignment
  581. 'dest[] = source' already happened so that we don't do trial deletion on a wrong
  582. graph -- this causes premature freeing of objects! The correct barrier looks like
  583. this::
  584. let tmp = dest
  585. incRef source
  586. dest[] = source
  587. decRef tmp
  588. ]#
  589. var actions = newNodeI(nkStmtList, c.info)
  590. let elemType = t.lastSon
  591. createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen)
  592. let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(c.g, elemType)
  593. let isInheritableAcyclicRef = c.g.config.selectedGC == gcOrc and
  594. (not isPureObject(elemType)) and
  595. tfAcyclic in skipTypes(elemType, abstractInst+{tyOwned}-{tyTypeDesc}).flags
  596. # dynamic Acyclic refs need to use dyn decRef
  597. let tmp =
  598. if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
  599. declareTempOf(c, body, x)
  600. else:
  601. x
  602. if isFinal(elemType):
  603. addDestructorCall(c, elemType, actions, genDeref(tmp, nkDerefExpr))
  604. var alignOf = genBuiltin(c, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType))
  605. alignOf.typ = getSysType(c.g, c.info, tyInt)
  606. actions.add callCodegenProc(c.g, "nimRawDispose", c.info, tmp, alignOf)
  607. else:
  608. addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(tmp, nkDerefExpr))
  609. actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, tmp)
  610. var cond: PNode
  611. if isCyclic:
  612. if isFinal(elemType):
  613. let typInfo = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
  614. typInfo.typ = getSysType(c.g, c.info, tyPointer)
  615. cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicStatic", c.info, tmp, typInfo)
  616. else:
  617. cond = callCodegenProc(c.g, "nimDecRefIsLastCyclicDyn", c.info, tmp)
  618. elif isInheritableAcyclicRef:
  619. cond = callCodegenProc(c.g, "nimDecRefIsLastDyn", c.info, x)
  620. else:
  621. cond = callCodegenProc(c.g, "nimDecRefIsLast", c.info, x)
  622. cond.typ = getSysType(c.g, x.info, tyBool)
  623. case c.kind
  624. of attachedSink:
  625. if isCyclic:
  626. body.add newAsgnStmt(x, y)
  627. body.add genIf(c, cond, actions)
  628. else:
  629. body.add genIf(c, cond, actions)
  630. body.add newAsgnStmt(x, y)
  631. of attachedAsgn:
  632. if isCyclic:
  633. body.add genIf(c, y, callCodegenProc(c.g,
  634. "nimIncRefCyclic", c.info, y, getCycleParam(c)))
  635. body.add newAsgnStmt(x, y)
  636. body.add genIf(c, cond, actions)
  637. else:
  638. body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y))
  639. body.add genIf(c, cond, actions)
  640. body.add newAsgnStmt(x, y)
  641. of attachedDestructor:
  642. body.add genIf(c, cond, actions)
  643. of attachedDeepCopy: assert(false, "cannot happen")
  644. of attachedTrace:
  645. if isCyclic:
  646. if isFinal(elemType):
  647. let typInfo = genBuiltin(c, mGetTypeInfoV2, "getTypeInfoV2", newNodeIT(nkType, x.info, elemType))
  648. typInfo.typ = getSysType(c.g, c.info, tyPointer)
  649. body.add callCodegenProc(c.g, "nimTraceRef", c.info, genAddrOf(x, c.idgen), typInfo, y)
  650. else:
  651. # If the ref is polymorphic we have to account for this
  652. body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x, c.idgen), y)
  653. #echo "can follow ", elemType, " static ", isFinal(elemType)
  654. of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
  655. of attachedDup:
  656. if isCyclic:
  657. body.add newAsgnStmt(x, y)
  658. body.add genIf(c, y, callCodegenProc(c.g,
  659. "nimIncRefCyclic", c.info, y, getCycleParam(c)))
  660. else:
  661. body.add newAsgnStmt(x, y)
  662. body.add genIf(c, y, callCodegenProc(c.g,
  663. "nimIncRef", c.info, y))
  664. proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
  665. ## Closures are really like refs except they always use a virtual destructor
  666. ## and we need to do the refcounting only on the ref field which we call 'xenv':
  667. let xenv = genBuiltin(c, mAccessEnv, "accessEnv", x)
  668. xenv.typ = getSysType(c.g, c.info, tyPointer)
  669. let isCyclic = c.g.config.selectedGC == gcOrc
  670. let tmp =
  671. if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
  672. declareTempOf(c, body, xenv)
  673. else:
  674. xenv
  675. var actions = newNodeI(nkStmtList, c.info)
  676. actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, tmp)
  677. let decRefProc =
  678. if isCyclic: "nimDecRefIsLastCyclicDyn"
  679. else: "nimDecRefIsLast"
  680. let cond = callCodegenProc(c.g, decRefProc, c.info, tmp)
  681. cond.typ = getSysType(c.g, x.info, tyBool)
  682. case c.kind
  683. of attachedSink:
  684. if isCyclic:
  685. body.add newAsgnStmt(x, y)
  686. body.add genIf(c, cond, actions)
  687. else:
  688. body.add genIf(c, cond, actions)
  689. body.add newAsgnStmt(x, y)
  690. of attachedAsgn:
  691. let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y)
  692. yenv.typ = getSysType(c.g, c.info, tyPointer)
  693. if isCyclic:
  694. body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c)))
  695. body.add newAsgnStmt(x, y)
  696. body.add genIf(c, cond, actions)
  697. else:
  698. body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRef", c.info, yenv))
  699. body.add genIf(c, cond, actions)
  700. body.add newAsgnStmt(x, y)
  701. of attachedDup:
  702. let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y)
  703. yenv.typ = getSysType(c.g, c.info, tyPointer)
  704. if isCyclic:
  705. body.add newAsgnStmt(x, y)
  706. body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c)))
  707. else:
  708. body.add newAsgnStmt(x, y)
  709. body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRef", c.info, yenv))
  710. of attachedDestructor:
  711. body.add genIf(c, cond, actions)
  712. of attachedDeepCopy: assert(false, "cannot happen")
  713. of attachedTrace:
  714. body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv, c.idgen), y)
  715. of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
  716. proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
  717. case c.kind
  718. of attachedSink:
  719. # we 'nil' y out afterwards so we *need* to take over its reference
  720. # count value:
  721. body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x))
  722. body.add newAsgnStmt(x, y)
  723. of attachedAsgn:
  724. body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y))
  725. body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x))
  726. body.add newAsgnStmt(x, y)
  727. of attachedDup:
  728. body.add newAsgnStmt(x, y)
  729. body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y))
  730. of attachedDestructor:
  731. # it's better to prepend the destruction of weak refs in order to
  732. # prevent wrong "dangling refs exist" problems:
  733. var actions = newNodeI(nkStmtList, c.info)
  734. actions.add callCodegenProc(c.g, "nimDecWeakRef", c.info, x)
  735. let des = genIf(c, x, actions)
  736. if body.len == 0:
  737. body.add des
  738. else:
  739. body.sons.insert(des, 0)
  740. of attachedDeepCopy: assert(false, "cannot happen")
  741. of attachedTrace: discard
  742. of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
  743. proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
  744. var actions = newNodeI(nkStmtList, c.info)
  745. let elemType = t.lastSon
  746. #fillBody(c, elemType, actions, genDeref(x), genDeref(y))
  747. #var disposeCall = genBuiltin(c, mDispose, "dispose", x)
  748. if isFinal(elemType):
  749. addDestructorCall(c, elemType, actions, genDeref(x, nkDerefExpr))
  750. var alignOf = genBuiltin(c, mAlignOf, "alignof", newNodeIT(nkType, c.info, elemType))
  751. alignOf.typ = getSysType(c.g, c.info, tyInt)
  752. actions.add callCodegenProc(c.g, "nimRawDispose", c.info, x, alignOf)
  753. else:
  754. addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(x, nkDerefExpr))
  755. actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, x)
  756. case c.kind
  757. of attachedSink, attachedAsgn:
  758. body.add genIf(c, x, actions)
  759. body.add newAsgnStmt(x, y)
  760. of attachedDup:
  761. body.add newAsgnStmt(x, y)
  762. of attachedDestructor:
  763. body.add genIf(c, x, actions)
  764. of attachedDeepCopy: assert(false, "cannot happen")
  765. of attachedTrace: discard
  766. of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
  767. proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
  768. if c.kind == attachedDeepCopy:
  769. # a big problem is that we don't know the environment's type here, so we
  770. # have to go through some indirection; we delegate this to the codegen:
  771. let call = newNodeI(nkCall, c.info, 2)
  772. call.typ = t
  773. call[0] = newSymNode(createMagic(c.g, c.idgen, "deepCopy", mDeepCopy))
  774. call[1] = y
  775. body.add newAsgnStmt(x, call)
  776. elif (optOwnedRefs in c.g.config.globalOptions and
  777. optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
  778. let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
  779. xx.typ = getSysType(c.g, c.info, tyPointer)
  780. case c.kind
  781. of attachedSink:
  782. # we 'nil' y out afterwards so we *need* to take over its reference
  783. # count value:
  784. body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
  785. body.add newAsgnStmt(x, y)
  786. of attachedAsgn:
  787. let yy = genBuiltin(c, mAccessEnv, "accessEnv", y)
  788. yy.typ = getSysType(c.g, c.info, tyPointer)
  789. body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
  790. body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
  791. body.add newAsgnStmt(x, y)
  792. of attachedDup:
  793. let yy = genBuiltin(c, mAccessEnv, "accessEnv", y)
  794. yy.typ = getSysType(c.g, c.info, tyPointer)
  795. body.add newAsgnStmt(x, y)
  796. body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
  797. of attachedDestructor:
  798. let des = genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
  799. if body.len == 0:
  800. body.add des
  801. else:
  802. body.sons.insert(des, 0)
  803. of attachedDeepCopy: assert(false, "cannot happen")
  804. of attachedTrace: discard
  805. of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
  806. proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
  807. let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
  808. xx.typ = getSysType(c.g, c.info, tyPointer)
  809. var actions = newNodeI(nkStmtList, c.info)
  810. #discard addDestructorCall(c, elemType, newNodeI(nkStmtList, c.info), genDeref(xx))
  811. actions.add callCodegenProc(c.g, "nimDestroyAndDispose", c.info, xx)
  812. case c.kind
  813. of attachedSink, attachedAsgn:
  814. body.add genIf(c, xx, actions)
  815. body.add newAsgnStmt(x, y)
  816. of attachedDup:
  817. body.add newAsgnStmt(x, y)
  818. of attachedDestructor:
  819. body.add genIf(c, xx, actions)
  820. of attachedDeepCopy: assert(false, "cannot happen")
  821. of attachedTrace: discard
  822. of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
  823. proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
  824. case t.kind
  825. of tyNone, tyEmpty, tyVoid: discard
  826. of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCstring,
  827. tyPtr, tyUncheckedArray, tyVar, tyLent:
  828. defaultOp(c, t, body, x, y)
  829. of tyRef:
  830. if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
  831. atomicRefOp(c, t, body, x, y)
  832. elif (optOwnedRefs in c.g.config.globalOptions and
  833. optRefCheck in c.g.config.options):
  834. weakrefOp(c, t, body, x, y)
  835. else:
  836. defaultOp(c, t, body, x, y)
  837. of tyProc:
  838. if t.callConv == ccClosure:
  839. if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
  840. atomicClosureOp(c, t, body, x, y)
  841. else:
  842. closureOp(c, t, body, x, y)
  843. else:
  844. defaultOp(c, t, body, x, y)
  845. of tyOwned:
  846. let base = t.skipTypes(abstractInstOwned)
  847. if optOwnedRefs in c.g.config.globalOptions:
  848. case base.kind
  849. of tyRef:
  850. ownedRefOp(c, base, body, x, y)
  851. return
  852. of tyProc:
  853. if base.callConv == ccClosure:
  854. ownedClosureOp(c, base, body, x, y)
  855. return
  856. else: discard
  857. defaultOp(c, base, body, x, y)
  858. of tyArray:
  859. if tfHasAsgn in t.flags or useNoGc(c, t):
  860. forallElements(c, t, body, x, y)
  861. else:
  862. defaultOp(c, t, body, x, y)
  863. of tySequence:
  864. if useNoGc(c, t):
  865. useSeqOrStrOp(c, t, body, x, y)
  866. elif optSeqDestructors in c.g.config.globalOptions:
  867. # note that tfHasAsgn is propagated so we need the check on
  868. # 'selectedGC' here to determine if we have the new runtime.
  869. discard considerUserDefinedOp(c, t, body, x, y)
  870. elif tfHasAsgn in t.flags:
  871. if c.kind in {attachedAsgn, attachedSink, attachedDeepCopy}:
  872. body.add newSeqCall(c, x, y)
  873. forallElements(c, t, body, x, y)
  874. else:
  875. defaultOp(c, t, body, x, y)
  876. of tyString:
  877. if useNoGc(c, t):
  878. useSeqOrStrOp(c, t, body, x, y)
  879. elif tfHasAsgn in t.flags:
  880. discard considerUserDefinedOp(c, t, body, x, y)
  881. else:
  882. defaultOp(c, t, body, x, y)
  883. of tyObject:
  884. if not considerUserDefinedOp(c, t, body, x, y):
  885. if t.sym != nil and sfImportc in t.sym.flags:
  886. case c.kind
  887. of {attachedAsgn, attachedSink, attachedDup}:
  888. body.add newAsgnStmt(x, y)
  889. of attachedWasMoved:
  890. body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
  891. else:
  892. fillBodyObjT(c, t, body, x, y)
  893. else:
  894. if c.kind == attachedDup:
  895. var op2 = getAttachedOp(c.g, t, attachedAsgn)
  896. if op2 != nil and sfOverridden in op2.flags:
  897. #markUsed(c.g.config, c.info, op, c.g.usageSym)
  898. onUse(c.info, op2)
  899. body.add newHookCall(c, t.assignment, x, y)
  900. else:
  901. fillBodyObjT(c, t, body, x, y)
  902. else:
  903. fillBodyObjT(c, t, body, x, y)
  904. of tyDistinct:
  905. if not considerUserDefinedOp(c, t, body, x, y):
  906. fillBody(c, t[0], body, x, y)
  907. of tyTuple:
  908. fillBodyTup(c, t, body, x, y)
  909. of tyVarargs, tyOpenArray:
  910. if c.kind == attachedDestructor and (tfHasAsgn in t.flags or useNoGc(c, t)):
  911. forallElements(c, t, body, x, y)
  912. else:
  913. discard "cannot copy openArray"
  914. of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
  915. tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
  916. tyGenericParam, tyGenericBody, tyNil, tyUntyped, tyTyped,
  917. tyTypeDesc, tyGenericInvocation, tyForward, tyStatic:
  918. #internalError(c.g.config, c.info, "assignment requested for type: " & typeToString(t))
  919. discard
  920. of tyOrdinal, tyRange, tyInferred,
  921. tyGenericInst, tyAlias, tySink:
  922. fillBody(c, lastSon(t), body, x, y)
  923. of tyConcept, tyIterable: raiseAssert "unreachable"
  924. proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
  925. kind: TTypeAttachedOp; info: TLineInfo;
  926. idgen: IdGenerator): PSym =
  927. assert typ.kind == tyDistinct
  928. let baseType = typ[0]
  929. if getAttachedOp(g, baseType, kind) == nil:
  930. discard produceSym(g, c, baseType, kind, info, idgen)
  931. result = getAttachedOp(g, baseType, kind)
  932. setAttachedOp(g, idgen.module, typ, kind, result)
  933. proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
  934. info: TLineInfo; idgen: IdGenerator): PSym =
  935. let procname = getIdent(g.cache, AttachedOpToStr[kind])
  936. result = newSym(skProc, procname, idgen, owner, info)
  937. let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
  938. let src = newSym(skParam, getIdent(g.cache, "src"),
  939. idgen, result, info)
  940. res.typ = typ
  941. src.typ = typ
  942. result.typ = newType(tyProc, nextTypeId idgen, owner)
  943. result.typ.n = newNodeI(nkFormalParams, info)
  944. rawAddSon(result.typ, res.typ)
  945. result.typ.n.add newNodeI(nkEffectList, info)
  946. result.typ.addParam src
  947. if g.config.selectedGC == gcOrc and
  948. cyclicType(g, typ.skipTypes(abstractInst)):
  949. let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
  950. idgen, result, info)
  951. cycleParam.typ = getSysType(g, info, tyBool)
  952. result.typ.addParam cycleParam
  953. var n = newNodeI(nkProcDef, info, bodyPos+2)
  954. for i in 0..<n.len: n[i] = newNodeI(nkEmpty, info)
  955. n[namePos] = newSymNode(result)
  956. n[paramsPos] = result.typ.n
  957. n[bodyPos] = newNodeI(nkStmtList, info)
  958. n[resultPos] = newSymNode(res)
  959. result.ast = n
  960. incl result.flags, sfFromGeneric
  961. incl result.flags, sfGeneratedOp
  962. proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
  963. info: TLineInfo; idgen: IdGenerator): PSym =
  964. if kind == attachedDup:
  965. return symDupPrototype(g, typ, owner, kind, info, idgen)
  966. let procname = getIdent(g.cache, AttachedOpToStr[kind])
  967. result = newSym(skProc, procname, idgen, owner, info)
  968. let dest = newSym(skParam, getIdent(g.cache, "dest"), idgen, result, info)
  969. let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"),
  970. idgen, result, info)
  971. if kind == attachedDestructor and typ.kind in {tyRef, tyString, tySequence} and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
  972. dest.typ = typ
  973. else:
  974. dest.typ = makeVarType(typ.owner, typ, idgen)
  975. if kind == attachedTrace:
  976. src.typ = getSysType(g, info, tyPointer)
  977. else:
  978. src.typ = typ
  979. result.typ = newProcType(info, nextTypeId(idgen), owner)
  980. result.typ.addParam dest
  981. if kind notin {attachedDestructor, attachedWasMoved}:
  982. result.typ.addParam src
  983. if kind == attachedAsgn and g.config.selectedGC == gcOrc and
  984. cyclicType(g, typ.skipTypes(abstractInst)):
  985. let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
  986. idgen, result, info)
  987. cycleParam.typ = getSysType(g, info, tyBool)
  988. result.typ.addParam cycleParam
  989. var n = newNodeI(nkProcDef, info, bodyPos+1)
  990. for i in 0..<n.len: n[i] = newNodeI(nkEmpty, info)
  991. n[namePos] = newSymNode(result)
  992. n[paramsPos] = result.typ.n
  993. n[bodyPos] = newNodeI(nkStmtList, info)
  994. result.ast = n
  995. incl result.flags, sfFromGeneric
  996. incl result.flags, sfGeneratedOp
  997. if kind == attachedWasMoved:
  998. incl result.flags, sfNoSideEffect
  999. incl result.typ.flags, tfNoSideEffect
  1000. proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) =
  1001. let xx = genBuiltin(c, mAccessTypeField, "accessTypeField", x)
  1002. let yy = genBuiltin(c, mAccessTypeField, "accessTypeField", y)
  1003. xx.typ = getSysType(c.g, c.info, tyPointer)
  1004. yy.typ = xx.typ
  1005. body.add newAsgnStmt(xx, yy)
  1006. proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
  1007. info: TLineInfo; idgen: IdGenerator): PSym =
  1008. if typ.kind == tyDistinct:
  1009. return produceSymDistinctType(g, c, typ, kind, info, idgen)
  1010. result = getAttachedOp(g, typ, kind)
  1011. if result == nil:
  1012. result = symPrototype(g, typ, typ.owner, kind, info, idgen)
  1013. var a = TLiftCtx(info: info, g: g, kind: kind, c: c, asgnForType: typ, idgen: idgen,
  1014. fn: result)
  1015. let dest = if kind == attachedDup: result.ast[resultPos].sym else: result.typ.n[1].sym
  1016. let d = if result.typ[1].kind == tyVar: newDeref(newSymNode(dest)) else: newSymNode(dest)
  1017. let src = case kind
  1018. of {attachedDestructor, attachedWasMoved}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
  1019. of attachedDup: newSymNode(result.typ.n[1].sym)
  1020. else: newSymNode(result.typ.n[2].sym)
  1021. # register this operation already:
  1022. setAttachedOpPartial(g, idgen.module, typ, kind, result)
  1023. if kind == attachedSink and destructorOverridden(g, typ):
  1024. ## compiler can use a combination of `=destroy` and memCopy for sink op
  1025. dest.flags.incl sfCursor
  1026. let op = getAttachedOp(g, typ, attachedDestructor)
  1027. result.ast[bodyPos].add newOpCall(a, op, if op.typ[1].kind == tyVar: d[0] else: d)
  1028. result.ast[bodyPos].add newAsgnStmt(d, src)
  1029. else:
  1030. var tk: TTypeKind
  1031. if g.config.selectedGC in {gcArc, gcOrc, gcHooks, gcAtomicArc}:
  1032. tk = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink}).kind
  1033. else:
  1034. tk = tyNone # no special casing for strings and seqs
  1035. case tk
  1036. of tySequence:
  1037. fillSeqOp(a, typ, result.ast[bodyPos], d, src)
  1038. of tyString:
  1039. fillStrOp(a, typ, result.ast[bodyPos], d, src)
  1040. else:
  1041. fillBody(a, typ, result.ast[bodyPos], d, src)
  1042. if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy, attachedDup} and not lacksMTypeField(typ):
  1043. # bug #19205: Do not forget to also copy the hidden type field:
  1044. genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)
  1045. if not a.canRaise: incl result.flags, sfNeverRaises
  1046. completePartialOp(g, idgen.module, typ, kind, result)
  1047. proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym,
  1048. info: TLineInfo; idgen: IdGenerator): PSym =
  1049. assert(typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject)
  1050. result = symPrototype(g, field.typ, typ.owner, attachedDestructor, info, idgen)
  1051. var a = TLiftCtx(info: info, g: g, kind: attachedDestructor, asgnForType: typ, idgen: idgen,
  1052. fn: result)
  1053. a.asgnForType = typ
  1054. a.filterDiscriminator = field
  1055. a.addMemReset = true
  1056. let discrimantDest = result.typ.n[1].sym
  1057. let dst = newSym(skVar, getIdent(g.cache, "dest"), idgen, result, info)
  1058. dst.typ = makePtrType(typ.owner, typ, idgen)
  1059. let dstSym = newSymNode(dst)
  1060. let d = newDeref(dstSym)
  1061. let v = newNodeI(nkVarSection, info)
  1062. v.addVar(dstSym, genContainerOf(a, typ, field, discrimantDest))
  1063. result.ast[bodyPos].add v
  1064. let placeHolder = newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
  1065. fillBody(a, typ, result.ast[bodyPos], d, placeHolder)
  1066. if not a.canRaise: incl result.flags, sfNeverRaises
  1067. template liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
  1068. discard "now a nop"
  1069. proc patchBody(g: ModuleGraph; c: PContext; n: PNode; info: TLineInfo; idgen: IdGenerator) =
  1070. if n.kind in nkCallKinds:
  1071. if n[0].kind == nkSym and n[0].sym.magic == mDestroy:
  1072. let t = n[1].typ.skipTypes(abstractVar)
  1073. if getAttachedOp(g, t, attachedDestructor) == nil:
  1074. discard produceSym(g, c, t, attachedDestructor, info, idgen)
  1075. let op = getAttachedOp(g, t, attachedDestructor)
  1076. if op != nil:
  1077. if op.ast.isGenericRoutine:
  1078. internalError(g.config, info, "resolved destructor is generic")
  1079. if op.magic == mDestroy and t.kind != tyString:
  1080. internalError(g.config, info, "patching mDestroy with mDestroy?")
  1081. n[0] = newSymNode(op)
  1082. for x in n: patchBody(g, c, x, info, idgen)
  1083. proc inst(g: ModuleGraph; c: PContext; t: PType; kind: TTypeAttachedOp; idgen: IdGenerator;
  1084. info: TLineInfo) =
  1085. let op = getAttachedOp(g, t, kind)
  1086. if op != nil and op.ast != nil and op.ast.isGenericRoutine:
  1087. if t.typeInst != nil:
  1088. var a = TLiftCtx(info: info, g: g, kind: kind, c: c, idgen: idgen)
  1089. let opInst = instantiateGeneric(a, op, t, t.typeInst)
  1090. if opInst.ast != nil:
  1091. patchBody(g, c, opInst.ast, info, a.idgen)
  1092. setAttachedOp(g, idgen.module, t, kind, opInst)
  1093. else:
  1094. localError(g.config, info, "unresolved generic parameter")
  1095. proc isTrival(s: PSym): bool {.inline.} =
  1096. s == nil or (s.ast != nil and s.ast[bodyPos].len == 0)
  1097. proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo;
  1098. idgen: IdGenerator) =
  1099. ## In the semantic pass this is called in strategic places
  1100. ## to ensure we lift assignment, destructors and moves properly.
  1101. ## The later 'injectdestructors' pass depends on it.
  1102. if orig == nil or {tfCheckedForDestructor, tfHasMeta} * orig.flags != {}: return
  1103. incl orig.flags, tfCheckedForDestructor
  1104. let skipped = orig.skipTypes({tyGenericInst, tyAlias, tySink})
  1105. if isEmptyContainer(skipped) or skipped.kind == tyStatic: return
  1106. let h = sighashes.hashType(skipped, g.config, {CoType, CoConsiderOwned, CoDistinct})
  1107. var canon = g.canonTypes.getOrDefault(h)
  1108. if canon == nil:
  1109. g.canonTypes[h] = skipped
  1110. canon = skipped
  1111. # multiple cases are to distinguish here:
  1112. # 1. we don't know yet if 'typ' has a nontrival destructor.
  1113. # 2. we have a nop destructor. --> mDestroy
  1114. # 3. we have a lifted destructor.
  1115. # 4. We have a custom destructor.
  1116. # 5. We have a (custom) generic destructor.
  1117. # we do not generate '=trace' procs if we
  1118. # have the cycle detection disabled, saves code size.
  1119. let lastAttached = if g.config.selectedGC == gcOrc: attachedTrace
  1120. else: attachedSink
  1121. # bug #15122: We need to produce all prototypes before entering the
  1122. # mind boggling recursion. Hacks like these imply we should rewrite
  1123. # this module.
  1124. var generics: array[attachedWasMoved..attachedTrace, bool] = default(array[attachedWasMoved..attachedTrace, bool])
  1125. for k in attachedWasMoved..lastAttached:
  1126. generics[k] = getAttachedOp(g, canon, k) != nil
  1127. if not generics[k]:
  1128. setAttachedOp(g, idgen.module, canon, k,
  1129. symPrototype(g, canon, canon.owner, k, info, idgen))
  1130. # we generate the destructor first so that other operators can depend on it:
  1131. for k in attachedWasMoved..lastAttached:
  1132. if not generics[k]:
  1133. discard produceSym(g, c, canon, k, info, idgen)
  1134. else:
  1135. inst(g, c, canon, k, idgen, info)
  1136. if canon != orig:
  1137. setAttachedOp(g, idgen.module, orig, k, getAttachedOp(g, canon, k))
  1138. if not isTrival(getAttachedOp(g, orig, attachedDestructor)):
  1139. #or not isTrival(orig.assignment) or
  1140. # not isTrival(orig.sink):
  1141. orig.flags.incl tfHasAsgn
  1142. # ^ XXX Breaks IC!