⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mal_interpreter.mx

📁 一个内存数据库的源代码这是服务器端还有客户端
💻 MX
📖 第 1 页 / 共 3 页
字号:
			(ptr) getArgReference(stk,pci,0),			(ptr) getArgReference(stk,pci,1),			(ptr) getArgReference(stk,pci,2),			(ptr) getArgReference(stk,pci,3),			(ptr) getArgReference(stk,pci,4),			(ptr) getArgReference(stk,pci,5)); 			 break;	case 7 : ret = (str) (*pci->fcn)(			(ptr) getArgReference(stk,pci,0),			(ptr) getArgReference(stk,pci,1),			(ptr) getArgReference(stk,pci,2),			(ptr) getArgReference(stk,pci,3),			(ptr) getArgReference(stk,pci,4),			(ptr) getArgReference(stk,pci,5),			(ptr) getArgReference(stk,pci,6)); 			 break;	case 8 : ret = (str) (*pci->fcn)(			(ptr) getArgReference(stk,pci,0),			(ptr) getArgReference(stk,pci,1),			(ptr) getArgReference(stk,pci,2),			(ptr) getArgReference(stk,pci,3),			(ptr) getArgReference(stk,pci,4),			(ptr) getArgReference(stk,pci,5),			(ptr) getArgReference(stk,pci,6),			(ptr) getArgReference(stk,pci,7)); 			 break;	case 9 : ret = (str) (*pci->fcn)(			(ptr) getArgReference(stk,pci,0),			(ptr) getArgReference(stk,pci,1),			(ptr) getArgReference(stk,pci,2),			(ptr) getArgReference(stk,pci,3),			(ptr) getArgReference(stk,pci,4),			(ptr) getArgReference(stk,pci,5),			(ptr) getArgReference(stk,pci,6),			(ptr) getArgReference(stk,pci,7),			(ptr) getArgReference(stk,pci,8)); 			 break;	default:		ret = createScriptException(mb, stkpc, MAL, NULL,				"too many arguments for command call");	}	@:restoreTarget@	@:exceptionHndlr@}@-@= patterncall	if( pci->fcn== NULL)		ret = createScriptException(mb, stkpc, MAL, NULL,				"address of pattern missing");	else {		@:safeTarget@		ret = (str) (*pci->fcn)(mb,stk,pci);		@:restoreTarget@		@:exceptionHndlr@	}@-MAL function calls are relatively expensive, because they have to assemblea new stack frame and do housekeeping, such as garbagecollection of allnon-returned values.@-@= functioncall{		stk->pcup = stkpc;	@:safeTarget@	ret= runMAL(cntxt,pci->blk,1,mb,stk,pci);	@:restoreTarget@	@:exceptionHndlr@}@-Factory calls are more involved. At this stage it is a synchrononouscall to the factory manager.Factory calls should deal with the reference counting.@= factorycall	if( pci->blk== NULL)		ret = createScriptException(mb, stkpc, MAL, NULL,				"reference to MAL function missing");	else		ret= runFactory(cntxt,pci->blk,mb,stk,pci);	@:exceptionHndlr@@-The type dispatching table in getArgValue can be removed if we determine at compile time the address offset within a ValRecord. We leave this optimization for the future, it leads to about 10%improvement (100ms for 1M calls).@+ Flow of control statementsEach assignment (function call) may be part of the initializationof a barrier- block. In that case we have to test theoutcome of the operation and possibly skip the block altogether.The latter is implemented as a linear scan for the correspondinglabeled statemtent. This might be optimized later.@= barrierControl{   v= &stk->stk[getDestVar(pci)];	/* skip to end of barrier, depends on the type */	switch(v->vtype){		case TYPE_bit:			if( v->val.cval[0] == FALSE || v->val.cval[0] == bit_nil)				stkpc= pci->jump;			break;		case TYPE_chr:			if( v->val.cval[0] == chr_nil )				stkpc= pci->jump;			break;		case TYPE_oid:			if( v->val.oval == oid_nil )				stkpc= pci->jump;			break;		case TYPE_sht:			if( v->val.shval < 0 || v->val.shval == sht_nil)				stkpc= pci->jump; 			break;		case TYPE_int:			if( v->val.ival < 0 || v->val.ival == int_nil)				stkpc= pci->jump; 			break;		case TYPE_lng:			if( v->val.lval < 0 || v->val.lval == lng_nil)				stkpc= pci->jump; 			break;		case TYPE_flt:		case TYPE_dbl:			if( v->val.dval < 0 || v->val.dval == dbl_nil)				stkpc= pci->jump; 			break;		case TYPE_str:			if( v->len == 0 || v->val.pval == str_nil)				stkpc= pci->jump; 			break;		default:			ret = createScriptException(mb, stkpc, MAL, NULL,					"%s: Unknown barrier type",					getVarName(mb, getDestVar(pci)));	}}@-You can skip to a catch block by searching for the corresponding 'lab'The return value should be set to pass the error automatically uponreaching end of function block.@-@= skipToCatch	if( stk->cmd == 'C') {		stk->cmd = 'n';		mdbStep(cntxt,mb,stk,stkpc);		if( stk->cmd == 'x') {			stkpc = mb->stop;			continue;		}	}	/* skip to catch block or end */	for( ; stkpc<mb->stop; stkpc++){		InstrPtr l= getInstrPtr(mb,stkpc);		if( l->barrier == CATCHsymbol ){			int j= -1;			for(j=0;j<l->retc; j++)				if( getArg(l,j) == @1) break;			if(j>=0) break;		}	}	if( stkpc== mb->stop) {		@:endProfile@ 			continue;	}@-Each time we enter a barrier block, we could keep its position in theinterpreter stack frame. It forms the starting point to issue a redo.Unfortunately, this does not easily work in the presence of optimizers, whichmay change the order/block structure. Therefore, we simple have to searchthe beginning or ensure that during chkProgram the barrier/redo/leave/catchjumps are re-established.@}@-@node Exception Handling, Garbage Collection, MAL API, The MAL Interpreter@+ Exception handlingCalling a built-in or user-defined routine may lead to an error or acached status message to be dealt with in MAL.To improve error handling in MAL, an exception handlingscheme based on @sc{catch}-@sc{exit} blocks. The @sc{catch}statement identifies a (string-valued) variable, which carries the exception message fromthe originally failed routine or @sc{raise} exception assignment.During normal processing @sc{catch}-@sc{exit} blocks are simply skipped.Upon receiving an exception status from a function call, we set the exception variable and skip to the first associated @sc{catch}-@sc{exit} block.MAL interpretation then continues until it reaches the end of the block.If no exception variable was defined, we should abandon the functionalltogether searching for a catch block at a higher layer.@{For the time being we have ignored cascaded/stacked exceptions.The policy is to pass the first recognized exception to a contextin which it can be handled.@}@-Exceptions raised within a linked-in function requires some care.First, the called procedure does not know anything about the MALinterpreter context. Thus, we need to return all relevant informationupon leaving the linked library routine.Second, exceptional cases can be handled deeply in the recursion, where theymay also be handled, i.e. by issueing an GDKerror message. The upper layersmerely receive a negative integer value to indicate occurrence of anerror somewhere in the calling sequence.We then have to also look into GDKerrbuf to see if there wasan error raised deeply inside the system.The policy is to require all C-functions to return a string-pointer. Upon a successfull call, this string function is NULL. Otherwise it contains anencoding of the exceptional state encountered. This messagestarts with the exception identifer, followed by contextual details.@{@= exceptionHndlr	@:timingHndlr@if( ret != MAL_SUCCEED ) {	str msg = 0, nxt;	if( stk->cmd  ) {		stream_printf(cntxt->fdout,"!ERROR: %s\n",ret);		stk->cmd='n';		mdbStep(cntxt,mb,stk,stkpc);		if( stk->cmd == 'x' || stk->cmd == 'q' ) {			stkpc= mb->stop;			continue;		}		if( stk->cmd == 'r') {			stk->cmd = 'n';			stkpc = startpc;			exceptionVar = -1;			continue;		}	}	/* Detect any exception received from the implementation. */	/* The first identifier is an optional exception name */	msg = strchr(ret,':');	if(msg) {		*msg= 0;		exceptionVar = findVariableLength(mb,ret,msg-ret);		*msg=':';		exceptionPC = stkpc;	} else {		if( ret == MAL_SUCCEED && cntxt->errbuf){			/* trap hidden (GDK) exception */			msg= GDKstrdup(cntxt->errbuf);			exceptionVar= findVariable(mb,"GDKerror");			exceptionPC = stkpc;		} else {			exceptionVar = getDestVar(pci);			exceptionPC = stkpc;		}	}	/* unknown exceptions lead to propagation */	if( exceptionVar == -1){		@:endProfile@		stkpc= mb->stop;		continue;	}	msg++;	/* assure correct variable type */	nxt= (str) setDynamicType(mb,getVar(mb,exceptionVar),TYPE_str,stkpc);	if( nxt == 0){		v=  &stk->stk[exceptionVar];		if( getVarType(mb,exceptionVar) == TYPE_any)			setVarType(mb, exceptionVar, TYPE_str);		v->vtype = TYPE_str;		v->val.pval= ret;		v->len= strlen(v->val.pval);		ret = 0;	} else GDKfree(nxt);	/* position yourself at the catch instruction for further decisions */	@:skipToCatch(exceptionVar)@	pci= getInstrPtr(mb,stkpc);}@-During instruction interpretation we may have to beassured that the type associated with a destination variableis in line with the result of an operation or exceoption.@cstr setDynamicType(MalBlkPtr mb, VarPtr v, int tpe, int pc){	if( v->type ==tpe) return 0;	if( v->type == TYPE_any) return 0;	return createScriptException(mb, pc, TYPE, NULL,			"variable '%s' has already type %s (!=%s)",			v->name, getTypeName(v->type), getTypeName(tpe));}@}@-@node Garbage Collection, Stack Management, Exception Handling, The MAL Interpreter@+ Garbage collectionGarbage collection is relatively straightforward, because most values areretained on the stackframe of an interpreter call. However, two storagetypes and possibly user-defined type garbage collector definitionsrequire attention: BATs and strings.A key issue is to deal with temporary BATs in an efficient way.References to bats in the buffer pool may cause dangling referencesat the language level. This appears as soons as your sharea reference and delete the BAT from one angle. If not carefull, thedangling pointer may subsequently be associated with another BATAll string values are private to the VALrecord, which means theyhave to be freed explicitly before a MAL function returns. The first step is to always safe the destination variablebefore a function call is made.@{@-@cvoid garbageElement(ValPtr v){   	if( v->vtype == TYPE_str) {		if(v->len && v->val.pval) {			GDKfree(v->val.pval);			v->val.pval= NULL;		}		v->len= 0;		return;	}	if( v->vtype== TYPE_bat ) {@}@-All operations are responsible to properly set thereference count of the BATs being produced or destroyed.The libraries should not leave thephysical reference count being set. This is onlyallowed during the execution of a GDK operation.All references should be logical.@-@{@c		int bid= ABS(v->val.bval);		/* printf("garbage collecting: %d lrefs=%d refs=%d\n",		   bid, BBP_lrefs(bid),BBP_refs(bid));*/		v->val.bval =0;		if( bid == 0 ) return;		if( BBP_lrefs(bid) )			BBPdecref(bid,TRUE);		}	}@-@}Before we return from the interpreter, we should free alldynamically allocated objects and adjust the BAT reference counts.Early experience shows that for small stack frames the overheadis about 200 ms for a 1M function call loop (tst400e). This means thatfor the time being we do not introduce more complex garbageadministration code.Also note that for top-level stack frames (no environment available),we should retain the value stack because it acts as a global variables. This situation is indicated by the 'global' in the stack frame. @{Upon termination of the session, the stack should be cleared.Beware that variables may be know polymorphic, their actualtype should be saved for variables that recide on a globalstack frame.@cvoid garbageCollector(MalBlkPtr mb, MalStkPtr stk, int flag){   int k;	ValPtr v;#ifdef STACKTRACE	stream_printf(GDKout,"--->stack before garbage collector\n");	printStack(GDKout,mb,stk,0);#endif	for(k=0;k<mb->vtop; k++) {		if(isVarGarbage(mb,k) && (flag || isTmpVar(mb,k) )){			garbageElement(v= &stk->stk[k]);			v->vtype= TYPE_int;			v->val.ival= int_nil;		}	}#ifdef STACKTRACE	stream_printf(GDKout,"--->stack after garbage collector\n");	printStack(GDKout,mb,stk,0);#endif}@-Sometimes it helps to release a BAT when it won;t be used anymore.In this case, we have to assure that all references are clearedas well. The routine below performs this action in the localstack frame and its parents only.@cvoid releaseBAT(MalBlkPtr mb, MalStkPtr stk, int bid){   int k;#ifdef STACKTRACE	stream_printf(GDKout,"--->release BAT %d \n", bid);	printStack(GDKout,mb,stk,0);#endif   do{		for(k=0;k<mb->vtop; k++) 		if( stk->stk[k].vtype== TYPE_bat && abs(stk->stk[k].val.br.id)==bid) {			BBPdecref(bid,TRUE);			stk->stk[k].val.ival= 0;		}#ifdef STACKTRACE		stream_printf(GDKout,"--->stack after release BAT %d\n", bid);		printStack(GDKout,mb,stk,0);#endif		if(stk->up){			stk= stk->up;			mb= stk->blk;		}else break;	} while(stk);}@-@+ Performance sectionThe interpreter has a built-in performance monitor hook, which isactivated using the compile option MALprofiler. Activation can lead toa significant performance degradation, because for all traced functionswe have to keep track of essential system counter information.See @url{The MAL Profiler} for more details.@= performanceVariables#ifdef MALprofiler	lng newclk=0;#endif@= beginProfile#ifdef MALprofiler	if( malProfileMode == 0)		/* mostly true */;	else {		if( mb->profiler== NULL)			initProfiler(mb);		mb->profiler[stkpc].clk= GDKusec();		time(&mb->profiler[stkpc].clock);#ifdef HAVE_TIMES		times(&mb->profiler[stkpc].timer);#endif	}#endif@= endProfile#ifdef MALprofiler	if( malProfileMode == 0)		/* mostly true */;	else{		if( mb->profiler== NULL)			initProfiler(mb);		newclk= GDKusec();		mb->profiler[stkpc].counter++;		mb->profiler[stkpc].ticks += (long) (newclk - mb->profiler[stkpc].clk);		if( mb->profiler[stkpc].clk)			profilerEvent(cntxt->nspace,mb,stk,stkpc);	}#endif@= timingHndlrif( cntxt->flags && stk->cmd != 't' && stk->cmd != 'C'){	if( cntxt->flags & timerFlag)		stream_printf(cntxt->fdout,"#%6d usec",GDKusec()-cntxt->timer);#ifdef HAVE_SYS_RESOURCE_H	if( cntxt-> flags & ioFlag){		struct  rusage resource;		getrusage(RUSAGE_SELF, &resource);		if(	resource.ru_inblock - oldinblock 		 ||	resource.ru_oublock - oldoublock ) {			stream_printf(cntxt->fdout,"# %3d R",				resource.ru_inblock- oldinblock);			stream_printf(cntxt->fdout," %3d W",				resource.ru_oublock- oldoublock);		}	}#endif	if( cntxt->flags & memoryFlag){		struct mallinfo memory;		memory= MT_mallinfo();		if( memory.arena- oldMemory.arena > 0)			stream_printf(cntxt->fdout,"# %6d bytes",				memory.arena-oldMemory.arena );	}	if( cntxt->flags & flowFlag){		/* calculate the read/write byte flow */		stream_printf(cntxt->fdout,"# ");		getVolume(cntxt,mb,stk,pci,0);		getVolume(cntxt,mb,stk,pci,1);		/* getVolume(cntxt,mb,stk,pci,2);*/	}	if( cntxt->flags & timerFlag){		printTraceCall(cntxt,mb,stk,stkpc);		cntxt->timer = GDKusec();	}}@-For performance evaluation it is handy to know the maximal amount of bytes read/written. The actualamount is harder to guess, because it too muchdepends on the operation.@cvoid getVolume(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int rd){	int i, limit, vol=0;	BAT *b;	(void) mb;	limit= rd ==0? pci->retc: pci->argc;	i= rd? pci->retc:0;	for(; i<limit; i++)	if( stk->stk[getArg(pci,i)].vtype == TYPE_bat){		b= BATdescriptor( stk->stk[getArg(pci,i)].val.br.id);		if( b==0) continue;		vol += BATcount(b) * BUNsize(b);		BBPunfix(b->batCacheid);	}	if( vol <1024)		stream_printf(cntxt->fdout,"%3d",vol);	else	if( vol <1024*1024)		stream_printf(cntxt->fdout,"%3dK",vol/1024);	else	if( vol <1024* 1024*1024)		stream_printf(cntxt->fdout,"%3dM",vol/1024/1024);	else		stream_printf(cntxt->fdout,"%3dG",vol/1024/1024/1024);}@}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -