mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-04 20:17:42 +00:00
use a full MD5 hash with no collision detection for proc names
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
|
||||
# ------------------------- Name Mangling --------------------------------
|
||||
|
||||
import debuginfo, sighashes
|
||||
import sighashes
|
||||
|
||||
proc isKeyword(w: PIdent): bool =
|
||||
# Nim and C++ share some keywords
|
||||
@@ -29,26 +29,29 @@ proc mangleField(name: PIdent): string =
|
||||
# Mangling makes everything lowercase,
|
||||
# but some identifiers are C keywords
|
||||
|
||||
proc hashOwner(s: PSym): SigHash =
|
||||
var m = s
|
||||
while m.kind != skModule: m = m.owner
|
||||
let p = m.owner
|
||||
assert p.kind == skPackage
|
||||
result = gDebugInfo.register(p.name.s, m.name.s)
|
||||
when false:
|
||||
proc hashOwner(s: PSym): SigHash =
|
||||
var m = s
|
||||
while m.kind != skModule: m = m.owner
|
||||
let p = m.owner
|
||||
assert p.kind == skPackage
|
||||
result = gDebugInfo.register(p.name.s, m.name.s)
|
||||
|
||||
proc idOrSig(m: BModule; s: PSym): BiggestInt =
|
||||
proc idOrSig(m: BModule; s: PSym): Rope =
|
||||
if s.kind in routineKinds and s.typ != nil and sfExported in s.flags and
|
||||
s.typ.callConv != ccInline:
|
||||
# signatures for exported routines are reliable enough to
|
||||
# produce a unique name and this means produced C++ is more stable wrt
|
||||
# Nim changes:
|
||||
let h = hashType(s.typ, {considerParamNames})
|
||||
if m.hashConflicts.containsOrIncl(cast[int](h)):
|
||||
result = s.id
|
||||
else:
|
||||
result = BiggestInt(h)
|
||||
when false:
|
||||
let h = hashType(s.typ, {considerParamNames})
|
||||
if m.hashConflicts.containsOrIncl(cast[int](h)):
|
||||
result = s.id
|
||||
else:
|
||||
result = BiggestInt(h)
|
||||
result = rope($hashProc(s))
|
||||
else:
|
||||
result = s.id
|
||||
result = rope s.id
|
||||
|
||||
proc mangleName(m: BModule; s: PSym): Rope =
|
||||
result = s.loc.r
|
||||
@@ -100,9 +103,9 @@ proc mangleName(m: BModule; s: PSym): Rope =
|
||||
result.add "0"
|
||||
else:
|
||||
add(result, ~"_")
|
||||
add(result, rope(m.idOrSig(s)))
|
||||
add(result, ~"_")
|
||||
add(result, rope(hashOwner(s).BiggestInt))
|
||||
add(result, m.idOrSig(s))
|
||||
#add(result, ~"_")
|
||||
#add(result, rope(hashOwner(s).BiggestInt))
|
||||
s.loc.r = result
|
||||
|
||||
proc typeName(typ: PType): Rope =
|
||||
@@ -114,7 +117,7 @@ proc getTypeName(m: BModule; typ: PType): Rope =
|
||||
result = typ.sym.loc.r
|
||||
else:
|
||||
if typ.loc.r == nil:
|
||||
when true:
|
||||
when false:
|
||||
# doesn't work yet and would require bigger rewritings
|
||||
let h = hashType(typ, {considerParamNames})# and 0x0fff_ffffu32
|
||||
let sig =
|
||||
@@ -125,8 +128,8 @@ proc getTypeName(m: BModule; typ: PType): Rope =
|
||||
else:
|
||||
let sig = BiggestInt typ.id
|
||||
typ.loc.r = typ.typeName & sig.rope #& ("_" & m.module.name.s)
|
||||
if typ.kind != tySet:
|
||||
typ.loc.r.add "_" & m.module.name.s
|
||||
#if typ.kind != tySet:
|
||||
# typ.loc.r.add "_" & m.module.name.s
|
||||
result = typ.loc.r
|
||||
if result == nil: internalError("getTypeName: " & $typ.kind)
|
||||
|
||||
@@ -625,15 +628,16 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): Rope =
|
||||
of 4: addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
|
||||
of 8: addf(m.s[cfsTypes], "typedef NI64 $1;$n", [result])
|
||||
else: internalError(t.sym.info, "getTypeDescAux: enum")
|
||||
let owner = hashOwner(t.sym)
|
||||
if not gDebugInfo.hasEnum(t.sym.name.s, t.sym.info.line, owner):
|
||||
var vals: seq[(string, int)] = @[]
|
||||
for i in countup(0, t.n.len - 1):
|
||||
assert(t.n.sons[i].kind == nkSym)
|
||||
let field = t.n.sons[i].sym
|
||||
vals.add((field.name.s, field.position.int))
|
||||
gDebugInfo.registerEnum(EnumDesc(size: size, owner: owner, id: t.sym.id,
|
||||
name: t.sym.name.s, values: vals))
|
||||
when false:
|
||||
let owner = hashOwner(t.sym)
|
||||
if not gDebugInfo.hasEnum(t.sym.name.s, t.sym.info.line, owner):
|
||||
var vals: seq[(string, int)] = @[]
|
||||
for i in countup(0, t.n.len - 1):
|
||||
assert(t.n.sons[i].kind == nkSym)
|
||||
let field = t.n.sons[i].sym
|
||||
vals.add((field.name.s, field.position.int))
|
||||
gDebugInfo.registerEnum(EnumDesc(size: size, owner: owner, id: t.sym.id,
|
||||
name: t.sym.name.s, values: vals))
|
||||
of tyProc:
|
||||
result = getTypeName(m, t)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## The compiler can generate debuginfo to help debuggers in translating back from C/C++/JS code
|
||||
## to Nim. The data structure has been designed to produce something useful with Nim's marshal
|
||||
## module.
|
||||
## The compiler can generate debuginfo to help debuggers in translating back
|
||||
## from C/C++/JS code to Nim. The data structure has been designed to produce
|
||||
## something useful with Nim's marshal module.
|
||||
|
||||
import sighashes
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import
|
||||
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs,
|
||||
securehash, streams
|
||||
|
||||
from debuginfo import writeDebugInfo
|
||||
#from debuginfo import writeDebugInfo
|
||||
|
||||
type
|
||||
TSystemCC* = enum
|
||||
@@ -734,8 +734,8 @@ proc callCCompiler*(projectfile: string) =
|
||||
if not noAbsolutePaths():
|
||||
if not exefile.isAbsolute():
|
||||
exefile = joinPath(splitFile(projectfile).dir, exefile)
|
||||
if optCDebug in gGlobalOptions:
|
||||
writeDebugInfo(exefile.changeFileExt("ndb"))
|
||||
#if optCDebug in gGlobalOptions:
|
||||
# writeDebugInfo(exefile.changeFileExt("ndb"))
|
||||
exefile = quoteShell(exefile)
|
||||
let linkOptions = getLinkOptions() & " " &
|
||||
getConfigVar(cCompiler, ".options.linker")
|
||||
|
||||
@@ -9,19 +9,63 @@
|
||||
|
||||
## Computes hash values for routine (proc, method etc) signatures.
|
||||
|
||||
import ast
|
||||
import ast, md5
|
||||
export md5.`==`
|
||||
|
||||
type
|
||||
SigHash* = uint32 ## a hash good enough for a filename or a proc signature
|
||||
when false:
|
||||
type
|
||||
SigHash* = uint32 ## a hash good enough for a filename or a proc signature
|
||||
|
||||
proc sdbmHash(hash: SigHash, c: char): SigHash {.inline.} =
|
||||
return SigHash(c) + (hash shl 6) + (hash shl 16) - hash
|
||||
proc sdbmHash(hash: SigHash, c: char): SigHash {.inline.} =
|
||||
return SigHash(c) + (hash shl 6) + (hash shl 16) - hash
|
||||
|
||||
template `&=`*(x: var SigHash, c: char) = x = sdbmHash(x, c)
|
||||
template `&=`*(x: var SigHash, s: string) =
|
||||
for c in s: x = sdbmHash(x, c)
|
||||
template `&=`*(x: var SigHash, c: char) = x = sdbmHash(x, c)
|
||||
template `&=`*(x: var SigHash, s: string) =
|
||||
for c in s: x = sdbmHash(x, c)
|
||||
|
||||
proc hashSym(c: var SigHash, s: PSym) =
|
||||
else:
|
||||
type
|
||||
SigHash* = Md5Digest
|
||||
|
||||
const
|
||||
cb64 = [
|
||||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
|
||||
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
|
||||
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9a",
|
||||
"9b", "9c"]
|
||||
|
||||
proc toBase64a(s: cstring, len: int): string =
|
||||
## encodes `s` into base64 representation.
|
||||
result = newStringOfCap(((len + 2) div 3) * 4)
|
||||
var i = 0
|
||||
while i < len - 2:
|
||||
let a = ord(s[i])
|
||||
let b = ord(s[i+1])
|
||||
let c = ord(s[i+2])
|
||||
result.add cb64[a shr 2]
|
||||
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
|
||||
result.add cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
|
||||
result.add cb64[c and 0x3F]
|
||||
inc(i, 3)
|
||||
if i < len-1:
|
||||
let a = ord(s[i])
|
||||
let b = ord(s[i+1])
|
||||
result.add cb64[a shr 2]
|
||||
result.add cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
|
||||
result.add cb64[((b and 0x0F) shl 2)]
|
||||
elif i < len:
|
||||
let a = ord(s[i])
|
||||
result.add cb64[a shr 2]
|
||||
result.add cb64[(a and 3) shl 4]
|
||||
|
||||
proc `$`*(u: SigHash): string =
|
||||
toBase64a(cast[cstring](unsafeAddr u), sizeof(u))
|
||||
proc `&=`(c: var MD5Context, s: string) = md5Update(c, s, s.len)
|
||||
proc `&=`(c: var MD5Context, ch: char) = md5Update(c, unsafeAddr ch, 1)
|
||||
|
||||
proc hashSym(c: var MD5Context, s: PSym) =
|
||||
if sfAnon in s.flags or s.kind == skGenericParam:
|
||||
c &= ":anon"
|
||||
else:
|
||||
@@ -31,9 +75,9 @@ proc hashSym(c: var SigHash, s: PSym) =
|
||||
c &= "."
|
||||
it = it.owner
|
||||
|
||||
proc hashTree(c: var SigHash, n: PNode) =
|
||||
proc hashTree(c: var MD5Context, n: PNode) =
|
||||
template lowlevel(v) =
|
||||
for i in 0..<sizeof(v): c = sdbmHash(c, cast[cstring](unsafeAddr(v))[i])
|
||||
md5Update(c, cast[cstring](unsafeAddr(v)), sizeof(v))
|
||||
|
||||
if n == nil:
|
||||
c &= "\255"
|
||||
@@ -63,7 +107,7 @@ type
|
||||
ConsiderFlag* = enum
|
||||
considerParamNames
|
||||
|
||||
proc hashType(c: var SigHash, t: PType; flags: set[ConsiderFlag]) =
|
||||
proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
|
||||
# modelled after 'typeToString'
|
||||
if t == nil:
|
||||
c &= "\254"
|
||||
@@ -133,5 +177,35 @@ proc hashType(c: var SigHash, t: PType; flags: set[ConsiderFlag]) =
|
||||
if tfNotNil in t.flags: c &= "not nil"
|
||||
|
||||
proc hashType*(t: PType; flags: set[ConsiderFlag]): SigHash =
|
||||
result = 0
|
||||
hashType result, t, flags
|
||||
var c: MD5Context
|
||||
md5Init c
|
||||
hashType c, t, flags
|
||||
md5Final c, result
|
||||
|
||||
proc hashProc*(s: PSym): SigHash =
|
||||
var c: MD5Context
|
||||
md5Init c
|
||||
hashType c, s.typ, {considerParamNames}
|
||||
|
||||
var m = s
|
||||
while m.kind != skModule: m = m.owner
|
||||
let p = m.owner
|
||||
assert p.kind == skPackage
|
||||
c &= p.name.s
|
||||
c &= "."
|
||||
c &= m.name.s
|
||||
|
||||
md5Final c, result
|
||||
|
||||
proc hashOwner*(s: PSym): SigHash =
|
||||
var c: MD5Context
|
||||
md5Init c
|
||||
var m = s
|
||||
while m.kind != skModule: m = m.owner
|
||||
let p = m.owner
|
||||
assert p.kind == skPackage
|
||||
c &= p.name.s
|
||||
c &= "."
|
||||
c &= m.name.s
|
||||
|
||||
md5Final c, result
|
||||
|
||||
@@ -173,21 +173,6 @@ proc sha1(src: string): Sha1Digest =
|
||||
## Calculate SHA1 from input string
|
||||
sha1(src, src.len)
|
||||
|
||||
proc `!&`*(h: Hash, val: int): Hash {.inline.} =
|
||||
## mixes a hash value `h` with `val` to produce a new hash value. This is
|
||||
## only needed if you need to implement a hash proc for a new datatype.
|
||||
result = h +% val
|
||||
result = result +% result shl 10
|
||||
result = result xor (result shr 6)
|
||||
|
||||
proc `!$`*(h: Hash): Hash {.inline.} =
|
||||
## finishes the computation of the hash value. This is
|
||||
## only needed if you need to implement a hash proc for a new datatype.
|
||||
|
||||
proc
|
||||
proc hashData*(data: pointer, size: int): Hash =
|
||||
|
||||
|
||||
proc secureHash*(str: string): SecureHash = SecureHash(sha1(str))
|
||||
proc secureHashFile*(filename: string): SecureHash = secureHash(readFile(filename))
|
||||
proc `$`*(self: SecureHash): string =
|
||||
|
||||
Reference in New Issue
Block a user