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);
}