comparison go/godc/godc.go @ 0:0cfcc391201f

initial from svn dyncall-1745
author Daniel Adler
date Thu, 19 Mar 2015 22:26:28 +0100
parents
children 8a45a05ff64e
comparison
equal deleted inserted replaced
-1:000000000000 0:0cfcc391201f
1 /*
2
3 godc.go
4 Copyright (c) 2014 Tassilo Philipp <tphilipp@potion-studios.com>
5
6 Permission to use, copy, modify, and distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 */
19
20
21 // Go/dyncall extension implementation.
22 package godc
23
24 // #cgo LDFLAGS: -L../../../dyncall/ -ldyncall_s
25 // #cgo LDFLAGS: -L../../../dynload/ -ldynload_s
26 // #cgo LDFLAGS: -L../../../dyncallback/ -ldyncallback_s
27 // #include <stdlib.h>
28 // #include "../../../dyncall/dyncall/dyncall.h"
29 // #include "../../../dyncall/dynload/dynload.h"
30 // #include "../../../dyncall/dyncall/dyncall_signature.h"
31 import "C"
32 import (
33 "unsafe"
34 "fmt"
35 "reflect"
36 )
37
38 type ExtLib struct {
39 lib *C.DLLib
40 syms *C.DLSyms
41 }
42
43 type CallVM struct {
44 cvm *C.DCCallVM
45 }
46
47
48 // dynload
49 func (p *ExtLib) Load(path string) error {
50 s := C.CString(path)
51 defer C.free(unsafe.Pointer(s))
52 p.lib = C.dlLoadLibrary(s)
53 if p.lib != nil { return nil }
54 return fmt.Errorf("Can't load %s", path)
55 }
56
57 func (p *ExtLib) Free() {
58 C.dlFreeLibrary(p.lib)
59 }
60
61 func (p *ExtLib) FindSymbol(name string) unsafe.Pointer {
62 s := C.CString(name)
63 defer C.free(unsafe.Pointer(s))
64 return unsafe.Pointer(C.dlFindSymbol(p.lib, s))
65 }
66
67
68 // dynload Syms
69 func (p *ExtLib) SymsInit(path string) error {
70 s := C.CString(path)
71 defer C.free(unsafe.Pointer(s))
72 p.syms = C.dlSymsInit(s)
73 if p.syms != nil { return nil }
74 return fmt.Errorf("Can't load %s", path)
75 }
76
77 func (p *ExtLib) SymsCleanup() {
78 C.dlSymsCleanup(p.syms)
79 }
80
81 func (p *ExtLib) SymsCount() int {
82 return int(C.dlSymsCount(p.syms))
83 }
84
85 func (p *ExtLib) SymsName(i int) string {
86 return C.GoString(C.dlSymsName(p.syms, C.int(i)))
87 }
88
89 func (p *ExtLib) SymsNameFromValue(v unsafe.Pointer) string {
90 return C.GoString(C.dlSymsNameFromValue(p.syms, v))
91 }
92
93
94 // dyncall
95 func (p *CallVM) InitCallVM() error {
96 return p.InitCallVMWithStackSize(4096)
97 }
98
99 func (p *CallVM) InitCallVMWithStackSize(stackSize int) error {
100 p.cvm = C.dcNewCallVM(C.DCsize(stackSize))
101 if p.cvm != nil { return nil }
102 return fmt.Errorf("Can't create CallVM")
103 }
104
105 func (p *CallVM) Free() {
106 C.dcFree(p.cvm)
107 }
108
109 func (p *CallVM) Reset() {
110 C.dcReset(p.cvm)
111 }
112
113
114
115 // Modes
116 const (
117 DC_CALL_C_DEFAULT = C.DC_CALL_C_DEFAULT
118 DC_CALL_C_ELLIPSIS = C.DC_CALL_C_ELLIPSIS
119 DC_CALL_C_ELLIPSIS_VARARGS = C.DC_CALL_C_ELLIPSIS_VARARGS
120 DC_CALL_C_X86_CDECL = C.DC_CALL_C_X86_CDECL
121 DC_CALL_C_X86_WIN32_STD = C.DC_CALL_C_X86_WIN32_STD
122 DC_CALL_C_X86_WIN32_FAST_MS = C.DC_CALL_C_X86_WIN32_FAST_MS
123 DC_CALL_C_X86_WIN32_FAST_GNU = C.DC_CALL_C_X86_WIN32_FAST_GNU
124 DC_CALL_C_X86_WIN32_THIS_MS = C.DC_CALL_C_X86_WIN32_THIS_MS
125 DC_CALL_C_X86_WIN32_THIS_GNU = C.DC_CALL_C_X86_WIN32_THIS_GNU
126 DC_CALL_C_X64_WIN64 = C.DC_CALL_C_X64_WIN64
127 DC_CALL_C_X64_SYSV = C.DC_CALL_C_X64_SYSV
128 DC_CALL_C_PPC32_DARWIN = C.DC_CALL_C_PPC32_DARWIN
129 DC_CALL_C_PPC32_OSX = C.DC_CALL_C_PPC32_OSX
130 DC_CALL_C_ARM_ARM_EABI = C.DC_CALL_C_ARM_ARM_EABI
131 DC_CALL_C_ARM_THUMB_EABI = C.DC_CALL_C_ARM_THUMB_EABI
132 DC_CALL_C_ARM_ARMHF = C.DC_CALL_C_ARM_ARMHF
133 DC_CALL_C_MIPS32_EABI = C.DC_CALL_C_MIPS32_EABI
134 DC_CALL_C_MIPS32_PSPSDK = C.DC_CALL_C_MIPS32_PSPSDK
135 DC_CALL_C_PPC32_SYSV = C.DC_CALL_C_PPC32_SYSV
136 DC_CALL_C_PPC32_LINUX = C.DC_CALL_C_PPC32_LINUX
137 DC_CALL_C_ARM_ARM = C.DC_CALL_C_ARM_ARM
138 DC_CALL_C_ARM_THUMB = C.DC_CALL_C_ARM_THUMB
139 DC_CALL_C_MIPS32_O32 = C.DC_CALL_C_MIPS32_O32
140 DC_CALL_C_MIPS64_N32 = C.DC_CALL_C_MIPS64_N32
141 DC_CALL_C_MIPS64_N64 = C.DC_CALL_C_MIPS64_N64
142 DC_CALL_C_X86_PLAN9 = C.DC_CALL_C_X86_PLAN9
143 DC_CALL_C_SPARC32 = C.DC_CALL_C_SPARC32
144 DC_CALL_C_SPARC64 = C.DC_CALL_C_SPARC64
145 DC_CALL_SYS_DEFAULT = C.DC_CALL_SYS_DEFAULT
146 DC_CALL_SYS_X86_INT80H_LINUX = C.DC_CALL_SYS_X86_INT80H_LINUX
147 DC_CALL_SYS_X86_INT80H_BSD = C.DC_CALL_SYS_X86_INT80H_BSD
148 )
149
150
151 func (p *CallVM) Mode(mode int) {
152 C.dcMode(p.cvm, C.DCint(mode))
153 }
154
155 // Error codes
156 const (
157 DC_ERROR_NONE = C.DC_ERROR_NONE
158 DC_ERROR_UNSUPPORTED_MODE = C.DC_ERROR_UNSUPPORTED_MODE
159 )
160
161
162 func (p *CallVM) GetError() int {
163 return int(C.dcGetError(p.cvm))
164 }
165
166
167 // Helper for string/pointer conversion, needed as low-level string alloc needs to be freed in different scope
168 func (p *CallVM) AllocCString(value string) unsafe.Pointer { s := C.CString(value); return unsafe.Pointer(s) }
169 func (p *CallVM) FreeCString (value unsafe.Pointer) { C.free(value) }
170
171 // Args
172 func (p *CallVM) ArgBool (value bool) { if value==true { C.dcArgBool(p.cvm, C.DC_TRUE) } else { C.dcArgBool(p.cvm, C.DC_FALSE) } }
173 func (p *CallVM) ArgChar (value int8) { C.dcArgChar (p.cvm, C.DCchar (value)) }
174 func (p *CallVM) ArgShort (value int16) { C.dcArgShort (p.cvm, C.DCshort (value)) }
175 func (p *CallVM) ArgInt (value int) { C.dcArgInt (p.cvm, C.DCint (value)) }
176 func (p *CallVM) ArgLong (value int32) { C.dcArgLong (p.cvm, C.DClong (value)) }
177 func (p *CallVM) ArgLongLong (value int64) { C.dcArgLongLong(p.cvm, C.DClonglong(value)) }
178 func (p *CallVM) ArgFloat (value float32) { C.dcArgFloat (p.cvm, C.DCfloat (value)) }
179 func (p *CallVM) ArgDouble (value float64) { C.dcArgDouble (p.cvm, C.DCdouble (value)) }
180 func (p *CallVM) ArgPointer (value unsafe.Pointer) { C.dcArgPointer (p.cvm, C.DCpointer (value)) }
181 //@@@func (p *CallVM) ArgStruct (s C.DCstruct*, value unsafe.Pointer)
182
183 // "Formatted" args
184 // - first takes Go's types (as they cover all C types dyncall supports) and pushes values accordingly
185 // - second uses a dyncall signature for implicit type conversion/casting, however it uses reflect package and is slower
186 // Note that first version doesn't feature calling convention mode switching.
187 func (p *CallVM) ArgF_Go(args ...interface{}) error {
188
189 for i, n := 0, len(args); i<n; i++ {
190 switch args[i].(type) {
191 case bool: p.ArgBool ( (args[i].(bool )))
192 case int8: p.ArgChar ( (args[i].(int8 )))
193 case uint8/*byte*/: p.ArgChar (int8 (args[i].(uint8 )))
194 case int16: p.ArgShort ( (args[i].(int16 )))
195 case uint16: p.ArgShort (int16 (args[i].(uint16 )))
196 case int: p.ArgInt ( (args[i].(int )))
197 case uint: p.ArgInt (int (args[i].(uint )))
198 case int32/*rune*/: p.ArgLong ( (args[i].(int32 )))
199 case uint32: p.ArgLong (int32 (args[i].(uint32 )))
200 case int64: p.ArgLongLong( (args[i].(int64 )))
201 case uint64: p.ArgLongLong(int64 (args[i].(uint64 )))
202 case float32: p.ArgFloat ( (args[i].(float32 )))
203 case float64: p.ArgDouble ( (args[i].(float64 )))
204 case uintptr: p.ArgPointer (unsafe.Pointer(args[i].(unsafe.Pointer)))
205 case unsafe.Pointer: p.ArgPointer ( (args[i].(unsafe.Pointer)))
206 default: return fmt.Errorf("Unknown type passed to ArgF_Go")
207 }
208 }
209 return nil
210 }
211
212 func (p *CallVM) ArgF(signature string, args ...interface{}) {
213
214 tb := reflect.TypeOf((*bool )(nil)).Elem()
215 ti := reflect.TypeOf((*int64 )(nil)).Elem()
216 tf := reflect.TypeOf((*float64)(nil)).Elem()
217 tp := reflect.TypeOf((*uintptr)(nil)).Elem()
218
219 for i, n := 0, len(signature); i<n; i++ {
220 //@@@ add support for calling convention mode(s)
221 switch s := signature[i]; s {
222 case C.DC_SIGCHAR_BOOL: p.ArgBool (bool (reflect.ValueOf(args[i]).Convert(tb).Bool ()))
223 case C.DC_SIGCHAR_CHAR, C.DC_SIGCHAR_UCHAR: p.ArgChar (int8 (reflect.ValueOf(args[i]).Convert(ti).Int ()))
224 case C.DC_SIGCHAR_INT, C.DC_SIGCHAR_UINT: p.ArgInt (int (reflect.ValueOf(args[i]).Convert(ti).Int ()))
225 case C.DC_SIGCHAR_LONG, C.DC_SIGCHAR_ULONG: p.ArgLong (int32 (reflect.ValueOf(args[i]).Convert(ti).Int ()))
226 case C.DC_SIGCHAR_LONGLONG, C.DC_SIGCHAR_ULONGLONG: p.ArgLongLong(int64 (reflect.ValueOf(args[i]).Convert(ti).Int ()))
227 case C.DC_SIGCHAR_FLOAT: p.ArgFloat (float32 (reflect.ValueOf(args[i]).Convert(tf).Float ()))
228 case C.DC_SIGCHAR_DOUBLE: p.ArgDouble (float64 (reflect.ValueOf(args[i]).Convert(tf).Float ()))
229 case C.DC_SIGCHAR_POINTER, C.DC_SIGCHAR_STRING: p.ArgPointer (unsafe.Pointer(reflect.ValueOf(args[i]).Convert(tp).Pointer()))
230 case C.DC_SIGCHAR_ENDARG: return
231 }
232 // Faster, but doesn't do cross-type conversions.
233 //switch s := signature[i]; s {
234 // case C.DC_SIGCHAR_BOOL: p.ArgBool (args[i].(bool ))
235 // case C.DC_SIGCHAR_CHAR, C.DC_SIGCHAR_UCHAR: p.ArgChar (args[i].(int8 ))
236 // case C.DC_SIGCHAR_SHORT, C.DC_SIGCHAR_USHORT: p.ArgShort (args[i].(int16 ))
237 // case C.DC_SIGCHAR_INT, C.DC_SIGCHAR_UINT: p.ArgInt (args[i].(int ))
238 // case C.DC_SIGCHAR_LONG, C.DC_SIGCHAR_ULONG: p.ArgLong (args[i].(int32 ))
239 // case C.DC_SIGCHAR_LONGLONG, C.DC_SIGCHAR_ULONGLONG: p.ArgLongLong(args[i].(int64 ))
240 // case C.DC_SIGCHAR_FLOAT: p.ArgFloat (args[i].(float32 ))
241 // case C.DC_SIGCHAR_DOUBLE: p.ArgDouble (args[i].(float64 ))
242 // case C.DC_SIGCHAR_POINTER, C.DC_SIGCHAR_STRING: p.ArgPointer (args[i].(unsafe.Pointer))
243 // case C.DC_SIGCHAR_ENDARG: return
244 //}
245 }
246 }
247
248
249 // Calls
250 func (p *CallVM) CallVoid (funcptr unsafe.Pointer) { C.dcCallVoid (p.cvm, C.DCpointer(funcptr)) }
251 func (p *CallVM) CallBool (funcptr unsafe.Pointer) bool { b := (C.dcCallBool(p.cvm, C.DCpointer(funcptr))); if b==C.DC_TRUE { return true } else { return false } }
252 func (p *CallVM) CallChar (funcptr unsafe.Pointer) int8 { return int8 (C.dcCallChar (p.cvm, C.DCpointer(funcptr))) }
253 func (p *CallVM) CallShort (funcptr unsafe.Pointer) int16 { return int16 (C.dcCallShort (p.cvm, C.DCpointer(funcptr))) }
254 func (p *CallVM) CallInt (funcptr unsafe.Pointer) int { return int (C.dcCallInt (p.cvm, C.DCpointer(funcptr))) }
255 func (p *CallVM) CallLong (funcptr unsafe.Pointer) int32 { return int32 (C.dcCallLong (p.cvm, C.DCpointer(funcptr))) }
256 func (p *CallVM) CallLongLong (funcptr unsafe.Pointer) int64 { return int64 (C.dcCallLongLong(p.cvm, C.DCpointer(funcptr))) }
257 func (p *CallVM) CallFloat (funcptr unsafe.Pointer) float32 { return float32 (C.dcCallFloat (p.cvm, C.DCpointer(funcptr))) }
258 func (p *CallVM) CallDouble (funcptr unsafe.Pointer) float64 { return float64 (C.dcCallDouble (p.cvm, C.DCpointer(funcptr))) }
259 func (p *CallVM) CallPointer (funcptr unsafe.Pointer) unsafe.Pointer { return unsafe.Pointer(C.dcCallPointer (p.cvm, C.DCpointer(funcptr))) }
260 func (p *CallVM) CallPointerToStr(funcptr unsafe.Pointer) string { return C.GoString((*C.char)(C.dcCallPointer (p.cvm, C.DCpointer(funcptr)))) } // For convenience
261 //@@@func (p *CallVM) CallStruct (funcptr unsafe.Pointer, s C.DCstruct* s, returnValue unsafe.Pointer)
262
263 // "Formatted" calls
264 //@@@func (p *CallVM) Call(result, funcptr unsafe.Pointer, signature string, args ...interface{}) {
265 //@@@...
266 //@@@}
267
268
269 //void dcCallF (DCCallVM* vm, DCValue* result, DCpointer funcptr, const DCsigchar* signature, ...);
270
271 /*
272 DC_API DCstruct* dcNewStruct (DCsize fieldCount, DCint alignment);
273 DC_API void dcStructField (DCstruct* s, DCint type, DCint alignment, DCsize arrayLength);
274 DC_API void dcSubStruct (DCstruct* s, DCsize fieldCount, DCint alignment, DCsize arrayLength);
275 DC_API void dcCloseStruct (DCstruct* s);
276 DC_API DCsize dcStructSize (DCstruct* s);
277 DC_API DCsize dcStructAlignment(DCstruct* s);
278 DC_API void dcFreeStruct (DCstruct* s);
279
280 DC_API DCstruct* dcDefineStruct (const char* signature);
281 */
282