Skip to content

Commit

Permalink
Merge branch 'devel' into js0
Browse files Browse the repository at this point in the history
  • Loading branch information
juancarlospaco authored Jun 19, 2024
2 parents 2aa0103 + 646bd99 commit 10f5061
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 33 deletions.
4 changes: 3 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ slots when enlarging a sequence.
- A `$` template is provided for `Path` in `std/paths`.
- Added [logical AND-assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND_assignment)
and [logical OR-Assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_OR_assignment) for JavaScript targets.

- `nimPreviewHashFarm` has been added to `lib/pure/hashes.nim` to default to a
64-bit string `Hash` (based upon Google's Farm Hash) which is also faster than
the present one. At present, this is incompatible with `--jsbigint=off` mode.

[//]: # "Deprecations:"

Expand Down
3 changes: 2 additions & 1 deletion compiler/ast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type
TNodeKinds* = set[TNodeKind]

type
TSymFlag* = enum # 51 flags!
TSymFlag* = enum # 52 flags!
sfUsed, # read access of sym (for warnings) or simply used
sfExported, # symbol is exported from module
sfFromGeneric, # symbol is instantiation of a generic; this is needed
Expand Down Expand Up @@ -126,6 +126,7 @@ type
sfByCopy # param is marked as pass bycopy
sfMember # proc is a C++ member of a type
sfCodegenDecl # type, proc, global or proc param is marked as codegenDecl
sfWasGenSym # symbol was 'gensym'ed

TSymFlags* = set[TSymFlag]

Expand Down
1 change: 1 addition & 0 deletions compiler/condsyms.nim
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,4 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasWarnStdPrefix")

defineSymbol("nimHasVtables")
defineSymbol("nimHasJsNoLambdaLifting")
1 change: 1 addition & 0 deletions compiler/evaltempl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
# internalAssert c.config, false
idTablePut(c.mapping, s, x)
if sfGenSym in s.flags:
# TODO: getIdent(c.ic, "`" & x.name.s & "`gensym" & $c.instID)
result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $c.instID),
if c.instLines: actual.info else: templ.info)
else:
Expand Down
4 changes: 3 additions & 1 deletion compiler/sem.nim
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
result.owner = getCurrOwner(c)
else:
result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info)
if find(result.name.s, '`') >= 0:
result.flags.incl sfWasGenSym
#if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
# incl(result.flags, sfGlobal)
when defined(nimsuggest):
Expand All @@ -263,7 +265,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
# identifier with visibility
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
allowed: TSymFlags, fromTopLevel = false): PSym

proc typeAllowedCheck(c: PContext; info: TLineInfo; typ: PType; kind: TSymKind;
flags: TTypeAllowedFlags = {}) =
Expand Down
2 changes: 1 addition & 1 deletion compiler/semstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ proc identWithin(n: PNode, s: PIdent): bool =

proc semIdentDef(c: PContext, n: PNode, kind: TSymKind, reportToNimsuggest = true): PSym =
if isTopLevel(c):
result = semIdentWithPragma(c, kind, n, {sfExported})
result = semIdentWithPragma(c, kind, n, {sfExported}, fromTopLevel = true)
incl(result.flags, sfGlobal)
#if kind in {skVar, skLet}:
# echo "global variable here ", n.info, " ", result.name.s
Expand Down
12 changes: 8 additions & 4 deletions compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
result = newSymG(kind, n, c)

proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym =
allowed: TSymFlags, fromTopLevel = false): PSym =
if n.kind == nkPragmaExpr:
checkSonsLen(n, 2, c.config)
result = semIdentVis(c, kind, n[0], allowed)
Expand All @@ -555,11 +555,15 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
else: discard
else:
result = semIdentVis(c, kind, n, allowed)
let invalidPragmasForPush = if fromTopLevel and sfWasGenSym notin result.flags:
{}
else:
{wExportc, wExportCpp, wDynlib}
case kind
of skField: implicitPragmas(c, result, n.info, fieldPragmas)
of skVar: implicitPragmas(c, result, n.info, varPragmas)
of skLet: implicitPragmas(c, result, n.info, letPragmas)
of skConst: implicitPragmas(c, result, n.info, constPragmas)
of skVar: implicitPragmas(c, result, n.info, varPragmas-invalidPragmasForPush)
of skLet: implicitPragmas(c, result, n.info, letPragmas-invalidPragmasForPush)
of skConst: implicitPragmas(c, result, n.info, constPragmas-invalidPragmasForPush)
else: discard

proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
Expand Down
204 changes: 184 additions & 20 deletions lib/pure/hashes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,145 @@ proc hashVmImplChar(x: openArray[char], sPos, ePos: int): Hash =
proc hashVmImplByte(x: openArray[byte], sPos, ePos: int): Hash =
raiseAssert "implementation override in compiler/vmops.nim"

const k0 = 0xc3a5c85c97cb3127u64 # Primes on (2^63, 2^64) for various uses
const k1 = 0xb492b66fbe98f273u64
const k2 = 0x9ae16a3b2f90404fu64

proc load4e(s: openArray[byte], o=0): uint32 {.inline.} =
uint32(s[o + 3]) shl 24 or uint32(s[o + 2]) shl 16 or
uint32(s[o + 1]) shl 8 or uint32(s[o + 0])

proc load8e(s: openArray[byte], o=0): uint64 {.inline.} =
uint64(s[o + 7]) shl 56 or uint64(s[o + 6]) shl 48 or
uint64(s[o + 5]) shl 40 or uint64(s[o + 4]) shl 32 or
uint64(s[o + 3]) shl 24 or uint64(s[o + 2]) shl 16 or
uint64(s[o + 1]) shl 8 or uint64(s[o + 0])

proc load4(s: openArray[byte], o=0): uint32 {.inline.} =
when nimvm: result = load4e(s, o)
else:
when declared copyMem: copyMem result.addr, s[o].addr, result.sizeof
else: result = load4e(s, o)

proc load8(s: openArray[byte], o=0): uint64 {.inline.} =
when nimvm: result = load8e(s, o)
else:
when declared copyMem: copyMem result.addr, s[o].addr, result.sizeof
else: result = load8e(s, o)

proc lenU(s: openArray[byte]): uint64 {.inline.} = s.len.uint64

proc shiftMix(v: uint64): uint64 {.inline.} = v xor (v shr 47)

proc rotR(v: uint64; bits: cint): uint64 {.inline.} =
(v shr bits) or (v shl (64 - bits))

proc len16(u: uint64; v: uint64; mul: uint64): uint64 {.inline.} =
var a = (u xor v)*mul
a = a xor (a shr 47)
var b = (v xor a)*mul
b = b xor (b shr 47)
b*mul

proc len0_16(s: openArray[byte]): uint64 {.inline.} =
if s.len >= 8:
let mul = k2 + 2*s.lenU
let a = load8(s) + k2
let b = load8(s, s.len - 8)
let c = rotR(b, 37)*mul + a
let d = (rotR(a, 25) + b)*mul
len16 c, d, mul
elif s.len >= 4:
let mul = k2 + 2*s.lenU
let a = load4(s).uint64
len16 s.lenU + (a shl 3), load4(s, s.len - 4), mul
elif s.len > 0:
let a = uint32(s[0])
let b = uint32(s[s.len shr 1])
let c = uint32(s[s.len - 1])
let y = a + (b shl 8)
let z = s.lenU + (c shl 2)
shiftMix(y*k2 xor z*k0)*k2
else: k2 # s.len == 0

proc len17_32(s: openArray[byte]): uint64 {.inline.} =
let mul = k2 + 2*s.lenU
let a = load8(s)*k1
let b = load8(s, 8)
let c = load8(s, s.len - 8)*mul
let d = load8(s, s.len - 16)*k2
len16 rotR(a + b, 43) + rotR(c, 30) + d, a + rotR(b + k2, 18) + c, mul

proc len33_64(s: openArray[byte]): uint64 {.inline.} =
let mul = k2 + 2*s.lenU
let a = load8(s)*k2
let b = load8(s, 8)
let c = load8(s, s.len - 8)*mul
let d = load8(s, s.len - 16)*k2
let y = rotR(a + b, 43) + rotR(c, 30) + d
let z = len16(y, a + rotR(b + k2, 18) + c, mul)
let e = load8(s, 16)*mul
let f = load8(s, 24)
let g = (y + load8(s, s.len - 32))*mul
let h = (z + load8(s, s.len - 24))*mul
len16 rotR(e + f, 43) + rotR(g, 30) + h, e + rotR(f + a, 18) + g, mul

type Pair = tuple[first, second: uint64]

proc weakLen32withSeeds2(w, x, y, z, a, b: uint64): Pair {.inline.} =
var a = a + w
var b = rotR(b + a + z, 21)
let c = a
a += x
a += y
b += rotR(a, 44)
result[0] = a + z
result[1] = b + c

proc weakLen32withSeeds(s: openArray[byte]; o: int; a,b: uint64): Pair {.inline.} =
weakLen32withSeeds2 load8(s, o ), load8(s, o + 8),
load8(s, o + 16), load8(s, o + 24), a, b

proc hashFarm(s: openArray[byte]): uint64 {.inline.} =
if s.len <= 16: return len0_16(s)
if s.len <= 32: return len17_32(s)
if s.len <= 64: return len33_64(s)
const seed = 81u64 # not const to use input `h`
var
o = 0 # s[] ptr arith -> variable origin variable `o`
x = seed
y = seed*k1 + 113
z = shiftMix(y*k2 + 113)*k2
v, w: Pair
x = x*k2 + load8(s)
let eos = ((s.len - 1) div 64)*64
let last64 = eos + ((s.len - 1) and 63) - 63
while true:
x = rotR(x + y + v[0] + load8(s, o+8), 37)*k1
y = rotR(y + v[1] + load8(s, o+48), 42)*k1
x = x xor w[1]
y += v[0] + load8(s, o+40)
z = rotR(z + w[0], 33)*k1
v = weakLen32withSeeds(s, o+0 , v[1]*k1, x + w[0])
w = weakLen32withSeeds(s, o+32, z + w[1], y + load8(s, o+16))
swap z, x
inc o, 64
if o == eos: break
let mul = k1 + ((z and 0xff) shl 1)
o = last64
w[0] += (s.lenU - 1) and 63
v[0] += w[0]
w[0] += v[0]
x = rotR(x + y + v[0] + load8(s, o+8), 37)*mul
y = rotR(y + v[1] + load8(s, o+48), 42)*mul
x = x xor w[1]*9
y += v[0]*9 + load8(s, o+40)
z = rotR(z + w[0], 33)*mul
v = weakLen32withSeeds(s, o+0 , v[1]*mul, x + w[0])
w = weakLen32withSeeds(s, o+32, z + w[1], y + load8(s, o+16))
swap z, x
len16 len16(v[0],w[0],mul) + shiftMix(y)*k0 + z, len16(v[1],w[1],mul) + x, mul

proc hash*(x: string): Hash =
## Efficient hashing of strings.
##
Expand All @@ -388,10 +527,13 @@ proc hash*(x: string): Hash =
runnableExamples:
doAssert hash("abracadabra") != hash("AbracadabrA")

when nimvm:
result = hashVmImpl(x, 0, high(x))
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
result = cast[Hash](hashFarm(toOpenArrayByte(x, 0, x.high)))
else:
result = murmurHash(toOpenArrayByte(x, 0, high(x)))
when nimvm:
result = hashVmImpl(x, 0, high(x))
else:
result = murmurHash(toOpenArrayByte(x, 0, high(x)))

proc hash*(x: cstring): Hash =
## Efficient hashing of null-terminated strings.
Expand All @@ -400,14 +542,21 @@ proc hash*(x: cstring): Hash =
doAssert hash(cstring"AbracadabrA") == hash("AbracadabrA")
doAssert hash(cstring"abracadabra") != hash(cstring"AbracadabrA")

when nimvm:
hashVmImpl(x, 0, high(x))
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
when defined js:
let xx = $x
result = cast[Hash](hashFarm(toOpenArrayByte(xx, 0, xx.high)))
else:
result = cast[Hash](hashFarm(toOpenArrayByte(x, 0, x.high)))
else:
when not defined(js):
murmurHash(toOpenArrayByte(x, 0, x.high))
when nimvm:
hashVmImpl(x, 0, high(x))
else:
let xx = $x
murmurHash(toOpenArrayByte(xx, 0, high(xx)))
when not defined(js):
murmurHash(toOpenArrayByte(x, 0, x.high))
else:
let xx = $x
murmurHash(toOpenArrayByte(xx, 0, high(xx)))

proc hash*(sBuf: string, sPos, ePos: int): Hash =
## Efficient hashing of a string buffer, from starting
Expand All @@ -418,7 +567,10 @@ proc hash*(sBuf: string, sPos, ePos: int): Hash =
var a = "abracadabra"
doAssert hash(a, 0, 3) == hash(a, 7, 10)

murmurHash(toOpenArrayByte(sBuf, sPos, ePos))
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
result = cast[Hash](hashFarm(toOpenArrayByte(sBuf, sPos, ePos)))
else:
murmurHash(toOpenArrayByte(sBuf, sPos, ePos))

proc hashIgnoreStyle*(x: string): Hash =
## Efficient hashing of strings; style is ignored.
Expand Down Expand Up @@ -553,12 +705,18 @@ proc hash*[A](x: openArray[A]): Hash =
## Efficient hashing of arrays and sequences.
## There must be a `hash` proc defined for the element type `A`.
when A is byte:
result = murmurHash(x)
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
result = cast[Hash](hashFarm(x))
else:
result = murmurHash(x)
elif A is char:
when nimvm:
result = hashVmImplChar(x, 0, x.high)
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
result = cast[Hash](hashFarm(toOpenArrayByte(x, 0, x.high)))
else:
result = murmurHash(toOpenArrayByte(x, 0, x.high))
when nimvm:
result = hashVmImplChar(x, 0, x.high)
else:
result = murmurHash(toOpenArrayByte(x, 0, x.high))
else:
result = 0
for a in x:
Expand All @@ -576,15 +734,21 @@ proc hash*[A](aBuf: openArray[A], sPos, ePos: int): Hash =
doAssert hash(a, 0, 1) == hash(a, 3, 4)

when A is byte:
when nimvm:
result = hashVmImplByte(aBuf, sPos, ePos)
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
result = cast[Hash](hashFarm(toOpenArray(aBuf, sPos, ePos)))
else:
result = murmurHash(toOpenArray(aBuf, sPos, ePos))
when nimvm:
result = hashVmImplByte(aBuf, sPos, ePos)
else:
result = murmurHash(toOpenArray(aBuf, sPos, ePos))
elif A is char:
when nimvm:
result = hashVmImplChar(aBuf, sPos, ePos)
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
result = cast[Hash](hashFarm(toOpenArrayByte(aBuf, sPos, ePos)))
else:
result = murmurHash(toOpenArrayByte(aBuf, sPos, ePos))
when nimvm:
result = hashVmImplChar(aBuf, sPos, ePos)
else:
result = murmurHash(toOpenArrayByte(aBuf, sPos, ePos))
else:
for i in sPos .. ePos:
result = result !& hash(aBuf[i])
Expand Down
25 changes: 25 additions & 0 deletions tests/pragmas/tpush.nim
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,28 @@ block: # bug #23019
k(w)
{.pop.}
{.pop.}

{.push exportC.}

block:
proc foo11() =
const factor = [1, 2, 3, 4]
doAssert factor[0] == 1
proc foo21() =
const factor = [1, 2, 3, 4]
doAssert factor[0] == 1

foo11()
foo21()

template foo31() =
let factor = [1, 2, 3, 4]
doAssert factor[0] == 1
template foo41() =
let factor = [1, 2, 3, 4]
doAssert factor[0] == 1

foo31()
foo41()

{.pop.}
Loading

0 comments on commit 10f5061

Please sign in to comment.