void readCode()

in modules/asc/src/java/adobe/abc/GlobalOptimizer.java [1037:1896]


		void readCode(Method m, Reader p, Reader ptry)
		{
			

			addTraceAttr("Method", m);
			addTraceAttr("code_start", p.pos);

			int local_count = m.local_count;
			int end_pos = p.pos + m.code_len;
			
			// initial state of frame
			
			Expr[] frame = new Expr[local_count + m.max_scope + m.max_stack];
			Map<Integer,Block> blocks = new TreeMap<Integer,Block>();
			Map<Block,FrameState> states = new TreeMap<Block,FrameState>();
			int scopep = local_count;
			int sp = local_count+m.max_scope;
			traceEntry("InitialFrame");
			addTraceAttr("length", frame.length);
			addTraceAttr("sp", sp);
			addTraceAttr("scopep", scopep);
			
			m.entry = new Edge(m,null,0);
			Block b = createBlock(m, m.entry, states, frame, sp, scopep);
			Expr e;
			
			{
				int i;

				for (i=0; i < m.getParams().length; i++)
				{
					// argument i
					b.add(e = frame[i] = new Expr(m, OP_arg, i));
					if (i==0)
						e.ref = new Name("this");
					else if (m.paramNames != null)
						e.ref = m.paramNames[i];
					else 
						e.ref = new Name("arg"+i);
				}
				
				if (m.needsArguments() || m.needsRest())
				{
					b.add(e = frame[i] = new Expr(m, OP_arg, i));
					e.ref = new Name(m.needsArguments() ? "arguments" : "rest");
					i++;
				}
				
				for (; i < local_count; i++)
				{
					// remaining locals are undefined, but we use OP_arg
					// to suppress any codegen.  sccp_eval knows what to do.
					b.add(e = frame[i] = new Expr(m, OP_arg, i));
					e.ref = new Name("local"+i);
				}
			}
			
			BitSet trylabels = new BitSet();
			BitSet catchlabels = new BitSet();
			
			//  Remember start position of the code reader to compute
			//  relative offsets vs. absolute positions.
			int code_start = p.pos;
			int try_start = ptry.pos;  //  FIXME: use m.handlers-based processing, remove this
			
			Handler[] handlers = m.handlers = new Handler[ptry.readU30()];
			
			if ( handlers.length > 0 )
			{
				//  TODO arg 0 only needs to be fixed if
				//  this is an instance method.
				m.fixedLocals.put(frame[0], -1);
				for (int j = 0, n=handlers.length; j < n; j++)
				{
					Handler h = handlers[j] = new Handler();
					
					int from = ptry.readU30();
					int to = ptry.readU30();
					int target = ptry.readU30();
					h.type = lookup(ptry.readU30()).ref.nonnull();
					int name_idx = ptry.readU30();
					Name name = h.name = names[name_idx];

					//  The name may be null if the catch variable
					//  did not have a name.
					//  NOTE: Also see the emitCode write logic.
					if ( name != null )
					{
						Type a = new Type(name,ANY());
						h.activation = a.ref.nonnull();
						Binding bind = new Binding(TRAIT_Var, name, this);
						bind.type = h.type;
						a.defs.put(name, bind);
					}
					else
					{
						h.activation = ANY().ref.nonnull();
					}

					trylabels.set(from);
					trylabels.set(to);
					catchlabels.set(target);
				}
			}
		
			boolean reachable = true;
			boolean in_catch_block = false;
			
			while (p.pos < end_pos)
			{
				int pos = p.pos;
				int op = p.readU8();

				if (
					OP_label == op || 
					blocks.containsKey(pos) ||
					trylabels.get(pos-code_start) || 
					catchlabels.get(pos-code_start) 
					)
				{	
					if ( catchlabels.get(pos-code_start) )
					{
						in_catch_block = true;
					}
					else
					{
						in_catch_block = false;
					}

					Edge edge = null;
					
					if (reachable)
					{
						assert(!in_catch_block);
						
						Edge succ[] = b.succ();
						if (0 == succ.length)
						{
							b.add(e = new Expr(m,OP_jump));
							e.succ = new Edge[] { edge = new Edge(m,b,0,blocks.get(pos)) };
						}
						else
						{
							edge = succ[0];
						}
						traceEntry("Successor");
						addTraceAttr("Edge", edge);
					}
					
					//  For non-catch blocks, the block's saved stack frame
					//  needs to be updated with the current stack frame --
					//  this may create that saved stack frame as a 
					//  side effect.  For a catch block, the stack frame
					//  set up by the catch handler is already present
					//  and is known to be the correct starting state
					//  of the block.
					if (! in_catch_block)
					{
						merge(m,edge, blocks, states, pos, frame, sp, scopep);
					}

					b = blocks.get(pos);
					assert(b != null);
					FrameState state = states.get(b);
					assert(state != null);
					System.arraycopy(state.frame, 0, frame, 0, frame.length);
					sp = state.sp;
					scopep = state.scopep;
										
					reachable = true;	
				}
				// now we know what block we're in and pos is where it starts.
				
				//  Do we need to set up exception handlers?
				if (handlers.length > 0 && b.xsucc == noedges)
				{
					// start of new block, add handlers.
					

					addTraceAttr("offset", pos - code_start);
					
					List<Edge> xsucc = new ArrayList<Edge>();
					ptry.pos = try_start;
					int n=ptry.readU30();
					addTraceAttr("NumHandlers", n);
					
					for (int j=0; j < n; j++)
					{
						int from = code_start + ptry.readU30();
						int to = code_start + ptry.readU30();
						int target = code_start + ptry.readU30();

						traceEntry("Handler");
						addTraceAttr("from", from - code_start);
						addTraceAttr("to", to - code_start);
						addTraceAttr("target", target - code_start);
						
						if (pos >= from && pos < to)
						{
							addTraceAttr("activeHandler");
							Edge edge = new Edge(m, b, j, handlers[j]);
							xmerge(m, edge, blocks, states, target, frame, sp, scopep);
							xsucc.add(edge);
						}
						ptry.readU30(); // type
						ptry.readU30(); // name
					}
					
					b.xsucc = xsucc.toArray(new Edge[xsucc.size()]);

				}
				

				addTraceAttr("offset", pos-code_start);
				addTraceAttr("op", op);
				addTraceAttr("opName", opNames[op]);
				
				switch (op)
				{
				case OP_label:
					// already handled above
					break;

				case OP_throw:
				case OP_returnvalue:
					b.add(e = new Expr(m,op, frame, sp--, 1));
					e.succ = noedges;
					reachable = false;
					merge(m,null, blocks, states, p.pos, frame, sp, scopep);
					break;
					
				case OP_dxnslate:
					b.add(new Expr(m,op,frame, sp--, 1));
					break;

				case OP_pushwith:
				case OP_pushscope:
				{
					// includes a null pointer check and moves value to scope stack, so this isn't just a copy
					b.add(frame[scopep++] = e = new Expr(m, op, frame, sp--, 1));
					
					//  The activation record saved for catch blocks' use
					//  is live across regions of code that the optimizer
					//  and verifier don't agree on, so it gets fixed into
					//  a local and "conflicts" with everything.
					if ( in_catch_block  && OP_phi == e.args[0].op  )
					{
						Expr activ = e.args[0];
						while ( OP_phi == activ.op && activ.args != null && activ.args.length > 0)
						{
							activ = activ.args[0];
						}
						
						if ( OP_newactivation == activ.op)
						{
							m.fixedLocals.put(activ, -1);
						}
							
					}
					break;
				}

				case OP_popscope:
					b.add(e = new Expr(m, op));
					e.scopes = new Expr[] { frame[--scopep] };
					frame[scopep] = null;
					break;
					
				case OP_nextname:
				case OP_hasnext:
				case OP_nextvalue:
					b.add(e = new Expr(m,op, frame, sp, 2));
					sp -= 2;
					frame[sp++] = e;
					break;
					
				case OP_pushnull:
					b.add(frame[sp++] = new Expr(m,op,NULL()));
					break;
				case OP_pushundefined:
					b.add(frame[sp++] = new Expr(m,op,UNDEFINED));
					break;
				case OP_pushtrue:
					b.add(frame[sp++] = new Expr(m,op,TRUE));
					break;
				case OP_pushfalse:
					b.add(frame[sp++] = new Expr(m,op,FALSE));
					break;
				case OP_pushnan:
					b.add(frame[sp++] = new Expr(m,op,Double.NaN));
					break;
					
				case OP_newactivation:
					b.add(frame[sp++] = new Expr(m,op));
					break;

				case OP_getglobalscope:
					b.add(e = frame[sp++] = new Expr(m, op));
					e.scopes = capture(frame, scopep, scopep-local_count);
					traceEntry("scopep", scopep);
					break;
					
				case OP_getscopeobject:
					b.add(e = frame[sp++] = new Expr(m, op));
					e.scopes = capture(frame, local_count+p.readU8()+1, 1);
					break;
					
				case OP_pop:
					sp--;
					break;

				case OP_dup:
					frame[sp] = frame[sp-1];
					sp++;
					break;
					
				case OP_swap:
				{
					e = frame[sp-1];
					frame[sp-1] = frame[sp-2];
					frame[sp-2] = e;
					break;
				}
				
				case OP_returnvoid:
					b.add(e = new Expr(m,op));
					e.succ = noedges;
					reachable = false;
					merge(m,null, blocks, states, p.pos, frame, sp, scopep);
					break;

				case OP_convert_s:
				case OP_esc_xelem:
				case OP_esc_xattr:
				case OP_convert_i:
				case OP_convert_u:
				case OP_convert_d:
				case OP_coerce_s:
				case OP_negate:
				case OP_increment:
				case OP_decrement:
				case OP_not:
				case OP_bitnot:
				case OP_increment_i:
				case OP_decrement_i:
				case OP_negate_i:
				case OP_coerce_o:
				case OP_convert_o:
				case OP_typeof:
				case OP_convert_b:
				case OP_coerce_a:
					// unary w/ possible side effect
					b.add(frame[sp-1] = new Expr(m,op, frame, sp, 1));
					break;

				case OP_checkfilter:
					// possible exception
					b.add(new Expr(m,op, frame, sp, 1));
					break;

				case OP_astypelate:
				case OP_add:
				case OP_subtract:
				case OP_multiply:
				case OP_divide:
				case OP_modulo:
				case OP_lshift:
				case OP_rshift:
				case OP_urshift:
				case OP_bitand:
				case OP_bitor:
				case OP_bitxor:
				case OP_equals:
				case OP_lessthan:
				case OP_lessequals:
				case OP_greaterthan:
				case OP_greaterequals:
				case OP_instanceof:
				case OP_in:
				case OP_add_i:
				case OP_subtract_i:
				case OP_multiply_i:
				case OP_istypelate:
				case OP_strictequals:
					b.add(frame[sp-2] = new Expr(m,op, frame, sp, 2));
					sp--;
					break;
					
				case OP_getlocal0:
				case OP_getlocal1:
				case OP_getlocal2:
				case OP_getlocal3:
					frame[sp++] = frame[op-OP_getlocal0];
					break;

				case OP_setlocal0:
				case OP_setlocal1:
				case OP_setlocal2:
				case OP_setlocal3:
					frame[op-OP_setlocal0] = frame[--sp];
					break;

				case OP_kill:
					b.add(frame[p.readU30()] = new Expr(m,OP_pushundefined,UNDEFINED)); 
					break;
					
				case OP_pushshort:
					b.add(frame[sp++] = new Expr(m,op, new Integer((short)p.readU30())));
					break;
				case OP_pushstring:
					b.add(frame[sp++] = new Expr(m,op, strings[p.readU30()]));
					break;
				case OP_pushint:
					b.add(frame[sp++] = new Expr(m,op, new Integer(ints[p.readU30()])));
					break;
				case OP_pushuint:
					b.add(frame[sp++] = new Expr(m,op, new Long(uints[p.readU30()])));
					break;
				case OP_pushdouble:
					b.add(frame[sp++] = new Expr(m,op, new Double(doubles[p.readU30()])));
					break;
				case OP_pushnamespace:
					b.add(frame[sp++] = new Expr(m,op, namespaces[p.readU30()]));
					break;

				case OP_getlocal:
					frame[sp++] = frame[p.readU30()];
					break;
					
				case OP_setlocal:
					frame[p.readU30()] = frame[--sp];
					break;
					
				case OP_coerce:
				case OP_astype:
				case OP_istype:
				{
					b.add(e = frame[sp-1] = new Expr(m, op, names[p.readU30()], frame, sp, 1));
					break;
				}
					
				case OP_dxns:
					b.add(new Expr(m,op, strings[p.readU30()]));
					break;
				
				case OP_inclocal_i:
				case OP_declocal_i:
				case OP_inclocal:
				case OP_declocal:
				{
					// turn these into increment/decrement, forget which local was used.
					int i = p.readU30();
					op = op == OP_inclocal_i ? OP_increment_i :
						 op == OP_inclocal   ? OP_increment   :
						 op == OP_declocal_i ? OP_decrement_i : 
					 	                       OP_decrement;
					b.add(e = frame[i] = new Expr(m, op, i, frame, i+1, 1));
					break;
				}

				case OP_newfunction:
				{
					e = new Expr(m,op);
					e.m = methods[p.readU30()];
					e.scopes = capture(frame, scopep, scopep-local_count);
					traceEntry("scopep", scopep);
					b.add(frame[sp++] = e);
					break;
				}
				
				case OP_newclass:
				{
					e = new Expr(m, op, frame, sp, 1);
					e.scopes = capture(frame, scopep, scopep-local_count);
					traceEntry("scopep", scopep);
					e.c = classes[p.readU30()];
					b.add(frame[sp-1] = e);
					break;
				}
				
				case OP_newobject:
				{
					int argc = 2*p.readU30();
					e = new Expr(m,op, frame, sp, argc);
					sp -= argc;
					b.add(frame[sp++] = e);
					break;
				}
				
				case OP_newarray:
				{
					int argc = p.readU30();
					e = new Expr(m,op, frame, sp, argc);
					sp -= argc;
					b.add(frame[sp++] = e);
					break;
				}

				case OP_newcatch:
				{
					e = new Expr(m, op, p.readU30());
					b.add(frame[sp++] = e);
					break;
				}
				
				case OP_getsuper:
				{
					Name ref = names[p.readU30()];
					int argc = 1 + refArgc[ref.kind];
					e = new Expr(m,op, ref, frame, sp, argc);
					sp -= argc;
					b.add(frame[sp++] = e);
					break;
				}
				
				case OP_setsuper:
				{
					Name ref = names[p.readU30()];
					int argc = 2 + refArgc[ref.kind];
					b.add(e = new Expr(m,op, ref, frame, sp, argc));
					sp -= argc;
					break;
				}
				
				case OP_call:
				{
					int argc = 2+p.readU30();
					e = new Expr(m, op, frame, sp, argc);
					sp -= argc;
					b.add(frame[sp++] = e);
					break;
				}

				case OP_construct:
				{
					int argc = 1+p.readU30();
					e = new Expr(m,op, frame, sp, argc);
					sp -= argc;
					b.add(frame[sp++] = e);
					break;
				}

				case OP_getdescendants:
				case OP_deldescendants:
				case OP_deleteproperty:
				case OP_getproperty:
				{
					Name ref = names[p.readU30()];
					int argc = 1 + refArgc[ref.kind];
					e = new Expr(m, op, ref, frame, sp, argc);
					sp -= argc;
					b.add(frame[sp++] = e);
					break;
				}
				
				case OP_getlex:
				{
					Name ref = names[p.readU30()];
					assert(refArgc[ref.kind] == 0);
					e = new Expr(m, OP_findpropstrict, ref, frame, sp, 0);
					e.scopes = capture(frame, scopep, scopep-local_count);
					b.add(e);
					e = new Expr(m, OP_getproperty, ref, new Expr[] { e }, 1, 1);
					b.add(frame[sp++] = e);
					break;
				}

				case OP_findpropstrict:
				case OP_findproperty:
				{
					Name ref = names[p.readU30()];
					int argc = refArgc[ref.kind];
					e = new Expr(m,op, ref, frame, sp, argc);
					e.scopes = capture(frame, scopep, scopep-local_count);
					sp -= argc;
					b.add(frame[sp++] = e);
					break;
				}

				case OP_finddef:
				{
					Name ref = names[p.readU30()];
					int argc = refArgc[ref.kind];
					e = new Expr(m,op, ref, frame, sp, argc);
					sp -= argc;
					b.add(frame[sp++] = e);
					break;
				}
					
				case OP_setproperty:
				case OP_initproperty:
				{
					Name ref = names[p.readU30()];
					int argc = 2 + refArgc[ref.kind];
					e = new Expr(m,op, ref, frame, sp, argc);
					sp -= argc;
					b.add(e);
					break;
				}
				
				case OP_getslot:
				{
					e = new Expr(m,op, p.readU30(), frame, sp, 1);
					b.add(e);
					frame[sp-1] = e;
					break;
				}
				
				case OP_setslot:
				{
					e = new Expr(m,op, p.readU30(), frame, sp, 2);
					b.add(e);
					sp -= 2;
					break;
				}
				
				case OP_jump:
				{
					int offset = p.readS24();
					if (reachable)
					{
						b.add(e = new Expr(m,op));
						e.succ = new Edge[] { new Edge(m,b, 0, blocks.get(p.pos+offset)) };
						merge(m, null, blocks, states, p.pos, frame, sp, scopep);
						merge(m,e.succ[0], blocks, states, p.pos+offset, frame, sp, scopep);
						reachable = false;
					}
					break;
				}

				case OP_iftrue:
				case OP_iffalse:
				{
					b.add(e = new Expr(m, op, frame, sp--, 1));
					int offset = p.readS24();
					e.succ = new Edge[] { 
							new Edge(m,b,0,blocks.get(p.pos)), 
							new Edge(m,b,1,blocks.get(p.pos+offset)) };
					merge(m,null, blocks, states, p.pos, frame, sp, scopep);
					merge(m,e.succ[1], blocks, states, p.pos+offset, frame, sp, scopep);
					break;
				}
				
				case OP_ifnlt:
				case OP_ifnle:
				case OP_ifngt:
				case OP_ifnge:
				case OP_ifne:
				case OP_ifstrictne:
				{
					b.add(e = new Expr(m, ifoper(op), frame, sp, 2));
					traceEntry("ConditionalBranch");
					addTraceAttr(e);
					b.add(e = new Expr(m, OP_iffalse, new Expr[] { e }, 1, 1));
					int offset = p.readS24();
					sp-=2;
					e.succ = new Edge[] { 
							new Edge(m,b,0,blocks.get(p.pos)),
							new Edge(m,b,1,blocks.get(p.pos+offset)) };
					merge(m,null, blocks, states, p.pos, frame, sp, scopep);
					merge(m,e.succ[1], blocks, states, p.pos+offset, frame, sp, scopep);
					break;
				}

				case OP_ifeq:
				case OP_iflt:
				case OP_ifle:
				case OP_ifgt:
				case OP_ifge:
				case OP_ifstricteq:
				{
					b.add(e = new Expr(m, ifoper(op), frame, sp, 2));
					traceEntry("ConditionalBranch");
					addTraceAttr(e);
					b.add(e = new Expr(m, OP_iftrue, new Expr[] { e }, 1, 1));
					int offset = p.readS24();
					sp-=2;
					e.succ = new Edge[] { 
							new Edge(m,b,0,blocks.get(p.pos)),
							new Edge(m,b,1,blocks.get(p.pos+offset)) };
					merge(m,null, blocks, states, p.pos, frame, sp, scopep);
					merge(m,e.succ[1], blocks, states, p.pos+offset, frame, sp, scopep);
					break;
				}
					
				case OP_lookupswitch:
				{
					b.add(e = new Expr(m,op, frame,sp--,1));
					//  Default target
					int target = pos+p.readS24();
					// "There are case_count+1 case offsets."
					int case_count = 1+p.readU30();
					e.succ = new Edge[case_count+1];
					//  Default case goes last.
					e.succ[case_count] = new Edge(m,b, case_count, blocks.get(target));
					merge(m,e.succ[case_count], blocks, states, target, frame, sp, scopep);
					for (int i=0; i < case_count; i++)
					{
						target = pos+p.readS24();
						e.succ[i] = new Edge(m,b, i, blocks.get(target));
						merge(m,e.succ[i], blocks, states, target, frame, sp, scopep);
					}
					
					// no fall-through for switch
					reachable = false;
					break;
				}

				case OP_pushbyte:
				{
					e = frame[sp++] = new Expr(m,op, new Integer((byte)p.readU8()));
					b.add(e);
					break;
				}
				
				case OP_hasnext2:
				{

					int oloc = p.readU30();
					int iloc = p.readU30();
					Expr index = frame[iloc];
					Expr obj = frame[oloc];
					addTraceAttr("index", index);
					addTraceAttr("obj", obj);
					b.add(e = frame[sp] = new Expr(m,op));
					e.locals = new Expr[] { obj, index };
					b.add(e = frame[oloc] = new Expr(m, OP_hasnext2_o));
					e.locals = new Expr[] { obj };
					b.add(e = frame[iloc] = new Expr(m, OP_hasnext2_i));
					e.locals = new Expr[] { index };
					sp++;
					b.must_isolate_block = true;

					break;
				}
				
				case OP_callmethod:
				{
					int id = p.readU30();
					int argc = 1+p.readU30();
					e = new Expr(m,op, id, frame, sp, argc);
					sp -= argc;
					b.add(frame[sp++] = e);
					break;
				}
				
				case OP_callstatic:
				{
					int id = p.readU30();
					int argc = 1+p.readU30();
					e = new Expr(m,op, frame, sp, argc);
					e.m = methods[id];
					sp -= argc;
					b.add(frame[sp++] = e);
					break;
				}
				
				case OP_applytype:
				{
					int argc = 1+p.readU30();
					e = new Expr(m,op, frame, sp, argc);
					sp -= argc;
					b.add(frame[sp++] = e);
					break;
				}
				
				case OP_constructsuper:
				{
					int argc = 1+p.readU30();
					e = new Expr(m,op, frame, sp, argc);
					sp -= argc;
					b.add(e);
					break;
				}
				
				case OP_callsuper:
				case OP_callproperty:
				case OP_constructprop:
				case OP_callproplex:
				{
					Name ref = names[p.readU30()];
					int argc = 1 + p.readU30() + refArgc[ref.kind];
					e = new Expr(m,op, ref, frame, sp, argc);
					sp -= argc;
					b.add(frame[sp++] = e);
					break;
				}
				
				case OP_callsupervoid:
				case OP_callpropvoid:
				{
					Name ref = names[p.readU30()];
					int argc = 1 + p.readU30() + refArgc[ref.kind];
					e = new Expr(m,op, ref, frame, sp, argc);
					sp -= argc;
					b.add(e);
					break;
				}
				
				case OP_debugfile:
				{
					int ii = p.readU30();
					if (!STRIP_DEBUG_INFO)
						b.add(e = new Expr(m,op, strings[ii]));
					addTraceAttr("file", strings[ii]);
					break;
				}	

				case OP_debugline:
				case OP_bkptline:
				{
					int ii = p.readU30();
					if (!STRIP_DEBUG_INFO)
						b.add(e = new Expr(m,op, ii));
					addTraceAttr("line", ii);
					break;
				}
				case OP_debug:
				{
					int i1 = p.readU8();
					int i2 = p.readU30();
					int i3 = p.readU8();
					int i4 = p.readU30();
					if (!STRIP_DEBUG_INFO)
					{
						e = new Expr(m,op);
						e.imm = new int[] { i1, i2, i3, i4 };
						b.add(e);
					}
					break;
				}

				case OP_bkpt:
					if (!STRIP_DEBUG_INFO)
					{
						// no args but position matters
						b.add(new Expr(m,op));
					}
					break;

				case OP_timestamp:
					// no args but position matters
					b.add(new Expr(m,op));
					break;
					
				case OP_nop:
					break;
					
				default:
					System.err.println("Unknown ABC bytecode "+op);
					assert (false);
				}
				

			}			

			dce(m);
			

		}