326 lines · 5.7 KB · Brainfuck
RawDownload
roots:	array of ref BB;	# root basic blocksnr:	int;			# number of root basic blocksmaxr:	int;			# maximum number of roots setflags(pc: int, flags: byte){	j: ref Jinst; 	j = code.j[pc];	if(j.bb == nil) {		j.bb = ref BB(j, nil, 0, nil, byte 0, byte BB_PRESIM, 0, nil, 0, nil);		# record root basic blocks		if(int (flags & (BB_ENTRY | BB_FINALLY | BB_HANDLER))) {			if(nr >= maxr) {				oldmaxr := maxr;				maxr += ALLOCINCR;				newroots := array [maxr] of ref BB;				for(i := 0; i < oldmaxr; i++)					newroots[i] = roots[i];				roots = newroots;			}			roots[nr] = j.bb;			nr += 1;		}	}	j.bb.flags |= flags;} ## Verify that the target of a jump is valid.# verifyjump(j: ref Jinst, offset: int){	dst: int; 	dst = j.pc + offset;	if(dst < 0 || dst >= code.code_length || code.j[dst] == nil)		verifyerror(j);} ## Mark the instructions of a method that are basic block leaders.# markldrs(){	j: ref Jinst;	jpi: ref Jinst.Pi;	jpt1: ref Jinst.Pt1;	jpt2: ref Jinst.Pt2;	jpw: ref Jinst.Pw;	i: int;	pc, pcnext: int; 	# first instruction is a leader	setflags(0, BB_LDR | BB_ENTRY); 	# exception handler entry points are leaders	for(i = 0; i < code.nex; i++)		setflags(code.ex[i].handler_pc, BB_LDR | BB_HANDLER); 	pc = 0;	while(pc < code.code_length) {		j = code.j[pc];		pcnext = pc+j.size;		pick jp := j {		Pi =>			jpi = jp;		Pt1 =>			jpt1 = jp;		Pt2 =>			jpt2 = jp;		Pw =>			jpw = jp;		}		case int j.op {		Jwide =>			if(int jpw.w.op == Jret && pcnext < code.code_length)				setflags(pcnext, BB_LDR);		Jret or		Jireturn or		Jlreturn or		Jfreturn or		Jdreturn or		Jareturn or		Jreturn or		Jathrow =>			if(pcnext < code.code_length)				setflags(pcnext, BB_LDR);		Jifeq or		Jifne or		Jiflt or		Jifge or		Jifgt or		Jifle or		Jif_icmpeq or		Jif_icmpne or		Jif_icmplt or		Jif_icmpge or		Jif_icmpgt or		Jif_icmple or		Jif_acmpeq or		Jif_acmpne or		Jifnull or		Jifnonnull =>			verifyjump(j, jpi.i);			setflags(pc+jpi.i, BB_LDR);			setflags(pcnext, BB_LDR);		Jgoto or		Jgoto_w =>			verifyjump(j, jpi.i);			setflags(pc+jpi.i, BB_LDR);			if(pcnext < code.code_length)				setflags(pcnext, BB_LDR);		Jjsr or		Jjsr_w =>			# target of jsr is leader, jsr successor isn't			verifyjump(j, jpi.i);			setflags(pc+jpi.i, BB_LDR | BB_FINALLY);			finallyentry(pc+jpi.i);		Jtableswitch =>			for(i = 0; i < jpt1.t1.hb - jpt1.t1.lb + 1; i++) {				verifyjump(j, jpt1.t1.tbl[i]);				setflags(pc+jpt1.t1.tbl[i], BB_LDR);			}			verifyjump(j, jpt1.t1.dflt);			setflags(pc+jpt1.t1.dflt, BB_LDR);			if(pcnext < code.code_length)				setflags(pcnext, BB_LDR);		Jlookupswitch =>			for(i = 0; i < jpt2.t2.np; i++) {				verifyjump(j, jpt2.t2.tbl[2*i+1]);				setflags(pc+jpt2.t2.tbl[2*i+1], BB_LDR);			}			verifyjump(j, jpt2.t2.dflt);			setflags(pc+jpt2.t2.dflt, BB_LDR);			if(pcnext < code.code_length)				setflags(pcnext, BB_LDR);		}		pc = pcnext;	}} ## Link basic block bb to its successors.# linksucc(bb: ref BB){	i: int;	pc: int;	je: ref Jinst;	jpi: ref Jinst.Pi;	jpt1: ref Jinst.Pt1;	jpt2: ref Jinst.Pt2;	jpw: ref Jinst.Pw; 	bb.nsucc = 0;	bb.succ = nil;	je = bb.je;	pc = je.pc; 	pick jp := je {	Pi =>		jpi = jp;	Pt1 =>		jpt1 = jp;	Pt2 =>		jpt2 = jp;	Pw =>		jpw = jp;	} 	case int je.op {	Jwide =>		if(int jpw.w.op != Jret && pc+je.size < code.code_length) {			bb.nsucc = 1;			bb.succ = array [1] of ref BB;			bb.succ[0] = code.j[pc+je.size].bb;		}	* =>		if(pc+je.size < code.code_length) {			bb.nsucc = 1;			bb.succ = array [1] of ref BB;			bb.succ[0] = code.j[pc+je.size].bb;		}	Jret or	Jireturn or	Jlreturn or	Jfreturn or	Jdreturn or	Jareturn or	Jreturn or	Jathrow =>		;	Jifeq or	Jifne or	Jiflt or	Jifge or	Jifgt or	Jifle or	Jif_icmpeq or	Jif_icmpne or	Jif_icmplt or	Jif_icmpge or	Jif_icmpgt or	Jif_icmple or	Jif_acmpeq or	Jif_acmpne or	Jifnull or	Jifnonnull =>		bb.nsucc = 2;		bb.succ = array [2] of ref BB;		bb.succ[0] = code.j[pc+jpi.i].bb;	# branch target		bb.succ[1] = code.j[pc+je.size].bb;	# fall through	Jgoto or	Jgoto_w =>		bb.nsucc = 1;		bb.succ = array [1] of ref BB;		bb.succ[0] = code.j[pc+jpi.i].bb;	Jtableswitch =>		bb.nsucc = jpt1.t1.hb - jpt1.t1.lb + 2;		bb.succ = array [bb.nsucc] of ref BB;		for(i = 0; i < bb.nsucc-1; i++)			bb.succ[i] = code.j[pc+jpt1.t1.tbl[i]].bb;		bb.succ[i] = code.j[pc+jpt1.t1.dflt].bb;	Jlookupswitch =>		bb.nsucc = jpt2.t2.np + 1;		bb.succ = array [bb.nsucc] of ref BB;		for(i = 0; i < bb.nsucc-1; i++)			bb.succ[i] = code.j[pc+jpt2.t2.tbl[2*i+1]].bb;		bb.succ[i] = code.j[pc+jpt2.t2.dflt].bb;	}} ## Build the basic block control flow graph.# flowgraph(){	js, je: ref Jinst;	pc, pcnext: int; 	markldrs(); 	pc = 0;	while(pc < code.code_length) {		js = code.j[pc];		if(js.bb == nil)			fatal("flowgraph: nil bb");		# find last instruction in basic block		je = js;		while() {			pcnext = je.pc + je.size;			if(pcnext >= code.code_length			|| code.j[pcnext].bb != nil)	# hence a leader				break;			je = code.j[pcnext];			je.bb = js.bb;		}		js.bb.je = je;		linksucc(js.bb);		pc = pcnext;	}	finallyalloc();} ## Free basic block structures after each method is translated.# bbfree(){	j: ref Jinst;	jix: int; 	jix = 0;	while(jix < code.code_length) {		j = code.j[jix];		if(j.bb.je == j) {			j.bb.succ = nil;			j.bb = nil;		}		jix += j.size;	}	roots = nil;	nr = 0;	maxr = 0;} ## The following stuff is used during method simulation.# SSIZE:		con 128;bbstack :=	array [SSIZE] of ref BB;bbtos:		int; bbput(bb: ref BB){	if(bbtos == SSIZE)		fatal("bbstack overflow");	bb.state = BB_ACTIVE;	bb.flags |= BB_REACHABLE;	bbstack[bbtos++] = bb;} bbget(): ref BB{	ret: ref BB; 	if(bbtos != 0)		ret = bbstack[--bbtos];	return ret;} bbinit(){	i: int; 	bbtos = 0;	for(i = 0; i < nr; i++)		bbput(roots[i]);}