/** -*- 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 erjang.EObject; import erjang.EAtom; import erjang.ESmall; import erjang.EBig; import erjang.EDouble; import erjang.ETuple; import erjang.ESeq; import erjang.EString; import erjang.EBitString; import erjang.ERT; import java.util.ArrayList; import java.math.BigInteger; import static erjang.beam.CodeAtoms.*; public class Operands { public static abstract class Operand { public SourceOperand asSource() { throw new IllegalArgumentException("Not a source: "+this); } public DestinationOperand asDestination() { throw new IllegalArgumentException("Not a destination: "+this); } public Label asLabel() { throw new IllegalArgumentException("Not a label: "+this); } public Literal asLiteral() { throw new IllegalArgumentException("Not a literal: "+this); } public Atom asAtom() { throw new IllegalArgumentException("Not an atom: "+this); } public CodeInt asCodeInt() { throw new IllegalArgumentException("Not a code integer: "+this); } public SelectList asSelectList() { throw new IllegalArgumentException("Not a select list: "+this); } public AllocList asAllocList() { throw new IllegalArgumentException("Not an alloc list: "+this); } public YReg asYReg() { throw new IllegalArgumentException("Not a Y register: "+this); } public TableLiteral testTableLiteral() { return null; } public Atom testAtom() { return null; } public Int testInt() { return null; } public BigInt testBigInt() { return null; } public Float testFloat() { return null; } public SelectList testSelectList() { return null; } public AllocList testAllocList() { return null; } public DestinationOperand testDestination() {return null;} public XReg testXReg() { return null; } public YReg testYReg() { return null; } public FReg testFReg() { return null; } public abstract EObject toSymbolic(); } public static ESeq toSymbolicList(Operand[] args) { ESeq res = ERT.NIL; for (int i = args.length-1; i >= 0; i--) { res = res.cons(args[i].toSymbolic()); } return res; } public static abstract class SourceOperand extends Operand { @Override public SourceOperand asSource() {return this;} } public static abstract class DestinationOperand extends SourceOperand { @Override public DestinationOperand asDestination() {return this;} @Override public DestinationOperand testDestination() {return this;} } public static abstract class Literal extends SourceOperand { @Override public Literal asLiteral() {return this;} public abstract EObject literalValue(); } public static Literal makeInt(byte[] d) { BigInteger tmp = new BigInteger(d); return (d.length<=4) ? new Int(tmp.intValue()) : new BigInt(tmp); } /** CodeInt is present in jump-table-by-arity (select_arity). */ public static class CodeInt extends Operand { public final int value; public CodeInt(int value) {this.value=value;} @Override public CodeInt asCodeInt() {return this;} public EObject toSymbolic() { return new ESmall(value); } } public static class Int extends Literal { public final int value; public Int(int value) {this.value=value;} public boolean equals(int val) { return value == val; } @Override public Int testInt() {return this;} @Override public EObject literalValue() {return new ESmall(value);} public EObject toSymbolic() { return ETuple.make(INTEGER_ATOM, new ESmall(value)); } } public static class BigInt extends Literal { public final BigInteger value; public BigInt(BigInteger value) {this.value=value;} @Override public BigInt testBigInt() {return this;} @Override public EObject literalValue() {return new EBig(value);} public EObject toSymbolic() { return ETuple.make(INTEGER_ATOM, new EBig(value)); } } public static class Float extends Literal { public final double value; public Float(double value) {this.value=value;} @Override public Float testFloat() {return this;} @Override public EObject literalValue() {return new EDouble(value);} public EObject toSymbolic() { return ETuple.make(FLOAT_ATOM, new EDouble(value)); } } public static final Nil Nil = new Nil(); public static class Nil extends Literal { private Nil() {} @Override public EObject literalValue() {return ERT.NIL;} public EObject toSymbolic() {return NIL_ATOM;} } public static class SelectList extends Operand { Operand[] list; public SelectList(Operand[] list) {this.list=list;} @Override public SelectList asSelectList() {return this;} public int size() {return list.length / 2;} public Operand getValue(int i) {return list[2*i];} public Label getLabel(int i) {return (Label)list[2*i+1];} // when used in MapQuery/MapUpdate insns public int size(boolean keys_only) { if (keys_only) return list.length; return list.length / 2; } public SourceOperand getKey(int i, boolean keys_only) { if (keys_only) return (SourceOperand)list[i]; return (SourceOperand)list[2*i]; } public DestinationOperand getKeyDest(int i) {return (DestinationOperand)list[2*i+1];} public SourceOperand getKeySrc(int i) {return (SourceOperand)list[2*i+1];} public EObject toSymbolic() { EObject[] elems = new EObject[list.length]; for (int i=0; i<list.length; i++) { elems[i] = list[i].toSymbolic(); } return ETuple.make(LIST_ATOM, ESeq.fromArray(elems)); } } public static class AllocList extends Operand { static final int WORDS = 0; static final int FLOATS = 1; int[] list; public AllocList(int[] list) {this.list=list;} public AllocList(int words) { list=new int[2]; list[0] = WORDS; list[1] = words; } @Override public AllocList asAllocList() {return this;} public EObject toSymbolic() { int len = list.length/2; if (len==1 && list[0] == WORDS) return new ESmall(list[1]); // Just words. EObject[] elems = new EObject[len]; for (int i=0; i<len; i++) { elems[i] = ETuple.make(kindToSymbolic(list[2*i]), new ESmall(list[2*i+1])); } return ETuple.make(ALLOC_ATOM, ESeq.fromArray(elems)); } protected EAtom kindToSymbolic(int kind) { switch (kind) { case WORDS: return WORDS_ATOM; case FLOATS: return FLOATS_ATOM; default: throw new IllegalArgumentException("Unknown alloc kind: "+kind); } // switch } } public static class Atom extends Literal { private EAtom value; public Atom(EAtom value) {this.value=value;} @Override public Atom asAtom() {return this;} @Override public Atom testAtom() {return this;} @Override public EObject literalValue() {return value;} public EAtom getEAtom() {return value;} public EObject toSymbolic() { return ETuple.make(ATOM_ATOM, value); } @Override public String toString() { return "atom:" + value.toString(); } } public static class BitString extends Literal { public final EBitString value; public BitString(EBitString value) { this.value = value; } @Override public EObject literalValue() {return value;} public long bitLength() {return value.bitSize();} @Override public EObject toSymbolic() { return value; // OBS: beam_disasm round up to nearest byte. } } public static class ByteString extends Literal { public final EString value; public ByteString(EString value) { this.value = value; } @Override public EObject literalValue() {return value;} public int byteLength() {return value.length();} @Override public EObject toSymbolic() { return ETuple.make(STRING_ATOM, value); } } public static class TableLiteral extends Literal { public final EObject value; public TableLiteral(EObject value) {this.value=value;} @Override public EObject literalValue() {return value;} @Override public TableLiteral testTableLiteral() {return this;} public EObject toSymbolic() { return ETuple.make(LITERAL_ATOM, value); } } public static class Label extends Operand { public final int nr; public Label(int nr) {this.nr=nr;} @Override public Label asLabel() {return this;} public EObject toSymbolic() { return ETuple.make(F_ATOM, new ESmall(nr)); } @Override public int hashCode() { return nr; } @Override public boolean equals(Object obj) { if (obj instanceof Label) { Label lab = (Label) obj; return lab.nr == nr; } else { return false; } } } public static class XReg extends DestinationOperand { public final int nr; public XReg(int nr) {this.nr=nr;} @Override public XReg testXReg() {return this;} private static ArrayList<XReg> cache = new ArrayList<XReg>(); public static XReg get(int nr) { while (cache.size() <= nr) { cache.add(new XReg(cache.size())); } return cache.get(nr); } public EObject toSymbolic() { return ETuple.make(X_ATOM, new ESmall(nr)); } } public static class YReg extends DestinationOperand { public final int nr; public YReg(int nr) {this.nr=nr;} @Override public YReg asYReg() {return this;} @Override public YReg testYReg() {return this;} private static ArrayList<YReg> cache = new ArrayList<YReg>(); public static YReg get(int nr) { while (cache.size() <= nr) { cache.add(new YReg(cache.size())); } return cache.get(nr); } public EObject toSymbolic() { return ETuple.make(Y_ATOM, new ESmall(nr)); } } public static class FReg extends DestinationOperand { public final int nr; public FReg(int nr) {this.nr=nr;} @Override public FReg testFReg() {return this;} private static ArrayList<FReg> cache = new ArrayList<FReg>(); public static FReg get(int nr) { while (cache.size() <= nr) { cache.add(new FReg(cache.size())); } return cache.get(nr); } public EObject toSymbolic() { return ETuple.make(FR_ATOM, new ESmall(nr)); } } }