summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/evalffi.nim66
-rwxr-xr-xlib/pure/dynlib.nim9
-rwxr-xr-xlib/system.nim13
3 files changed, 65 insertions, 23 deletions
diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim
index 464c932f9..0c5301b76 100644
--- a/compiler/evalffi.nim
+++ b/compiler/evalffi.nim
@@ -17,11 +17,12 @@ else:
   const libcDll = "libc.so(.6|.5|)"
 
 type
-  TDllCache* = tables.TTable[string, TLibHandle]
+  TDllCache = tables.TTable[string, TLibHandle]
 var
   gDllCache = initTable[string, TLibHandle]()
+  gExeHandle = LoadLib()
 
-proc getDll(cache: var TDllCache; dll: string): pointer =
+proc getDll(cache: var TDllCache; dll: string; info: TLineInfo): pointer =
   result = cache[dll]
   if result.isNil:
     var libs: seq[string] = @[]
@@ -30,7 +31,7 @@ proc getDll(cache: var TDllCache; dll: string): pointer =
       result = LoadLib(c)
       if not result.isNil: break
     if result.isNil:
-      InternalError("cannot load: " & dll)
+      GlobalError(info, errGenerated, "cannot load: " & dll)
     cache[dll] = result
 
 const
@@ -41,7 +42,7 @@ proc importcSymbol*(sym: PSym): PNode =
   
   # the AST does not support untyped pointers directly, so we use an nkIntLit
   # that contains the address instead:
-  result = newNodeIT(nkIntLit, sym.info, sym.typ)
+  result = newNodeIT(nkPtrLit, sym.info, sym.typ)
   case name
   of "stdin":  result.intVal = cast[TAddress](system.stdin)
   of "stdout": result.intVal = cast[TAddress](system.stdout)
@@ -49,12 +50,19 @@ proc importcSymbol*(sym: PSym): PNode =
   else:
     let lib = sym.annex
     if lib != nil and lib.path.kind notin {nkStrLit..nkTripleStrLit}:
-      InternalError(sym.info, "dynlib needs to be a string literal for the REPL")
-    
-    let dllpath = if lib.isNil: libcDll else: lib.path.strVal
-    let dllhandle = gDllCache.getDll(dllpath)
-    let theAddr = dllhandle.checkedSymAddr(name)
-    
+      GlobalError(sym.info, errGenerated,
+        "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:
+      theAddr = gExehandle.symAddr(name)
+      # then try libc:
+      if theAddr.isNil:
+        let dllhandle = gDllCache.getDll(libcDll)
+        theAddr = dllhandle.checkedSymAddr(name)
+    else:
+      let dllhandle = gDllCache.getDll(lib.path.strVal, sym.info)
+      theAddr = dllhandle.checkedSymAddr(name)
     result.intVal = cast[TAddress](theAddr)
 
 proc mapType(t: ast.PType): ptr libffi.TType =
@@ -90,11 +98,12 @@ proc mapCallConv(cc: TCallingConvention): TABI =
 
 template rd(T, p: expr): expr {.immediate.} = (cast[ptr T](p))[]
 template wr(T, p, v: expr) {.immediate.} = (cast[ptr T](p))[] = v
+template `+!`(x, y: expr): expr {.immediate.} =
+  cast[pointer](cast[TAddress](x) + y)
 
-proc pack(v: PNode, typ: PType): pointer =
+proc pack(v: PNode, typ: PType, res: pointer) =
   template awr(T, v: expr) {.immediate, dirty.} =
-    result = alloc0(sizeof(T))
-    wr(T, result, v)
+    wr(T, res, v)
 
   case typ.kind
   of tyBool: awr(bool, v.intVal != 0)
@@ -121,18 +130,37 @@ proc pack(v: PNode, typ: PType): pointer =
   of tyFloat32: awr(float32, v.floatVal)
   of tyFloat64: awr(float64, v.floatVal)
   
-  of tyPointer, tyProc, tyPtr, tyRef:
+  of tyPointer, tyProc:
     if v.kind == nkNilLit:
-      result = alloc0(sizeof(pointer))
+      # nothing to do since the memory is 0 initialized anyway
+      nil
+    elif v.kind == nkPtrLit:
+      awr(pointer, cast[pointer](v.intVal))
     else:
+      InternalError("cannot map pointer/proc value to FFI")
+  of tyPtr, tyRef, tyVar:
+    if v.kind == nkNilLit:
+      # nothing to do since the memory is 0 initialized anyway
+      nil
+    elif v.kind == nkPtrLit:
       awr(pointer, cast[pointer](v.intVal))
+    else:
+      # XXX this is pretty hard: we need to allocate a new buffer and store it
+      # somewhere to be freed; we also need to write back any changes to the
+      # data!
+      InternalError("cannot map pointer/proc value to FFI")
   of tyCString, tyString:
     if v.kind == nkNilLit:
-      result = alloc0(sizeof(pointer))
+      nil
     else:
       awr(cstring, cstring(v.strVal))
+  of tyArray, tyArrayConstr:
+    let baseSize = typ.sons[1].getSize
+    assert(v.len == lengthOrd(typ.sons[0]))
+    for i in 0 .. <v.len:
+      pack(v.sons[i], typ.sons[1], res +! i * baseSize)
   of tyNil:
-    result = alloc0(sizeof(pointer))
+    nil
   of tyDistinct, tyGenericInst:
     result = pack(v, typ.sons[0])
   else:
@@ -205,7 +233,9 @@ proc callForeignFunction*(call: PNode): PNode =
   var args: TArgList
   let fn = cast[pointer](call.sons[0].intVal)
   for i in 1 .. call.len-1:
-    args[i-1] = pack(call.sons[i], call.sons[i].typ)
+    var t = call.sons[i].typ
+    args[i-1] = alloc0(typ.sons[0].getSize.int)
+    pack(call.sons[i], t, args[i-1])
   let retVal = if isEmptyType(typ.sons[0]): pointer(nil)
                else: alloc(typ.sons[0].getSize.int)
 
diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim
index 3ade1cbf9..a64b7f138 100755
--- a/lib/pure/dynlib.nim
+++ b/lib/pure/dynlib.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2009 Andreas Rumpf
+#        (c) Copyright 2012 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -18,6 +18,10 @@ proc LoadLib*(path: string): TLibHandle
   ## loads a library from `path`. Returns nil if the library could not 
   ## be loaded.
 
+proc LoadLib*(): TLibHandle
+  ## gets the handle from the current executable. Returns nil if the 
+  ## library could not be loaded.
+
 proc UnloadLib*(lib: TLibHandle)
   ## unloads the library `lib`
 
@@ -57,6 +61,7 @@ when defined(posix):
       importc, header: "<dlfcn.h>".}
 
   proc LoadLib(path: string): TLibHandle = return dlopen(path, RTLD_NOW)
+  proc LoadLib(): TLibHandle = return dlopen(nil, RTLD_NOW)
   proc UnloadLib(lib: TLibHandle) = dlclose(lib)
   proc symAddr(lib: TLibHandle, name: cstring): pointer = 
     return dlsym(lib, name)
@@ -78,6 +83,8 @@ elif defined(windows) or defined(dos):
 
   proc LoadLib(path: string): TLibHandle =
     result = cast[TLibHandle](winLoadLibrary(path))
+  proc LoadLib(): TLibHandle =
+    result = cast[TLibHandle](winLoadLibrary(nil))
   proc UnloadLib(lib: TLibHandle) = FreeLibrary(cast[THINSTANCE](lib))
 
   proc symAddr(lib: TLibHandle, name: cstring): pointer =
diff --git a/lib/system.nim b/lib/system.nim
index e199d7611..cbca90a3b 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1716,8 +1716,8 @@ when not defined(EcmaScript) and not defined(NimrodVM):
 
   proc initStackBottom() {.inline, compilerproc.} =
     # WARNING: This is very fragile! An array size of 8 does not work on my
-    # Linux 64bit system. Very strange, but we are at the will of GCC's 
-    # optimizer...
+    # Linux 64bit system. -- That's because the stack direction is the other
+    # way round.
     when defined(setStackBottom):
       var locals {.volatile.}: pointer
       locals = addr(locals)
@@ -1754,7 +1754,6 @@ when not defined(EcmaScript) and not defined(NimrodVM):
     proc endbStep()
 
   # ----------------- IO Part ------------------------------------------------
-
   type
     CFile {.importc: "FILE", nodecl, final.} = object  # empty record for
                                                        # data hiding
@@ -1783,7 +1782,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
       ## The standard error stream.
       ##
       ## Note: In my opinion, this should not be used -- the concept of a
-      ## separate error stream is a design flaw of UNIX. A seperate *message
+      ## separate error stream is a design flaw of UNIX. A separate *message
       ## stream* is a good idea, but since it is named ``stderr`` there are few
       ## programs out there that distinguish properly between ``stdout`` and
       ## ``stderr``. So, that's what you get if you don't name your variables
@@ -2121,6 +2120,8 @@ when not defined(EcmaScript) and not defined(NimrodVM):
 
 elif defined(ecmaScript) or defined(NimrodVM):
   # Stubs:
+  proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = nil
+
   proc GC_disable() = nil
   proc GC_enable() = nil
   proc GC_fullCollect() = nil
@@ -2151,6 +2152,10 @@ elif defined(ecmaScript) or defined(NimrodVM):
       if x == y: return 0
       if x < y: return -1
       return 1
+  
+  when defined(nimffi):
+    include "system/sysio"
+
 
 proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} =
   ## a shorthand for ``echo(errormsg); quit(errorcode)``.