/** -*- tab-width: 4 -*- * This file is part of Erjang - A JVM-based Erlang VM * * Copyright (c) 2010 by Trifork * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **/ package erjang.beam.repr; import static erjang.beam.CodeAtoms.ARITHFBIF_ATOM; import static erjang.beam.CodeAtoms.ATOM_ATOM; import static erjang.beam.CodeAtoms.BIF_ATOM; import static erjang.beam.CodeAtoms.FIELD_FLAGS_ATOM; import static erjang.beam.CodeAtoms.F_ATOM; import static erjang.beam.CodeAtoms.GCBIF_ATOM; import static erjang.beam.CodeAtoms.NOFAIL_ATOM; import static erjang.beam.CodeAtoms.START_ATOM; import static erjang.beam.CodeAtoms.TEST_ATOM; import erjang.EList; import erjang.EObject; import erjang.ERT; import erjang.ESmall; import erjang.ETuple; import erjang.beam.BeamInstruction; import erjang.beam.BeamOpcode; import erjang.beam.repr.Operands.AllocList; import erjang.beam.repr.Operands.Atom; import erjang.beam.repr.Operands.BitString; import erjang.beam.repr.Operands.ByteString; import erjang.beam.repr.Operands.DestinationOperand; import erjang.beam.repr.Operands.Label; import erjang.beam.repr.Operands.SelectList; import erjang.beam.repr.Operands.SourceOperand; import erjang.beam.repr.Operands.XReg; import erjang.beam.repr.Operands.YReg; public class Insn implements BeamInstruction { protected final BeamOpcode opcode; public Insn(BeamOpcode opcode) {this.opcode = opcode;} public BeamOpcode opcode() {return opcode;} public String toString() {return toSymbolic().toString();} public EObject toSymbolic() { return opcode.symbol; } public final ETuple toSymbolicTuple() { EObject symInsn0 = toSymbolic(); ETuple symInsn = (symInsn0 instanceof ETuple)? ((ETuple)symInsn0) : ETuple.make(symInsn0); return symInsn; } private static EObject NOFAIL_REPR = ETuple.make(F_ATOM, new ESmall(0)); private static EObject START_REPR = ETuple.make(ATOM_ATOM, START_ATOM); static EObject labelToSymbolic(Label label) { return label==null? NOFAIL_REPR : label.toSymbolic(); } static EObject labelToSymbolic_nf(Label label) { return label==null? NOFAIL_ATOM : label.toSymbolic(); } static EObject bsFieldFlagsToSymbolic(int flags) { return ETuple.make(FIELD_FLAGS_ATOM, new ESmall(flags)); } /*============================================================ * Instruction formats * Class names encode the format - the parameter types - as follows: * I - Integer * A - Atom * Bi - Bitstring * By - Bytestring * S - Source operand: register or literal * D - Destination operand: register * L - Label * K - Optional label (fail label) * E - External function * F - Anonymous function object * W - Allocation size */ public static class I extends Insn { // E.g. 'deallocate' public final int i1; public I(BeamOpcode opcode, int i1) { super(opcode); this.i1 = i1; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, new ESmall(i1)); } } public static class S extends Insn { // E.g. 'put' public final SourceOperand src; public S(BeamOpcode opcode, SourceOperand src) { super(opcode); this.src = src; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, src.toSymbolic()); } } public static class D extends Insn { // E.g. 'init' public final DestinationOperand dest; public D(BeamOpcode opcode, DestinationOperand dest) { super(opcode); this.dest = dest; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, dest.toSymbolic()); } } public static class L extends Insn { // E.g. 'jump' public final Label label; public L(BeamOpcode opcode, Label label) { super(opcode); this.label = label; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, label.toSymbolic()); } } public static class F extends Insn { // E.g. 'make_fun2' public final int anon_fun_no; public final AnonFun anon_fun; public F(BeamOpcode opcode, int anon_fun_no, AnonFun anon_fun) { super(opcode); this.anon_fun_no = anon_fun_no; this.anon_fun = anon_fun; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, anon_fun.toSymbolic(), new ESmall(anon_fun_no), new ESmall(anon_fun.old_uniq), new ESmall(anon_fun.free_vars)); } } public static class Y extends Insn { // E.g. 'catch' public final YReg y; public Y(BeamOpcode opcode, YReg y) { super(opcode); this.y = y; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, y.toSymbolic()); } } public static class By extends Insn { // E.g. 'bs_put_string' public final ByteString bin; public By(BeamOpcode opcode, ByteString bin) { super(opcode); this.bin = bin; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, new ESmall(bin.byteLength()), bin.toSymbolic()); } } public static class DI extends Insn { // E.g. 'bs_save2' public final DestinationOperand dest; public final int i2; public final boolean is_saverestore; public DI(BeamOpcode opcode, DestinationOperand dest, int i2, boolean is_saverestore) { super(opcode); this.dest = dest; this.i2 = i2; this.is_saverestore = is_saverestore; } public ETuple toSymbolic() { if (is_saverestore) return ETuple.make(opcode.symbol, dest.toSymbolic(), (i2==-1 ? START_REPR : new ESmall(i2))); else return ETuple.make(opcode.symbol, dest.toSymbolic(), new ESmall(i2)); } } public static class SD extends Insn { // E.g. 'move' public final SourceOperand src; public final DestinationOperand dest; public SD(BeamOpcode opcode, SourceOperand src, DestinationOperand dest) { super(opcode); this.src = src; this.dest = dest; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, src.toSymbolic(), dest.toSymbolic()); } } public static class LD extends L { // E.g. 'loop_rec' public final DestinationOperand dest; public final boolean is_test; public LD(BeamOpcode opcode, Label label, DestinationOperand dest) { super(opcode, label); this.dest = dest; this.is_test = false; } public LD(BeamOpcode opcode, Label label, DestinationOperand dest, boolean is_test) { super(opcode, label); this.dest = dest; this.is_test = is_test; } public ETuple toSymbolic() { if (is_test) return ETuple.make(TEST_ATOM, opcode.symbol, label.toSymbolic(), EList.make(dest.toSymbolic())); else return ETuple.make(opcode.symbol, label.toSymbolic(), dest.toSymbolic()); } } public static class YL extends Insn { // E.g. 'catch' public final YReg y; public final Label label; public YL(BeamOpcode opcode, YReg y, Label label) { super(opcode); this.y = y; this.label = label; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, y.toSymbolic(), label.toSymbolic()); } } public static class LS extends L { // E.g. 'is_nil' public final SourceOperand src; public final boolean is_test; public LS(BeamOpcode opcode, Label label, SourceOperand src, boolean is_test) { super(opcode, label); this.src = src; this.is_test = is_test; } public ETuple toSymbolic() { if (is_test) return ETuple.make(TEST_ATOM, opcode.symbol, label.toSymbolic(), EList.make(src.toSymbolic())); else return ETuple.make(opcode.symbol, label.toSymbolic(), src.toSymbolic()); } } public static class II extends I { // E.g. 'allocate' public final int i2; public II(BeamOpcode opcode, int i1, int i2) { super(opcode, i1); this.i2 = i2; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, new ESmall(i1), new ESmall(i2)); } } public static class IL extends I { // E.g. 'call' public final Label label; public final boolean is_call; public final FunctionInfo functionAtLabel; public IL(BeamOpcode opcode, int i1, Label label, FunctionInfo fal) { super(opcode, i1); this.label = label; this.is_call = true; this.functionAtLabel = fal; } public ETuple toSymbolic() { if (is_call) return ETuple.make(opcode.symbol, new ESmall(i1), functionAtLabel.toSymbolic()); else return ETuple.make(opcode.symbol, new ESmall(i1), label.toSymbolic()); } } public static class SS extends Insn { // E.g. 'raise' public final SourceOperand src1, src2; public SS(BeamOpcode opcode, SourceOperand src1, SourceOperand src2) { super(opcode); this.src1 = src1; this.src2 = src2; } public ETuple toSymbolic() { if (opcode == BeamOpcode.raise) return ETuple.make(opcode.symbol, new Label(0).toSymbolic(), EList.make(src1.toSymbolic(), src2.toSymbolic()), XReg.get(0).toSymbolic()); else return ETuple.make(opcode.symbol, src1.toSymbolic(), src2.toSymbolic()); } } public static class AAI extends Insn { // E.g. 'func_info' public final Atom a1,a2; public final int i3; public AAI(BeamOpcode opcode, Atom a1, Atom a2, int i3) { super(opcode); this.a1 = a1; this.a2 = a2; this.i3 = i3; } public ExtFun getExtFun() { return new ExtFun(a1.getEAtom(), a2.getEAtom(), i3); } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, a1.toSymbolic(), a2.toSymbolic(), new ESmall(i3)); } } public static class IE extends I { // E.g. 'call_ext' public final ExtFun ext_fun; public IE(BeamOpcode opcode, int i1, ExtFun ext_fun) { super(opcode, i1); this.ext_fun = ext_fun; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, new ESmall(i1), ext_fun.toSymbolic()); } } public static class ID extends Insn { // E.g. 'put_tuple' public final int i1; public final DestinationOperand dest; public ID(BeamOpcode opcode, int i1, DestinationOperand dest) { super(opcode); this.i1 = i1; this.dest = dest; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, new ESmall(i1), dest.toSymbolic()); } } public static class WI extends Insn { // E.g. 'test_heap' public final AllocList alist; public final int i2; public WI(BeamOpcode opcode, AllocList alist, int i2) { super(opcode); this.alist = alist; this.i2 = i2; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, alist.toSymbolic(), new ESmall(i2)); } } public static class IWI extends I { // E.g. 'allocate_heap' public final int i3; public final AllocList al; public IWI(BeamOpcode opcode, int i1, AllocList al, int i3) { super(opcode, i1); this.al = al; this.i3 = i3; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, new ESmall(i1), al.toSymbolic(), new ESmall(i3)); } } public static class LDI extends LD { // E.g. 'test_arity' public final int i; public LDI(BeamOpcode opcode, Label label, DestinationOperand dest, int i, boolean is_test) { super(opcode, label, dest, is_test); this.i = i; } public ETuple toSymbolic() { if (is_test) return ETuple.make(TEST_ATOM, opcode.symbol, label.toSymbolic(), EList.make(dest.toSymbolic(), new ESmall(i))); else return ETuple.make(opcode.symbol, label.toSymbolic(), dest.toSymbolic(), new ESmall(i)); } } public static class SID extends Insn { // E.g. 'get_tuple_element' public final SourceOperand src; public final int i; public final DestinationOperand dest; public SID(BeamOpcode opcode, SourceOperand src, int i, DestinationOperand dest) { super(opcode); this.src = src; this.i = i; this.dest = dest; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, src.toSymbolic(), new ESmall(i), dest.toSymbolic()); } } public static class LSS extends L { // E.g. 'is_eq_exact' public final SourceOperand src1, src2; public final boolean is_test; public LSS(BeamOpcode opcode, Label label, SourceOperand src1, SourceOperand src2, boolean is_test) { super(opcode, label); this.src1 = src1; this.src2 = src2; this.is_test = is_test; } public ETuple toSymbolic() { if (is_test) return ETuple.make(TEST_ATOM, opcode.symbol, label.toSymbolic(), EList.make(src1.toSymbolic(), src2.toSymbolic())); else return ETuple.make(opcode.symbol, label.toSymbolic(), src1.toSymbolic(), src2.toSymbolic()); } } public static class LDS extends LD { // E.g. 'is_function2' public final SourceOperand src; public LDS(BeamOpcode opcode, Label label, DestinationOperand dest, SourceOperand src, boolean is_test) { super(opcode, label, dest, is_test); this.src = src; } public ETuple toSymbolic() { if (is_test) return ETuple.make(TEST_ATOM, opcode.symbol, label.toSymbolic(), EList.make(dest.toSymbolic(), src.toSymbolic())); else return ETuple.make(opcode.symbol, label.toSymbolic(), dest.toSymbolic(), src.toSymbolic()); } } public static class LSD extends Insn { // E.g. 'bs_utf8_size' public final Label label; public final SourceOperand src; public final DestinationOperand dest; public LSD(BeamOpcode opcode, Label label, SourceOperand src, DestinationOperand dest) { super(opcode); this.label = label; this.src = src; this.dest = dest; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, label.toSymbolic(), src.toSymbolic(), dest.toSymbolic()); } } public static class SDD extends Insn { // E.g. 'get_list' public final SourceOperand src; public final DestinationOperand dest1; public final DestinationOperand dest2; public SDD(BeamOpcode opcode, SourceOperand src, DestinationOperand dest1, DestinationOperand dest2) { super(opcode); this.src = src; this.dest1 = dest1; this.dest2 = dest2; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, src.toSymbolic(), dest1.toSymbolic(), dest2.toSymbolic()); } } public static class SSD extends Insn { // E.g. 'move' public final SourceOperand src1; public final SourceOperand src2; public final DestinationOperand dest; public SSD(BeamOpcode opcode, SourceOperand src1, SourceOperand src2, DestinationOperand dest) { super(opcode); this.src1 = src1; this.src2 = src2; this.dest = dest; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, src1.toSymbolic(), src2.toSymbolic(), dest.toSymbolic()); } } public static class SDI extends Insn { // E.g. 'set_tuple_element' public final SourceOperand src; public final DestinationOperand dest; public final int i; public SDI(BeamOpcode opcode, SourceOperand src, DestinationOperand dest, int i) { super(opcode); this.src = src; this.dest = dest; this.i = i; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, src.toSymbolic(), dest.toSymbolic(), new ESmall(i)); } } public static class ILI extends IL { // E.g. 'call' public final int i3; public final boolean is_call; public ILI(BeamOpcode opcode, int i1, Label label, int i3, FunctionInfo fal) { super(opcode, i1, label, fal); this.i3 = i3; this.is_call = true; } public ETuple toSymbolic() { if (is_call) return ETuple.make(opcode.symbol, new ESmall(i1), functionAtLabel.toSymbolic(), new ESmall(i3)); else return ETuple.make(opcode.symbol, new ESmall(i1), label.toSymbolic(), new ESmall(i3)); } } public static class IEI extends IE { // E.g. 'call' public final int i3; public IEI(BeamOpcode opcode, int i1, ExtFun ext_fun, int i3) { super(opcode, i1, ext_fun); this.i3 = i3; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, new ESmall(i1), ext_fun.toSymbolic(), new ESmall(i3)); } } public static class ByD extends Insn { // E.g. 'put_string' public final ByteString bin; public final DestinationOperand dest; public ByD(BeamOpcode opcode, ByteString bin, DestinationOperand dest) { super(opcode); this.bin = bin; this.dest = dest; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, new ESmall(bin.byteLength()), bin.toSymbolic(), dest.toSymbolic()); } } public static class LSSD extends Insn { // E.g. 'fmul' public final Label label; public final SourceOperand src1; public final SourceOperand src2; public final DestinationOperand dest; public final boolean is_arithfbif; public LSSD(BeamOpcode opcode, Label label, SourceOperand src1, SourceOperand src2, DestinationOperand dest, boolean is_arithfbif) { super(opcode); this.label = label; this.src1 = src1; this.src2 = src2; this.dest = dest; this.is_arithfbif = is_arithfbif; } public ETuple toSymbolic() { if (is_arithfbif) return ETuple.make(ARITHFBIF_ATOM, opcode.symbol, label.toSymbolic(), EList.make(src1.toSymbolic(), src2.toSymbolic()), dest.toSymbolic()); else return ETuple.make(opcode.symbol, label.toSymbolic(), src1.toSymbolic(), src2.toSymbolic(), dest.toSymbolic()); } } public static class LSSID extends Insn { // E.g. 'bs_add' public final Label label; public final SourceOperand src1; public final SourceOperand src2; public final int i3; public final DestinationOperand dest; public LSSID(BeamOpcode opcode, Label label, SourceOperand src1, SourceOperand src2, int i3, DestinationOperand dest) { super(opcode); this.label = label; this.src1 = src1; this.src2 = src2; this.i3 = i3; this.dest = dest; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, label.toSymbolic(), EList.make(src1.toSymbolic(), src2.toSymbolic(), new ESmall(i3)), dest.toSymbolic()); } } public static class LDBi extends LD { // E.g. 'bs_match_string' public final BitString bin; public LDBi(BeamOpcode opcode, Label label, DestinationOperand dest, BitString bin) { super(opcode, label, dest, true); this.bin = bin; } public ETuple toSymbolic() { return ETuple.make(TEST_ATOM, opcode.symbol, label.toSymbolic(), EList.make(dest.toSymbolic(), ERT.box(bin.bitLength()), bin.toSymbolic())); } } public static class LDII extends LD { // E.g. 'bs_skip_utf8' public final int i3, i4; public LDII(BeamOpcode opcode, Label label, DestinationOperand dest, int i3, int i4) { super(opcode, label, dest, true); this.i3 = i3; this.i4 = i4; } public ETuple toSymbolic() { return ETuple.make(TEST_ATOM, opcode.symbol, label.toSymbolic(), EList.make(dest.toSymbolic(), new ESmall(i3), bsFieldFlagsToSymbolic(i4))); } } public static class LSIIS extends Insn { // E.g. 'bs_put_integer' public final Label label; public final SourceOperand src2, src5; public final int i3, i4; public final boolean is_bs; public LSIIS(BeamOpcode opcode, Label label, SourceOperand src2, int i3, int i4, SourceOperand src5, boolean is_bs) { super(opcode); this.label = label; this.src2 = src2; this.i3 = i3; this.i4 = i4; this.src5 = src5; this.is_bs = is_bs; } public ETuple toSymbolic() { if (is_bs) return ETuple.make(opcode.symbol, label.toSymbolic(), src2.toSymbolic(), new ESmall(i3), bsFieldFlagsToSymbolic(i4), src5.toSymbolic()); else throw new erjang.NotImplemented(); } } public static class LIS extends Insn { // E.g. 'bs_put_utf8' public final Label label; public final int i2; public final SourceOperand src; public final boolean is_bsput; public LIS(BeamOpcode opcode, Label label, int i2, SourceOperand src, boolean is_bsput) { super(opcode); this.label = label; this.i2 = i2; this.src = src; this.is_bsput = is_bsput; } public ETuple toSymbolic() { if (is_bsput) return ETuple.make(opcode.symbol, label.toSymbolic(), bsFieldFlagsToSymbolic(i2), src.toSymbolic()); else throw new erjang.NotImplemented(); } } public static class LDIID extends LD { // E.g. 'bs_start_match2' public final int i3, i4; public final DestinationOperand dest5; public final boolean i4_is_bsflags; public LDIID(BeamOpcode opcode, Label label, DestinationOperand dest2, int i3, int i4, DestinationOperand dest5, boolean i4_is_bsflags) { super(opcode, label, dest2, true); this.i3 = i3; this.i4 = i4; this.dest5 = dest5; this.i4_is_bsflags = i4_is_bsflags; } public ETuple toSymbolic() { return ETuple.make(TEST_ATOM, opcode.symbol, label.toSymbolic(), EList.make(dest.toSymbolic(), new ESmall(i3), i4_is_bsflags ? bsFieldFlagsToSymbolic(i4) : new ESmall(i4), dest5.toSymbolic())); } } public static class LSIIID extends Insn { // E.g. 'bs_init2' public final Label label; public final SourceOperand src2; public final int i3, i4,i5; public final DestinationOperand dest; public final boolean is_bs; public LSIIID(BeamOpcode opcode, Label label, SourceOperand src2, int i3, int i4, int i5, DestinationOperand dest, boolean is_bs) { super(opcode); this.label = label; this.src2 = src2; this.i3 = i3; this.i4 = i4; this.i5 = i5; this.dest = dest; this.is_bs = is_bs; } public ETuple toSymbolic() { if (is_bs) return ETuple.make(opcode.symbol, labelToSymbolic(label), src2.toSymbolic(), new ESmall(i3), new ESmall(i4), bsFieldFlagsToSymbolic(i5), dest.toSymbolic()); else throw new erjang.NotImplemented(); } } public static class LDSII extends LD { // E.g. 'bs_skip_bits2' public final SourceOperand src3; public final int i4, i5; public LDSII(BeamOpcode opcode, Label label, DestinationOperand dest, SourceOperand src3, int i4, int i5) { super(opcode, label, dest, true); this.src3 = src3; this.i4 = i4; this.i5 = i5; } public ETuple toSymbolic() { return ETuple.make(TEST_ATOM, opcode.symbol, label.toSymbolic(), EList.make(dest.toSymbolic(), src3.toSymbolic(), new ESmall(i4), bsFieldFlagsToSymbolic(i5))); } } public static class LDISIID extends LD { // E.g. 'bs_get_integer2' public final int i3; public final SourceOperand src4; public final int i5, i6; public final DestinationOperand dest7; public LDISIID(BeamOpcode opcode, Label label, DestinationOperand dest2, int i3, SourceOperand src4, int i5, int i6, DestinationOperand dest7) { super(opcode, label, dest2, true); this.i3 = i3; this.src4 = src4; this.i5 = i5; this.i6 = i6; this.dest7 = dest7; } public ETuple toSymbolic() { if (is_test) return ETuple.make(TEST_ATOM, opcode.symbol, label.toSymbolic(), EList.make(dest.toSymbolic(), new ESmall(i3), src4.toSymbolic(), new ESmall(i5), bsFieldFlagsToSymbolic(i6), dest7.toSymbolic())); else throw new erjang.NotImplemented(); } } //============================================================ public static class Bif extends Insn { // 'bif0-2' public final Label label; public final ExtFun ext_fun; public final SourceOperand[] args; public final DestinationOperand dest; protected Bif(BeamOpcode opcode, Label label, ExtFun ext_fun, SourceOperand[] args, DestinationOperand dest) { super(opcode); this.label = label; this.ext_fun = ext_fun; this.dest = dest; this.args = args; } private static SourceOperand[] NO_ARGS = new SourceOperand[] {}; public Bif(BeamOpcode opcode, Label label, ExtFun ext_fun, DestinationOperand dest) { this(opcode, label, ext_fun, NO_ARGS, dest); } public Bif(BeamOpcode opcode, Label label, ExtFun ext_fun, SourceOperand src, DestinationOperand dest) { this(opcode, label, ext_fun, new SourceOperand[] {src}, dest); } public Bif(BeamOpcode opcode, Label label, ExtFun ext_fun, SourceOperand src1, SourceOperand src2, DestinationOperand dest) { this(opcode, label, ext_fun, new SourceOperand[] {src1, src2}, dest); } public SourceOperand[] argList() {return args;} public ETuple toSymbolic() { return ETuple.make(BIF_ATOM, ext_fun.fun, labelToSymbolic_nf(label), Operands.toSymbolicList(args), dest.toSymbolic()); } } public static class GcBif extends Insn { // 'gc_bif1-2' public final Label label; public final ExtFun ext_fun; public final int i; public final SourceOperand[] args; public final DestinationOperand dest; protected GcBif(BeamOpcode opcode, Label label, ExtFun ext_fun, int i, SourceOperand[] args, DestinationOperand dest) { super(opcode); this.label = label; this.ext_fun = ext_fun; this.i = i; this.args = args; this.dest = dest; } public GcBif(BeamOpcode opcode, Label label, ExtFun ext_fun, int i, SourceOperand src, DestinationOperand dest) { this(opcode, label, ext_fun, i, new SourceOperand[]{src}, dest); } public GcBif(BeamOpcode opcode, Label label, ExtFun ext_fun, int i, SourceOperand src1, SourceOperand src2, DestinationOperand dest) { this(opcode, label, ext_fun, i, new SourceOperand[]{src1,src2}, dest); } public GcBif(BeamOpcode opcode, Label label, ExtFun ext_fun, int i, SourceOperand src1, SourceOperand src2, SourceOperand src3, DestinationOperand dest) { this(opcode, label, ext_fun, i, new SourceOperand[]{src1,src2,src3}, dest); } public SourceOperand[] argList() {return args;} public ETuple toSymbolic() { return ETuple.make(GCBIF_ATOM, ext_fun.fun, label.toSymbolic(), new ESmall(i), Operands.toSymbolicList(args), dest.toSymbolic()); } } public static class Select extends Insn { // E.g. 'select_val' public final SourceOperand src; public final Label defaultLabel; public final SelectList jumpTable; // TODO: Improve representation. public Select(BeamOpcode opcode, SourceOperand src, Label defaultLabel, SelectList jumpTable) { super(opcode); this.src = src; this.defaultLabel = defaultLabel; this.jumpTable = jumpTable; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, src.toSymbolic(), defaultLabel.toSymbolic(), jumpTable.toSymbolic()); } } public static class MapQuery extends Insn { // E.g. 'select_val' public final SourceOperand src; public final Label defaultLabel; public final SelectList kvs; // TODO: Improve representation. public MapQuery(BeamOpcode opcode, Label defaultLabel, SourceOperand map, SelectList kvs) { super(opcode); this.src = map; this.defaultLabel = defaultLabel; this.kvs = kvs; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, defaultLabel.toSymbolic(), src.toSymbolic(), kvs.toSymbolic()); } } public static class MapUpdate extends Insn { // E.g. 'select_val' public final SourceOperand src; public final Label defaultLabel; public final SelectList kvs; // TODO: Improve representation. public final DestinationOperand dest; private int kvCount; public MapUpdate(BeamOpcode opcode, Label defaultLabel, SourceOperand map, int kvCount, SelectList kvs, DestinationOperand dest) { super(opcode); this.src = map; this.defaultLabel = defaultLabel; this.kvs = kvs; this.kvCount = kvCount; this.dest = dest; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, defaultLabel.toSymbolic(), src.toSymbolic(), dest.toSymbolic(), ESmall.make(kvCount), kvs.toSymbolic()); } } public static class BSAppend extends Insn { // E.g. 'bs_append' // LSIIISID public final Label label; public final SourceOperand src2; public final int i3, i4, i5, i7; public final SourceOperand src6; public final DestinationOperand dest8; public BSAppend(BeamOpcode opcode, Label label, SourceOperand src2, int i3, int i4, int i5, SourceOperand src6, int i7, DestinationOperand dest8) { super(opcode); this.label = label; this.src2 = src2; this.i3 = i3; this.i4 = i4; this.i5 = i5; this.src6 = src6; this.i7 = i7; this.dest8 = dest8; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, label.toSymbolic(), src2.toSymbolic(), new ESmall(i3), new ESmall(i4), new ESmall(i5), src6.toSymbolic(), bsFieldFlagsToSymbolic(i7), dest8.toSymbolic()); } } public static class BSPrivateAppend extends Insn { // E.g. 'bs_private_append' // // LSISID public final Label label; public final SourceOperand src2, src4; public final int i3, i5; public final DestinationOperand dest; public BSPrivateAppend(BeamOpcode opcode, Label label, SourceOperand src2, int i3, SourceOperand src4, int i5, DestinationOperand dest) { super(opcode); this.label = label; this.src2 = src2; this.i3 = i3; this.src4 = src4; this.i5 = i5; this.dest = dest; } public ETuple toSymbolic() { return ETuple.make(opcode.symbol, label.toSymbolic(), src2.toSymbolic(), new ESmall(i3), src4.toSymbolic(), bsFieldFlagsToSymbolic(i5), dest.toSymbolic()); } } }