⚡ optimize vm
This commit is contained in:
parent
452bb4a5d8
commit
92d68b357c
55
README.md
55
README.md
|
@ -551,31 +551,48 @@ And `get` has the same process.
|
||||||
And we must remind you that if you do this:
|
And we must remind you that if you do this:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var b=a.get;
|
var trait={
|
||||||
println(b());
|
get:func{return me.val;},
|
||||||
println(b());
|
set:func(x){me.val=x;}
|
||||||
|
};
|
||||||
|
|
||||||
|
var class={
|
||||||
|
new:func(){
|
||||||
|
return {
|
||||||
|
val:nil,
|
||||||
|
parents:[trait]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var a=class.new();
|
||||||
|
var b=class.new();
|
||||||
|
a.set(114);
|
||||||
|
b.set(514);
|
||||||
|
println(a.get());
|
||||||
|
println(b.get());
|
||||||
|
|
||||||
|
var c=a.get;
|
||||||
|
var d=b.get;
|
||||||
|
|
||||||
|
println(c());
|
||||||
|
println(c());
|
||||||
|
println(d());
|
||||||
|
println(d());
|
||||||
```
|
```
|
||||||
|
|
||||||
You will find the vm crashes:
|
You will get this result now:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
114514
|
114
|
||||||
114514
|
514
|
||||||
[vm] callh: must call a hash
|
514
|
||||||
trace back:
|
514
|
||||||
0x0000050f: 3d 00 00 00 08 callh 0x8 ("val") (a.nas:2)
|
514
|
||||||
0x00000544: 3e 00 00 00 00 callfv 0x0 (a.nas:19)
|
514
|
||||||
vm stack(0x7fffd1b38250<sp+83>, limit 10, total 7):
|
|
||||||
0x00000059 | nil |
|
|
||||||
0x00000058 | pc | 0x544
|
|
||||||
0x00000057 | addr | 0x0
|
|
||||||
0x00000056 | nil |
|
|
||||||
0x00000055 | nil |
|
|
||||||
0x00000054 | nil |
|
|
||||||
0x00000053 | func | <0x1a3b250> entry:0x125
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Because `a.get` will set `me=a` in the `trait.get`. First time we running it, it works. But when the function returns, `me` is set to `nil`, so the second time, we failed to call the function.
|
Because `a.get` will set `me=a` in the `trait.get`. Then `b.get` do the `me=b`. So in fact c is `b.get` too after running `var d=b.get`.
|
||||||
|
If you want to use this trick to make the program running more efficiently, you must know this special mechanism.
|
||||||
|
|
||||||
### __native functions__
|
### __native functions__
|
||||||
|
|
||||||
|
|
|
@ -518,31 +518,48 @@ println(a.get());
|
||||||
不过我们必须提醒你一点,如果你在这个地方使用该优化来减少hash的搜索开销:
|
不过我们必须提醒你一点,如果你在这个地方使用该优化来减少hash的搜索开销:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var b=a.get;
|
var trait={
|
||||||
println(b());
|
get:func{return me.val;},
|
||||||
println(b());
|
set:func(x){me.val=x;}
|
||||||
|
};
|
||||||
|
|
||||||
|
var class={
|
||||||
|
new:func(){
|
||||||
|
return {
|
||||||
|
val:nil,
|
||||||
|
parents:[trait]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var a=class.new();
|
||||||
|
var b=class.new();
|
||||||
|
a.set(114);
|
||||||
|
b.set(514);
|
||||||
|
println(a.get());
|
||||||
|
println(b.get());
|
||||||
|
|
||||||
|
var c=a.get;
|
||||||
|
var d=b.get;
|
||||||
|
|
||||||
|
println(c());
|
||||||
|
println(c());
|
||||||
|
println(d());
|
||||||
|
println(d());
|
||||||
```
|
```
|
||||||
|
|
||||||
那么你会发现虚拟机崩溃了:
|
那么你会发现现在虚拟机会输出这个结果:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
114514
|
114
|
||||||
114514
|
514
|
||||||
[vm] callh: must call a hash
|
514
|
||||||
trace back:
|
514
|
||||||
0x0000050f: 3d 00 00 00 08 callh 0x8 ("val") (a.nas:2)
|
514
|
||||||
0x00000544: 3e 00 00 00 00 callfv 0x0 (a.nas:19)
|
514
|
||||||
vm stack(0x7fffd1b38250<sp+83>, limit 10, total 7):
|
|
||||||
0x00000059 | nil |
|
|
||||||
0x00000058 | pc | 0x544
|
|
||||||
0x00000057 | addr | 0x0
|
|
||||||
0x00000056 | nil |
|
|
||||||
0x00000055 | nil |
|
|
||||||
0x00000054 | nil |
|
|
||||||
0x00000053 | func | <0x1a3b250> entry:0x125
|
|
||||||
```
|
```
|
||||||
|
|
||||||
因为执行`a.get`时在`trait.get`函数的属性中进行了`me=a`的操作。所以接下来第一次运行的时候它确实成功运行了。但是当函数返回时,`me`会被自动设置为`nil`以保证安全,所以第二次调用的时候,`me`不再是个hash类型,故虚拟机抛出了错误。这不意味着这种优化方法是不可行的,只要你理解了它的运行机制,这种优化方式仍然可以使用。
|
因为执行`a.get`时在`trait.get`函数的属性中进行了`me=a`的操作。而`b.get`则执行了`me=b`的操作。所以在运行`var d=b.get`后实际上c也变成`b.get`了。
|
||||||
|
如果你想要用这种小技巧来让程序运行更高效的话,最好是要知道这里存在这样一个机制。
|
||||||
|
|
||||||
### __内置函数__
|
### __内置函数__
|
||||||
|
|
||||||
|
|
2
nasal.h
2
nasal.h
|
@ -43,7 +43,7 @@
|
||||||
#define PRTINT64 "%lld"
|
#define PRTINT64 "%lld"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const uint32_t STACK_DEPTH=8192;
|
const uint32_t STACK_DEPTH=4096;
|
||||||
|
|
||||||
inline double hex_to_double(const char* str)
|
inline double hex_to_double(const char* str)
|
||||||
{
|
{
|
||||||
|
|
|
@ -182,7 +182,7 @@ void nasal_dbg::run(
|
||||||
{
|
{
|
||||||
detail_info=true;
|
detail_info=true;
|
||||||
init(gen.get_strs(),gen.get_nums(),gen.get_code(),linker.get_file(),argv);
|
init(gen.get_strs(),gen.get_nums(),gen.get_code(),linker.get_file(),argv);
|
||||||
const void* opr_table[]=
|
const void* oprs[]=
|
||||||
{
|
{
|
||||||
&&vmexit, &&intg, &&intl, &&loadg,
|
&&vmexit, &&intg, &&intl, &&loadg,
|
||||||
&&loadl, &&loadu, &&pnum, &&pnil,
|
&&loadl, &&loadu, &&pnum, &&pnil,
|
||||||
|
@ -207,7 +207,7 @@ void nasal_dbg::run(
|
||||||
std::vector<const void*> code;
|
std::vector<const void*> code;
|
||||||
for(auto& i:gen.get_code())
|
for(auto& i:gen.get_code())
|
||||||
{
|
{
|
||||||
code.push_back(opr_table[i.op]);
|
code.push_back(oprs[i.op]);
|
||||||
imm.push_back(i.num);
|
imm.push_back(i.num);
|
||||||
}
|
}
|
||||||
// goto the first operand
|
// goto the first operand
|
||||||
|
|
|
@ -624,8 +624,8 @@ void nasal_gc::info()
|
||||||
const char* name[]={"str ","func ","vec ","hash ","upval","obj ","co "};
|
const char* name[]={"str ","func ","vec ","hash ","upval","obj ","co "};
|
||||||
std::cout<<"\ngarbage collector info\n";
|
std::cout<<"\ngarbage collector info\n";
|
||||||
for(uint8_t i=0;i<gc_obj_size;++i)
|
for(uint8_t i=0;i<gc_obj_size;++i)
|
||||||
std::cout<<" "<<name[i]<<" | mark-sweep | "<<count[i]<<"\n"
|
std::cout<<" "<<name[i]<<" | gc | "<<count[i]<<"\n"
|
||||||
<<" | mem-alloc | "<<allocc[i]<<"\n";
|
<<" | new | "<<allocc[i]<<"\n";
|
||||||
std::cout<<"\nmemory allocator info(max size)\n";
|
std::cout<<"\nmemory allocator info(max size)\n";
|
||||||
for(uint8_t i=0;i<gc_obj_size;++i)
|
for(uint8_t i=0;i<gc_obj_size;++i)
|
||||||
std::cout<<" "<<name[i]<<" | "<<ini[i]+size[i]*incr[i]<<" (+"<<size[i]<<")\n";
|
std::cout<<" "<<name[i]<<" | "<<ini[i]+size[i]*incr[i]<<" (+"<<size[i]<<")\n";
|
||||||
|
|
33
nasal_vm.h
33
nasal_vm.h
|
@ -4,22 +4,19 @@
|
||||||
class nasal_vm
|
class nasal_vm
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
/* values of nasal_vm */
|
/* registers and constants of nasal_vm */
|
||||||
nasal_ref stack[STACK_DEPTH];
|
|
||||||
uint32_t pc; // program counter
|
uint32_t pc; // program counter
|
||||||
nasal_ref* global; // global scope register
|
|
||||||
nasal_ref* localr; // local scope register
|
nasal_ref* localr; // local scope register
|
||||||
nasal_ref* memr; // used for mem_call
|
nasal_ref* memr; // used for mem_call
|
||||||
nasal_ref funcr; // function register
|
nasal_ref funcr; // function register
|
||||||
nasal_ref upvalr; // upvalue register
|
nasal_ref upvalr; // upvalue register
|
||||||
nasal_ref* canary; // avoid stackoverflow
|
nasal_ref* canary; // avoid stackoverflow
|
||||||
nasal_ref* top; // stack top
|
nasal_ref* top; // stack top
|
||||||
|
|
||||||
/* constant */
|
|
||||||
const double* num_table;// const numbers, ref from nasal_codegen
|
const double* num_table;// const numbers, ref from nasal_codegen
|
||||||
const std::string* str_table;// const symbols, ref from nasal_codegen
|
const std::string* str_table;// const symbols, ref from nasal_codegen
|
||||||
std::vector<uint32_t> imm; // immediate number
|
std::vector<uint32_t> imm; // immediate number
|
||||||
|
/* main stack */
|
||||||
|
nasal_ref stack[STACK_DEPTH];
|
||||||
/* garbage collector */
|
/* garbage collector */
|
||||||
nasal_gc gc;
|
nasal_gc gc;
|
||||||
|
|
||||||
|
@ -125,9 +122,7 @@ protected:
|
||||||
void opr_mcallh();
|
void opr_mcallh();
|
||||||
void opr_ret();
|
void opr_ret();
|
||||||
public:
|
public:
|
||||||
nasal_vm():
|
nasal_vm():gc(pc,localr,memr,funcr,upvalr,canary,top,stack){}
|
||||||
global(stack),
|
|
||||||
gc(pc,localr,memr,funcr,upvalr,canary,top,stack){}
|
|
||||||
void run(
|
void run(
|
||||||
const nasal_codegen&,
|
const nasal_codegen&,
|
||||||
const nasal_import&,
|
const nasal_import&,
|
||||||
|
@ -152,7 +147,6 @@ void nasal_vm::init(
|
||||||
|
|
||||||
/* set canary and program counter */
|
/* set canary and program counter */
|
||||||
pc=0;
|
pc=0;
|
||||||
global=stack;
|
|
||||||
localr=nullptr;
|
localr=nullptr;
|
||||||
memr=nullptr;
|
memr=nullptr;
|
||||||
funcr=nil;
|
funcr=nil;
|
||||||
|
@ -290,7 +284,7 @@ void nasal_vm::register_info()
|
||||||
{
|
{
|
||||||
printf("registers(%s):\n",gc.coroutine?"coroutine":"main");
|
printf("registers(%s):\n",gc.coroutine?"coroutine":"main");
|
||||||
printf(" [ pc ] | pc | 0x%x\n",pc);
|
printf(" [ pc ] | pc | 0x%x\n",pc);
|
||||||
printf(" [ global ] | addr | 0x" PRTHEX64 "\n",(uint64_t)global);
|
printf(" [ global ] | addr | 0x" PRTHEX64 "\n",(uint64_t)stack);
|
||||||
printf(" [ localr ] | addr | 0x" PRTHEX64 "\n",(uint64_t)localr);
|
printf(" [ localr ] | addr | 0x" PRTHEX64 "\n",(uint64_t)localr);
|
||||||
printf(" [ memr ] | addr | 0x" PRTHEX64 "\n",(uint64_t)memr);
|
printf(" [ memr ] | addr | 0x" PRTHEX64 "\n",(uint64_t)memr);
|
||||||
if(funcr.type==vm_nil)
|
if(funcr.type==vm_nil)
|
||||||
|
@ -312,11 +306,11 @@ void nasal_vm::global_state()
|
||||||
{
|
{
|
||||||
if(!bytecode[0].num || stack[0].type==vm_none) // bytecode[0].op is op_intg
|
if(!bytecode[0].num || stack[0].type==vm_none) // bytecode[0].op is op_intg
|
||||||
return;
|
return;
|
||||||
printf("global(0x" PRTHEX64 "<sp+0>):\n",(uint64_t)global);
|
printf("global(0x" PRTHEX64 "<sp+0>):\n",(uint64_t)stack);
|
||||||
for(uint32_t i=0;i<bytecode[0].num;++i)
|
for(uint32_t i=0;i<bytecode[0].num;++i)
|
||||||
{
|
{
|
||||||
printf(" 0x%.8x",i);
|
printf(" 0x%.8x",i);
|
||||||
valinfo(global[i]);
|
valinfo(stack[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void nasal_vm::local_state()
|
void nasal_vm::local_state()
|
||||||
|
@ -413,7 +407,7 @@ inline void nasal_vm::opr_intl()
|
||||||
}
|
}
|
||||||
inline void nasal_vm::opr_loadg()
|
inline void nasal_vm::opr_loadg()
|
||||||
{
|
{
|
||||||
global[imm[pc]]=(top--)[0];
|
stack[imm[pc]]=(top--)[0];
|
||||||
}
|
}
|
||||||
inline void nasal_vm::opr_loadl()
|
inline void nasal_vm::opr_loadl()
|
||||||
{
|
{
|
||||||
|
@ -687,7 +681,7 @@ inline void nasal_vm::opr_feach()
|
||||||
}
|
}
|
||||||
inline void nasal_vm::opr_callg()
|
inline void nasal_vm::opr_callg()
|
||||||
{
|
{
|
||||||
(++top)[0]=global[imm[pc]];
|
(++top)[0]=stack[imm[pc]];
|
||||||
}
|
}
|
||||||
inline void nasal_vm::opr_calll()
|
inline void nasal_vm::opr_calll()
|
||||||
{
|
{
|
||||||
|
@ -898,7 +892,7 @@ inline void nasal_vm::opr_slc2()
|
||||||
}
|
}
|
||||||
inline void nasal_vm::opr_mcallg()
|
inline void nasal_vm::opr_mcallg()
|
||||||
{
|
{
|
||||||
memr=global+imm[pc];
|
memr=stack+imm[pc];
|
||||||
(++top)[0]=memr[0];
|
(++top)[0]=memr[0];
|
||||||
// push value in this memory space on stack
|
// push value in this memory space on stack
|
||||||
// to avoid being garbage collected
|
// to avoid being garbage collected
|
||||||
|
@ -984,7 +978,6 @@ inline void nasal_vm::opr_ret()
|
||||||
upvalr=top[-3];
|
upvalr=top[-3];
|
||||||
|
|
||||||
top=local-1;
|
top=local-1;
|
||||||
func.func().local[0]=nil;// get func and set 'me' to nil
|
|
||||||
funcr=top[0];
|
funcr=top[0];
|
||||||
|
|
||||||
top[0]=ret; // rewrite func with returned value
|
top[0]=ret; // rewrite func with returned value
|
||||||
|
@ -1012,7 +1005,7 @@ void nasal_vm::run(
|
||||||
detail_info=detail;
|
detail_info=detail;
|
||||||
init(gen.get_strs(),gen.get_nums(),gen.get_code(),linker.get_file(),argv);
|
init(gen.get_strs(),gen.get_nums(),gen.get_code(),linker.get_file(),argv);
|
||||||
uint64_t count[op_ret+1]={0};
|
uint64_t count[op_ret+1]={0};
|
||||||
const void* opr_table[]=
|
const void* oprs[]=
|
||||||
{
|
{
|
||||||
&&vmexit, &&intg, &&intl, &&loadg,
|
&&vmexit, &&intg, &&intl, &&loadg,
|
||||||
&&loadl, &&loadu, &&pnum, &&pnil,
|
&&loadl, &&loadu, &&pnum, &&pnil,
|
||||||
|
@ -1037,7 +1030,7 @@ void nasal_vm::run(
|
||||||
std::vector<const void*> code;
|
std::vector<const void*> code;
|
||||||
for(auto& i:gen.get_code())
|
for(auto& i:gen.get_code())
|
||||||
{
|
{
|
||||||
code.push_back(opr_table[i.op]);
|
code.push_back(oprs[i.op]);
|
||||||
imm.push_back(i.num);
|
imm.push_back(i.num);
|
||||||
}
|
}
|
||||||
// goto the first operand
|
// goto the first operand
|
||||||
|
@ -1048,7 +1041,7 @@ vmexit:
|
||||||
die("stack overflow");
|
die("stack overflow");
|
||||||
if(opcnt)
|
if(opcnt)
|
||||||
opcallsort(count);
|
opcallsort(count);
|
||||||
if(detail_info)
|
if(detail)
|
||||||
gc.info();
|
gc.info();
|
||||||
gc.clear();
|
gc.clear();
|
||||||
imm.clear();
|
imm.clear();
|
||||||
|
|
Loading…
Reference in New Issue