Optimize lent in JS [backport:1.6] (#19393)

* 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
This commit is contained in:
hlaaftana
2022-01-17 15:03:40 +03:00
committed by GitHub
parent dc8ac66873
commit 07c7a8a526
3 changed files with 81 additions and 23 deletions

View File

@@ -178,7 +178,7 @@ 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:
@@ -186,7 +186,8 @@ proc mapType(typ: PType): TJSTypeKind =
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
@@ -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")
@@ -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])
@@ -1288,7 +1297,7 @@ template isIndirect(x: PSym): bool =
v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator,
skConst, skTemp, skLet})
proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) =
proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) =
let s = n.sym
if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3")
case s.kind
@@ -1456,13 +1465,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
@@ -1703,7 +1716,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)
@@ -1745,7 +1758,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:
@@ -2394,16 +2407,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]
@@ -2579,8 +2593,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)

33
tests/js/tlent.nim Normal file
View File

@@ -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()

View File

@@ -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).addr == a.addr
doAssert sameAddress(byLent(a), a)
doAssert byLent(b) == @[21,23]
when not defined(js): # pending bug #16073
doAssert byLent(b).addr == b.addr
# pending bug #16073
doAssert sameAddress(byLent(b), b)
doAssert byLent(ss) == {1, 2, 3, 5}
doAssert byLent(ss).addr == ss.addr
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)
@@ -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).addr == a[0].addr
doAssert sameAddress(byLent2(a), a[0])
doAssert byLent2(b) == 21
doAssert byLent2(b).addr == b[0].addr
doAssert sameAddress(byLent2(b), b[0])
proc byLent3[T](a: varargs[T]): lent T = a[1]
let