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

📄 mal_interpreter.mx

📁 一个内存数据库的源代码这是服务器端还有客户端
💻 MX
📖 第 1 页 / 共 3 页
字号:
@' The contents of this file are subject to the MonetDB Public License@' Version 1.1 (the "License"); you may not use this file except in@' compliance with the License. You may obtain a copy of the License at@' http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html@'@' Software distributed under the License is distributed on an "AS IS"@' basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the@' License for the specific language governing rights and limitations@' under the License.@'@' The Original Code is the MonetDB Database System.@'@' The Initial Developer of the Original Code is CWI.@' Portions created by CWI are Copyright (C) 1997-2007 CWI.@' All Rights Reserved.@a M. Kersten@v 0.0@* The MAL InterpreterThe MAL interpreter always works in the context of a single user session,which provides for storage access to global variables and modules.@menu* MAL API::* Exception Handling::* Garbage Collection::* Stack Management::@end menu@{@h#ifndef _MAL_INTERPRET_H#define _MAL_INTERPRET_H#include "mal_client.h"#include "mal_factory.h"#include "mal_profiler.h"@-Activation of a thread requires construction of the argument listto be passed by a handle.@h/*#define DEBUG_MAL_INTERPRETER *//*#define DEBUG_MAL_PARALLEL *//*#define STACKTRACE*/mal_export void showErrors(void);mal_export MalStkPtr prepareMALstack(MalBlkPtr mb);mal_export str runMAL(Client c, MalBlkPtr mb, int startpc,			MalBlkPtr mbcaller, MalStkPtr env, InstrPtr pcicaller);mal_export str runMALdataflow( Client cntxt, MalBlkPtr mb, int startpc, 		int stoppc, MalStkPtr stk, MalStkPtr env, InstrPtr pcicaller);mal_export str reenterMAL(Client cntxt, MalBlkPtr mb, int startpc,	int stoppc, MalStkPtr stk, MalStkPtr env, InstrPtr pcicaller);mal_export str callMAL(Client cntxt, MalBlkPtr mb, MalStkPtr *glb, 	ValPtr argv[], char debug);mal_export void garbageElement(ValPtr v);mal_export void garbageCollector(MalBlkPtr mb, MalStkPtr stk, int flag);mal_export void releaseBAT(MalBlkPtr mb, MalStkPtr stk, int bid);mal_export ptr getArgValue(MalStkPtr stk, InstrPtr pci, int k);mal_export ptr getArgReference(MalStkPtr stk, InstrPtr pci, int k);#define VALcopy2(lhs,rhs) if( (rhs)->vtype < TYPE_str) *lhs = *rhs; else VALcopy(lhs,rhs);#endif /*  _MAL_INTERPRET_H*/@c#include "mal_config.h"#include "mal_interpreter.h"#include "mal_debugger.h"   /* for mdbStep() */#include "mal_type.h"static str runMALsequence( Client cntxt, MalBlkPtr mb, int startpc, 		int stoppc, MalStkPtr stk, MalStkPtr env, InstrPtr pcicaller);static str setDynamicType(MalBlkPtr mb, VarPtr v, int tpe, int pc);static void getVolume(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int rd);@-We can speed up the copying, provided we ignore copying ptr-basedobjects.@cptr getArgValue(MalStkPtr stk, InstrPtr pci, int k){	int j=0;	ValRecord *v;	ptr val = NULL;	int tpe ;	j = pci->argv[k];	v= &stk->stk[j];	tpe = v->vtype;tstagain:	switch(tpe){	/* switch(ATOMstorage(v->vtype)){ */	case TYPE_void: val= (ptr) & v->val.ival; break;	case TYPE_bit: val= (ptr) & v->val.cval[0]; break;	case TYPE_chr: val= (ptr) & v->val.cval[0]; break;	case TYPE_sht: val= (ptr) & v->val.shval; break;	case TYPE_bat: val= (ptr) & v->val.br.id; break;	case TYPE_int: val= (ptr) & v->val.ival; break;	case TYPE_wrd: val= (ptr) & v->val.wval; break;	case TYPE_bte: val= (ptr) & v->val.btval; break;	case TYPE_oid: val= (ptr) & v->val.oval; break;	case TYPE_ptr: val= (ptr) v->val.pval; break;/*!!*/	case TYPE_flt: val= (ptr) & v->val.fval; break;	case TYPE_dbl: val= (ptr) & v->val.dval; break;	case TYPE_lng: val= (ptr) & v->val.lval; break;	case TYPE_str: val= (ptr) v->val.sval; break;/*!!*/	default:		tpe= ATOMstorage(tpe);		goto tstagain;	}	return val;} @-Alternatively, the routines can obtain a reference to a particularvalue. This is particularly handy for the optimizers, while the formeris mostly used to prepare a call to the linked libraries.The struct alignment leads to 40% gain in simple instructions when set.@cINLINEptr getArgReference(MalStkPtr stk, InstrPtr pci, int k){#ifdef STRUCT_ALIGNED	return (ptr) & stk->stk[pci->argv[k]].val.ival;#else	int j=0;	ValRecord *v=0;	ptr ret = NULL;	j = pci->argv[k];	v= &stk->stk[j];	switch(ATOMstorage(v->vtype)){	case TYPE_void: ret= (ptr) & v->val.ival; break;	case TYPE_bit: ret= (ptr) & v->val.cval[0]; break;	case TYPE_chr: ret= (ptr) & v->val.cval[0]; break;	case TYPE_sht: ret= (ptr) & v->val.shval; break;	case TYPE_bat: ret= (ptr) & v->val.br.id; break;	case TYPE_int: ret= (ptr) & v->val.ival; break;	case TYPE_wrd: ret= (ptr) & v->val.wval; break;	case TYPE_bte: ret= (ptr) & v->val.btval; break;	case TYPE_oid: ret= (ptr) & v->val.oval; break;	case TYPE_ptr: ret= (ptr) & v->val.pval; break;	case TYPE_flt: ret= (ptr) & v->val.fval; break;	case TYPE_dbl: ret= (ptr) & v->val.dval; break;	case TYPE_lng: ret= (ptr) & v->val.lval; break;	case TYPE_str: ret= (ptr) & v->val.sval; break;	default:		ret= (ptr) & v->val.pval; 	}	return ret;#endif} void showErrors() {	Client cntxt = MCgetClient();	int i;	if (cntxt->errbuf == '\0')		return;	if (*cntxt->errbuf) {		i = strlen(cntxt->errbuf);		stream_printf(cntxt->fdout, "%s", cntxt->errbuf);		if (cntxt->errbuf[i - 1] != '\n')			stream_printf(cntxt->fdout, "\n");		*cntxt->errbuf = '\0';	}}@-Copy the constant values onto the stack frame@= initStack	for(i= @1; i< mb->vtop; i++)	if( isConstant(mb,i) > 0 ){		lhs = &stk->stk[i];		rhs = &getVarConstant(mb,i);		VALcopy2(lhs,rhs);	} else {		lhs = &stk->stk[i];		lhs->vtype = getVarGDKType(mb,i);	}@cMalStkPtrprepareMALstack(MalBlkPtr mb){	MalStkPtr stk= NULL;	int i;	ValPtr lhs,rhs;	stk= newGlobalStack(mb->vsize);	memset((char *) stk, 0, stackSize(mb->vtop));	stk->stktop= mb->vtop; 	stk->stksize= mb->vsize;	stk->blk= mb;	@:initStack(1)@	return stk;}str runMAL(Client cntxt, MalBlkPtr mb, int startpc, MalBlkPtr mbcaller, 	   MalStkPtr env, InstrPtr pcicaller){	MalStkPtr stk= NULL;	int i;	ValPtr lhs,rhs;	InstrPtr pci=0;	str ret;	if (mb->errors) {		showErrors();		if (cntxt->itrace == 0) /* permit debugger analysis */			return createScriptException(mb, 0, MAL, NULL, "Syntax error in script");	}@-Prepare a new interpreter call. This involves two steps, (1) allocatethe minimum amount of stack space needed, some slack resourcesare included to permit code optimizers to add a few variables at run time,(2) copying the arguments into the new stack frame.Notice that arguments are always the first entries on the stack.The env stackframe is set when a MAL function is called recursively.Alternatively, there is no caller but a stk to be re-used for interpretation.We assume here that it aligns with the variable table of the routinebeing called.@c	/* allocate space for value stack */	/* the global stack should be large enough */	if( mbcaller== NULL && env != NULL){		stk = env;		if( mb != stk->blk) 			showScriptException(mb,0,MAL,"runMAL:misalignment of symbols\n");		if( mb->vtop > stk->stksize)			showScriptException(mb,0,MAL,"stack too small\n");		pci= pcicaller;	} else {		newStack(stk,mb->vsize);		memset((char *) stk, 0, stackSize(mb->vtop));		stk->stktop= mb->vtop; 		stk->stksize= mb->vsize;		stk->blk= mb;		stk->cmd= cntxt->itrace; /* set debug mode */		if( env) {			stk->stkdepth= stk->stksize + env->stkdepth;			@:safeguardStack@		}	} 	if( env && mbcaller){		InstrPtr pp;		int k;@-Beware, a function signature f(a1..an):(b1..bn) is parsed in such a way thatthe symbol table and stackframe contains the sequence f,a1..an,b1..bn. This slightly complicates the implementationof the return statement.@c		pci= pcicaller;		pp = getInstrPtr(mb, 0);		/* set return types */		for(i=0; i< pci->retc; i++){			lhs = &stk->stk[i];			lhs->vtype =getVarGDKType(mb,i);		}		for(k=pp->retc; i<pci->argc; i++,k++){			lhs = &stk->stk[pp->argv[k]];			/* variable arguments ? */			if( k== pp->argc-1) k--; 			rhs = &env->stk[pci->argv[i]];			VALcopy2(lhs,rhs);			if( lhs->vtype == TYPE_bat)				BBPincref(lhs->val.br.id, TRUE);		}		stk->up = env;		env->down = stk;	} @-An optimization is to copy all constant variables used in functions immediatelyonto the value stack. Then we do not have to check for their locationlater on any more. At some point, the effect is optimal, if at least severalconstants are referenced in a function (a gain on tst400a of 20% has been observed due the small size of the function).Moreover, we have to copy the result types to the stack for lateruse. The stack value is cleared to avoid misinterpretation of left-overinformation. Since a stack frame may contain values of a previous call,we should first remove garbage. @c	@:initStack((env && mbcaller)?pci->argc:1)@	if(stk->cmd  && env && stk->cmd!='f') stk->cmd = env->cmd ;	ret = runMALsequence(cntxt, mb, startpc,  0, stk, env, pcicaller);	/* pass the new debug mode to the caller */	if(stk->cmd  && env && stk->cmd!='f') env->cmd = stk->cmd; 	if( !stk->keepAlive && garbageControl(getInstrPtr(mb,0)) )		garbageCollector(mb,stk, env != stk);	return ret;}@-@+ Single instructionIt is possible to re-enter the interpreter at a specific place.This is used in the area where we need to support co-routines.A special case for MAL interpretation is to execute just one instruction.This is typically used by optimizers and schedulers that need part of the answer to direct their actions. Or, a dataflow scheduler could step into enforce a completely different execution order.@cstr reenterMAL(Client cntxt, MalBlkPtr mb, int startpc, int stoppc,	MalStkPtr stk, MalStkPtr env, InstrPtr pcicaller){	str ret;	if(env && stk && stk->cmd!='f') stk->cmd = env->cmd ;	ret = runMALsequence(cntxt, mb, startpc,  stoppc, stk, env, pcicaller);	/* pass the new debug mode to the caller */	if(env && stk->cmd!='f') env->cmd = stk->cmd;	if( !stk->keepAlive && garbageControl(getInstrPtr(mb,0)) )		garbageCollector(mb,stk,env!=stk);	return ret;}@-Front ends may benefit from a more direct call to any of the MALprocedural abstractions. The argument list points to the argumentsfor the block to be executed. An old stack frame may be re-used,but it is then up to the caller to ensure it is properlyinitialized. The call does not return values, they are ignored.@cstr callMAL(Client cntxt, MalBlkPtr mb, MalStkPtr *env, ValPtr argv[], char debug){	MalStkPtr stk;	str ret;	int i;	ValPtr lhs,rhs;	InstrPtr p= getInstrPtr(mb,0);#ifdef DEBUG_CALLMAL	stream_printf(GDKout,"callMAL\n");	printInstruction(GDKout,mb,p,LIST_MAL_ALL);#endif	switch( p->token){	case FUNCTIONsymbol:	case FCNcall:@-Prepare the stack frame for this operation. Copy all the argumentsin place. We assume that the caller has supplied pointers forall arguments and return values.@c		if( *env==NULL){			stk=newGlobalStack(mb->vsize);			memset((char *) stk, 0, stackSize(mb->vtop));			stk->stktop= mb->vtop; 			stk->stksize= mb->vsize;			stk->blk= mb;			stk->up = 0;			@:initStack(p->argc)@			stk->keepAlive = TRUE;			*env= stk;		} else stk = *env;		assert(stk);		for(i=p->retc; i<p->argc; i++){			lhs= &stk->stk[p->argv[i]];			VALcopy2(lhs, argv[i]);			if( lhs->vtype == TYPE_bat)				BBPincref(lhs->val.br.id,TRUE);		}#ifdef STACKTRACE	stream_printf(GDKout,"before execution\n");	printStack(GDKout,mb,stk,0); 	printFunction(GDKout,mb,LIST_MAL_ALL);#endif		stk->cmd = debug;#ifdef DEBUG_CALLMAL	stream_printf(GDKout,"start evaluation\n");#endif		ret = runMALsequence(cntxt, mb, 1,  0, stk, 0, 0);#ifdef STACKTRACE		stream_printf(GDKout,"Stack after loop\n");		printStack(GDKout,mb,stk,0); #endif		return ret;	case FACTORYsymbol:	case FACcall:		return callFactory(cntxt, mb, argv,debug);	case PATcall:	case CMDcall:	default:		throw(MAL, "mal.interpreter",				"Non-supported call the MAL interpreter");	}	return MAL_SUCCEED;}@-The core of the interpreter is presented next. It takes the context informationand starts the interpretation at the designated instruction.Note that the stack frame is aligned and initialized in the enclosing routine.@cstr runMALsequence( Client cntxt, MalBlkPtr mb, int startpc, 		int stoppc, MalStkPtr stk, MalStkPtr env, InstrPtr pcicaller){   	ValPtr lhs,rhs,v;	int stkpc,i,k; 	InstrPtr pci=0; 	int exceptionVar, exceptionPC;	str ret=0;	int stamp= -1;	int backup[MAXARG];	str sbackup[MAXARG];	lng oldtimer=0;	struct mallinfo oldMemory;#ifdef HAVE_SYS_RESOURCE_H	int oldinblock=0;	int oldoublock=0;	struct rusage oldResource;#endif	@:performanceVariables@	if( cntxt->flags & timerFlag)		oldtimer= cntxt->timer= GDKusec();	oldMemory.arena= 0;			stkpc = startpc;	exceptionVar = exceptionPC = -1;	(void)exceptionPC; /* TODO maybe we should use this variable somewhere*/	while(stkpc < mb->stop && stkpc != stoppc ){		pci = getInstrPtr(mb,stkpc);		if( stk->cmd  ) {			lng t=0;			if( oldtimer)				t= GDKusec();			mdbStep(cntxt,mb,stk,stkpc);			if( stk->cmd == 'x') {				stkpc = mb->stop;				continue;			}			if( oldtimer ) {				/* ignore debugger waiting time*/				t= GDKusec()-t;				oldtimer += t;#ifdef HAVE_SYS_RESOURCE_H				getrusage(RUSAGE_SELF, &oldResource);#endif				oldMemory= MT_mallinfo();			}		}		@:beginProfile@		@:MALinterpret@		@:MALflowofcontrol@		@:endProfile@	}	@:MALwrapup@	return ret;}@- Out of order executionThe alternative is to execute the instructions out of orderusing a dataflow dependencies. It only works on a codesequence that does not include additional (implicit) flow of controlstatements and, ideally, consist of expensive BAT operations.The dataflow interpreter selects cheap instructionsusing a simple costfunction based on the size of the BATs involved.The dataflow portion is identified as a guarded block,whose entry is controlled by the function language.dataflow();This way the function can inform the caller to skip the blockwhen dataflow execution was performed.@hmal_export str runMALdataflow( Client cntxt, MalBlkPtr mb, int startpc, 		int stoppc, MalStkPtr stk, MalStkPtr env, InstrPtr pcicaller);@ctypedef struct{	InstrPtr p;	int pending;	lng	cost;} *FlowStep, FlowStepRec;#define DEBUG_FLOW@-The cost of a flow step depends on availability of itsarguments and the total size of the BATs being accessed.@clngMALflowCost(MalBlkPtr mb, MalStkPtr stk, InstrPtr p){	int i,bid;	lng cost=0;	BAT *b;	for(i= p->retc; i<p->argc; i++)	if( isaBatType(getArgType(mb,p,i)) &&		(bid= ABS(stk->stk[getArg(p,i)].val.bval)) ){		b= BATdescriptor(bid);		if( b == NULL) continue;		cost += BATcount(b);		BBPreleaseref(bid);	}	return cost;}voidaddMALflowStep(FlowStep flow, int top, char *pending, MalBlkPtr mb, MalStkPtr stk, InstrPtr p){	int j;	flow[top].p= p;	flow[top].pending= 0L;	for(j=p->retc; j< p->argc; j++)		flow[top].pending+= pending[getArg(p,j)];		for(j=0; j<p->retc; j++)		pending[getArg(p,j)]= 1;		flow[top].cost=  MALflowCost(mb, stk,p);#ifdef DEBUG_FLOW	stream_printf(GDKout,"#[%d]cost %d ",top,flow[top].cost);	stream_printf(GDKout,"pending %d",flow[top].pending);	printInstruction(GDKout,mb,p, 0);#endif}voiddropMALflowStep(FlowStep flow, int first, int last, char *pending, MalBlkPtr mb, MalStkPtr stk){	int i,j;

⌨️ 快捷键说明

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