new VM: some progress for the FFI support
This commit is contained in:
parent
e2a4d591e5
commit
9145bcfbb6
8 changed files with 80 additions and 60 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue