liftdestructors.nim 48 KB

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