From a64f03230afa69f2143b0eb159c9294998c5e19b Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Tue, 10 Apr 2012 20:53:44 +0300 Subject: [PATCH] proper order of initialization for .global. variables --- compiler/ccgstmts.nim | 2 +- compiler/cgen.nim | 6 +++++- compiler/cgendata.nim | 4 ++++ doc/manual.txt | 18 +++++++++++++++++- tests/run/globalaux.nim | 15 +++++++++++++++ tests/run/globalaux2.nim | 4 ++++ tests/run/tglobal.nim | 16 ++++++++++++++++ 7 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 tests/run/globalaux.nim create mode 100644 tests/run/globalaux2.nim create mode 100644 tests/run/tglobal.nim diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index f627ee0368..e018a3ac94 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -53,7 +53,7 @@ proc genSingleVar(p: BProc, a: PNode) = var targetProc = p var immediateAsgn = a.sons[2].kind != nkEmpty if sfGlobal in v.flags: - targetProc = p.module.initProc + targetProc = p.module.preInitProc assignGlobalVar(targetProc, v) genObjectInit(targetProc, cpsInit, v.typ, v.loc, true) else: diff --git a/compiler/cgen.nim b/compiler/cgen.nim index a56053f799..de91205e2c 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -859,6 +859,7 @@ proc genInitCode(m: BModule) = app(prc, genSectionStart(cpsLocals)) app(prc, m.initProc.s[cpsLocals]) + app(prc, m.preInitProc.s[cpsLocals]) app(prc, genSectionEnd(cpsLocals)) app(prc, genSectionStart(cfsTypeInit1)) @@ -875,10 +876,12 @@ proc genInitCode(m: BModule) = app(prc, genSectionEnd(i)) app(prc, genSectionStart(cpsInit)) + app(prc, m.preInitProc.s[cpsInit]) app(prc, m.initProc.s[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]) if optStackTrace in m.initProc.options and not m.PreventStackTrace: app(prc, deinitFrame(m.initProc)) @@ -916,6 +919,7 @@ proc rawNewModule(module: PSym, filename: string): BModule = result.typeInfoMarker = initIntSet() result.initProc = newProc(nil, result) result.initProc.options = gOptions + result.preInitProc = newProc(nil, result) initNodeTable(result.dataCache) result.typeStack = @[] result.forwardedProcs = @[] diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index c58c64250f..fafccce187 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -93,6 +93,10 @@ type headerFiles*: TLinkedList # needed headers to include typeInfoMarker*: TIntSet # needed for generating type information 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 dataCache*: TNodeTable forwardedProcs*: TSymSeq # keep forwarded procs here diff --git a/doc/manual.txt b/doc/manual.txt index 9b53623241..9618bdbc7d 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -3267,7 +3267,7 @@ but are used to override the settings temporarily. Example: {.pop.} # restore old settings -Register pragma +register pragma --------------- 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 @@ -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 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 ------------------- diff --git a/tests/run/globalaux.nim b/tests/run/globalaux.nim new file mode 100644 index 0000000000..5f6f727210 --- /dev/null +++ b/tests/run/globalaux.nim @@ -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 + diff --git a/tests/run/globalaux2.nim b/tests/run/globalaux2.nim new file mode 100644 index 0000000000..6c77f1f485 --- /dev/null +++ b/tests/run/globalaux2.nim @@ -0,0 +1,4 @@ +import globalaux + +echo "in globalaux2: ", globalInstance[int]().val + diff --git a/tests/run/tglobal.nim b/tests/run/tglobal.nim new file mode 100644 index 0000000000..84c4510c1f --- /dev/null +++ b/tests/run/tglobal.nim @@ -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 +