new VM: some progress for the FFI support

This commit is contained in:
Araq 2013-12-23 01:17:48 +01:00
commit 9145bcfbb6
8 changed files with 80 additions and 60 deletions

View file

@ -9,7 +9,7 @@
## This file implements the FFI part of the evaluator for Nimrod code.
import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs
import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs, os
when defined(windows):
const libcDll = "msvcrt.dll"
@ -20,7 +20,11 @@ type
TDllCache = tables.TTable[string, TLibHandle]
var
gDllCache = initTable[string, TLibHandle]()
gExeHandle = LoadLib()
when defined(windows):
var gExeHandle = loadLib(os.getAppFilename())
else:
var gExeHandle = loadLib()
proc getDll(cache: var TDllCache; dll: string; info: TLineInfo): pointer =
result = cache[dll]
@ -28,10 +32,10 @@ proc getDll(cache: var TDllCache; dll: string; info: TLineInfo): pointer =
var libs: seq[string] = @[]
libCandidates(dll, libs)
for c in libs:
result = LoadLib(c)
result = loadLib(c)
if not result.isNil: break
if result.isNil:
GlobalError(info, "cannot load: " & dll)
globalError(info, "cannot load: " & dll)
cache[dll] = result
const
@ -50,7 +54,7 @@ proc importcSymbol*(sym: PSym): PNode =
else:
let lib = sym.annex
if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
GlobalError(sym.info, "dynlib needs to be a string lit for the REPL")
globalError(sym.info, "dynlib needs to be a string lit for the REPL")
var theAddr: pointer
if lib.isNil and not gExehandle.isNil:
# first try this exe itself:
@ -58,10 +62,12 @@ proc importcSymbol*(sym: PSym): PNode =
# then try libc:
if theAddr.isNil:
let dllhandle = gDllCache.getDll(libcDll, sym.info)
theAddr = dllhandle.checkedSymAddr(name)
else:
let dllhandle = gDllCache.getDll(lib.path.strVal, sym.info)
theAddr = dllhandle.checkedSymAddr(name)
theAddr = dllhandle.symAddr(name)
elif not lib.isNil:
let dllhandle = gDllCache.getDll(if lib.kind == libHeader: libcDll
else: lib.path.strVal, sym.info)
theAddr = dllhandle.symAddr(name)
if theAddr.isNil: globalError(sym.info, "cannot import: " & sym.name.s)
result.intVal = cast[TAddress](theAddr)
proc mapType(t: ast.PType): ptr libffi.TType =
@ -139,7 +145,7 @@ proc getField(n: PNode; position: int): PSym =
else: internalError(n.info, "getField(record case branch)")
of nkSym:
if n.sym.position == position: result = n.sym
else: nil
else: discard
proc packObject(x: PNode, typ: PType, res: pointer) =
InternalAssert x.kind in {nkObjConstr, nkPar}
@ -192,7 +198,7 @@ proc pack(v: PNode, typ: PType, res: pointer) =
of tyPointer, tyProc, tyCString, tyString:
if v.kind == nkNilLit:
# nothing to do since the memory is 0 initialized anyway
nil
discard
elif v.kind == nkPtrLit:
awr(pointer, cast[pointer](v.intVal))
elif v.kind in {nkStrLit..nkTripleStrLit}:
@ -202,7 +208,7 @@ proc pack(v: PNode, typ: PType, res: pointer) =
of tyPtr, tyRef, tyVar:
if v.kind == nkNilLit:
# nothing to do since the memory is 0 initialized anyway
nil
discard
elif v.kind == nkPtrLit:
awr(pointer, cast[pointer](v.intVal))
else:
@ -220,7 +226,7 @@ proc pack(v: PNode, typ: PType, res: pointer) =
of tyObject, tyTuple:
packObject(v, typ, res)
of tyNil:
nil
discard
of tyDistinct, tyGenericInst:
pack(v, typ.sons[0], res)
else:
@ -241,7 +247,7 @@ proc unpackObjectAdd(x: pointer, n, result: PNode) =
pair.sons[1] = unpack(x +! n.sym.offset, n.sym.typ, nil)
#echo "offset: ", n.sym.name.s, " ", n.sym.offset
result.add pair
else: nil
else: discard
proc unpackObject(x: pointer, typ: PType, n: PNode): PNode =
# compute the field's offsets:

View file

@ -632,12 +632,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
# we pass 'tos.slots' instead of 'regs' so that the compiler can keep
# 'regs' in a register:
when hasFFI:
if c.globals.sons[prc.position-1].kind == nkEmpty:
globalError(c.debug[pc], errGenerated, "canot run " & prc.name.s)
let newValue = callForeignFunction(c.globals.sons[prc.position-1],
prc.typ, tos.slots,
rb+1, rc-1, c.debug[pc])
if newValue.kind != nkEmpty:
assert instr.opcode == opcIndCallAsgn
regs[ra] = newValue
asgnRef(regs[ra], newValue)
else:
globalError(c.debug[pc], errGenerated, "VM not built with FFI support")
elif prc.kind != skTemplate:
@ -796,7 +798,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
decodeB(nkBracket)
let newLen = regs[rb].getOrdValue.int
setLen(regs[ra].sons, newLen)
of opcSwap, opcCast, opcReset:
of opcSwap, opcReset:
internalError(c.debug[pc], "too implement")
of opcIsNil:
decodeB(nkIntLit)
@ -938,6 +940,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
stackTrace(c, tos, pc, errGenerated,
msgKindToString(errIllegalConvFromXtoY) % [
"unknown type" , "unknown type"])
of opcCast:
let rb = instr.regB
inc pc
let typ = c.types[c.code[pc].regBx - wordExcess]
when hasFFI:
let dest = fficast(regs[rb], typ)
asgnRef(regs[ra], dest)
else:
globalError(c.debug[pc], "cannot evaluate cast")
of opcNSetIntVal:
decodeB(nkMetaNode)
var dest = regs[ra].uast
@ -1074,6 +1085,8 @@ proc myOpen(module: PSym): PPassContext =
# XXX produce a new 'globals' environment here:
setupGlobalCtx(module)
result = globalCtx
when hasFFI:
globalCtx.features = {allowFFI, allowCast}
var oldErrorCount: int

View file

@ -945,7 +945,10 @@ proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
proc importcSym(c: PCtx; info: TLineInfo; s: PSym) =
when hasFFI:
if allowFFI in c.features:
c.globals.add(importcSymbol(s))
if s.kind == skVar and lfNoDecl in s.loc.flags:
c.globals.add(copyNode(emptyNode))
else:
c.globals.add(importcSymbol(s))
s.position = c.globals.len
else:
localError(info, errGenerated, "VM is not allowed to 'importc'")
@ -1303,6 +1306,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest) =
of nkCurly: genSetConstr(c, n, dest)
of nkObjConstr: genObjConstr(c, n, dest)
of nkPar, nkClosure: genTupleConstr(c, n, dest)
of nkCast:
if allowCast in c.features:
genConv(c, n, n.sons[1], dest, opcCast)
else:
localError(n.info, errGenerated, "VM is not allowed to 'cast'")
else:
InternalError n.info, "too implement " & $n.kind