summary refs log tree commit diff stats
path: root/tools/heapdump2dot.nim
Commit message (Expand)AuthorAgeFilesLines
* move prelude so that `include std/prelude` also works (#17110)Timothee Cour2021-02-201-1/+1
* further progress on --gc:v2Andreas Rumpf2016-02-171-0/+66
d='n35' href='#n35'>35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
#
#
#           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, astalgo, ropes, hashes, strutils, types, msgs, wordrecg,
  platform, trees, options

proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
  case n.kind
  of nkStmtList:
    for i in 0 ..< n.len:
      result = getPragmaStmt(n[i], w)
      if result != nil: break
  of nkPragma:
    for i in 0 ..< n.len:
      if whichPragma(n[i]) == w: return n[i]
  else: discard

proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
  result = getPragmaStmt(n, w) != nil

proc hashString*(s: string): BiggestInt =
  # has to be the same algorithm as system.hashString!
  if CPU[targetCPU].bit == 64:
    # we have to use the same bitwidth
    # as the target CPU
    var b = 0'i64
    for i in countup(0, len(s) - 1):
      b = b +% ord(s[i])
      b = b +% `shl`(b, 10)
      b = b xor `shr`(b, 6)
    b = b +% `shl`(b, 3)
    b = b xor `shr`(b, 11)
    b = b +% `shl`(b, 15)
    result = b
  else:
    var a = 0'i32
    for i in countup(0, len(s) - 1):
      a = a +% ord(s[i]).int32
      a = a +% `shl`(a, 10'i32)
      a = a xor `shr`(a, 6'i32)
    a = a +% `shl`(a, 3'i32)
    a = a xor `shr`(a, 11'i32)
    a = a +% `shl`(a, 15'i32)
    result = a

var
  gTypeTable: array[TTypeKind, TIdTable]  # XXX globals here
  gCanonicalTypes: array[TTypeKind, PType]

proc initTypeTables() =
  for i in countup(low(TTypeKind), high(TTypeKind)): initIdTable(gTypeTable[i])

proc resetCaches* =
  ## XXX: fix that more properly
  initTypeTables()
  for i in low(gCanonicalTypes)..high(gCanonicalTypes):
    gCanonicalTypes[i] = nil

when false:
  proc echoStats*() =
    for i in countup(low(TTypeKind), high(TTypeKind)):
      echo i, " ", gTypeTable[i].counter

proc slowSearch(key: PType; k: TTypeKind): PType =
  # tuples are quite horrible as C does not support them directly and
  # tuple[string, string] is a (strange) subtype of
  # tuple[nameA, nameB: string]. This bites us here, so we
  # use 'sameBackendType' instead of 'sameType'.
  if idTableHasObjectAsKey(gTypeTable[k], key): return key
  for h in countup(0, high(gTypeTable[k].data)):
    var t = PType(gTypeTable[k].data[h].key)
    if t != nil and sameBackendType(t, key):
      return t
  idTablePut(gTypeTable[k], key, key)
  result = key

proc getUniqueType*(key: PType): PType =
  # this is a hotspot in the compiler!
  result = key
  when false:
    if key == nil: return
    var k = key.kind
    case k
    of tyBool, tyChar, tyInt..tyUInt64:
      # no canonicalization for integral types, so that e.g. ``pid_t`` is
      # produced instead of ``NI``.
      result = key
    of  tyEmpty, tyNil, tyExpr, tyStmt, tyPointer, tyString,
        tyCString, tyNone, tyVoid:
      result = gCanonicalTypes[k]
      if result == nil:
        gCanonicalTypes[k] = key
        result = key
    of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr:
      if key.isResolvedUserTypeClass:
        return getUniqueType(lastSon(key))
      if key.sym != nil:
        internalError(key.sym.info, "metatype not eliminated")
      else:
        internalError("metatype not eliminated")
    of tyDistinct:
      if key.deepCopy != nil: result = key
      else: result = getUniqueType(lastSon(key))
    of tyGenericInst, tyOrdinal, tyStatic, tyAlias, tySink, tyInferred:
      result = getUniqueType(lastSon(key))
      #let obj = lastSon(key)
      #if obj.sym != nil and obj.sym.name.s == "TOption":
      #  echo "for ", typeToString(key), " I returned "
      #  debug result
    of tyPtr, tyRef, tyVar, tyLent:
      let elemType = lastSon(key)
      if elemType.kind in {tyBool, tyChar, tyInt..tyUInt64}:
        # no canonicalization for integral types, so that e.g. ``ptr pid_t`` is
        # produced instead of ``ptr NI``.
        result = key
      else:
        result = slowSearch(key, k)
    of tyGenericInvocation, tyGenericBody,
       tyOpenArray, tyArray, tySet, tyRange, tyTuple,
       tySequence, tyForward, tyVarargs, tyProxy, tyOpt:
      # we have to do a slow linear search because types may need
      # to be compared by their structure:
      result = slowSearch(key, k)
    of tyObject:
      if tfFromGeneric notin key.flags:
        # fast case; lookup per id suffices:
        result = PType(idTableGet(gTypeTable[k], key))
        if result == nil:
          idTablePut(gTypeTable[k], key, key)
          result = key
      else:
        # ugly slow case: need to compare by structure
        if idTableHasObjectAsKey(gTypeTable[k], key): return key
        for h in countup(0, high(gTypeTable[k].data)):
          var t = PType(gTypeTable[k].data[h].key)
          if t != nil and sameBackendType(t, key):
            return t
        idTablePut(gTypeTable[k], key, key)
        result = key
    of tyEnum:
      result = PType(idTableGet(gTypeTable[k], key))
      if result == nil:
        idTablePut(gTypeTable[k], key, key)
        result = key
    of tyProc:
      if key.callConv != ccClosure:
        result = key
      else:
        # ugh, we need the canon here:
        result = slowSearch(key, k)
    of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("getUniqueType")

proc makeSingleLineCString*(s: string): string =
  result = "\""
  for c in items(s):
    result.add(c.toCChar)
  result.add('\"')

proc mangle*(name: string): string =
  result = newStringOfCap(name.len)
  var start = 0
  if name[0] in Digits:
    result.add("X" & name[0])
    start = 1
  var requiresUnderscore = false
  template special(x) =
    result.add x
    requiresUnderscore = true
  for i in start..(name.len-1):
    let c = name[i]
    case c
    of 'a'..'z', '0'..'9', 'A'..'Z':
      add(result, c)
    of '_':
      # we generate names like 'foo_9' for scope disambiguations and so
      # disallow this here:
      if i > 0 and i < name.len-1 and name[i+1] in Digits:
        discard
      else:
        add(result, c)
    of '$': special "dollar"
    of '%': special "percent"
    of '&': special "amp"
    of '^': special "roof"
    of '!': special "emark"
    of '?': special "qmark"
    of '*': special "star"
    of '+': special "plus"
    of '-': special "minus"
    of '/': special "slash"
    of '=': special "eq"
    of '<': special "lt"
    of '>': special "gt"
    of '~': special "tilde"
    of ':': special "colon"
    of '.': special "dot"
    of '@': special "at"
    of '|': special "bar"
    else:
      add(result, "X" & toHex(ord(c), 2))
      requiresUnderscore = true
  if requiresUnderscore:
    result.add "_"

initTypeTables()