summary refs log tree commit diff stats
path: root/tests/gc/weakrefs.nim
Commit message (Expand)AuthorAgeFilesLines
* ARC: ported the GC tests over to --gc:arcAraq2019-11-261-1/+8
* code cleanup for mark&sweep GCAraq2013-02-071-0/+2
* added devel/logging; weakrefs test; next steps for proper unsigned supportAraq2012-07-051-0/+48
href='#n49'>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
include prelude
import intsets

type
  NodeKind = enum
    internal, local, localInvalid, global, globalInvalid
  Color = enum
    white, grey, black
  Node = ref object
    id, rc: int
    kids: seq[int]
    k: NodeKind
    col: Color
  Graph = object
    nodes: Table[int, Node]
    roots: Table[int, NodeKind]

proc add(father: Node; son: int) =
  if father.kids.isNil: father.kids = @[]
  father.kids.add(son)

proc renderNode(g: Graph; id: int) =
  let n = g.nodes[id]
  echo n[]

proc toNodeId(aliases: var Table[string,int]; s: string): int =
  result = aliases.getOrDefault(s)
  if result == 0:
    if s.startsWith("x"):
      discard s.parseHex(result, 1)
    else:
      result = s.parseInt

proc parseHex(s: string): int =
  discard parseutils.parseHex(s, result, 0)

proc reachable(g: Graph; stack: var seq[int]; goal: int): bool =
  var t = initIntSet()
  while stack.len > 0:
    let it = stack.pop
    if not t.containsOrIncl(it):
      if it == goal: return true
      if it in g.nodes:
        for kid in g.nodes[it].kids:
          stack.add(kid)

const Help = """
quit          -- quits this REPL
locals, l     -- output the list of local stack roots
globals, g    -- output the list of global roots
alias name addr -- give addr a name. start 'addr' with 'x' for hexidecimal
                   notation
print name|addr  -- print a node by name or address
reachable,r  l|g|node  dest   -- outputs TRUE or FALSE depending on whether
                    dest is reachable by (l)ocals, (g)lobals or by the
                    other given node. Nodes can be node names or node
                    addresses.
"""

proc repl(g: Graph) =
  var aliases = initTable[string,int]()
  while true:
    let line = stdin.readLine()
    let data = line.split()
    if data.len == 0: continue
    case data[0]
    of "quit":
      break
    of "help":
      echo Help
    of "locals", "l":
      for k,v in g.roots:
        if v == local: renderNode(g, k)
    of "globals", "g":
      for k,v in g.roots:
        if v == global: renderNode(g, k)
    of "alias", "a":
      # generate alias
      if data.len == 3:
        aliases[data[1]] = toNodeId(aliases, data[2])
    of "print", "p":
      if data.len == 2:
        renderNode(g, toNodeId(aliases, data[1]))
    of "reachable", "r":
      if data.len == 3:
        var stack: seq[int] = @[]
        case data[1]
        of "locals", "l":
          for k,v in g.roots:
            if v == local: stack.add k
        of "globals", "g":
          for k,v in g.roots:
            if v == global: stack.add k
        else:
          stack.add(toNodeId(aliases, data[1]))
        let goal = toNodeId(aliases, data[2])
        echo reachable(g, stack, goal)
    else: discard

proc importData(input: string): Graph =
  #c_fprintf(file, "%s %p %d rc=%ld color=%c\n",
  #          msg, c, kind, c.refcount shr rcShift, col)
  # cell  0x10a908190 22 rc=2 color=w
  var i: File
  var
    nodes = initTable[int, Node]()
    roots = initTable[int, NodeKind]()
  if open(i, input):
    var currNode: Node
    for line in lines(i):
      let data = line.split()
      if data.len == 0: continue
      case data[0]
      of "end":
        currNode = nil
      of "cell":
        let rc = parseInt(data[3].substr("rc=".len))
        let col = case data[4].substr("color=".len)
                  of "b": black
                  of "w": white
                  of "g": grey
                  else: (assert(false); grey)
        let id = parseHex(data[1])
        currNode = Node(id: id,
          k: roots.getOrDefault(id),
          rc: rc, col: col)
        nodes[currNode.id] = currNode
      of "child":
        assert currNode != nil
        currNode.add parseHex(data[1])
      of "global_root":
        roots[data[1].parseHex] = global
      of "global_root_invalid":
        roots[data[1].parseHex] = globalInvalid
      of "onstack":
        roots[data[1].parseHex] = local
      of "onstack_invalid":
        roots[data[1].parseHex] = localInvalid
      else: discard
    close(i)
  else:
    quit "error: cannot open " & input
  shallowCopy(result.nodes, nodes)
  shallowCopy(result.roots, roots)

if paramCount() == 1:
  repl(importData(paramStr(1)))
else:
  quit "usage: heapdumprepl inputfile"