some progress on the VM

This commit is contained in:
Araq 2014-07-15 01:14:37 +02:00
commit e8fc470310
103 changed files with 294 additions and 11 deletions

151
compiler/main/nimbatch.nim Normal file
View file

@ -0,0 +1,151 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# This file implements the new "batch compiler" that can translate Nimrod
# code into POSIX shell scripts or Windows ``.bat`` files. Only a small
# subset of Nimrod can be translated. This compiler also acts as a new
# "hacking the Nimrod compiler" tutorial.
## ==============================
## Let's hack the Nimrod compiler
## ==============================
## Starting with version 0.9.6 the compiler's internals have been cleaned up
## quite a bit. However, still lot's of weird modules need to be imported
## before we can start:
import
llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
os, condsyms, rodread, rodwrite, times,
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
cgen, jsgen, json, nversion,
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
tables, docgen2, service, parser, modules
proc `=~`(s: PSym; name: string): bool =
let a = name.split('.')
var s = s
for i in countdown(a.high, a.low):
if s == nil or not identEq(s.name, a[i]): return false
s = s.owner
return true
type
ShellTarget = enum
targetBatch, targetSh
Context = ref object
target: ShellTarget
code: string
proc `=~`(n: PNode; name: string): bool =
result = n.kind == nkSym and match(n.sym, name)
proc gen(c: Context; n: PNode) =
template `~`(x): expr = op =~ x
template `|`(a, b): expr = (if c.target == targetBatch: a else: b)
template add(x) = c.code.add(x)
template addf(x, y) = c.code.addf(x, y)
case n.kind
of nkIfStmt, nkIfExpr:
of nkForStmt:
of nkCallKinds:
let op = n[0]
if ~"stdlib.os.changeDir":
addf("" | "",
elif ~"stdlib.os.createDir":
addf("mkdir $#",
proc semanticPasses() =
registerPass verbosePass
registerPass semPass
proc commandCompileToSH =
#incl(gGlobalOptions, optSafeCode)
setTarget(osJS, cpuJS)
#initDefines()
defineSymbol("nimrod") # 'nimrod' is always defined
defineSymbol("batch")
semanticPasses()
registerPass(JSgenPass)
compileProject()
proc wantMainModule =
if gProjectFull.len == 0:
if optMainModule.len == 0:
fatal(gCmdLineInfo, errCommandExpectsFilename)
else:
gProjectName = optMainModule
gProjectFull = gProjectPath / gProjectName
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
proc requireMainModuleOption =
if optMainModule.len == 0:
fatal(gCmdLineInfo, errMainModuleMustBeSpecified)
else:
gProjectName = optMainModule
gProjectFull = gProjectPath / gProjectName
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
proc mainCommand* =
# In "nimrod serve" scenario, each command must reset the registered passes
clearPasses()
gLastCmdTime = epochTime()
appendStr(searchPaths, options.libpath)
if gProjectFull.len != 0:
# current path is always looked first for modules
prependStr(searchPaths, gProjectPath)
setId(100)
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
case command.normalize
of "c", "cc", "compile", "compiletoc":
# compile means compileToC currently
gCmd = cmdCompileToC
wantMainModule()
commandCompileToC()
of "cpp", "compiletocpp":
extccomp.cExt = ".cpp"
gCmd = cmdCompileToCpp
if cCompiler == ccGcc: setCC("gcc")
wantMainModule()
defineSymbol("cpp")
commandCompileToC()
of "objc", "compiletooc":
extccomp.cExt = ".m"
gCmd = cmdCompileToOC
wantMainModule()
defineSymbol("objc")
commandCompileToC()
of "run":
gCmd = cmdRun
wantMainModule()
when hasTinyCBackend:
extccomp.setCC("tcc")
commandCompileToC()
else:
rawMessage(errInvalidCommandX, command)
of "js", "compiletojs":
gCmd = cmdCompileToJS
wantMainModule()
commandCompileToJS()
else:
rawMessage(errInvalidCommandX, command)
if (msgs.gErrorCounter == 0 and
gCmd notin {cmdInterpret, cmdRun, cmdDump} and
gVerbosity > 0):
rawMessage(hintSuccessX, [$gLinesCompiled,
formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
formatSize(getTotalMem())])

View file

@ -5,7 +5,25 @@ mainModule:"nimrod.nim"
# gc:markAndSweep
hint[XDeclaredButNotUsed]:off
path:"llvm"
path:"ast"
path:"caas"
path:"cgen"
path:"common"
path:"docgen"
path:"jsgen"
path:"keywords"
path:"lexer"
path:"main"
path:"options"
path:"parsers"
path:"passes"
path:"renderers"
path:"rodfiles"
path:"sem"
path:"symtab"
path:"transformations"
path:"vm"
path:"$projectPath/.."
path:"$lib/packages/docutils"

View file

@ -277,8 +277,7 @@ when noTimeMachine:
##
## The whole proc is optional and will ignore all kinds of errors. The only
## way to be sure that it works is to call ``tmutil isexcluded path``.
if alreadyExcludedDirs.contains(dir): return
alreadyExcludedDirs.incl(dir)
if alreadyExcludedDirs.containsOrIncl(dir): return
try:
var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir])
discard p.waitForExit

View file

@ -44,6 +44,7 @@ type
# parameters come first
next: PStackFrame # for stacking
comesFrom: int
firstArg, argsLen, resultPos: Byte # used when frame is passed to callback
safePoints: seq[int] # used for exception handling
# XXX 'break' should perform cleanup actions
# What does the C backend do for it?
@ -141,6 +142,51 @@ template createStr(x) =
template createSet(x) =
x.node = newNode(nkCurly)
proc argsLen*(f: VmFrame): Natural =
## returns the number of arguments that this frame contains. Normally you
## should already know this number due to nimrod's static typing.
result = Natural(cast[PStackFrame](f).argsLen)
proc getInt*(f: VmFrame; index: Natural): BiggestInt =
## returns the value of the index'th slot in the frame. The slot has to be
## of the type: int|int16|...
let f = cast[PStackFrame](f)
result = f.slots[index + f.firstArg].intVal
proc getFloat*(f: VmFrame; index: Natural): BiggestFloat =
## returns the value of the index'th slot in the frame. The slot has to be
## of the type: float|float32|float64 or a distinct type of float or a
## float range.
let f = cast[PStackFrame](f)
result = f.slots[index + f.firstArg].floatVal
proc getString*(f: VmFrame; index: Natural): string =
## returns the value of the index'th slot in the frame. The slot has to be
## of the type string.
let f = cast[PStackFrame](f)
result = f.slots[index + f.firstArg].n.strVal
template rawSetResult(a, k, field) {.immediate, dirty.} =
if a.kind != k:
myreset a
a.kind = k
a.field = x
proc setResultInt*(f: VmFrame; x: BiggestInt) =
## sets the result value of the wrapped proc.
let f = cast[PStackFrame](f)
rawSetResult(f.slots[f.firstArg-1], rkInt, intVal)
proc setResultFloat*(f: VmFrame; x: BiggestFloat) =
## sets the result value of the wrapped proc.
let f = cast[PStackFrame](f)
rawSetResult(f.slots[f.firstArg-1], rkFloat, floatVal)
proc setResultString*(f: VmFrame; x: string) =
## sets the result value of the wrapped proc.
let f = cast[PStackFrame](f)
rawSetResult(f.slots[f.firstArg-1], rkStr, n.strVal)
proc moveConst(x: var TFullReg, y: TFullReg) =
if x.kind != y.kind:
myreset(x)
@ -791,7 +837,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let bb = regs[rb].node
let isClosure = bb.kind == nkPar
let prc = if not isClosure: bb.sym else: bb.sons[0].sym
if sfImportc in prc.flags:
if prc.offset < 0:
tos.firstArg = rb
tos.argsLen = rc
tos.resultPos = ra
c.vmProcs[-prc.offset - 1].prc(tos)
elif sfImportc in prc.flags:
if allowFFI notin c.features:
globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI")
# we pass 'tos.slots' instead of 'regs' so that the compiler can keep

View file

@ -10,7 +10,7 @@
## This module contains the type definitions for the new evaluation engine.
## An instruction is 1-3 int32s in memory, it is a register based VM.
import ast, passes, msgs, intsets
import ast, passes, msgs, intsets, strtabs
const
byteExcess* = 128 # we use excess-K for immediates
@ -170,7 +170,13 @@ type
sym*: PSym
slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
maxSlots*: int
VmFrame* = distinct pointer
VmProc* = proc (f: VmFrame) {.closure.}
VmSym* = object
name*: string
prc*: VmProc
PCtx* = ref TCtx
TCtx* = object of passes.TPassContext # code gen context
code*: seq[TInstr]
@ -188,6 +194,8 @@ type
features*: TSandboxFlags
traceActive*: bool
loopIterations*: int
vmProcs*: seq[VmSym]
marked*: PStringTable
TPosition* = distinct int
@ -196,7 +204,8 @@ type
proc newCtx*(module: PSym): PCtx =
PCtx(code: @[], debug: @[],
globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations)
prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations,
vmProcs: @[], marked: nil)
proc refresh*(c: PCtx, module: PSym) =
c.module = module

Some files were not shown because too many files have changed in this diff Show more