# # # The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # This module declares some helpers for the C code generator. import ast, types, msgs, wordrecg, platform, trees, options, cgendata, mangleutils, renderer, modulegraphs import std/[hashes, strutils, formatfloat] when defined(nimPreviewSlimSystem): import std/assertions proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode = case n.kind of nkStmtList: result = nil for i in 0.. conf.target.floatSize * 3): result = true # requested anyway elif (tfFinal in pt.flags) and (pt[0] == nil): result = false # no need, because no subtyping possible else: result = true # ordinary objects are always passed by reference, # otherwise casting doesn't work of tyTuple: result = (getSize(conf, pt) > conf.target.floatSize*3) or (optByRef in s.options) else: result = false # first parameter and return type is 'lent T'? --> use pass by pointer if s.position == 0 and retType != nil and retType.kind == tyLent: result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or pt.kind == tySet and mapSetType(conf, pt) == ctArray) proc encodeName*(name: string): string = result = mangle(name) result = $result.len & result proc makeUnique(m: BModule; s: PSym, name: string = ""): string = result = if name == "": s.name.s else: name # keep backend-minted ids out of the `_u` namespace; their item counter # restarts at 0 and would collide with loaded symbols' ids if s.itemId.isBackendMinted: result.add "_c" if (s.disamb and HookDisambBit) != 0'i32: # A backend-minted sym whose `disamb` is content-derived (setHookDisamb gave # it HookDisambBit) — e.g. the `rttiDestroy` wrapper. Its `itemId.item` is a # PER-PROCESS backend counter, so using it makes the C name diverge across # the emit-everywhere processes: the type's RTTI table (emit-everywhere, # merge-deduped) ends up referencing one process's `_c` while the # wrapper is defined with another's -> undefined at link (`rttiDestroy_c23`). # The content-derived disamb is stable across processes, so use it. result.add $s.disamb else: result.add $s.itemId.item else: result.add "_u" # Mirror `mangleProcNameExt`: use the per-(module,name) `disamb`, NOT # `itemId.item`. Under the per-module IC backend the same symbol is loaded # from a NIF in many processes and `itemId.item` is a fresh, load-order # dependent counter — so a method base would mangle to `_u1` in one module, # `_u3` in another and clean at its owner, none of which link. `disamb` is # assigned deterministically per (module, name) and is serialized, so every # process that touches the symbol derives the identical C name. result.add $s.disamb # module suffix LAST (a strippable trailing token; see `mangleProcNameExt`) result.add "__" result.add m.g.graph.ifaces[s.itemId.module].uniqueName proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false; extra: string = ""): string = #Module::Type var name = s.name.s & extra if makeUnique: name = makeUnique(m, s, name) "N" & encodeName(s.skipGenericOwner.name.s) & encodeName(name) & "E" proc encodeType*(m: BModule; t: PType; staticLists: var string): string = result = "" var kindName = ($t.kind)[2..^1] kindName[0] = toLower($kindName[0])[0] case t.kind of tyObject, tyEnum, tyDistinct, tyUserTypeClass, tyGenericParam: result = encodeSym(m, t.sym) of tyGenericInst, tyUserTypeClassInst, tyGenericBody: result = encodeName(t[0].sym.name.s) result.add "I" for i in 1..