case move: {
Insn.SD insn = (Insn.SD) insn_;
SourceOperand src = insn.src;
DestinationOperand dst = insn.dest;
Type srcType = getType(current, src);
// Determine type after possible conversion:
Type dstType = srcType;
if (dst.testFReg() != null) {
dstType = Type.DOUBLE_TYPE; // FRegs are always unboxed
} else if (sizeof(current, src) > sizeof(current, dst)) { // Conversion needed
if (srcType.equals(Type.DOUBLE_TYPE)) {
dstType = EDOUBLE_TYPE; // Box
} else {
throw new Error("why?" + insn.toSymbolic()
+ "; srcType="+getType(current,src));
}
}
current = setType(current, dst, dstType);
continue next_insn;
}
case put_string: {
Insn.ByD insn = (Insn.ByD) insn_;
DestinationOperand dst = insn.dest;
current = setType(current, dst, ESEQ_TYPE);
continue next_insn;
}
case jump: {
Insn.L insn = (Insn.L) insn_;
current = branch(current, insn.label, insn_idx);
continue next_insn;
}
case send: {
current.touchx(0, 2);
current = current.setx(0, current.getx(1), FV.this);
continue next_insn;
}
case fnegate: {
Insn.LSD insn = (Insn.LSD)insn_;
EAtom name = insn.opcode().symbol;
SourceOperand[] parms = new SourceOperand[] {
insn.src
};
Type type = getBifResult("erlang", name.getName(),
parmTypes(current, parms), false);
current = setType(current, insn.dest, type);
continue next_insn;
}
case fadd:
case fsub:
case fmul:
case fdiv:
{
Insn.LSSD insn = (Insn.LSSD) insn_;
EAtom name = insn.opcode().symbol;
SourceOperand[] parms = new SourceOperand[] {
insn.src1, insn.src2
};
Type type = getBifResult("erlang", name.getName(),
parmTypes(current, parms), false);
current = setType(current, insn.dest, type);
continue next_insn;
}
case gc_bif1:
case gc_bif2:
case gc_bif3:
{
// {gc_bif,BifName,F,Live,[A1,A2?],Reg};
Insn.GcBif insn = (Insn.GcBif) insn_;
boolean is_guard = (insn.label.nr != 0);
current = branch(current, insn.label, insn_idx);
EAtom name = insn.ext_fun.fun;
SourceOperand[] parms = insn.argList();
Type type = getBifResult("erlang", name.getName(),
parmTypes(current, parms), is_guard);
current = setType(current, insn.dest, type);
continue next_insn;
}
case bif0:
case bif1:
case bif2:
{
Insn.Bif insn = (Insn.Bif) insn_;
current = branch(current, insn.label, insn_idx);
EAtom name = insn.ext_fun.fun;
SourceOperand[] parms = insn.argList();
Type type = getBifResult("erlang", name.getName(),
parmTypes(current, parms), false);
current = setType(current, insn.dest, type);
continue next_insn;
}
case is_tuple: {
if (insn_idx+1 < insns.size()) {
Insn next_insn = insns.get(insn_idx+1);
if (next_insn.opcode() == BeamOpcode.test_arity) {
if (this.map[insn_idx+1] == null) {
this.map[insn_idx+1] = this.map[insn_idx];
}
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!
continue next_insn;
}
}
}
}
}
// 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:
{
try {
current = analyze_test(current, (Insn.L)insn_, insn_idx);
} catch (Error e) {
throw new Error(" at "
+ LabeledBlock.this.block_label + ":"
+ insn_idx, e);
}
assert (current != null);
continue next_insn;
}
case fconv: {
// unbox and convert to DOUBLE
Insn.SD insn = (Insn.SD) insn_;
getType(current, insn.src);
current = setType(current, insn.dest,
Type.DOUBLE_TYPE);
continue next_insn;
}
case init: {
Insn.D insn = (Insn.D) insn_;
current = setType(current, insn.dest, ENIL_TYPE);
continue next_insn;
}
case set_tuple_element: {
Insn.SDI insn = (Insn.SDI) insn_;
getType(current, insn.src);
getType(current, insn.dest);
continue next_insn;
}
case get_tuple_element: {
Insn.SID insn = (Insn.SID) insn_;
getType(current, insn.src);
current = setType(current, insn.dest, EOBJECT_TYPE);
continue next_insn;
}
case get_list: {
Insn.SDD insn = (Insn.SDD) insn_;
current = setType(current, insn.dest1, EOBJECT_TYPE);
Type list_type = getType(current, insn.src);
Type tail_type =
(list_type == ELIST_TYPE || list_type == ESEQ_TYPE)
? ESEQ_TYPE : EOBJECT_TYPE;
current = setType(current, insn.dest2, tail_type);
continue next_insn;
}
case put_list: {
Insn.SSD insn = (Insn.SSD) insn_;
Type head_type = getType(current, insn.src1);
Type tail_type = getType(current, insn.src2);
if (tail_type == null) {
throw new Error("value: " + insn.src2.toSymbolic()
+ " has no type");
}
Type list_type = (tail_type.equals(ENIL_TYPE)
|| tail_type.equals(ESEQ_TYPE)
|| tail_type.equals(ELIST_TYPE))
? ELIST_TYPE : ECONS_TYPE;
current = setType(current, insn.dest, list_type);