mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
Don't depend on string.h in codegen (#8299)
This commit is contained in:
committed by
Andreas Rumpf
parent
54a85b4ff5
commit
dfe3f16022
@@ -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:
|
||||
|
||||
@@ -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("<string.h>")
|
||||
|
||||
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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -25,6 +25,8 @@ proc c_memset(p: pointer, value: cint, size: csize): pointer {.
|
||||
importc: "memset", header: "<string.h>", discardable.}
|
||||
proc c_strcmp(a, b: cstring): cint {.
|
||||
importc: "strcmp", header: "<string.h>", noSideEffect.}
|
||||
proc c_strlen(a: cstring): csize {.
|
||||
importc: "strlen", header: "<string.h>", noSideEffect.}
|
||||
|
||||
when defined(linux) and defined(amd64):
|
||||
type
|
||||
|
||||
47
lib/system/memory.nim
Normal file
47
lib/system/memory.nim
Normal file
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user