Skip to content

Commit

Permalink
Optimize lent in JS [backport:1.6] (#19393)
Browse files Browse the repository at this point in the history
* Optimize lent in JS [backport:1.6]

* addr on lent doesn't work anymore, don't use it

* use unsafeAddr  in test again for older versions

(cherry picked from commit 07c7a8a)
  • Loading branch information
metagn authored and narimiran committed Jan 20, 2022
1 parent 7cafd22 commit fc0aec6
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 22 deletions.
49 changes: 35 additions & 14 deletions compiler/jsgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,16 @@ const
proc mapType(typ: PType): TJSTypeKind =
let t = skipTypes(typ, abstractInst)
case t.kind
of tyVar, tyRef, tyPtr, tyLent:
of tyVar, tyRef, tyPtr:
if skipTypes(t.lastSon, abstractInst).kind in MappedToObject:
result = etyObject
else:
result = etyBaseIndex
of tyPointer:
# treat a tyPointer like a typed pointer to an array of bytes
result = etyBaseIndex
of tyRange, tyDistinct, tyOrdinal, tyProxy:
of tyRange, tyDistinct, tyOrdinal, tyProxy, tyLent:
# tyLent is no-op as JS has pass-by-reference semantics
result = mapType(t[0])
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt
of tyBool: result = etyBool
Expand Down Expand Up @@ -1060,14 +1061,14 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
xtyp = etySeq
case xtyp
of etySeq:
if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
else:
useMagic(p, "nimCopy")
lineF(p, "$1 = nimCopy(null, $2, $3);$n",
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
of etyObject:
if x.typ.kind in {tyVar} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
if x.typ.kind in {tyVar, tyLent} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
else:
useMagic(p, "nimCopy")
Expand All @@ -1092,10 +1093,18 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res])
lineF(p, "$1 = $2;$n", [a.address, b.res])
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
elif a.typ == etyBaseIndex:
# array indexing may not map to var type
if b.address != nil:
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
else:
lineF(p, "$1 = $2;$n", [a.address, b.res])
else:
internalError(p.config, x.info, $("genAsgn", b.typ, a.typ))
else:
elif b.address != nil:
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
else:
lineF(p, "$1 = $2;$n", [a.address, b.res])
else:
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])

Expand Down Expand Up @@ -1442,13 +1451,17 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
else:
if s.loc.r == nil:
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
r.res = s.loc.r
if mapType(p, s.typ) == etyBaseIndex:
r.address = s.loc.r
r.res = s.loc.r & "_Idx"
else:
r.res = s.loc.r
r.kind = resVal

proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
let it = n[0]
let t = mapType(p, it.typ)
if t == etyObject:
if t == etyObject or it.typ.kind == tyLent:
gen(p, it, r)
else:
var a: TCompRes
Expand Down Expand Up @@ -1689,7 +1702,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
result = putToSeq("0", indirect)
of tyFloat..tyFloat128:
result = putToSeq("0.0", indirect)
of tyRange, tyGenericInst, tyAlias, tySink, tyOwned:
of tyRange, tyGenericInst, tyAlias, tySink, tyOwned, tyLent:
result = createVar(p, lastSon(typ), indirect)
of tySet:
result = putToSeq("{}", indirect)
Expand Down Expand Up @@ -1731,7 +1744,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
createObjInitList(p, t, initIntSet(), initList)
result = ("({$1})") % [initList]
if indirect: result = "[$1]" % [result]
of tyVar, tyPtr, tyLent, tyRef, tyPointer:
of tyVar, tyPtr, tyRef, tyPointer:
if mapType(p, t) == etyBaseIndex:
result = putToSeq("[null, 0]", indirect)
else:
Expand Down Expand Up @@ -2380,16 +2393,17 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
if prc.typ[0] != nil and sfPure notin prc.flags:
resultSym = prc.ast[resultPos].sym
let mname = mangleName(p.module, resultSym)
if not isIndirect(resultSym) and
let returnAddress = not isIndirect(resultSym) and
resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef, tyOwned} and
mapType(p, resultSym.typ) == etyBaseIndex:
mapType(p, resultSym.typ) == etyBaseIndex
if returnAddress:
resultAsgn = p.indentLine(("var $# = null;$n") % [mname])
resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
else:
let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar])
gen(p, prc.ast[resultPos], a)
if mapType(p, resultSym.typ) == etyBaseIndex:
if returnAddress:
returnStmt = "return [$#, $#];$n" % [a.address, a.res]
else:
returnStmt = "return $#;$n" % [a.res]
Expand Down Expand Up @@ -2565,8 +2579,15 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkObjConstr: genObjConstr(p, n, r)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
of nkAddr, nkHiddenAddr:
genAddr(p, n, r)
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r)
if n.typ.kind in {tyLent}:
gen(p, n[0], r)
else:
genAddr(p, n, r)
of nkDerefExpr, nkHiddenDeref:
if n.typ.kind in {tyLent}:
gen(p, n[0], r)
else:
genDeref(p, n, r)
of nkBracketExpr: genArrayAccess(p, n, r)
of nkDotExpr: genFieldAccess(p, n, r)
of nkCheckedFieldExpr: genCheckedFieldOp(p, n, nil, r)
Expand Down
33 changes: 33 additions & 0 deletions tests/js/tlent.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
discard """
output: '''
hmm
100
hmm
100
'''
"""

# #16800

type A = object
b: int
var t = A(b: 100)
block:
proc getValues: lent int =
echo "hmm"
result = t.b
echo getValues()
block:
proc getValues: lent int =
echo "hmm"
t.b
echo getValues()

when false: # still an issue, #16908
template main =
iterator fn[T](a:T): lent T = yield a
let a = @[10]
for b in fn(a): echo b

static: main()
main()
20 changes: 12 additions & 8 deletions tests/lent/tbasic_lent_check.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,26 @@ proc main =
main()

template main2 = # bug #15958
when defined(js):
proc sameAddress[T](a, b: T): bool {.importjs: "(# === #)".}
else:
template sameAddress(a, b): bool = a.unsafeAddr == b.unsafeAddr
proc byLent[T](a: T): lent T = a
let a = [11,12]
let b = @[21,23]
let ss = {1, 2, 3, 5}
doAssert byLent(a) == [11,12]
doAssert byLent(a).unsafeAddr == a.unsafeAddr
doAssert sameAddress(byLent(a), a)
doAssert byLent(b) == @[21,23]
when not defined(js): # pending bug #16073
doAssert byLent(b).unsafeAddr == b.unsafeAddr
# bug #16073
doAssert sameAddress(byLent(b), b)
doAssert byLent(ss) == {1, 2, 3, 5}
doAssert byLent(ss).unsafeAddr == ss.unsafeAddr
doAssert sameAddress(byLent(ss), ss)

let r = new(float)
r[] = 10.0
when not defined(js): # pending bug #16073
doAssert byLent(r)[] == 10.0
# bug #16073
doAssert byLent(r)[] == 10.0

when not defined(js): # pending bug https://github.com/timotheecour/Nim/issues/372
let p = create(float)
Expand All @@ -41,9 +45,9 @@ template main2 = # bug #15958

proc byLent2[T](a: openarray[T]): lent T = a[0]
doAssert byLent2(a) == 11
doAssert byLent2(a).unsafeAddr == a[0].unsafeAddr
doAssert sameAddress(byLent2(a), a[0])
doAssert byLent2(b) == 21
doAssert byLent2(b).unsafeAddr == b[0].unsafeAddr
doAssert sameAddress(byLent2(b), b[0])

proc byLent3[T](a: varargs[T]): lent T = a[1]
let
Expand Down

0 comments on commit fc0aec6

Please sign in to comment.