name mangling bugfixes; ndi file generation for debugger support

This commit is contained in:
Andreas Rumpf
2017-02-03 09:49:36 +01:00
parent 04c4d3d77f
commit 848676cec6
6 changed files with 71 additions and 65 deletions

View File

@@ -64,7 +64,7 @@ proc genVarTuple(p: BProc, n: PNode) =
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
else:
if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)]
field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n.sons[i].sym, t)]
putLocIntoDest(p, v.loc, field)
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false)

View File

@@ -22,12 +22,10 @@ proc isKeyword(w: PIdent): bool =
ord(wInline): return true
else: return false
proc mangleField(name: PIdent): string =
proc mangleField(m: BModule; name: PIdent): string =
result = mangle(name.s)
if isKeyword(name):
result[0] = result[0].toUpperAscii
# Mangling makes everything lowercase,
# but some identifiers are C keywords
if isKeyword(name) or m.g.config.cppDefines.contains(result):
result.add "_0"
when false:
proc hashOwner(s: PSym): SigHash =
@@ -67,54 +65,10 @@ proc idOrSig(m: BModule; s: PSym): Rope =
proc mangleName(m: BModule; s: PSym): Rope =
result = s.loc.r
if result == nil:
let keepOrigName = s.kind in skLocalVars - {skForVar} and
{sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
not isKeyword(s.name)
# Even with all these inefficient checks, the bootstrap
# time is actually improved. This is probably because so many
# rope concatenations are now eliminated.
#
# sfFromGeneric is needed in order to avoid multiple
# definitions of certain variables generated in transf with
# names such as:
# `r`, `res`
# I need to study where these come from.
#
# about sfShadowed:
# consider the following Nim code:
# var x = 10
# block:
# var x = something(x)
# The generated C code will be:
# NI x;
# x = 10;
# {
# NI x;
# x = something(x); // Oops, x is already shadowed here
# }
# Right now, we work-around by not keeping the original name
# of the shadowed variable, but we can do better - we can
# create an alternative reference to it in the outer scope and
# use that in the inner scope.
#
# about isCKeyword:
# Nim variable names can be C keywords.
# We need to avoid such names in the generated code.
#
# about sfGlobal:
# This seems to be harder - a top level extern variable from
# another modules can have the same name as a local one.
# Maybe we should just implement sfShadowed for them too.
#
# about skForVar:
# These are not properly scoped now - we need to add blocks
# around for loops in transf
result = s.name.s.mangle.rope
if keepOrigName:
result.add "0"
else:
add(result, m.idOrSig(s))
add(result, m.idOrSig(s))
s.loc.r = result
writeMangledName(m.ndi, s)
proc mangleParamName(m: BModule; s: PSym): Rope =
## we cannot use 'sigConflicts' here since we have a BModule, not a BProc.
@@ -122,10 +76,12 @@ proc mangleParamName(m: BModule; s: PSym): Rope =
## cause any trouble.
result = s.loc.r
if result == nil:
result = s.name.s.mangle.rope
if isKeyword(s.name) or m.g.config.cppDefines.contains(s.name.s):
result.add "0"
var res = s.name.s.mangle
if isKeyword(s.name) or m.g.config.cppDefines.contains(res):
res.add "_0"
result = res.rope
s.loc.r = result
writeMangledName(m.ndi, s)
proc mangleLocalName(p: BProc; s: PSym): Rope =
assert s.kind in skLocalVars+{skTemp}
@@ -139,10 +95,11 @@ proc mangleLocalName(p: BProc; s: PSym): Rope =
if s.kind == skTemp:
# speed up conflict search for temps (these are quite common):
if counter != 0: result.add "_" & rope(counter+1)
elif counter != 0 or isKeyword(s.name) or p.module.g.config.cppDefines.contains(s.name.s):
elif counter != 0 or isKeyword(s.name) or p.module.g.config.cppDefines.contains(key):
result.add "_" & rope(counter+1)
p.sigConflicts.inc(key)
s.loc.r = result
if s.kind != skTemp: writeMangledName(p.module.ndi, s)
proc scopeMangledParam(p: BProc; param: PSym) =
## parameter generation only takes BModule, not a BProc, so we have to
@@ -472,12 +429,12 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
else: add(params, ")")
params = "(" & params
proc mangleRecFieldName(field: PSym, rectype: PType): Rope =
proc mangleRecFieldName(m: BModule; field: PSym, rectype: PType): Rope =
if (rectype.sym != nil) and
({sfImportc, sfExportc} * rectype.sym.flags != {}):
result = field.loc.r
else:
result = rope(mangleField(field.name))
result = rope(mangleField(m, field.name))
if result == nil: internalError(field.info, "mangleRecFieldName")
proc genRecordFieldsAux(m: BModule, n: PNode,
@@ -516,7 +473,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
let field = n.sym
if field.typ.kind == tyVoid: return
#assert(field.ast == nil)
let sname = mangleRecFieldName(field, rectype)
let sname = mangleRecFieldName(m, field, rectype)
let ae = if accessExpr != nil: "$1.$2" % [accessExpr, sname]
else: sname
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)

View File

@@ -164,9 +164,6 @@ proc makeSingleLineCString*(s: string): string =
result.add('\"')
proc mangle*(name: string): string =
## Lowercases the given name and manges any non-alphanumeric characters
## so they are represented as `HEX____`. If the name starts with a number,
## `N` is prepended
result = newStringOfCap(name.len)
var start = 0
if name[0] in Digits:
@@ -179,8 +176,15 @@ proc mangle*(name: string): string =
for i in start..(name.len-1):
let c = name[i]
case c
of 'a'..'z', '0'..'9', 'A'..'Z', '_':
of 'a'..'z', '0'..'9', 'A'..'Z':
add(result, c)
of '_':
# we generate names like 'foo_9' for scope disambiguations and so
# disallow this here:
if i < name.len-1 and name[i] in Digits:
discard
else:
add(result, c)
of '$': special "dollar"
of '%': special "percent"
of '&': special "amp"

View File

@@ -14,7 +14,7 @@ import
nversion, nimsets, msgs, securehash, bitsets, idents, lists, types,
ccgutils, os, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
lowerings, semparallel, tables, sets
lowerings, semparallel, tables, sets, ndi
import strutils except `%` # collides with ropes.`%`
@@ -1152,6 +1152,9 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
incl result.flags, preventStackTrace
excl(result.preInitProc.options, optStackTrace)
excl(result.postInitProc.options, optStackTrace)
let ndiName = if optCDebug in gGlobalOptions: changeFileExt(completeCFilePath(filename), "ndi")
else: ""
open(result.ndi, ndiName)
proc nullify[T](arr: var T) =
for i in low(arr)..high(arr):
@@ -1343,6 +1346,7 @@ proc writeModule(m: BModule, pending: bool) =
var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
if not existsFile(cf.obj): cf.flags = {CfileFlag.Cached}
addFileToCompile(cf)
close(m.ndi)
proc updateCachedModule(m: BModule) =
let cfile = getCFile(m)

View File

@@ -11,7 +11,7 @@
import
ast, astalgo, ropes, passes, options, intsets, lists, platform, sighashes,
tables
tables, ndi
from msgs import TLineInfo
@@ -146,6 +146,7 @@ type
injectStmt*: Rope
sigConflicts*: CountTable[SigHash]
g*: BModuleList
ndi*: NdiFile
proc s*(p: BProc, s: TCProcSection): var Rope {.inline.} =
# section in the current block

40
compiler/ndi.nim Normal file
View File

@@ -0,0 +1,40 @@
#
#
# The Nim Compiler
# (c) Copyright 2017 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements the generation of ``.ndi`` files for better debugging
## support of Nim code. "ndi" stands for "Nim debug info".
import ast, msgs, ropes
type
NdiFile* = object
enabled: bool
f: File
buf: string
proc doWrite(f: var NdiFile; s: PSym) =
f.buf.setLen 0
f.buf.add s.info.line.int
f.buf.add "\t"
f.buf.add s.info.col.int
f.f.write(s.name.s, "\t")
f.f.writeRope(s.loc.r)
f.f.writeLine("\t", s.info.toFullPath, "\t", f.buf)
template writeMangledName*(f: NdiFile; s: PSym) =
if f.enabled: doWrite(f, s)
proc open*(f: var NdiFile; filename: string) =
f.enabled = filename.len > 0
if f.enabled:
f.f = open(filename, fmWrite, 8000)
f.buf = newStringOfCap(20)
proc close*(f: var NdiFile) =
if f.enabled: close(f.f)