该版本修复了zenglApi_CacheMemData接口生成的编译缓存问题,修复b = b;语句,当b为数组时会将自己给释放掉的BUG,修复POP指令在弹出内存块时,没有将refcount引用数还原的问题,修复调试命令r会多返回一层的问题...
/** * API接口,将编译器和解释器中主要的内存数据缓存起来,缓存的内存数据可以存储到文件或者别的地方, * 之后可以利用缓存起来的内存数据跳过编译过程,直接执行虚拟汇编指令,缓存起来的内存数据只可以用于当前机器 */ ZL_EXPORT ZL_EXP_INT zenglApi_CacheMemData(ZL_EXP_VOID * VM_ARG, ZL_EXP_VOID ** cachePoint, ZL_EXP_INT * cacheSize) { ......................................................... // 将指令列表中所有的指令都拷贝到缓存中 tmp_point += sizeof(ZENGL_RUN_INST_LIST); ZENGL_SYS_MEM_COPY(tmp_point, run->inst_list.insts, run->inst_list.count * sizeof(ZENGL_RUN_INST_LIST_MEMBER)); for(i=0; i < run->inst_list.count ;i++) { if(run->inst_list.insts[i].type == ZL_R_IT_CALL) { // 如果CALL指令的src源操作数在执行时,被替换为了模块函数的整数索引值,则将其还原为字符串。 // 如果不进行还原操作,那么当客户端调整了模块函数时,原索引值可能会对应到错误的模块函数 if(run->inst_list.insts[i].src.type == ZL_R_DT_NUM) { ZENGL_RUN_INST_LIST_MEMBER * tmp_member = (((ZENGL_RUN_INST_LIST_MEMBER *)tmp_point) + i); tmpIndex = run->inst_list.insts[i].src.val.num; tmp_member->src.type = ZL_R_DT_STR; tmp_member->src.val.str_Index = run->ModFunTable.mod_funs[tmpIndex].strIndex; } } } ......................................................... } |
// 该函数专门用于释放局部变量中的内存块,当内存块被赋值给AX寄存器进行脚本函数返回时,就只将refcount数减一,而不进行实际的释放操作。这样外部脚本函数的调用者就可以使用返回的内存块了。 static ZL_VOID zenglrun_memblock_free_local(ZL_VOID * VM_ARG,ZENGL_RUN_VIRTUAL_MEM_LIST * memblock,ZL_INT * index) { ZENGL_RUN_TYPE * run = &((ZENGL_VM_TYPE *)VM_ARG)->run; ZL_INT i; if(memblock == ZL_NULL) return; memblock->refcount--; // 如果当前局部变量的内存块等于AX返回寄存器的内存块,说明该内存块很有可能会被外部调用者使用,就只将refcount引用计数减一,而不执行具体的释放内存块的操作。 if(ZENGL_RUN_REG(ZL_R_RT_AX).runType == ZL_R_RDT_MEM_BLOCK && ZENGL_RUN_REGVAL(ZL_R_RT_AX).memblock == memblock) { if(memblock->refcount < 0) memblock->refcount = 0; return; // 直接返回,不进行后面的释放操作 } if(memblock->refcount <= 0) { for(i=0;i<memblock->size;i++) { if(memblock->mem_array[i].runType == ZL_R_RDT_STR && memblock->mem_array[i].str_Index > 0) { run->memFreeIndex(VM_ARG,memblock->mem_array[i].val.str,&memblock->mem_array[i].str_Index); memblock->mem_array[i].val.str = ZL_NULL; } else if(memblock->mem_array[i].runType == ZL_R_RDT_MEM_BLOCK && memblock->mem_array[i].val.memblock != ZL_NULL) { zenglrun_memblock_free_local(VM_ARG,(ZENGL_RUN_VIRTUAL_MEM_LIST *)memblock->mem_array[i].val.memblock,&memblock->mem_array[i].memblk_Index); memblock->mem_array[i].val.memblock = ZL_NULL; } } run->memFreeIndex(VM_ARG,memblock->mem_array,&memblock->mempool_index); // 将内存块的mem_array动态数组释放掉 if(memblock->hash_array.hash_code_table.members != ZL_NULL) run->memFreeIndex(VM_ARG,memblock->hash_array.hash_code_table.members,&(memblock->hash_array.hash_code_table.mempool_index)); // 释放哈希数组中的哈希表 if(memblock->hash_array.str_pool.ptr != ZL_NULL) run->memFreeIndex(VM_ARG,memblock->hash_array.str_pool.ptr,&(memblock->hash_array.str_pool.mempool_index)); // 释放哈希数组中的字符串池 run->memFreeIndex(VM_ARG,memblock,index); // 将内存块自己给释放掉 } } ............................................................. /*释放栈中参数部分和局部变量部分的所有内存块*/ ZL_VOID zenglrun_memblock_freeall_local(ZL_VOID * VM_ARG) { ZENGL_RUN_TYPE * run = &((ZENGL_VM_TYPE *)VM_ARG)->run; ZL_INT locIndex = ZENGL_RUN_REGVAL(ZL_R_RT_ARG).dword; for(;locIndex < run->vstack_list.count;locIndex++) { switch(run->vstack_list.mem_array[locIndex].runType) { case ZL_R_RDT_MEM_BLOCK: if(run->vstack_list.mem_array[locIndex].val.memblock != ZL_NULL) { zenglrun_memblock_free_local(VM_ARG,run->vstack_list.mem_array[locIndex].val.memblock, &run->vstack_list.mem_array[locIndex].memblk_Index); run->vstack_list.mem_array[locIndex].runType = ZL_R_RDT_NONE; run->vstack_list.mem_array[locIndex].val.dword = 0; run->vstack_list.mem_array[locIndex].val.memblock = ZL_NULL; } break; case ZL_R_RDT_ADDR: //将局部变量和参数里的引用也释放掉 case ZL_R_RDT_ADDR_LOC: case ZL_R_RDT_ADDR_MEMBLK: run->vstack_list.mem_array[locIndex].runType = ZL_R_RDT_NONE; run->vstack_list.mem_array[locIndex].val.dword = 0; run->vstack_list.mem_array[locIndex].val.memblock = ZL_NULL; run->vstack_list.mem_array[locIndex].memblk_Index = 0; break; } } } |
// 专用于VMemBlockOps,VMemListOps,VStackListOps的内存块释放函数 static ZL_VOID zenglrun_memblock_free_for_ops(ZL_VOID * VM_ARG,ZENGL_RUN_VIRTUAL_MEM_LIST * memblock,ZL_INT * index, ZENGL_RUN_VMEM_OP_TYPE op, ZENGL_RUN_VIRTUAL_MEM_STRUCT * tmpmem); .............................................................. /** 虚拟机的虚拟内存操作函数 第一个参数ZENGL_RUN_VMEM_OP_TYPE opType为内存操作类型 如 ZL_R_VMOPT_GETMEM 为从某虚拟内存读取值。 */ ZENGL_RUN_VIRTUAL_MEM_STRUCT zenglrun_VMemListOps(ZL_VOID * VM_ARG,ZENGL_RUN_VMEM_OP_TYPE opType,ZL_INT memloc, ZENGL_RUN_VIRTUAL_MEM_STRUCT argval) { ....................................................... if(opType != ZL_R_VMOPT_GETMEM) { //如果所访问的内存原先是个数组之类的内存块的话,就将该内存块的内存空间释放掉 if(run->vmem_list.mem_array[memloc].runType == ZL_R_RDT_MEM_BLOCK && run->vmem_list.mem_array[memloc].val.memblock != ZL_NULL) { zenglrun_memblock_free_for_ops(VM_ARG,run->vmem_list.mem_array[memloc].val.memblock, &run->vmem_list.mem_array[memloc].memblk_Index, opType, &argval); run->vmem_list.mem_array[memloc].val.memblock = ZL_NULL; } else if(run->vmem_list.mem_array[memloc].runType == ZL_R_RDT_ADDR_MEMBLK) //如果是内存块引用,则直接将memblock内存块指针设为ZL_NULL run->vmem_list.mem_array[memloc].val.memblock = ZL_NULL; } ....................................................... } .............................................................. /** 虚拟堆栈空间的操作函数,虚拟机中堆栈的概念类似汇编语言里的堆栈概念。用于保存和恢复数据的地方。经常用于存放局部变量,函数的返回地址,寄存器的值等。 参数valid用于判断是否需要将某栈内存设为占用状态,占用表示该栈内存已经被初始化,主要用于判断函数参数是否被初始化 */ ZENGL_RUN_VIRTUAL_MEM_STRUCT zenglrun_VStackListOps(ZL_VOID * VM_ARG,ZENGL_RUN_VMEM_OP_TYPE opType,ZL_INT index, ZENGL_RUN_VIRTUAL_MEM_STRUCT argval,ZL_BOOL valid) { ....................................................... if(opType != ZL_R_VMOPT_GETMEM) { if(run->vstack_list.mem_array[index].runType == ZL_R_RDT_MEM_BLOCK && run->vstack_list.mem_array[index].val.memblock != ZL_NULL) //如果栈中该元素之前是个数组之类的内存块,就将内存块进行释放 { zenglrun_memblock_free_for_ops(VM_ARG,run->vstack_list.mem_array[index].val.memblock, &run->vstack_list.mem_array[index].memblk_Index, opType, &argval); run->vstack_list.mem_array[index].val.memblock = ZL_NULL; } else if(run->vstack_list.mem_array[index].runType == ZL_R_RDT_ADDR_MEMBLK) //如果是内存块引用,就直接将memblock内存块指针设为ZL_NULL run->vstack_list.mem_array[index].val.memblock = ZL_NULL; } ....................................................... } .............................................................. /*对数组ptr里的index索引指向的内存进行操作*/ ZENGL_RUN_VIRTUAL_MEM_STRUCT zenglrun_VMemBlockOps(ZL_VOID * VM_ARG,ZENGL_RUN_VMEM_OP_TYPE op,ZENGL_RUN_VIRTUAL_MEM_LIST * ptr,ZL_INT index, ZENGL_RUN_VIRTUAL_MEM_STRUCT * tmpmem) { ....................................................... if(op != ZL_R_VMOPT_GETMEM) { if(tmpmem->runType != ZL_R_RDT_STR && ptr->mem_array[index].runType == ZL_R_RDT_STR && ptr->mem_array[index].str_Index > 0) //在设置某数组元素时,先将数组元素之前存储的字符串内存空间释放掉。 { run->memFreeIndex(VM_ARG,ptr->mem_array[index].val.str,&ptr->mem_array[index].str_Index); ptr->mem_array[index].val.str = ZL_NULL; } else if(ptr->mem_array[index].runType == ZL_R_RDT_MEM_BLOCK) //在设置某数组元素时,如果该数组元素本身又是一个数组,则将该数组元素分配的内存块释放掉。 { zenglrun_memblock_free_for_ops(VM_ARG,(ZENGL_RUN_VIRTUAL_MEM_LIST *)ptr->mem_array[index].val.memblock,&ptr->mem_array[index].memblk_Index, op, tmpmem); ptr->mem_array[index].val.memblock = ZL_NULL; } } ....................................................... } .............................................................. // 专用于VMemBlockOps,VMemListOps,VStackListOps的内存块释放函数 static ZL_VOID zenglrun_memblock_free_for_ops(ZL_VOID * VM_ARG,ZENGL_RUN_VIRTUAL_MEM_LIST * memblock,ZL_INT * index, ZENGL_RUN_VMEM_OP_TYPE op, ZENGL_RUN_VIRTUAL_MEM_STRUCT * tmpmem) { ZENGL_RUN_TYPE * run = &((ZENGL_VM_TYPE *)VM_ARG)->run; // 如果和要操作的数据相同,则不进行实际的释放操作,例如假设变量b是一个数组,那么b = b;语句在执行时就不会将自己给释放掉 switch(op) { case ZL_R_VMOPT_SETMEM_MEMBLOCK: case ZL_R_VMOPT_ADDMEM_MEMBLOCK: if(memblock == tmpmem->val.memblock) { memblock->refcount--; if(memblock->refcount < 0) memblock->refcount = 0; return; } break; } // 否则执行实际的释放操作 run->memblock_free(VM_ARG, memblock, index); } |
/** 虚拟堆栈空间的操作函数,虚拟机中堆栈的概念类似汇编语言里的堆栈概念。用于保存和恢复数据的地方。经常用于存放局部变量,函数的返回地址,寄存器的值等。 参数valid用于判断是否需要将某栈内存设为占用状态,占用表示该栈内存已经被初始化,主要用于判断函数参数是否被初始化 */ ZENGL_RUN_VIRTUAL_MEM_STRUCT zenglrun_VStackListOps(ZL_VOID * VM_ARG,ZENGL_RUN_VMEM_OP_TYPE opType,ZL_INT index, ZENGL_RUN_VIRTUAL_MEM_STRUCT argval,ZL_BOOL valid) { ....................................................... if(index < 0) //小于0属于压栈操作 { switch(opType) { ........................................................ case ZL_R_VMOPT_GETMEM: //获取堆栈的最后一个值,并弹出该值,有点像汇编的POP操作。 if(run->vstack_list.count <= 0) //过分弹出数据或未知原因导致堆栈反向溢出。 run->exit(VM_ARG,ZL_ERR_RUN_VSTACK_LIST_OVERFLOW,ZL_R_REG_PC,ZL_R_REG_PC); switch(run->vstack_list.mem_array[run->vstack_list.count - 1].runType) { case ZL_R_RDT_ADDR: //如果是全局变量内存的引用,就通过VMemListOps来访问 retmem = run->VMemListOps(VM_ARG,opType,run->vstack_list.mem_array[run->vstack_list.count - 1].val.dword,argval); break; case ZL_R_RDT_ADDR_LOC: ////如果是局部变量栈内存的引用,就通过VStackListOps来访问 retmem = run->VStackListOps(VM_ARG,opType,run->vstack_list.mem_array[run->vstack_list.count - 1].val.dword,argval,ZL_TRUE); break; case ZL_R_RDT_MEM_BLOCK: // 如果要弹出的数据是内存块,则将引用数减一,这样之前PUSH操作增加的引用数就可以被还原 { ZENGL_RUN_VIRTUAL_MEM_LIST * tmp_memblock = run->vstack_list.mem_array[run->vstack_list.count - 1].val.memblock; tmp_memblock->refcount--; if(tmp_memblock->refcount < 0) tmp_memblock->refcount = 0; } // 继续执行default里的操作,将最后一个元素返回,所以这里不需要break default: retmem = run->vstack_list.mem_array[run->vstack_list.count - 1]; //如果不是引用,就将栈中最后一个元素返回 break; } run->vstack_list.count--; //栈顶计数器减一。 return retmem; break; } } ....................................................... } |
ZL_EXP_INT main_debug_break(ZL_EXP_VOID * VM_ARG,ZL_EXP_CHAR * cur_filename,ZL_EXP_INT cur_line,ZL_EXP_INT breakIndex,ZL_EXP_CHAR * log) { ................................................................... while(!exit) { ........................................................... switch(command[0]) { ........................................................... case 'r': { int arg = -1; int loc = -1; int pc = -1; int tmpPC; int ret; int size,i; int line = 0; char * fileName = ZL_EXP_NULL; ZL_EXP_BOOL hasBreaked = ZL_EXP_FALSE; ret = zenglApi_DebugGetTrace(VM_ARG,&arg,&loc,&pc,&fileName,&line,ZL_EXP_NULL,ZL_EXP_NULL); if(ret == 1) { // zenglApi_DebugGetTrace(VM_ARG,&arg,&loc,&pc,&fileName,&line,ZL_EXP_NULL,ZL_EXP_NULL); // 该行会让r返回到上一层的上一层,多返回一层,所以注释掉 pc++; size = zenglApi_DebugGetBreak(VM_ARG,-1,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL); for(i=0;i<size;i++) { if(zenglApi_DebugGetBreak(VM_ARG,i,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,ZL_EXP_NULL,&tmpPC) == -1) continue; else if(pc == tmpPC) { hasBreaked = ZL_EXP_TRUE; break; } } if(!hasBreaked) { if(zenglApi_DebugSetBreakEx(VM_ARG,pc,ZL_EXP_NULL,ZL_EXP_NULL,1,ZL_EXP_FALSE) == -1) printf("%s",zenglApi_GetErrorString(VM_ARG)); else exit = 1; } else exit = 1; } else if(ret == 0) exit = 1; else if(ret == -1) printf("%s",zenglApi_GetErrorString(VM_ARG)); } break; ........................................................... } } //while(!exit) if(str != ZL_EXP_NULL) zenglApi_FreeMem(VM_ARG,str); return 0; } |
/*设置调试器所在的脚本函数环境*/ ZL_INT zenglDebug_SetFunInfo(ZL_VOID * VM_ARG) { .............................................................. for(;arg > 0 && loc > 0;) { PJmp = PRun->vstack_list.mem_array[loc - 1].val.dword - 1; if(PDebug->api_call_pc > 0 && PDebug->api_call_arg == arg) //如果在zenglApi_Call调用的最外层时 { ...................................................... run->reg_list[ZL_R_RT_ARG].val.dword = arg; // 如果不设置ZL_R_RDT_INT,则默认是ZL_R_RDT_NONE类型,ZL_R_RDT_NONE类型的寄存器在PUSH的时候会被强制当成0,这样设置的dword值就会失效了! run->reg_list[ZL_R_RT_ARG].runType = ZL_R_RDT_INT; run->reg_list[ZL_R_RT_LOC].val.dword = loc; // 和上面同理 run->reg_list[ZL_R_RT_LOC].runType = ZL_R_RDT_INT; return 0; } else if(PRun->inst_list.insts[PJmp].type == ZL_R_IT_CALL) { tmp_arg = arg; arg = PRun->vstack_list.mem_array[tmp_arg - 3].val.dword; loc = PRun->vstack_list.mem_array[tmp_arg - 2].val.dword; continue; } else if(PRun->inst_list.insts[PJmp].type == ZL_R_IT_JMP) { ...................................................... run->reg_list[ZL_R_RT_ARG].val.dword = arg; // 如果不设置ZL_R_RDT_INT,则默认是ZL_R_RDT_NONE类型,ZL_R_RDT_NONE类型的寄存器在PUSH的时候会被强制当成0,这样设置的dword值就会失效了! run->reg_list[ZL_R_RT_ARG].runType = ZL_R_RDT_INT; run->reg_list[ZL_R_RT_LOC].val.dword = loc; // 和上面同理 run->reg_list[ZL_R_RT_LOC].runType = ZL_R_RDT_INT; return 0; } else break; } .............................................................. } |
use builtin; def TRUE 1; def FALSE 0; fun test() a['test'] = array(); a['test', 'name'] = 'zengl'; print 'test,name:'+a['test', 'name']; return a['test']; // 测试返回数组成员 endfun fun show_bool(bool = TRUE) // 测试r调试命令是否会返回上一层 print bool ? "true" : "false"; endfun fun test2(posts = 0) // 测试p bltCount(posts) && posts['id'] > 0调试命令是否会得到整数1 if(bltCount(posts) && posts['id'] > 0) show_bool(TRUE); else show_bool(FALSE); endif // 测试POP指令是否会将posts数组的refcount引用计数器还原 if(posts && posts['id'] > 0) show_bool(TRUE); else show_bool(FALSE); endif endfun b = test(); b = b; // 测试是否会释放掉自己 print 'b,name:'+b['name']; print 'test2:'; posts['id'] = 12; test2(posts); |
zengl@zengl-ubuntu:~/zengl_v1.8.1/zengl_language/linux$ ./zengl test_scripts/v1.8.1/test.zl run(编译执行中)... test_scripts/v1.8.1/test.zl mtime:1523615373 reuse cache file: "caches/1_8_1_8_abf6b392622260993e2d5e7acaa9f99b" mtime:1523615642 test,name:zengl b,name:zengl test2: true true run finished(编译执行结束) zengl@zengl-ubuntu:~/zengl_v1.8.1/zengl_language/linux$ |
zengl@zengl-ubuntu:~/zengl_v1.8.1/zengl_language/linux$ ./zengl test_scripts/v1.8.1/test.zl -d run(编译执行中)... test_scripts/v1.8.1/test.zl mtime:1523615373 reuse cache file: "caches/1_8_1_8_abf6b392622260993e2d5e7acaa9f99b" mtime:1523615642 * test_scripts/v1.8.1/test.zl:1 Break index:0 [current] .............................................................. >>> debug input:s * test_scripts/v1.8.1/test.zl:19 Single Break [current] >>> debug input:p bltCount(posts) && posts['id'] > 0 bltCount(posts) && posts['id'] > 0 :integer:1 .............................................................. >>> debug input:s * test_scripts/v1.8.1/test.zl:14 Single Break [current] >>> debug input:T test_scripts/v1.8.1/test.zl:14 show_bool test_scripts/v1.8.1/test.zl:20 test2 test_scripts/v1.8.1/test.zl:38 >>> debug input:r true * test_scripts/v1.8.1/test.zl:20 Break index:0 [current] >>> debug input:c true run finished(编译执行结束) zengl@zengl-ubuntu:~/zengl_v1.8.1/zengl_language/linux$ |