add new ways of calling dylib function

This commit is contained in:
ValKmjolnir 2022-11-11 00:11:01 +08:00
parent ca527ec931
commit 97b3cefe75
14 changed files with 201 additions and 107 deletions

View File

@ -674,10 +674,21 @@ dylib.dlclose(dlhandle);
`dylib.dlsym` is used to get the function address.
`dylib.dlcall` is used to call the function, the first argument is the function address, make sure this argument is vm_obj and type=obj_extern.
`dylib.dlcall` is used to call the function, the first argument is the function address, make sure this argument is `vm_obj` and `type=obj_extern`.
`dylib.dlclose` is used to unload the library, at the moment that you call the function, all the function addresses that got from it are invalid.
`dylib.limitcall` is used to get `dlcall` function that has limited parameter size, this function will prove the performance of your code because it does not use `vm_vec` to store the arguments, instead it uses local scope to store them, so this could avoid frequently garbage collecting. And the code above could also be written like this:
```javascript
var dlhandle=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib=dylib.dlsym(dlhandle,"fib");
var invoke=dylib.limitcall(1); # this means the called function has only one parameter
for(var i=1;i<30;i+=1)
println(invoke(fib,i));
dylib.dlclose(dlhandle);
```
If get this, Congratulations!
```bash

View File

@ -647,10 +647,21 @@ dylib.dlclose(dlhandle);
`dylib.dlsym`通过符号从动态库中获得函数地址。
`dylib.dlcall`用于调用函数第一个参数是动态库函数的地址这是个特殊类型一定要保证这个参数是vm_obj类型并且type=obj_extern。
`dylib.dlcall`用于调用函数,第一个参数是动态库函数的地址,这是个特殊类型,一定要保证这个参数是`vm_obj`类型并且`type=obj_extern`
`dylib.dlclose`用于卸载动态库,当然,在这个函数调用之后,所有从该库中获取的函数都作废。
`dylib.limitcall`用于获取使用固定长度传参的 `dlcall` 函数,这种函数可以提高你的程序运行效率,因为它不需要用 `vm_vec` 来存储传入参数,而是使用局部作用域来直接存储,从而避免了频繁调用可能导致的频繁垃圾收集。所以上面展示的代码同样可以这样写:
```javascript
var dlhandle=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib=dylib.dlsym(dlhandle,"fib");
var invoke=dylib.limitcall(1); # 这说明我们要调用的函数只有一个参数
for(var i=1;i<30;i+=1)
println(invoke(fib,i));
dylib.dlclose(dlhandle);
```
如果接下来你看到了这个运行结果,恭喜你!
```bash

39
lib.nas
View File

@ -280,8 +280,7 @@ var md5=func(str){
return __md5(str);
}
var io=
{
var io={
SEEK_SET:0,
SEEK_CUR:1,
SEEK_END:2,
@ -333,8 +332,7 @@ var fstat=func(filename){
# functions that do bitwise calculation.
# carefully use it, all the calculations are based on integer.
var bits=
{
var bits={
# i32 xor
i32_xor: func(a,b){return __i32xor(a,b); },
# i32 and
@ -378,8 +376,7 @@ var bits=
};
# mostly used math functions and special constants, you know.
var math=
{
var math={
e: 2.7182818284590452354,
pi: 3.14159265358979323846264338327950288,
D2R: 2.7182818284590452354/180,
@ -402,8 +399,7 @@ var math=
min: func(x,y){return x<y?x:y; }
};
var unix=
{
var unix={
pipe: func(){return __pipe;},
fork: func(){return __fork;},
dup2: func(fd0,fd1){die("not supported yet");},
@ -425,8 +421,7 @@ var unix=
# dylib is the core hashmap for developers to load their own library.
# for safe using dynamic library, you could use 'module' in stl/module.nas
var dylib=
{
var dylib={
# open dynamic lib.
dlopen: func(libname){
# find dynamic lib from local dir first
@ -451,22 +446,34 @@ var dylib=
dlsym: func(lib,sym){return __dlsym; },
# close dynamic lib, this operation will make all the symbols loaded from it invalid.
dlclose: func(lib){return __dlclose; },
# call the loaded symbol.
dlcall: func(ptr,args...){return __dlcall}
# call the loaded symbol, with infinite parameters:
# Caution: this may cause garbage collection process, be aware of the performance.
dlcall: func(ptr,args...){return __dlcallv},
# get dlcall function with limited parameter list
limitcall: func(arg_size=0){
if(arg_size==0){return func(ptr){return __dlcall};}
else if(arg_size==1){return func(ptr,_0){return __dlcall};}
else if(arg_size==2){return func(ptr,_0,_1){return __dlcall};}
else if(arg_size==3){return func(ptr,_0,_1,_2){return __dlcall};}
else if(arg_size==4){return func(ptr,_0,_1,_2,_3){return __dlcall};}
else if(arg_size==5){return func(ptr,_0,_1,_2,_3,_4){return __dlcall};}
else if(arg_size==6){return func(ptr,_0,_1,_2,_3,_4,_5){return __dlcall};}
else if(arg_size==7){return func(ptr,_0,_1,_2,_3,_4,_5,_6){return __dlcall};}
else if(arg_size==8){return func(ptr,_0,_1,_2,_3,_4,_5,_6,_7){return __dlcall};}
else{return func(ptr,args...){return __dlcallv};}
}
};
# os is used to use or get some os-related info/functions.
# windows/macOS/linux are supported.
var os=
{
var os={
# get a string that tell which os it runs on.
platform: func(){return __platform;},
time: func(){return __logtime; }
};
# runtime gives us some functions that we could manage it manually.
var runtime=
{
var runtime={
# command line arguments
argv: func(){return __sysargv;}
};

View File

@ -8,26 +8,20 @@ double fibonaci(double x){
}
var fib(var* args,usize size,gc* ngc){
std::cout<<"[mod] this is the first test module of nasal\n";
if(!size)
return nas_err("fib","lack arguments");
var num=args[0];
if(num.type!=vm_num)
return nas_err("extern_fib","\"num\" must be number");
return {vm_num,fibonaci(num.tonum())};
}
var quick_fib(var* args,usize size,gc* ngc){
std::cout<<"[mod] this is the first test module of nasal\n";
if(!size)
return nas_err("fib","lack arguments");
var num=args[0];
if(num.type!=vm_num)
return nas_err("extern_quick_fib","\"num\" must be number");
if(num.num()<2)
return num;
return nas_err("quick_fib","lack arguments");
double num=args[0].tonum();
if(num<2)
return {vm_num,num};
double a=1,b=1,res=0;
for(double i=1;i<num.num();i+=1){
for(double i=1;i<num;i+=1){
res=a+b;
a=b;
b=res;

View File

@ -2,7 +2,7 @@ var libfib=func(){
var dl=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fib=dylib.dlsym(dl,"fib");
var qfib=dylib.dlsym(dl,"quick_fib");
var call=dylib.dlcall;
var call=dylib.limitcall(1);
return {
fib: func(x){return call(fib,x)},
qfib:func(x){return call(qfib,x)}

View File

@ -3,7 +3,7 @@ var libkey=func(){
var kb=dylib.dlsym(lib,"nas_kbhit");
var gt=dylib.dlsym(lib,"nas_getch");
var nb=dylib.dlsym(lib,"nas_noblock");
var call=dylib.dlcall;
var call=dylib.limitcall(0);
return {
kbhit:func(){return call(kb);},
getch:func(){return call(gt);},

View File

@ -27,32 +27,36 @@ var libmat=func(){
dylib.dlsym(dl,"nas_rotate_y"),
dylib.dlsym(dl,"nas_rotate_z")
);
var call=dylib.dlcall;
var (invoke_i,invoke_ii,invoke_iii)=(
dylib.limitcall(1),
dylib.limitcall(2),
dylib.limitcall(3)
);
return {
vec2:{
new:func(x,y){return call(vec2,x,y);},
add:func(v0,v1){return call(vec2add,v0,v1);},
sub:func(v0,v1){return call(vec2sub,v0,v1);},
mul:func(v0,v1){return call(vec2mul,v0,v1);},
div:func(v0,v1){return call(vec2div,v0,v1);},
neg:func(v0){return call(vec2neg,v0);},
norm:func(v0){return call(vec2norm,v0);},
len:func(v0){return call(vec2len,v0);},
dot:func(v0,v1){return call(vec2dot,v0,v1);}
new: func(x,y){return invoke_ii(vec2,x,y);},
add: func(v0,v1){return invoke_ii(vec2add,v0,v1);},
sub: func(v0,v1){return invoke_ii(vec2sub,v0,v1);},
mul: func(v0,v1){return invoke_ii(vec2mul,v0,v1);},
div: func(v0,v1){return invoke_ii(vec2div,v0,v1);},
neg: func(v0){return invoke_i(vec2neg,v0);},
norm: func(v0){return invoke_i(vec2norm,v0);},
len: func(v0){return invoke_i(vec2len,v0);},
dot: func(v0,v1){return invoke_ii(vec2dot,v0,v1);}
},
vec3:{
new:func(x,y,z){return call(vec3,x,y,z);},
add:func(v0,v1){return call(vec3add,v0,v1);},
sub:func(v0,v1){return call(vec3sub,v0,v1);},
mul:func(v0,v1){return call(vec3mul,v0,v1);},
div:func(v0,v1){return call(vec3div,v0,v1);},
neg:func(v0){return call(vec3neg,v0);},
norm:func(v0){return call(vec3norm,v0);},
len:func(v0){return call(vec3len,v0);},
rx:func(v0,angle){return call(rotate_x,v0,angle);},
ry:func(v0,angle){return call(rotate_y,v0,angle);},
rz:func(v0,angle){return call(rotate_z,v0,angle);},
dot:func(v0,v1){return call(vec3dot,v0,v1);}
new: func(x,y,z){return invoke_iii(vec3,x,y,z);},
add: func(v0,v1){return invoke_ii(vec3add,v0,v1);},
sub: func(v0,v1){return invoke_ii(vec3sub,v0,v1);},
mul: func(v0,v1){return invoke_ii(vec3mul,v0,v1);},
div: func(v0,v1){return invoke_ii(vec3div,v0,v1);},
neg: func(v0){return invoke_i(vec3neg,v0);},
norm: func(v0){return invoke_i(vec3norm,v0);},
len: func(v0){return invoke_i(vec3len,v0);},
rx: func(v0,angle){return invoke_ii(rotate_x,v0,angle);},
ry: func(v0,angle){return invoke_ii(rotate_y,v0,angle);},
rz: func(v0,angle){return invoke_ii(rotate_z,v0,angle);},
dot: func(v0,v1){return invoke_ii(vec3dot,v0,v1);}
}
};
}();

View File

@ -1,5 +1,6 @@
var socket=func(){
var lib=dylib.dlopen("libnasock"~(os.platform()=="windows"?".dll":".so"));
var sock=dylib.dlsym(lib,"nas_socket");
var closesocket=dylib.dlsym(lib,"nas_closesocket");
var shutdown=dylib.dlsym(lib,"nas_shutdown");
@ -12,17 +13,46 @@ var socket=func(){
var recv=dylib.dlsym(lib,"nas_recv");
var recvfrom=dylib.dlsym(lib,"nas_recvfrom");
var errno=dylib.dlsym(lib,"nas_errno");
var call=dylib.dlcall;
var (invoke,invoke_i,invoke_ii,invoke_iii,invoke_iiii,invoke_iiiii)=(
dylib.limitcall(0),
dylib.limitcall(1),
dylib.limitcall(2),
dylib.limitcall(3),
dylib.limitcall(4),
dylib.limitcall(5),
);
return {
AF_UNSPEC:0,AF_UNIX:1,AF_INET:2,AF_IMPLINK:3,
AF_PUP:4,AF_CHAOS:5,AF_IPX:6,AF_NS:6,
AF_ISO:7,AF_OSI:7,AF_ECMA:8,AF_DATAKIT:9,
AF_CCITT:10,AF_SNA:11,AF_DECnet:12,AF_DLI:13,
AF_LAT:14,AF_HYLINK:15,AF_APPLETALK:16,AF_NETBIOS:17,
AF_VOICEVIEW:18,AF_FIREFOX:19,AF_UNKNOWN1:20,AF_BAN:21,
AF_UNSPEC:0,
AF_UNIX:1,
AF_INET:2,
AF_IMPLINK:3,
AF_PUP:4,
AF_CHAOS:5,
AF_IPX:6,
AF_NS:6,
AF_ISO:7,
AF_OSI:7,
AF_ECMA:8,
AF_DATAKIT:9,
AF_CCITT:10,
AF_SNA:11,
AF_DECnet:12,
AF_DLI:13,
AF_LAT:14,
AF_HYLINK:15,
AF_APPLETALK:16,
AF_NETBIOS:17,
AF_VOICEVIEW:18,
AF_FIREFOX:19,
AF_UNKNOWN1:20,
AF_BAN:21,
AF_MAX:22,
SOCK_STREAM:1,SOCK_DGRAM:2,SOCK_RAW:3,SOCK_RDM:4,
SOCK_STREAM:1,
SOCK_DGRAM:2,
SOCK_RAW:3,
SOCK_RDM:4,
SOCK_SEQPACKET:5,
IPPROTO_IP:0,IPPROTO_ICMP:1,IPPROTO_IGMP:2,IPPROTO_GGP:3,
@ -46,40 +76,40 @@ var socket=func(){
MSG_DONTROUTE:0x4,
socket:func(af,type,proto){
return call(sock,af,type,proto);
return invoke_iii(sock,af,type,proto);
},
closesocket:func(sd){
return call(closesocket,sd);
return invoke_i(closesocket,sd);
},
shutdown: func(sd,how){
return call(shutdown,sd,how);
return invoke_ii(shutdown,sd,how);
},
bind: func(sd,ip,port){
return call(bind,sd,ip,port);
return invoke_iii(bind,sd,ip,port);
},
listen: func(sd,backlog){
return call(listen,sd,backlog);
return invoke_ii(listen,sd,backlog);
},
connect: func(sd,hostname,port){
return call(connect,sd,hostname,port);
return invoke_iii(connect,sd,hostname,port);
},
accept: func(sd){
return call(accept,sd);
return invoke_i(accept,sd);
},
send: func(sd,buff,flags=0){
return call(send,sd,buff,flags);
return invoke_iii(send,sd,buff,flags);
},
sendto: func(sd,hostname,port,buff,flags=0){
return call(sendto,sd,hostname,port,buff,flags);
return invoke_iiiii(sendto,sd,hostname,port,buff,flags);
},
recv: func(sd,len,flags=0){
return call(recv,sd,len,flags);
return invoke_iii(recv,sd,len,flags);
},
recvfrom: func(sd,len,flags=0){
return call(recvfrom,sd,len,flags);
return invoke_iii(recvfrom,sd,len,flags);
},
errno: func(){
return call(errno);
return invoke(errno);
}
};
}();

View File

@ -5,6 +5,11 @@ dynamic_libs_dll=libfib.dll libkey.dll libnasock.dll libmat.dll
STD=c++14
all: $(dynamic_libs_so)
@ echo "[Compiling] done"
winall: $(dynamic_libs_dll)
@ echo [Compiling] done
libfib.so: fib.cpp
@ echo "[Compiling] libfib.so"
@ $(CXX) -std=$(STD) -c -O3 fib.cpp -fPIC -o fib.o
@ -54,8 +59,3 @@ clean:
-@ rm $(dynamic_libs_so)
@ echo "[clean] dll"
-@ rm $(dynamic_libs_dll)
all: $(dynamic_libs_so)
@ echo "[Compiling] done"
winall: $(dynamic_libs_dll)
@ echo [Compiling] done

View File

@ -964,7 +964,7 @@ var builtin_dlclose(var* local,gc& ngc)
return nil;
}
var builtin_dlcall(var* local,gc& ngc)
var builtin_dlcallv(var* local,gc& ngc)
{
var fp=local[1];
var args=local[2];
@ -974,6 +974,15 @@ var builtin_dlcall(var* local,gc& ngc)
return ((mod)fp.obj().ptr)(vec.data(),vec.size(),&ngc);
}
var builtin_dlcall(var* local,gc& ngc)
{
var fp=local[1];
if(!fp.objchk(nas_obj::faddr))
return nas_err("dlcall","\"ptr\" is not a valid function pointer");
// arguments' stored place begins at local +2
return ((mod)fp.obj().ptr)(local+2,ngc.top-local-2,&ngc);
}
var builtin_platform(var* local,gc& ngc)
{
#if defined _WIN32 || defined _WIN64
@ -1282,6 +1291,7 @@ struct
{"__dlopen", builtin_dlopen },
{"__dlsym", builtin_dlsym },
{"__dlclose", builtin_dlclose },
{"__dlcallv", builtin_dlcallv },
{"__dlcall", builtin_dlcall },
{"__platform",builtin_platform},
{"__md5", builtin_md5 },

View File

@ -706,11 +706,8 @@ inline void vm::o_callfv()
for(u32 i=psize;i<argc;++i)
dynamic.vec().elems.push_back(local[i]);
}
#ifdef _MSC_VER
u32 min_size=(std::min)(psize,argc);
#else
u32 min_size=std::min(psize,argc);
#endif
u32 min_size=(std::min)(psize,argc); // avoid error in MSVC
for(u32 i=min_size;i>=1;--i)// load arguments
local[i]=local[i-1];
local[0]=func.local[0];// load "me"

View File

@ -280,8 +280,7 @@ var md5=func(str){
return __md5(str);
}
var io=
{
var io={
SEEK_SET:0,
SEEK_CUR:1,
SEEK_END:2,
@ -333,8 +332,7 @@ var fstat=func(filename){
# functions that do bitwise calculation.
# carefully use it, all the calculations are based on integer.
var bits=
{
var bits={
# i32 xor
i32_xor: func(a,b){return __i32xor(a,b); },
# i32 and
@ -378,8 +376,7 @@ var bits=
};
# mostly used math functions and special constants, you know.
var math=
{
var math={
e: 2.7182818284590452354,
pi: 3.14159265358979323846264338327950288,
D2R: 2.7182818284590452354/180,
@ -402,8 +399,7 @@ var math=
min: func(x,y){return x<y?x:y; }
};
var unix=
{
var unix={
pipe: func(){return __pipe;},
fork: func(){return __fork;},
dup2: func(fd0,fd1){die("not supported yet");},
@ -425,8 +421,7 @@ var unix=
# dylib is the core hashmap for developers to load their own library.
# for safe using dynamic library, you could use 'module' in stl/module.nas
var dylib=
{
var dylib={
# open dynamic lib.
dlopen: func(libname){
# find dynamic lib from local dir first
@ -451,22 +446,34 @@ var dylib=
dlsym: func(lib,sym){return __dlsym; },
# close dynamic lib, this operation will make all the symbols loaded from it invalid.
dlclose: func(lib){return __dlclose; },
# call the loaded symbol.
dlcall: func(ptr,args...){return __dlcall}
# call the loaded symbol, with infinite parameters:
# Caution: this may cause garbage collection process, be aware of the performance.
dlcall: func(ptr,args...){return __dlcallv},
# get dlcall function with limited parameter list
limitcall: func(arg_size=0){
if(arg_size==0){return func(ptr){return __dlcall};}
else if(arg_size==1){return func(ptr,_0){return __dlcall};}
else if(arg_size==2){return func(ptr,_0,_1){return __dlcall};}
else if(arg_size==3){return func(ptr,_0,_1,_2){return __dlcall};}
else if(arg_size==4){return func(ptr,_0,_1,_2,_3){return __dlcall};}
else if(arg_size==5){return func(ptr,_0,_1,_2,_3,_4){return __dlcall};}
else if(arg_size==6){return func(ptr,_0,_1,_2,_3,_4,_5){return __dlcall};}
else if(arg_size==7){return func(ptr,_0,_1,_2,_3,_4,_5,_6){return __dlcall};}
else if(arg_size==8){return func(ptr,_0,_1,_2,_3,_4,_5,_6,_7){return __dlcall};}
else{return func(ptr,args...){return __dlcallv};}
}
};
# os is used to use or get some os-related info/functions.
# windows/macOS/linux are supported.
var os=
{
var os={
# get a string that tell which os it runs on.
platform: func(){return __platform;},
time: func(){return __logtime; }
};
# runtime gives us some functions that we could manage it manually.
var runtime=
{
var runtime={
# command line arguments
argv: func(){return __sysargv;}
};

View File

@ -6,7 +6,7 @@
# all the invalid functions cannot be called
var module_call_func=func(fptr,args){
return __dlcall;
return __dlcallv;
}
var extern={
new: func(fptr){
@ -14,9 +14,7 @@ var extern={
return {
close:func(){isopen=0;},
call:func(args...){
return (!isopen)?
nil:
module_call_func(fptr,args);
return isopen?module_call_func(fptr,args):nil;
}
};
}

View File

@ -1,5 +1,6 @@
var libfib=func(){
var (dd,fib,qfib)=(nil,nil,nil);
var invoke=dylib.limitcall(1);
return {
open:func(){
if(dd==nil){
@ -20,13 +21,13 @@ var libfib=func(){
},
fib:func(x){
if(fib!=nil)
return dylib.dlcall(fib,x);
return invoke(fib,x);
println("[error ] cannot call fib.");
return nil;
},
qfib:func(x){
if(qfib!=nil)
return dylib.dlcall(qfib,x);
return invoke(qfib,x);
println("[error ] cannot call qfib.");
return nil;
}
@ -36,9 +37,33 @@ var libfib=func(){
println("[keys ] ",keys(libfib));
libfib.open();
libfib.open();
var tm=maketimestamp();
tm.stamp();
println("[result] ",libfib.fib(40));
println("[time ] ",tm.elapsedMSec()," ms");
tm.stamp();
println("[result] ",libfib.qfib(40));
println("[time ] ",tm.elapsedMSec()," ms");
libfib.close();
println("[result] ",libfib.fib(40));
println("[result] ",libfib.qfib(40));
libfib.close();
libfib.close();
var speed_test=func(){
var d=dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var fd=dylib.dlsym(d,"quick_fib");
var vec_call=dylib.dlcall;
var invoke=dylib.limitcall(1);
var tm=maketimestamp();
tm.stamp();
for(var i=0;i<1e7;i+=1)
invoke(fd,40);
println("[time ] limited call: ",tm.elapsedMSec()," ms");
tm.stamp();
for(var i=0;i<1e7;i+=1)
vec_call(fd,40);
println("[time ] dynamic call: ",tm.elapsedMSec()," ms");
}
speed_test();