From dfe3f160227dadd5d93bd6c697106e71899eccce Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Fri, 13 Jul 2018 18:41:59 +0300 Subject: [PATCH] Don't depend on string.h in codegen (#8299) --- compiler/ccgexprs.nim | 34 ++++++++++++------------------- compiler/cgen.nim | 13 +++--------- lib/pure/memfiles.nim | 3 +-- lib/system.nim | 34 +++++++++++++++---------------- lib/system/alloc.nim | 4 ++-- lib/system/ansi_c.nim | 2 ++ lib/system/memory.nim | 47 +++++++++++++++++++++++++++++++++++++++++++ lib/system/sysio.nim | 2 +- lib/system/sysstr.nim | 2 +- 9 files changed, 87 insertions(+), 54 deletions(-) create mode 100644 lib/system/memory.nim diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 9b31167e3e..2e9fb2cc2a 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -257,9 +257,8 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = if needToCopy notin flags or tfShallow in skipTypes(dest.t, abstractVarRange).flags: if dest.storage == OnStack or not usesNativeGC(p.config): - useStringh(p.module) linefmt(p, cpsStmts, - "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", + "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest)) else: linefmt(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n", @@ -336,9 +335,8 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = if needsComplexAssignment(dest.t): genGenericAsgn(p, dest, src, flags) else: - useStringh(p.module) linefmt(p, cpsStmts, - "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", + "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", rdLoc(dest), rdLoc(src), getTypeDesc(p.module, dest.t)) of tyOpenArray, tyVarargs: # open arrays are always on the stack - really? What if a sequence is @@ -349,16 +347,14 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfo(p.module, dest.t, dest.lode.info)) else: - useStringh(p.module) linefmt(p, cpsStmts, - # bug #4799, keep the memcpy for a while - #"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);$n", + # bug #4799, keep the nimCopyMem for a while + #"#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len_0);$n", "$1 = $2;$n", rdLoc(dest), rdLoc(src)) of tySet: if mapType(p.config, ty) == ctArray: - useStringh(p.module) - linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n", + linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n", rdLoc(dest), rdLoc(src), rope(getSize(p.config, dest.t))) else: linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) @@ -403,8 +399,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) = genTypeInfo(p.module, dest.t, dest.lode.info)) of tySet: if mapType(p.config, ty) == ctArray: - useStringh(p.module) - linefmt(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n", + linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, $3);$n", rdLoc(dest), rdLoc(src), rope(getSize(p.config, dest.t))) else: linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) @@ -1481,9 +1476,8 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)") else: unaryExpr(p, e, d, "$1Len_0") of tyCString: - useStringh(p.module) - if op == mHigh: unaryExpr(p, e, d, "($1 ? (strlen($1)-1) : -1)") - else: unaryExpr(p, e, d, "($1 ? strlen($1) : 0)") + if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)") + else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)") of tyString: if not p.module.compileToCpp: if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->Sup.len-1) : -1)") @@ -1632,7 +1626,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = " $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & " if (!$3) break;}$n", "for ($1 = 0; $1 < $2; $1++) { $n" & " $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & " if (!$3) break;}$n" & - "if ($3) $3 = (memcmp($4, $5, $2) != 0);$n", + "if ($3) $3 = (#nimCmpMem($4, $5, $2) != 0);$n", "&", "|", "& ~", "^"] var a, b, i: TLoc var setType = skipTypes(e.sons[1].typ, abstractVar) @@ -1671,11 +1665,10 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) if d.k == locNone: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyBool), d) - lineF(p, cpsStmts, lookupOpr[op], + linefmt(p, cpsStmts, lookupOpr[op], [rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b)]) of mEqSet: - useStringh(p.module) - binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)") + binaryExprChar(p, e, d, "(#nimCmpMem($1, $2, " & $(size) & ")==0)") of mMulSet, mPlusSet, mMinusSet, mSymDiffSet: # we inline the simple for loop for better code generation: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) # our counter @@ -1934,7 +1927,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = # example: { a..b, c, d, e, f..g } # we have to emit an expression of the form: - # memset(tmp, 0, sizeof(tmp)); inclRange(tmp, a, b); incl(tmp, c); + # nimZeroMem(tmp, sizeof(tmp)); inclRange(tmp, a, b); incl(tmp, c); # incl(tmp, d); incl(tmp, e); inclRange(tmp, f, g); var a, b, idx: TLoc @@ -1944,8 +1937,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) = if d.k == locNone: getTemp(p, e.typ, d) if getSize(p.config, e.typ) > 8: # big set: - useStringh(p.module) - lineF(p, cpsStmts, "memset($1, 0, sizeof($2));$n", + linefmt(p, cpsStmts, "#nimZeroMem($1, sizeof($2));$n", [rdLoc(d), getTypeDesc(p.module, e.typ)]) for it in e.sons: if it.kind == nkRange: diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 32891c62ca..ea82c496f5 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -80,11 +80,6 @@ proc isSimpleConst(typ: PType): bool = {tyTuple, tyObject, tyArray, tySet, tySequence} and not (t.kind == tyProc and t.callConv == ccClosure) -proc useStringh(m: BModule) = - if includesStringh notin m.flags: - incl m.flags, includesStringh - m.includeHeader("") - proc useHeader(m: BModule, sym: PSym) = if lfHeader in sym.loc.flags: assert(sym.annex != nil) @@ -320,10 +315,9 @@ proc resetLoc(p: BProc, loc: var TLoc) = # field, so disabling this should be safe: genObjectInit(p, cpsStmts, loc.t, loc, true) else: - useStringh(p.module) # array passed as argument decayed into pointer, bug #7332 # so we use getTypeDesc here rather than rdLoc(loc) - linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n", + linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", addrLoc(p.config, loc), getTypeDesc(p.module, loc.t)) # XXX: We can be extra clever here and call memset only # on the bytes following the m_type field? @@ -336,11 +330,10 @@ proc constructLoc(p: BProc, loc: TLoc, isTemp = false) = getTypeDesc(p.module, typ)) else: if not isTemp or containsGarbageCollectedRef(loc.t): - # don't use memset for temporary values for performance if we can + # don't use nimZeroMem for temporary values for performance if we can # avoid it: if not isImportedCppType(typ): - useStringh(p.module) - linefmt(p, cpsStmts, "memset((void*)$1, 0, sizeof($2));$n", + linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n", addrLoc(p.config, loc), getTypeDesc(p.module, typ)) genObjectInit(p, cpsStmts, loc.t, loc, true) diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index bda0ecb771..0249b74135 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -322,8 +322,7 @@ type MemSlice* = object ## represent slice of a MemFile for iteration over deli proc `==`*(x, y: MemSlice): bool = ## Compare a pair of MemSlice for strict equality. - proc memcmp(a, b: pointer, n:int):int {.importc: "memcmp",header: "string.h".} - result = (x.size == y.size and memcmp(x.data, y.data, x.size) == 0) + result = (x.size == y.size and equalMem(x.data, y.data, x.size)) proc `$`*(ms: MemSlice): string {.inline.} = ## Return a Nim string built from a MemSlice. diff --git a/lib/system.nim b/lib/system.nim index 10f1df1508..fed02f6d0f 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2903,6 +2903,22 @@ when not defined(JS): #and not defined(nimscript): ## useful for low-level file access include "system/ansi_c" + include "system/memory" + + proc zeroMem(p: pointer, size: Natural) = + nimZeroMem(p, size) + when declared(memTrackerOp): + memTrackerOp("zeroMem", p, size) + proc copyMem(dest, source: pointer, size: Natural) = + nimCopyMem(dest, source, size) + when declared(memTrackerOp): + memTrackerOp("copyMem", dest, size) + proc moveMem(dest, source: pointer, size: Natural) = + c_memmove(dest, source, size) + when declared(memTrackerOp): + memTrackerOp("moveMem", dest, size) + proc equalMem(a, b: pointer, size: Natural): bool = + nimCmpMem(a, b, size) == 0 proc cmp(x, y: string): int = when nimvm: @@ -2911,7 +2927,7 @@ when not defined(JS): #and not defined(nimscript): else: result = 0 else: let minlen = min(x.len, y.len) - result = int(c_memcmp(x.cstring, y.cstring, minlen.csize)) + result = int(nimCmpMem(x.cstring, y.cstring, minlen.csize)) if result == 0: result = x.len - y.len @@ -3200,22 +3216,6 @@ when not defined(JS): #and not defined(nimscript): when defined(memtracker): include "system/memtracker" - when not defined(nimscript): - proc zeroMem(p: pointer, size: Natural) = - c_memset(p, 0, size) - when declared(memTrackerOp): - memTrackerOp("zeroMem", p, size) - proc copyMem(dest, source: pointer, size: Natural) = - c_memcpy(dest, source, size) - when declared(memTrackerOp): - memTrackerOp("copyMem", dest, size) - proc moveMem(dest, source: pointer, size: Natural) = - c_memmove(dest, source, size) - when declared(memTrackerOp): - memTrackerOp("moveMem", dest, size) - proc equalMem(a, b: pointer, size: Natural): bool = - c_memcmp(a, b, size) == 0 - when hostOS == "standalone": include "system/embedded" else: diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 6aef4f4117..95becde229 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -830,7 +830,7 @@ proc rawDealloc(a: var MemRegion, p: pointer) = c.freeList = f when overwriteFree: # set to 0xff to check for usage after free bugs: - c_memset(cast[pointer](cast[int](p) +% sizeof(FreeCell)), -1'i32, + nimSetMem(cast[pointer](cast[int](p) +% sizeof(FreeCell)), -1'i32, s -% sizeof(FreeCell)) # check if it is not in the freeSmallChunks[s] list: if c.free < s: @@ -847,7 +847,7 @@ proc rawDealloc(a: var MemRegion, p: pointer) = s == 0, "rawDealloc 2") else: # set to 0xff to check for usage after free bugs: - when overwriteFree: c_memset(p, -1'i32, c.size -% bigChunkOverhead()) + when overwriteFree: nimSetMem(p, -1'i32, c.size -% bigChunkOverhead()) # free big chunk var c = cast[PBigChunk](c) dec a.occ, c.size diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 52cb15e39b..4d21f87479 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -25,6 +25,8 @@ proc c_memset(p: pointer, value: cint, size: csize): pointer {. importc: "memset", header: "", discardable.} proc c_strcmp(a, b: cstring): cint {. importc: "strcmp", header: "", noSideEffect.} +proc c_strlen(a: cstring): csize {. + importc: "strlen", header: "", noSideEffect.} when defined(linux) and defined(amd64): type diff --git a/lib/system/memory.nim b/lib/system/memory.nim new file mode 100644 index 0000000000..f86fd4696c --- /dev/null +++ b/lib/system/memory.nim @@ -0,0 +1,47 @@ +const useLibC = not defined(nimNoLibc) + +proc nimCopyMem(dest, source: pointer, size: Natural) {.compilerproc, inline.} = + when useLibC: + c_memcpy(dest, source, size) + else: + let d = cast[ptr UncheckedArray[byte]](dest) + let s = cast[ptr UncheckedArray[byte]](source) + var i = 0 + while i < size: + d[i] = s[i] + inc i + +proc nimSetMem(a: pointer, v: cint, size: Natural) {.inline.} = + when useLibC: + c_memset(a, v, size) + else: + let a = cast[ptr UncheckedArray[byte]](a) + var i = 0 + let v = cast[byte](v) + while i < size: + a[i] = v + inc i + +proc nimZeroMem(p: pointer, size: Natural) {.compilerproc, inline.} = + nimSetMem(p, 0, size) + +proc nimCmpMem(a, b: pointer, size: Natural): cint {.compilerproc, inline.} = + when useLibC: + c_memcmp(a, b, size) + else: + let a = cast[ptr UncheckedArray[byte]](a) + let b = cast[ptr UncheckedArray[byte]](b) + var i = 0 + while i < size: + let d = a[i].cint - b[i].cint + if d != 0: return d + inc i + +proc nimCStrLen(a: cstring): csize {.compilerproc, inline.} = + when useLibC: + c_strlen(a) + else: + var a = cast[ptr byte](a) + while a[] != 0: + a = cast[ptr byte](cast[uint](a) + 1) + inc result diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index f3a576be09..2ece56916f 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -154,7 +154,7 @@ proc readLine(f: File, line: var TaintedString): bool = while true: # memset to \L so that we can tell how far fgets wrote, even on EOF, where # fgets doesn't append an \L - c_memset(addr line.string[pos], '\L'.ord, sp) + nimSetMem(addr line.string[pos], '\L'.ord, sp) var fgetsSuccess = c_fgets(addr line.string[pos], sp, f) != nil if not fgetsSuccess: checkErr(f) let m = c_memchr(addr line.string[pos], '\L'.ord, sp) diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 90ae91cf53..8e9e18b053 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -32,7 +32,7 @@ proc cmpStrings(a, b: NimString): int {.inline, compilerProc.} = let blen = b.len let minlen = min(alen, blen) if minlen > 0: - result = c_memcmp(addr a.data, addr b.data, minlen.csize) + result = nimCmpMem(addr a.data, addr b.data, minlen.csize) if result == 0: result = alen - blen else: