*/
}
private void accept_2(BlockVisitor2 vis, BeamExceptionHandler exh) {
int tuple_pos = 0;
Arg tuple_reg = null;
vis.visitBegin(exh);
for (int insn_idx = 0; insn_idx < insns.size(); insn_idx++) {
Insn insn_ = insns.get(insn_idx);
BeamOpcode opcode = insn_.opcode();
TypeMap type_map = this.map[insn_idx];
switch (opcode) {
case func_info: {
Insn.AAI insn = (Insn.AAI)insn_;
// log.finer("go: " + insn);
vis.visitInsn(opcode, insn.getExtFun());
break;
}
case fnegate: {
Insn.LSD insn = (Insn.LSD)insn_;
EAtom name = opcode.symbol;
int failLabel = decode_labelref(insn.label, type_map.exh);
Arg[] in = new Arg[] {src_arg(insn_idx, insn.src)};
Type[] inTypes = new Type[] {in[0].type};
Arg out = dest_arg(insn_idx, insn.dest);
BuiltInFunction bif = BIFUtil.getMethod("erlang", name.getName(), inTypes,
failLabel != 0, true);
vis.visitInsn(opcode, failLabel, in, out, bif);
break;
}
case fconv:
case fmove:
case move: {
Insn.SD insn = (Insn.SD)insn_;
Arg src = src_arg(insn_idx, insn.src);
Arg dest = dest_arg(insn_idx, insn.dest);
if (insns.size() > insn_idx+1) {
Insn next_insn = insns.get(insn_idx+1);
if (next_insn.opcode() == BeamOpcode.K_return) {
vis.visitInsn(BeamOpcode.K_return, src);
insn_idx += 1;
break;
}
}
if (dest.kind != Kind.F) {
if (src.kind == Kind.F) {
dest = new Arg(dest, EDOUBLE_TYPE);
} else {
dest = new Arg(dest, src.type);
}
} else {
// arg2.kind == F
}
vis.visitInsn(opcode, src, dest);
break;
}
case put_string: {
Insn.ByD insn = (Insn.ByD)insn_;
Arg src = src_arg(insn_idx, insn.bin);
Arg dest = dest_arg(insn_idx, insn.dest);
// Arg arg1 = decode_arg(insn_idx, insn.elm(3));
// Arg arg2 = decode_out_arg(insn_idx, insn.elm(4));
dest = new Arg(dest, ESEQ_TYPE);
vis.visitInsn(BeamOpcode.move, src, dest);
break;
}
case fadd:
case fsub:
case fmul:
case fdiv:
{
Insn.LSSD insn = (Insn.LSSD)insn_;
EAtom name = opcode.symbol;
int failLabel = decode_labelref(insn.label, type_map.exh);
Arg[] in = new Arg[] {src_arg(insn_idx, insn.src1),
src_arg(insn_idx, insn.src2)};
Type[] inTypes = new Type[] {in[0].type,
in[1].type};
Arg out = dest_arg(insn_idx, insn.dest);
BuiltInFunction bif = BIFUtil.getMethod("erlang", name.getName(), inTypes,
failLabel != 0, true);
vis.visitInsn(opcode, failLabel, in, out, bif);
break;
}
case bif0:
case bif1:
case bif2:
{
Insn.Bif insn = (Insn.Bif)insn_;
EAtom name = insn.ext_fun.fun;
int failLabel = decode_labelref(insn.label, type_map.exh);
SourceOperand[] srcs = insn.args;
Arg[] in = src_args(insn_idx, srcs);
Arg out = dest_arg(insn_idx, insn.dest);
BuiltInFunction bif = BIFUtil.getMethod("erlang", name.getName(),
parmTypes(type_map, srcs),
failLabel != 0, true);
vis.visitInsn(opcode, failLabel, in, out, bif);
break;
}
case gc_bif1:
case gc_bif2:
case gc_bif3:
{
Insn.GcBif insn = (Insn.GcBif)insn_;
EAtom name = insn.ext_fun.fun;
int failLabel = decode_labelref(insn.label, type_map.exh);
SourceOperand[] srcs = insn.args;
Arg[] in = src_args(insn_idx, srcs);
Arg out = dest_arg(insn_idx, insn.dest);
// special case for X+1, 1+X, X-1.
Int lop = null, rop = null;
if (srcs.length==2
&& (((name==am_plus || name == am_minus) && (rop=srcs[1].testInt()) != null && rop.equals(1))
|| (name==am_plus && (lop=srcs[0].testInt()) != null && lop.equals(1))))
{
if (name == am_plus) {
Arg src = (lop == null) ? in[0] : in[1];
vis.visitIncrement(src, out);
break;
} else if (name == am_minus) {
Arg src = in[0];
vis.visitDecrement(src, out);
break;
}
}
BuiltInFunction bif = BIFUtil.getMethod("erlang", name.getName(),
parmTypes(type_map, srcs),
failLabel != 0, true);
vis.visitInsn(opcode, failLabel, in, out, bif);
break;
}
case is_tuple: {
if (insn_idx+1 < insns.size()) {
Insn next_insn = insns.get(insn_idx+1);
if (next_insn.opcode() == BeamOpcode.test_arity) {
int this_fail = decode_labelref(((Insn.L)insn_).label, this.map[insn_idx].exh);
int next_fail = decode_labelref(((Insn.L)next_insn).label, this.map[insn_idx+1].exh);
if (this_fail == next_fail) {
Arg this_arg = src_arg(insn_idx, ((Insn.LD)insn_).dest);
Arg next_arg = src_arg(insn_idx+1, ((Insn.LD)next_insn).dest);
if (this_arg.equals(next_arg)) {
// SKIP THIS INSTRUCTION!
break;
}
}
}
}
}
// Tests:
// LS:
case is_integer:
case is_float:
case is_number:
case is_atom:
case is_pid:
case is_reference:
case is_port:
case is_nil:
case is_binary:
case is_list:
case is_nonempty_list:
case is_function:
case is_boolean:
case is_bitstr:
// LSI:
case test_arity:
case bs_test_tail2:
case bs_test_unit:
// LSS:
case is_lt:
case is_ge:
case is_eq:
case is_ne:
case is_eq_exact:
case is_ne_exact:
case is_function2:
// LSBi:
case bs_match_string:
// LSII:
case bs_skip_utf8:
case bs_skip_utf16:
case bs_skip_utf32:
// LSIID:
case bs_start_match2:
case bs_get_utf8:
case bs_get_utf16:
case bs_get_utf32:
// LSSII:
case bs_skip_bits2:
// LSISIID:
case bs_get_integer2:
case bs_get_float2:
case bs_get_binary2:
accept_2_test(vis, (Insn.L)insn_, insn_idx);
break;
case K_return:
vis.visitInsn(opcode, new Arg(Arg.Kind.X, 0,
type_map.getx(0)));
break;
case allocate_heap_zero:
case allocate_zero: {
Insn.I insn = (Insn.I)insn_;
int depth = type_map.stacksize;
int count = insn.i1;
Arg[] ys = new Arg[count];
for (int i = 0; i < count; i++) {
ys[i] = new Arg(Arg.Kind.Y, depth + i, null);
}
vis.visitInsn(opcode, (Arg[]) ys);
break;
}
case test_heap:
break;
case fclearerror:
case fcheckerror:
break;
case recv_mark:
case recv_set:
break;
case call_ext_last:
case call_ext_only:
do_call(vis, insn_idx, (Insn.I)insn_, true, true);
break;
case call_ext:
do_call(vis, insn_idx, (Insn.I)insn_, false, true);
if (is_exceptional_call(insn_)) {
vis.visitUnreachablePoint();
}
break;
case call:
do_call(vis, insn_idx, (Insn.I)insn_, false, false);
break;
case call_last:
case call_only:
do_call(vis, insn_idx, (Insn.I)insn_, true, false);
break;
case apply_last:
case apply: {
Insn.I insn = (Insn.I) insn_;
Arg[] args = new Arg[2 + insn.i1];
for (int i = 0; i < args.length; i++) {
args[i] = new Arg(Arg.Kind.X, i, map[insn_idx]
.getx(i));
}
vis.visitInsn(opcode, args);
break;
}
case make_fun2: {
Insn.F insn = (Insn.F) insn_;
ExtFun efun = insn.anon_fun.asExtFun();
int numfree = insn.anon_fun.free_vars;
int index = insn.anon_fun.index;
int old_index = insn.anon_fun.old_index;
EBinary uniq = insn.anon_fun.mod_md5;
int old_uniq = insn.anon_fun.old_uniq;
Arg[] free = new Arg[numfree];
for (int i = 0; i < numfree; i++) {
free[i] = new Arg(Arg.Kind.X, i, map[insn_idx]
.getx(i));
}
vis.visitInsn(opcode, efun, free, index, old_index, uniq, old_uniq);
break;
}
case init: {
Insn.D insn = (Insn.D) insn_;
vis.visitInsn(opcode, dest_arg(insn_idx, insn.dest));
break;
}
case put_list: {
Insn.SSD insn = (Insn.SSD) insn_;
Arg[] in = new Arg[] {
src_arg(insn_idx, insn.src1),
src_arg(insn_idx, insn.src2)
};
Arg out = dest_arg(insn_idx, insn.dest);
vis.visitInsn(opcode, in, out);
break;
}
case put_tuple: {
Insn.ID insn = (Insn.ID) insn_;
int arity = insn.i1;
Arg[] puts = new Arg[arity];
boolean simple_tuple_create = true;
for (int i = 1; i <= arity; i++) {
if (insns.get(insn_idx+i).opcode() == BeamOpcode.put) {
Insn.S put_insn = (Insn.S) insns.get(insn_idx+i);
puts[i-1] = src_arg(insn_idx+i, put_insn.src);
continue;
}
simple_tuple_create = false;
break;
}
if (simple_tuple_create) {
tuple_reg = new Arg(dest_arg(insn_idx, insn.dest),
getTupleType(arity));
insn_idx += arity;
vis.visitMakeTuple(arity, tuple_reg, puts);
} else {
tuple_reg = new Arg(dest_arg(insn_idx, insn.dest),
getTupleType(arity));
vis.visitInsn(opcode, arity, tuple_reg);
tuple_pos = 1;
}
break;
}
case put: {
Insn.S insn = (Insn.S) insn_;
Arg val = src_arg(insn_idx, insn.src);
vis.visitInsn(opcode, val, tuple_reg, tuple_pos++);
break;
}
case set_tuple_element: {
Insn.SDI insn = (Insn.SDI) insn_;
Arg in = src_arg(insn_idx, insn.src);
Arg out = src_arg(insn_idx, insn.dest);
int idx = insn.i;
vis.visitInsn(opcode, in, out, idx);
break;
}
case allocate_heap:
case allocate:
case deallocate: {
// need to zero out refs?
break;
}
case select_tuple_arity: {
Insn.Select insn = (Insn.Select) insn_;
int failLabel = decode_labelref(insn.defaultLabel,
type_map.exh);
Arg in = src_arg(insn_idx, insn.src);
Operands.SelectList jumpTable = insn.jumpTable;
int len = jumpTable.size();
int[] arities = new int[len];
int[] targets = new int[len];
for (int i=0; i<len; i++) {
Operands.Operand value = jumpTable.getValue(i);
Operands.Label target = jumpTable.getLabel(i);
arities[i] = value.asCodeInt().value;
targets[i] = decode_labelref(target, type_map.exh);
}
vis.visitSelectTuple(in, failLabel, arities, targets);
break;
}
case select_val: {
Insn.Select insn = (Insn.Select) insn_;
int failLabel = decode_labelref(insn.defaultLabel,
type_map.exh);
Arg in = src_arg(insn_idx, insn.src);
Operands.SelectList jumpTable = insn.jumpTable;
int len = jumpTable.size();
Arg[] values = new Arg[len];
int[] targets = new int[len];
for (int i=0; i<len; i++) {
Operands.Operand value = jumpTable.getValue(i);
Operands.Label target = jumpTable.getLabel(i);
values[i] = arg(value.asLiteral());
targets[i] = decode_labelref(target, type_map.exh);
}
vis.visitSelectValue(in, failLabel, values, targets);
break;
}
case get_tuple_element: {
Insn.SID insn = (Insn.SID) insn_;
Arg in = src_arg(insn_idx, insn.src);
int idx = insn.i;
Arg out = dest_arg(insn_idx, insn.dest);
vis.visitInsn(opcode, in, out, idx);
break;
}
case jump: {
Insn.L insn = (Insn.L) insn_;
vis.visitJump(decode_labelref(insn.label, type_map.exh));
break;
}
case line: // TODO!
vis.visitLine(((Insn.I)insn_).i1);
case on_load: // ignore
case trim:
break;
case get_list: {
Insn.SDD insn = (Insn.SDD) insn_;
vis.visitInsn(opcode, new Arg[] {
src_arg(insn_idx, insn.src),
dest_arg(insn_idx, insn.dest1),
dest_arg(insn_idx, insn.dest2) });
break;
}
case try_case_end:
case badmatch:
case case_end: {
Insn.S insn = (Insn.S) insn_;
vis.visitInsn(opcode, src_arg(insn_idx, insn.src));
break;
}
case if_end:
vis.visitInsn(opcode);
break;
case send: {
vis.visitInsn(opcode,
new Arg[] { new Arg(Arg.Kind.X, 0),
new Arg(Arg.Kind.X, 1) });
break;
}
case K_try:{
Insn.YL insn = (Insn.YL) insn_;
TypeMap type_map_after = this.map[insn_idx+1];
vis.visitCatchBlockStart(opcode,
decode_labelref(insn.label, type_map.exh),
src_arg(insn_idx, insn.y),
type_map_after.exh);
break;
}
case K_catch: {
Insn.YL insn = (Insn.YL) insn_;
TypeMap type_map_after = this.map[insn_idx+1];
vis.visitCatchBlockStart(opcode,
decode_labelref(insn.label, type_map.exh),
src_arg(insn_idx, insn.y),
type_map_after.exh);
break;
}
case raise: {
Insn.SS insn = (Insn.SS) insn_;
Arg[] in = {src_arg(insn_idx, insn.src1),
src_arg(insn_idx, insn.src2) };
Arg ex = new Arg(Arg.Kind.X, 0);
int failLabel = 0;
// Half of the args are constants...
vis.visitInsn(opcode, failLabel, in, ex);
break;
}
case try_end:
case try_case:
case catch_end: {
Insn.Y insn = (Insn.Y) insn_;
vis.visitCatchBlockEnd(opcode,
src_arg(insn_idx, insn.y),
type_map.exh);
break;
}
case loop_rec: { /* loop receive */
Insn.LD insn = (Insn.LD) insn_;
vis.visitReceive(opcode,
decode_labelref(insn.label, type_map.exh),
dest_arg(insn_idx, insn.dest));
break;
}
case remove_message:
case timeout:
vis.visitInsn(opcode);
break;
case loop_rec_end:
case wait: {
Insn.L insn = (Insn.L) insn_;
vis.visitInsn(opcode, decode_labelref(insn.label, type_map.exh), null);
break;
}
case wait_timeout: {
Insn.LS insn = (Insn.LS) insn_;
vis.visitInsn(opcode,
decode_labelref(insn.label, type_map.exh),
src_arg(insn_idx, insn.src));
break;
}
case call_fun:
case i_call_fun_last: {
Insn.I insn = (Insn.I) insn_;
int nargs = insn.i1;
Arg[] args = new Arg[nargs + 1];
for (int i = 0; i < args.length; i++) {
args[i] = new Arg(Arg.Kind.X, i, map[insn_idx]
.getx(i));
}
vis.visitInsn(opcode, args,
new Arg(Arg.Kind.X, 0, null));
break;
}
// {bs_add,{f,0},[{x,3},{x,4},1],{x,3}}
case bs_add: {
Insn.LSSID insn = (Insn.LSSID) insn_;
vis.visitBSAdd(src_arg(insn_idx, insn.src1),
src_arg(insn_idx, insn.src2),
insn.i3,
dest_arg(insn_idx, insn.dest));
break;
}
case bs_context_to_binary: {
Insn.D insn = (Insn.D) insn_;
vis.visitBS(opcode, dest_arg(insn_idx, insn.dest), null, 0);
// do nothing for now
break;
}
case bs_restore2:
case bs_save2: {
Insn.DI insn = (Insn.DI) insn_;
vis.visitBS(opcode, src_arg(insn_idx, insn.dest),
//TODO: streamline - change API
insn.i2 == -1
? new Arg(EAtom.intern("start"))
: new Arg(new ESmall(insn.i2)), 0
);
break;
}
case bs_init_writable: {
Arg size = src_arg(insn_idx, new Operands.XReg(0));
Arg dest = dest_arg(new Operands.XReg(0));
vis.visitInitWritable(size, dest);
break;
}
case bs_init2:
case bs_init_bits: {
Insn.LSIIID insn = (Insn.LSIIID) insn_;
Arg size = src_arg(insn_idx, insn.src2);
int flags = insn.i5;
Arg out = dest_arg(insn_idx, insn.dest);
boolean unit_is_bits = (opcode == BeamOpcode.bs_init_bits);
vis.visitInitBitString(size, flags, out,
unit_is_bits);
break;
}
case bs_put_string: {
Insn.By insn = (Insn.By) insn_;
Arg str = arg(insn.bin);
vis.visitBitStringPut(opcode, str, null,-1,-1);
break;
}
case bs_put_binary:
case bs_put_integer:
case bs_put_float:
{
Insn.LSIIS insn = (Insn.LSIIS) insn_;
Arg size = src_arg(insn_idx, insn.src2);
int unit = insn.i3;
int flags = insn.i4;
Arg value = src_arg(insn_idx, insn.src5);
vis.visitBitStringPut(opcode, value, size, unit, flags);
break;
}
case bs_put_utf8:
case bs_put_utf16:
case bs_put_utf32:
{
Insn.LIS insn = (Insn.LIS) insn_;
int flags = insn.i2;
Arg value = src_arg(insn_idx, insn.src);
//TODO: is the label always 0? (Op may fail on bad chars)
vis.visitBitStringPut(opcode, value, null, -1, flags);
break;
}
case bs_utf8_size:
case bs_utf16_size: {
Insn.LSD insn = (Insn.LSD) insn_;
Arg value = src_arg(insn_idx, insn.src);
Arg out = dest_arg(insn_idx, insn.dest);
int label = decode_labelref(insn.label, type_map.exh);
vis.visitBS(opcode, value, out, label);
break;
}
case bs_private_append: {
Insn.BSPrivateAppend insn = (Insn.BSPrivateAppend) insn_;
// {bs_private_append,{f,0},{integer,8},1,{y,0},{field_flags,[]},{x,1}}.
// * tmp_arg1 = Number of bytes to build
// * tmp_arg2 = Source binary
// * Operands: Fail Unit Dst
Arg extra_size = src_arg(insn_idx, insn.src2);
Arg src = src_arg(insn_idx, insn.src4);
int unit = insn.i3;
int flags = insn.i5;
Arg dst = dest_arg(insn_idx, insn.dest);
vis.visitBitStringAppend(opcode, decode_labelref(insn.label, type_map.exh), extra_size, src, unit, flags, dst);
break;
}
case bs_append: {
Insn.BSAppend insn = (Insn.BSAppend) insn_;
// {bs_append,{f,0},{integer,32},0,3,8,{x,1},{field_flags,[]},{x,0}}.
// * tmp_arg1 = Number of bytes to build
// * tmp_arg2 = Source binary
// * Operands: Fail ExtraHeap Live Unit Dst
Arg extra_size = src_arg(insn_idx, insn.src2);
Arg src = src_arg(insn_idx, insn.src6);
int unit = insn.i5;
int flags = insn.i7;
Arg dst = dest_arg(insn_idx, insn.dest8);
vis.visitBitStringAppend(opcode, decode_labelref(insn.label, type_map.exh), extra_size, src, unit, flags, dst);
break;
}
//default: