signature hashing: more progress

This commit is contained in:
Araq 2016-11-11 08:58:42 +01:00
commit 860cbd3107
7 changed files with 301 additions and 300 deletions

View file

@ -10,7 +10,10 @@
## Computes hash values for routine (proc, method etc) signatures.
import ast, md5
export md5.`==`
from hashes import Hash
from astalgo import debug
from types import typeToString
from strutils import startsWith
when false:
type
@ -25,7 +28,7 @@ when false:
else:
type
SigHash* = Md5Digest
SigHash* = distinct Md5Digest
const
cb64 = [
@ -39,6 +42,7 @@ else:
proc toBase64a(s: cstring, len: int): string =
## encodes `s` into base64 representation.
result = newStringOfCap(((len + 2) div 3) * 4)
result.add '_'
var i = 0
while i < len - 2:
let a = ord(s[i])
@ -65,6 +69,15 @@ else:
proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
proc `&=`(c: var MD5Context, ch: char) = md5Update(c, unsafeAddr ch, 1)
proc `==`*(a, b: SigHash): bool =
# {.borrow.}
result = equalMem(unsafeAddr a, unsafeAddr b, sizeof(a))
proc hash*(u: SigHash): Hash =
result = 0
for x in 0..3:
result = (result shl 8) or u.MD5Digest[x].int
proc hashSym(c: var MD5Context, s: PSym) =
if sfAnon in s.flags or s.kind == skGenericParam:
c &= ":anon"
@ -105,28 +118,46 @@ proc hashTree(c: var MD5Context, n: PNode) =
type
ConsiderFlag* = enum
considerParamNames
CoProc
CoType
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
# modelled after 'typeToString'
if t == nil:
c &= "\254"
return
c &= char(t.kind)
# Every cyclic type in Nim need to be constructed via some 't.sym', so this
# is actually safe without an infinite recursion check:
if t.sym != nil and sfAnon notin t.sym.flags:
# t.n for literals, but not for e.g. objects!
if t.kind in {tyFloat, tyInt}: c.hashTree(t.n)
c.hashSym(t.sym)
case t.kind
of tyGenericInst:
var x = t.lastSon
if x.kind == tyGenericBody: x = x.lastSon
if x.kind == tyTuple:
c.hashType x, flags
return
for i in countup(0, sonsLen(t) - 2):
c.hashType t.sons[i], flags
return
of tyGenericInvocation:
for i in countup(0, sonsLen(t) - 1):
c.hashType t.sons[i], flags
return
of tyDistinct:
if CoType in flags:
c.hashType t.lastSon, flags
else:
c.hashSym(t.sym)
return
else:
discard
case t.kind
of tyGenericBody, tyGenericInst, tyGenericInvocation:
for i in countup(0, sonsLen(t) - 1 - ord(t.kind != tyGenericInvocation)):
c.hashType t.sons[i], flags
of tyObject, tyEnum:
# Every cyclic type in Nim need to be constructed via some 't.sym', so this
# is actually safe without an infinite recursion check:
c.hashSym(t.sym)
of tyRef, tyPtr, tyGenericBody:
c.hashType t.lastSon, flags
of tyUserTypeClass:
if t.sym != nil and t.sym.owner != nil:
c &= t.sym.owner.name.s
@ -139,11 +170,8 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
c.hashType t.sons[i], flags
of tyFromExpr, tyFieldAccessor:
c.hashTree(t.n)
of tyArrayConstr:
c.hashTree(t.sons[0].n)
c.hashType(t.sons[1], flags)
of tyTuple:
if t.n != nil:
if t.n != nil and CoType notin flags:
assert(sonsLen(t.n) == sonsLen(t))
for i in countup(0, sonsLen(t.n) - 1):
assert(t.n.sons[i].kind == nkSym)
@ -154,11 +182,11 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
else:
for i in countup(0, sonsLen(t) - 1): c.hashType t.sons[i], flags
of tyRange:
c.hashTree(t.n)
if CoType notin flags: c.hashTree(t.n)
c.hashType(t.sons[0], flags)
of tyProc:
c &= (if tfIterator in t.flags: "iterator " else: "proc ")
if considerParamNames in flags and t.n != nil:
if CoProc in flags and t.n != nil:
let params = t.n
for i in 1..<params.len:
let param = params[i].sym
@ -170,22 +198,23 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
else:
for i in 0.. <t.len: c.hashType(t.sons[i], flags)
c &= char(t.callConv)
if tfNoSideEffect in t.flags: c &= ".noSideEffect"
if tfThread in t.flags: c &= ".thread"
if CoType notin flags:
if tfNoSideEffect in t.flags: c &= ".noSideEffect"
if tfThread in t.flags: c &= ".thread"
else:
for i in 0.. <t.len: c.hashType(t.sons[i], flags)
if tfNotNil in t.flags: c &= "not nil"
if tfNotNil in t.flags and CoType notin flags: c &= "not nil"
proc hashType*(t: PType; flags: set[ConsiderFlag]): SigHash =
proc hashType*(t: PType; flags: set[ConsiderFlag] = {CoType}): SigHash =
var c: MD5Context
md5Init c
hashType c, t, flags
md5Final c, result
md5Final c, result.Md5Digest
proc hashProc*(s: PSym): SigHash =
var c: MD5Context
md5Init c
hashType c, s.typ, {considerParamNames}
hashType c, s.typ, {CoProc}
var m = s
while m.kind != skModule: m = m.owner
@ -195,7 +224,7 @@ proc hashProc*(s: PSym): SigHash =
c &= "."
c &= m.name.s
md5Final c, result
md5Final c, result.Md5Digest
proc hashOwner*(s: PSym): SigHash =
var c: MD5Context
@ -208,4 +237,4 @@ proc hashOwner*(s: PSym): SigHash =
c &= "."
c &= m.name.s
md5Final c, result
md5Final c, result.Md5Digest