Fix global destructor injection for JS backend (#19797)
* Fix global destructor injection for JS backend * Moved global destructors injection before the final call to transform and generate JS code. It had previously been after and thus not no JS was generated for them. * Added some internal documentation of `jsgen`. * Enable a current destructor test to cover the JS backend as well. * Fixes the JS aspect of #17237. * Fixed global destructor injection order for JS backend Co-authored-by: quantimnot <quantimnot@users.noreply.github.com>
This commit is contained in:
parent
a8426fc789
commit
05c0419658
2 changed files with 27 additions and 6 deletions
|
|
@ -2392,6 +2392,7 @@ proc optionalLine(p: Rope): Rope =
|
|||
return p & "\L"
|
||||
|
||||
proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
## Generate a JS procedure ('function').
|
||||
var
|
||||
resultSym: PSym
|
||||
a: TCompRes
|
||||
|
|
@ -2673,6 +2674,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
|||
else: internalError(p.config, n.info, "gen: unknown node type: " & $n.kind)
|
||||
|
||||
proc newModule(g: ModuleGraph; module: PSym): BModule =
|
||||
## Create a new JS backend module node.
|
||||
new(result)
|
||||
result.module = module
|
||||
result.sigConflicts = initCountTable[SigHash]()
|
||||
|
|
@ -2684,6 +2686,7 @@ proc newModule(g: ModuleGraph; module: PSym): BModule =
|
|||
PGlobals(g.backend).inSystem = true
|
||||
|
||||
proc genHeader(): Rope =
|
||||
## Generate the JS header.
|
||||
result = rope("""/* Generated by the Nim Compiler v$1 */
|
||||
var framePtr = null;
|
||||
var excHandler = 0;
|
||||
|
|
@ -2714,6 +2717,8 @@ proc addHcrInitGuards(p: PProc, n: PNode,
|
|||
genStmt(p, n)
|
||||
|
||||
proc genModule(p: PProc, n: PNode) =
|
||||
## Generate the JS module code.
|
||||
## Called for each top level node in a Nim module.
|
||||
if optStackTrace in p.options:
|
||||
p.body.add(frameCreate(p,
|
||||
makeJSString("module " & p.module.module.name.s),
|
||||
|
|
@ -2742,6 +2747,7 @@ proc genModule(p: PProc, n: PNode) =
|
|||
p.body.add(frameDestroy(p))
|
||||
|
||||
proc myProcess(b: PPassContext, n: PNode): PNode =
|
||||
## Generate JS code for a node.
|
||||
result = n
|
||||
let m = BModule(b)
|
||||
if passes.skipCodegen(m.config, n): return n
|
||||
|
|
@ -2754,6 +2760,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
|
|||
p.g.code.add(p.body)
|
||||
|
||||
proc wholeCode(graph: ModuleGraph; m: BModule): Rope =
|
||||
## Combine source code from all nodes.
|
||||
let globals = PGlobals(graph.backend)
|
||||
for prc in globals.forwarded:
|
||||
if not globals.generatedSyms.containsOrIncl(prc.id):
|
||||
|
|
@ -2779,28 +2786,41 @@ proc getClassName(t: PType): Rope =
|
|||
else: result = rope(s.name.s)
|
||||
|
||||
proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||
result = myProcess(b, n)
|
||||
## Finalize JS code generation of a Nim module.
|
||||
## Param `n` may contain nodes returned from the last module close call.
|
||||
var m = BModule(b)
|
||||
if sfMainModule in m.module.flags:
|
||||
for destructorCall in graph.globalDestructors:
|
||||
n.add destructorCall
|
||||
# Add global destructors to the module.
|
||||
# This must come before the last call to `myProcess`.
|
||||
for i in countdown(high(graph.globalDestructors), 0):
|
||||
n.add graph.globalDestructors[i]
|
||||
# Process any nodes left over from the last call to `myClose`.
|
||||
result = myProcess(b, n)
|
||||
# Some codegen is different (such as no stacktraces; see `initProcOptions`)
|
||||
# when `std/system` is being processed.
|
||||
if sfSystemModule in m.module.flags:
|
||||
PGlobals(graph.backend).inSystem = false
|
||||
# Check if codegen should continue before any files are generated.
|
||||
# It may bail early is if too many errors have been raised.
|
||||
if passes.skipCodegen(m.config, n): return n
|
||||
# Nim modules are compiled into a single JS file.
|
||||
# If this is the main module, then this is the final call to `myClose`.
|
||||
if sfMainModule in m.module.flags:
|
||||
var code = genHeader() & wholeCode(graph, m)
|
||||
let outFile = m.config.prepareToWriteOutput()
|
||||
|
||||
# Generate an optional source map.
|
||||
if optSourcemap in m.config.globalOptions:
|
||||
var map: SourceMap
|
||||
(code, map) = genSourceMap($(code), outFile.string)
|
||||
writeFile(outFile.string & ".map", $(%map))
|
||||
# Check if the generated JS code matches the output file, or else
|
||||
# write it to the file.
|
||||
if not equalsFile(code, outFile):
|
||||
if not writeRope(code, outFile):
|
||||
rawMessage(m.config, errCannotOpenFile, outFile.string)
|
||||
|
||||
|
||||
proc myOpen(graph: ModuleGraph; s: PSym; idgen: IdGenerator): PPassContext =
|
||||
## Create the JS backend pass context `BModule` for a Nim module.
|
||||
result = newModule(graph, s)
|
||||
result.idgen = idgen
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue