proper order of initialization for .global. variables

This commit is contained in:
Zahary Karadjov 2012-04-10 20:53:44 +03:00
commit a64f03230a
7 changed files with 62 additions and 3 deletions

View file

@ -53,7 +53,7 @@ proc genSingleVar(p: BProc, a: PNode) =
var targetProc = p var targetProc = p
var immediateAsgn = a.sons[2].kind != nkEmpty var immediateAsgn = a.sons[2].kind != nkEmpty
if sfGlobal in v.flags: if sfGlobal in v.flags:
targetProc = p.module.initProc targetProc = p.module.preInitProc
assignGlobalVar(targetProc, v) assignGlobalVar(targetProc, v)
genObjectInit(targetProc, cpsInit, v.typ, v.loc, true) genObjectInit(targetProc, cpsInit, v.typ, v.loc, true)
else: else:

View file

@ -859,6 +859,7 @@ proc genInitCode(m: BModule) =
app(prc, genSectionStart(cpsLocals)) app(prc, genSectionStart(cpsLocals))
app(prc, m.initProc.s[cpsLocals]) app(prc, m.initProc.s[cpsLocals])
app(prc, m.preInitProc.s[cpsLocals])
app(prc, genSectionEnd(cpsLocals)) app(prc, genSectionEnd(cpsLocals))
app(prc, genSectionStart(cfsTypeInit1)) app(prc, genSectionStart(cfsTypeInit1))
@ -875,10 +876,12 @@ proc genInitCode(m: BModule) =
app(prc, genSectionEnd(i)) app(prc, genSectionEnd(i))
app(prc, genSectionStart(cpsInit)) app(prc, genSectionStart(cpsInit))
app(prc, m.preInitProc.s[cpsInit])
app(prc, m.initProc.s[cpsInit]) app(prc, m.initProc.s[cpsInit])
app(prc, genSectionEnd(cpsInit)) app(prc, genSectionEnd(cpsInit))
app(prc, genSectionStart(cpsStmts)) app(prc, genSectionStart(cpsStmts))
app(prc, m.preInitProc.s[cpsStmts])
app(prc, m.initProc.s[cpsStmts]) app(prc, m.initProc.s[cpsStmts])
if optStackTrace in m.initProc.options and not m.PreventStackTrace: if optStackTrace in m.initProc.options and not m.PreventStackTrace:
app(prc, deinitFrame(m.initProc)) app(prc, deinitFrame(m.initProc))
@ -916,6 +919,7 @@ proc rawNewModule(module: PSym, filename: string): BModule =
result.typeInfoMarker = initIntSet() result.typeInfoMarker = initIntSet()
result.initProc = newProc(nil, result) result.initProc = newProc(nil, result)
result.initProc.options = gOptions result.initProc.options = gOptions
result.preInitProc = newProc(nil, result)
initNodeTable(result.dataCache) initNodeTable(result.dataCache)
result.typeStack = @[] result.typeStack = @[]
result.forwardedProcs = @[] result.forwardedProcs = @[]

View file

@ -93,6 +93,10 @@ type
headerFiles*: TLinkedList # needed headers to include headerFiles*: TLinkedList # needed headers to include
typeInfoMarker*: TIntSet # needed for generating type information typeInfoMarker*: TIntSet # needed for generating type information
initProc*: BProc # code for init procedure initProc*: BProc # code for init procedure
preInitProc*: BProc # code executed before the init proc
# used for initialization code for
# .global. variables
# (or instantiated generic variables)
typeStack*: TTypeSeq # used for type generation typeStack*: TTypeSeq # used for type generation
dataCache*: TNodeTable dataCache*: TNodeTable
forwardedProcs*: TSymSeq # keep forwarded procs here forwardedProcs*: TSymSeq # keep forwarded procs here

View file

@ -3267,7 +3267,7 @@ but are used to override the settings temporarily. Example:
{.pop.} # restore old settings {.pop.} # restore old settings
Register pragma register pragma
--------------- ---------------
The `register`:idx: pragma is for variables only. It declares the variable as The `register`:idx: pragma is for variables only. It declares the variable as
``register``, giving the compiler a hint that the variable should be placed ``register``, giving the compiler a hint that the variable should be placed
@ -3277,6 +3277,22 @@ though and for good reasons: Often they do a better job without it anyway.
In highly specific cases (a dispatch loop of an bytecode interpreter for In highly specific cases (a dispatch loop of an bytecode interpreter for
example) it may provide benefits, though. example) it may provide benefits, though.
global pragma
---------------
The `global`:idx pragma can be applied to a variable within a proc to instruct
the compiler to store it in a global location and initialize it once at program
startup.
.. code-block:: nimrod
proc isHexNumber(s: string): bool =
var pattern {.global.} = re"[0-9a-fA-F]+"
result = s.match(pattern)
When used within a generic proc, a separate unique global variable will be
created for each instantiation of the proc. The order of initialization of
the created global variables within a module is not defined, but all of them
will be initialized after any top-level variables in their originating module
and before any variable in a module that imports it.
DeadCodeElim pragma DeadCodeElim pragma
------------------- -------------------

15
tests/run/globalaux.nim Normal file
View file

@ -0,0 +1,15 @@
type
TObj*[T] = object
val*: T
var
totalGlobals* = 0
proc makeObj[T](x: T): TObj[T] =
totalGlobals += 1
result.val = x
proc globalInstance*[T]: var TObj[T] =
var g {.global.} = when T is int: makeObj(10) else: makeObj("hello")
result = g

4
tests/run/globalaux2.nim Normal file
View file

@ -0,0 +1,4 @@
import globalaux
echo "in globalaux2: ", globalInstance[int]().val

16
tests/run/tglobal.nim Normal file
View file

@ -0,0 +1,16 @@
discard """
file: "toop1.nim"
output: "in globalaux2: 10\ntotal globals: 2\nint value: 100\nstring value: second"
"""
import globalaux, globalaux2
echo "total globals: ", totalGlobals
globalInstance[int]().val = 100
echo "int value: ", globalInstance[int]().val
globalInstance[string]().val = "first"
globalInstance[string]().val = "second"
echo "string value: ", globalInstance[string]().val