mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-28 11:26:39 +00:00
name mangling bugfixes; ndi file generation for debugger support
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
40
compiler/ndi.nim
Normal 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)
|
||||
Reference in New Issue
Block a user