diff --git a/.classpath b/.classpath
index a45a21e2..413f84bb 100644
--- a/.classpath
+++ b/.classpath
@@ -6,11 +6,9 @@
-
-
-
-
-
+
+
+
diff --git a/erl/test1.beam b/erl/test1.beam
index 58f21758..136fd99e 100644
Binary files a/erl/test1.beam and b/erl/test1.beam differ
diff --git a/src/erjang/ENumber.java b/src/erjang/ENumber.java
index 6f6ba026..27dba1cf 100644
--- a/src/erjang/ENumber.java
+++ b/src/erjang/ENumber.java
@@ -99,4 +99,21 @@ public ENumber add(int i2) {
throw new NotImplemented();
}
+ /**
+ * @param v2
+ * @return
+ */
+ public ENumber divide(EObject v2) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * @param d2
+ * @return
+ */
+ public ENumber divide(double d2) {
+ throw new NotImplemented();
+ }
+
}
diff --git a/src/erjang/beam/analysis/BasicBlock.java b/src/erjang/beam/analysis/BasicBlock.java
index 05d02bee..23ed507f 100644
--- a/src/erjang/beam/analysis/BasicBlock.java
+++ b/src/erjang/beam/analysis/BasicBlock.java
@@ -1,10 +1,28 @@
-package org.erlang.beam;
+/**
+ * This file is part of Erjang - A JVM-based Erlang VM
+ *
+ * Copyright (c) 2009 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.analysis;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
-import org.erlang.ETuple2;
+import erjang.ETuple2;
class BasicBlock {
@@ -13,16 +31,17 @@ class BasicBlock {
TreeSet use = new TreeSet();
TreeSet kill = new TreeSet();
-
+
TreeSet in = new TreeSet();
TreeSet out = new TreeSet();
-
+
Set succ = new TreeSet(
new Comparator() {
@Override
public int compare(BasicBlock o1, BasicBlock o2) {
- if (o1==o2) return 0;
-
+ if (o1 == o2)
+ return 0;
+
int loff = o1.label - o2.label;
if (loff != 0) {
return loff;
@@ -41,18 +60,32 @@ public void succ(BasicBlock bb) {
succ.add(bb);
}
- public void use_x(int reg) { use.add(KEY_X | reg); }
- public void use_y(TypeMap map, int reg) { use.add(KEY_X | map.get_ypos(reg)); }
- public void use_fr(int reg) { use.add(KEY_X | reg); }
+ public void use_x(int reg) {
+ use.add(KEY_X | reg);
+ }
+
+ public void use_y(TypeMap map, int reg) {
+ use.add(KEY_X | map.get_ypos(reg));
+ }
+
+ public void use_fr(int reg) {
+ use.add(KEY_X | reg);
+ }
+
+ public void kill_x(int reg) {
+ kill.add(KEY_X | reg);
+ }
+
+ public void kill_y(TypeMap map, int reg) {
+ kill.add(KEY_X | map.get_ypos(reg));
+ }
- public void kill_x(int reg) { kill.add(KEY_X | reg); }
- public void kill_y(TypeMap map, int reg) { kill.add(KEY_X | map.get_ypos(reg)); }
- public void kill_fr(int reg) { kill.add(KEY_X | reg); }
+ public void kill_fr(int reg) {
+ kill.add(KEY_X | reg);
+ }
static final int KEY_X = 0 << 16;
static final int KEY_Y = 1 << 16;
static final int KEY_FR = 2 << 16;
-
-}
-
+}
diff --git a/src/erjang/beam/analysis/BeamTypeAnalysis.java b/src/erjang/beam/analysis/BeamTypeAnalysis.java
index 70465ac7..85a22f33 100644
--- a/src/erjang/beam/analysis/BeamTypeAnalysis.java
+++ b/src/erjang/beam/analysis/BeamTypeAnalysis.java
@@ -1,8 +1,27 @@
-package org.erlang.beam;
+/**
+ * This file is part of Erjang - A JVM-based Erlang VM
+ *
+ * Copyright (c) 2009 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.analysis;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -10,39 +29,67 @@
import java.util.TreeMap;
import java.util.TreeSet;
-import org.erlang.EAtom;
-import org.erlang.ECons;
-import org.erlang.EDouble;
-import org.erlang.EFun;
-import org.erlang.EInteger;
-import org.erlang.EList;
-import org.erlang.ENil;
-import org.erlang.EObject;
-import org.erlang.EPID;
-import org.erlang.EPort;
-import org.erlang.ESeq;
-import org.erlang.ETerm;
-import org.erlang.ETuple;
-import org.erlang.ETuple2;
-import org.erlang.beam.BeamFile.FunctionVisitor;
-import org.erlang.beam.BeamFile.LabeledBlockVisitor;
-import org.erlang.beam.BeamFile.ModuleVisitor;
import org.objectweb.asm.Type;
-
-public class BeamTypeAnalysis extends ModuleVisitor {
+import org.objectweb.asm.commons.Method;
+
+import erjang.EAtom;
+import erjang.EBinMatchState;
+import erjang.EBinary;
+import erjang.ECons;
+import erjang.EDouble;
+import erjang.EFun;
+import erjang.EInteger;
+import erjang.EList;
+import erjang.ENil;
+import erjang.ENumber;
+import erjang.EObject;
+import erjang.EPID;
+import erjang.EPort;
+import erjang.ESeq;
+import erjang.ETerm;
+import erjang.ETuple;
+import erjang.ETuple2;
+import erjang.beam.Arg;
+import erjang.beam.BIF;
+import erjang.beam.BIFUtil;
+import erjang.beam.BeamCodeBlock;
+import erjang.beam.BeamFunction;
+import erjang.beam.BeamInstruction;
+import erjang.beam.BeamOpcode;
+import erjang.beam.BlockVisitor;
+import erjang.beam.BlockVisitor2;
+import erjang.beam.ExtFunc;
+import erjang.beam.FunctionAdapter;
+import erjang.beam.FunctionVisitor;
+import erjang.beam.FunctionVisitor2;
+import erjang.beam.ModuleAdapter;
+import erjang.beam.ModuleVisitor;
+import erjang.beam.Arg.Kind;
+
+public class BeamTypeAnalysis extends ModuleAdapter {
+
+ /**
+ *
+ */
+ public BeamTypeAnalysis(ModuleVisitor mv) {
+ super(mv);
+ }
static final Type EINTEGER_TYPE = Type.getType(EInteger.class);
+ static final Type ENUMBER_TYPE = Type.getType(ENumber.class);
static final Type EOBJECT_TYPE = Type.getType(EObject.class);
static final Type EDOUBLE_TYPE = Type.getType(EDouble.class);
static final Type ENIL_TYPE = Type.getType(ENil.class);
static final Type EATOM_TYPE = Type.getType(EAtom.class);
static final Type ETUPLE_TYPE = Type.getType(ETuple.class);
+ static final Type EBINARY_TYPE = Type.getType(EBinary.class);
static final Type ECONS_TYPE = Type.getType(ECons.class);
static final Type ESEQ_TYPE = Type.getType(ESeq.class);
static final Type ELIST_TYPE = Type.getType(EList.class);
static final Type EFUN_TYPE = Type.getType(EFun.class);
static final Type EPID_TYPE = Type.getType(EPID.class);
static final Type EPORT_TYPE = Type.getType(EPort.class);
+ static final Type EMATCHSTATE_TYPE = Type.getType(EBinMatchState.class);
static final ETerm X_ATOM = EAtom.intern("x");
static final ETerm Y_ATOM = EAtom.intern("y");
@@ -54,16 +101,24 @@ public class BeamTypeAnalysis extends ModuleVisitor {
static final ETerm LITERAL_ATOM = EAtom.intern("literal");
static final ETerm NOFAIL_ATOM = EAtom.intern("nofail");
static final ETerm F_ATOM = EAtom.intern("f");
+ static final ETerm FIELD_FLAGS_ATOM = EAtom.intern("field_flags");
+ static final ETerm EXTFUNC_ATOM = EAtom.intern("extfunc");
private static final ETuple X0_REG = ETuple.make(new ETerm[] { X_ATOM,
new EInteger(0) });
+ private EAtom moduleName;
+
+ private List functions = new ArrayList();
@Override
- FunctionVisitor visitFunction(EAtom name, int arity, int startLabel) {
- return new FV(name, arity, startLabel);
+ public FunctionVisitor visitFunction(EAtom name, int arity, int startLabel) {
+ FV f = new FV(super.visitFunction(name, arity, startLabel), name,
+ arity, startLabel);
+ functions.add(f);
+ return f;
}
- class FV extends FunctionVisitor {
+ class FV extends FunctionAdapter implements BeamFunction {
BasicBlock makeBasicBlock(int label, int index) {
assert ((label & 0xffff) == label);
@@ -86,7 +141,9 @@ void live_analysis() {
boolean change = false;
+ int iter = 0;
do {
+ iter += 1;
for (int n = all.length - 1; n >= 0; n--) {
BasicBlock bb = bbs.get(all[n]);
@@ -113,6 +170,9 @@ void live_analysis() {
}
} while (change);
+
+ // System.err.println("live analysis for " + name + "/" + arity
+ // + " completed in " + iter + " iterations.");
}
public TypeMap getTypeMap(int i) {
@@ -140,7 +200,16 @@ public int compare(LabeledBlock o1, LabeledBlock o2) {
}
});
- public FV(EAtom name, int arity, int startLabel) {
+ public int max_stack;
+
+ public int max_xreg;
+
+ public int max_freg;
+
+ private boolean is_tail_recursive;
+
+ public FV(FunctionVisitor fv, EAtom name, int arity, int startLabel) {
+ super(fv);
this.name = name;
this.arity = arity;
this.startLabel = startLabel;
@@ -166,13 +235,16 @@ public void visitEnd() {
throw t;
}
+ // woo!
+ live_analysis();
+
SortedSet labels = new TreeSet();
labels.addAll(lbs.keySet());
boolean has_unreachable_code = false;
for (int i : labels) {
lb = lbs.get(i);
- if (lb.isUnreached()) {
+ if (lb.isDeadCode()) {
if (BeamOpcode.get(lb.insns.get(0).nth(1).asAtom()) == BeamOpcode.func_info) {
// ignore this
} else {
@@ -184,6 +256,27 @@ public void visitEnd() {
if (has_unreachable_code) {
this.dump();
}
+
+ function_visit_end();
+
+ }
+
+ private void function_visit_end() {
+
+ if (fv instanceof FunctionVisitor2) {
+ ((FunctionVisitor2) fv).visitMaxs(this.max_xreg,
+ this.max_stack, this.max_freg, this.is_tail_recursive);
+ }
+
+ for (LabeledBlock block : this.lbs.values()) {
+
+ BlockVisitor vis = super.fv
+ .visitLabeledBlock(block.block_label);
+
+ block.accept(vis);
+ }
+
+ super.fv.visitEnd();
}
private void dump() {
@@ -197,7 +290,7 @@ private void dump() {
}
@Override
- public LabeledBlockVisitor visitLabeledBlock(int label) {
+ public BlockVisitor visitLabeledBlock(int label) {
return get_lb(label, true);
}
@@ -225,7 +318,7 @@ private LabeledBlock get_lb(int label, boolean create) {
}
}
- class LabeledBlock extends LabeledBlockVisitor {
+ class LabeledBlock implements BlockVisitor, BeamCodeBlock {
private final int block_label;
TypeMap initial;
@@ -237,7 +330,258 @@ public LabeledBlock(int label) {
initial = null;
}
- public boolean isUnreached() {
+ /**
+ * @param vis
+ */
+ public void accept(BlockVisitor vis) {
+
+ if (!isDeadCode()) {
+
+ if (vis instanceof BlockVisitor2) {
+ accept_2((BlockVisitor2) vis);
+ } else {
+ accept_1(vis);
+ }
+
+ }
+
+ vis.visitEnd();
+ }
+
+ private void accept_1(BlockVisitor vis) {
+ for (int i = 0; i < insns.size(); i++) {
+ ETuple insn = insns.get(i);
+ BeamOpcode opcode = BeamOpcode.get(insn.nth(1).asAtom());
+ vis.visitInsn(opcode, insn);
+ }
+ }
+
+ private void accept_2(BlockVisitor2 vis) {
+ for (int insn_idx = 0; insn_idx < insns.size(); insn_idx++) {
+ ETuple insn = insns.get(insn_idx);
+ BeamOpcode opcode = BeamOpcode.get(insn.nth(1).asAtom());
+
+ switch (opcode) {
+ case func_info:
+ vis.visitInsn(opcode, (Arg) new ExtFunc(insn.nth(2)
+ .asAtom(), insn.nth(3).asAtom(), insn.nth(4)
+ .asInt()));
+ break;
+
+ case fconv:
+ case fmove:
+ case move: {
+ System.err.println(insn);
+ Arg arg1 = decode_arg(insn_idx, insn.nth(2));
+ Arg arg2 = decode_arg(insn_idx, insn.nth(3));
+
+ if (arg2.kind != Kind.F) {
+ if (arg1.kind == Kind.F) {
+ arg2 = new Arg(arg2, EDOUBLE_TYPE);
+ } else {
+ arg2 = new Arg(arg2, arg1.type);
+ }
+ } else {
+ // arg2.kind == F
+ }
+
+ vis.visitInsn(opcode, arg1, arg2);
+ break;
+ }
+
+ case arithfbif:
+ {
+ System.err.println("gen: "+insn);
+ EAtom name = insn.nth(2).asAtom();
+ int failLabel = decode_labelref(insn.nth(3));
+ ESeq parms = insn.nth(4).asSeq();
+ Arg[] in = decode_args(insn_idx, parms.toArray());
+ Arg out = decode_out_arg(insn_idx, insn.nth(5));
+
+ BIF bif = BIFUtil.getMethod(name.getName(), parmTypes(
+ this.map[insn_idx], parms), failLabel != 0);
+
+
+ vis.visitInsn(opcode, failLabel, in, out, bif);
+ break;
+ }
+
+ case gc_bif:
+ case bif:
+ {
+ System.err.println("gen: "+insn);
+ EAtom name = insn.nth(2).asAtom();
+ int failLabel = decode_labelref(insn.nth(3));
+ ESeq parms = insn.nth(5).asSeq();
+ Arg[] in = decode_args(insn_idx, parms.toArray());
+ Arg out = decode_out_arg(insn_idx, insn.nth(6));
+
+ BIF bif = BIFUtil.getMethod(name.getName(), parmTypes(
+ this.map[insn_idx], parms), failLabel != 0);
+
+
+ vis.visitInsn(opcode, failLabel, in, out, bif);
+ break;
+ }
+
+ case test:
+ accept_2_test(vis, insn, insn_idx);
+ break;
+
+ case K_return:
+ vis.visitInsn(opcode);
+ break;
+
+ case test_heap:
+ break;
+
+ case fclearerror:
+ case fcheckerror:
+ break;
+
+ case call_ext_only:
+ {
+ boolean is_tail = true;
+ boolean is_external = true;
+ int arg_count = insn.nth(2).asInt();
+ Arg[] args = new Arg[arg_count];
+ for (int i = 0; i < arg_count; i++) {
+ args[i] = new Arg(Kind.X, i, this.map[insn_idx].getx(i));
+ }
+ ETuple ft = insn.nth(3).asTuple();
+ if (ft.nth(1) != EXTFUNC_ATOM) throw new Error();
+ ExtFunc fun = new ExtFunc(ft.nth(2).asAtom(), ft.nth(3).asAtom(), ft.nth(4).asInt());
+ vis.visitCall(fun, args, is_tail, is_external);
+ }
+ break;
+
+ default:
+ throw new Error("unhandled insn: " + insn);
+ }
+
+ }
+ }
+
+ private void accept_2_test(BlockVisitor2 vis, ETuple insn,
+ int insn_idx) {
+
+ int failLabel = decode_labelref(insn.nth(3));
+
+ Arg[] args = decode_args(insn_idx, insn.nth(4).asSeq()
+ .toArray());
+
+ BeamOpcode test = BeamOpcode.get(insn.nth(2).asAtom());
+ switch (test) {
+ case is_list:
+ vis.visitTest(test, failLabel, args[0], ECONS_TYPE);
+ break;
+
+ case is_nonempty_list:
+ vis.visitTest(test, failLabel, args[0], ESEQ_TYPE);
+ break;
+
+ case is_nil:
+ vis.visitTest(test, failLabel, args[0], ENIL_TYPE);
+ break;
+
+ case is_eq:
+ vis.visitTest(test, failLabel, args, (Arg)null, Type.VOID_TYPE);
+ break;
+
+ default:
+ throw new Error("unhandled test: " + insn + " at index "
+ + insn_idx);
+ }
+
+ }
+
+ /**
+ * @param insn_idx
+ * @param array
+ * @return
+ */
+ private Arg[] decode_args(int insn_idx, EObject[] input) {
+ Arg[] output = new Arg[input.length];
+ for (int i = 0; i < input.length; i++) {
+ output[i] = decode_arg(insn_idx, input[i]);
+ }
+ return output;
+ }
+
+ /**
+ * @param insnIdx
+ * @param eObject
+ * @return
+ */
+ private Arg decode_arg(int insn_idx, EObject src) {
+ TypeMap current = this.map[insn_idx];
+
+ if (src instanceof ETuple2) {
+ ETuple2 tup = (ETuple2) src;
+ if (tup.elem1 == X_ATOM) {
+ int xreg = tup.elem2.asInt();
+ return new Arg(Arg.Kind.X, xreg, current.getx(xreg));
+ } else if (tup.elem1 == Y_ATOM) {
+ int yreg = tup.elem2.asInt();
+ return new Arg(Arg.Kind.Y, current.get_ypos(yreg),
+ current.gety(yreg));
+ } else if (tup.elem1 == FR_ATOM) {
+ int freg = tup.elem2.asInt();
+ return new Arg(Arg.Kind.F, freg, Type.DOUBLE_TYPE);
+ } else if (tup.elem1 == ATOM_ATOM) {
+ return new Arg(tup.elem2);
+ } else if (tup.elem1 == LITERAL_ATOM) {
+ return new Arg(tup.elem2);
+ } else if (tup.elem1 == INTEGER_ATOM) {
+ if (tup.elem2.asInteger() != null) {
+ return new Arg(tup.elem2, Type.INT_TYPE);
+ } else {
+ return new Arg(tup.elem2);
+ }
+ } else if (tup.elem1 == FLOAT_ATOM) {
+ return new Arg(tup.elem2, Type.DOUBLE_TYPE);
+ }
+
+ } else if (src == NIL_ATOM) {
+ return new Arg(src);
+
+ }
+
+ return null;
+
+ }
+
+ private Arg decode_out_arg(int insn_idx, EObject src) {
+ TypeMap current = this.map[insn_idx];
+
+ if (src instanceof ETuple2) {
+ ETuple2 tup = (ETuple2) src;
+ if (tup.elem1 == X_ATOM) {
+ int xreg = tup.elem2.asInt();
+ return new Arg(Arg.Kind.X, xreg);
+ } else if (tup.elem1 == Y_ATOM) {
+ int yreg = tup.elem2.asInt();
+ return new Arg(Arg.Kind.Y, current.get_ypos(yreg));
+ } else if (tup.elem1 == FR_ATOM) {
+ int freg = tup.elem2.asInt();
+ return new Arg(Arg.Kind.F, freg);
+ }
+ }
+
+ throw new Error();
+
+ }
+
+ /**
+ * @param nth
+ * @return
+ */
+ private int decode_labelref(EObject f_tup) {
+ assert (f_tup.asTuple().nth(1) == F_ATOM);
+ return f_tup.asTuple().nth(2).asInt();
+ }
+
+ public boolean isDeadCode() {
return initial == null;
}
@@ -267,11 +611,14 @@ public void analyze0() {
map = new TypeMap[insns.size()];
next_insn: for (int insn_idx = 0; insn_idx < insns.size(); insn_idx++) {
-
+
+ update_max_regs(current);
+
if (is_term(last_opcode)) {
- throw new Error("how did we get here then...? "+this.block_label+":"+insn_idx);
+ throw new Error("how did we get here then...? "
+ + this.block_label + ":" + insn_idx);
}
-
+
map[insn_idx] = current;
ETuple insn = insns.get(insn_idx);
BeamOpcode code = BeamOpcode.get(insn.nth(1).asAtom());
@@ -285,21 +632,23 @@ public void analyze0() {
case move: {
EObject src = insn.nth(2);
EObject dst = insn.nth(3);
-
+
Type srcType = getType(current, src);
+ boolean boxed = false;
if (sizeof(current, src) > sizeof(current, dst)) {
System.err.println(insn);
- if (getType(current, src) == Type.INT_TYPE) {
- current = setType(current, dst, EINTEGER_TYPE);
- } else if (getType(current, src) == Type.DOUBLE_TYPE) {
+ if (getType(current, src).equals(Type.DOUBLE_TYPE)) {
current = setType(current, dst, EDOUBLE_TYPE);
+ boxed = true;
} else {
throw new Error("why?" + insn);
}
}
- current = setType(current, (ETuple2) dst, srcType);
+ if (!boxed) {
+ current = setType(current, (ETuple2) dst, srcType);
+ }
continue next_insn;
}
@@ -340,8 +689,7 @@ public void analyze0() {
// System.err.println(insn);
current = branch(current, insn.nth(3), insn_idx);
-
-
+
EAtom name = insn.nth(2).asAtom();
ESeq parms = insn.nth(5).asSeq();
@@ -431,7 +779,7 @@ public void analyze0() {
}
case put_list: {
-
+
Type head_type = getType(current, insn.nth(2));
Type tail_type = getType(current, insn.nth(3));
@@ -458,6 +806,34 @@ public void analyze0() {
continue next_insn;
}
+ case K_try:
+ current = setType(current, insn.nth(2), EOBJECT_TYPE);
+ current = branch(current, insn.nth(3), insn_idx);
+ continue next_insn;
+
+ case try_case_end:
+ case try_end:
+ // no exception happened
+ continue next_insn;
+
+ case try_case:
+ getType(current, insn.nth(2));
+ current = current.setx(0, EATOM_TYPE); // reason
+ current = current.setx(1, EOBJECT_TYPE); // value
+ current = current.setx(2, EOBJECT_TYPE); // trace
+ continue next_insn;
+
+ case raise:
+ boolean is_guard = false;
+ if (insn.nth(2).asTuple().nth(2).asInt() != 0) {
+ is_guard = true;
+ }
+
+ checkArgs(current, insn.nth(3), insn);
+ current = setType(current, insn.nth(4), EOBJECT_TYPE);
+
+ continue next_insn;
+
case K_catch:
current = branch(current, insn.nth(3), insn_idx);
continue next_insn;
@@ -477,14 +853,13 @@ public void analyze0() {
continue next_insn;
}
- case remove_message:
+ case remove_message:
// assume this insn overrides X0
// current = current.setx(0, EOBJECT_TYPE);
continue next_insn;
case loop_rec_end:
- case timeout:
- {
+ case timeout: {
// System.err.println(insn);
continue next_insn;
}
@@ -575,14 +950,13 @@ public void analyze0() {
case apply:
case call:
- case call_ext:
- {
+ case call_ext: {
int argCount = insn.nth(2).asInt();
current.touchx(0, argCount);
current = current.setx(0, EOBJECT_TYPE);
continue next_insn;
}
-
+
// all these exit
case K_return:
getType(current, X0_REG);
@@ -592,10 +966,11 @@ public void analyze0() {
case call_only:
case call_ext_last:
case call_ext_only:
+ is_tail_recursive = true;
int argCount = insn.nth(2).asInt();
current.touchx(0, argCount);
continue next_insn;
-
+
case func_info:
continue next_insn;
@@ -604,12 +979,18 @@ public void analyze0() {
case case_end:
continue next_insn;
+ case bs_context_to_binary: {
+ Type ctx = getType(current, insn.nth(2));
+ current = current.setx(0, EBINARY_TYPE);
+ continue next_insn;
+ }
+
default:
throw new Error("unhandled: " + insn + "::" + current);
}
}
-
-
+
+ update_max_regs(current);
if (is_term(last_opcode) == false) {
LabeledBlock lbv = get_lb(this.block_label + 1, false);
@@ -624,6 +1005,12 @@ public void analyze0() {
}
}
+ private void update_max_regs(TypeMap current) {
+ max_stack = Math.max(max_stack, current.stacksize);
+ max_xreg = Math.max(max_xreg, current.max_xreg());
+ max_freg = Math.max(max_freg, current.max_freg());
+ }
+
boolean is_term(BeamOpcode code) {
switch (code) {
case K_return:
@@ -635,11 +1022,11 @@ boolean is_term(BeamOpcode code) {
case call_ext_last:
case call_ext_only:
case func_info:
-
+
case wait:
case select_tuple_arity:
case select_val:
-
+
case jump:
return true;
default:
@@ -648,16 +1035,19 @@ boolean is_term(BeamOpcode code) {
}
private int sizeof(TypeMap current, EObject cell) {
-
+
ETuple at;
- if ((at=cell.asTuple()) != null) {
+ if ((at = cell.asTuple()) != null) {
if (at.arity() == 2) {
- if (at.nth(1) == X_ATOM) return 32;
- if (at.nth(1) == Y_ATOM) return 32;
- if (at.nth(1) == FR_ATOM) return 64;
+ if (at.nth(1) == X_ATOM)
+ return 32;
+ if (at.nth(1) == Y_ATOM)
+ return 32;
+ if (at.nth(1) == FR_ATOM)
+ return 64;
}
}
-
+
Type t = getType(current, cell);
if (t == Type.DOUBLE_TYPE) {
return 64;
@@ -666,7 +1056,8 @@ private int sizeof(TypeMap current, EObject cell) {
}
}
- private Type getBifResult(String name, Type[] parmTypes, boolean is_guard) {
+ private Type getBifResult(String name, Type[] parmTypes,
+ boolean is_guard) {
return BIFUtil.getBifResult(name, parmTypes, is_guard);
}
@@ -701,8 +1092,6 @@ private TypeMap analyze_test(TypeMap current, ETuple insn,
current = branch(current, insn.nth(3), insn_idx);
- checkArgs(current, insn.nth(4), insn);
-
EObject[] args = insn.nth(4).asSeq().toArray();
EObject arg1 = args[0];
EObject arg2 = (args.length > 1) ? args[1] : null;
@@ -710,51 +1099,66 @@ private TypeMap analyze_test(TypeMap current, ETuple insn,
BeamOpcode test = BeamOpcode.get(insn.nth(2).asAtom());
switch (test) {
case is_nil: {
+ checkArgs(current, insn.nth(4), insn);
return setType(current, arg1.asTuple(), ENIL_TYPE);
}
case is_list:
case is_nonempty_list: {
+ checkArgs(current, insn.nth(4), insn);
return setType(current, arg1.asTuple(), ECONS_TYPE);
}
+ case is_binary: {
+ checkArgs(current, insn.nth(4), insn);
+ return setType(current, arg1.asTuple(), EBINARY_TYPE);
+ }
case is_tuple: {
+ checkArgs(current, insn.nth(4), insn);
return setType(current, arg1.asTuple(), ETUPLE_TYPE);
}
case test_arity: {
+ checkArgs(current, insn.nth(4), insn);
return setType(current, arg1.asTuple(), getTupleType(arg2
.asInt()));
}
case is_boolean:
case is_atom: {
+ checkArgs(current, insn.nth(4), insn);
return setType(current, arg1.asTuple(), EATOM_TYPE);
}
case is_integer: {
+ checkArgs(current, insn.nth(4), insn);
return setType(current, arg1, EINTEGER_TYPE);
}
case is_pid: {
+ checkArgs(current, insn.nth(4), insn);
return setType(current, arg1, EPID_TYPE);
}
case is_port: {
+ checkArgs(current, insn.nth(4), insn);
return setType(current, arg1, EPORT_TYPE);
}
case is_float: {
+ checkArgs(current, insn.nth(4), insn);
return setType(current, arg1, EDOUBLE_TYPE);
}
case is_ge:
case is_ne:
case is_ne_exact:
+ checkArgs(current, insn.nth(4), insn);
return current;
case is_eq:
case is_eq_exact: {
+ checkArgs(current, insn.nth(4), insn);
Type t1 = getType(current, arg1);
Type t2 = getType(current, arg2);
@@ -770,6 +1174,59 @@ private TypeMap analyze_test(TypeMap current, ETuple insn,
}
case is_lt:
+ checkArgs(current, insn.nth(4), insn);
+ return current;
+
+ case bs_start_match2:
+ check(current, args[0]);
+ current = setType(current, args[3], EMATCHSTATE_TYPE);
+ return current;
+
+ case bs_get_integer2: {
+ if (!EMATCHSTATE_TYPE.equals(getType(current, args[0]))) {
+ throw new Error("matching without a state");
+ }
+
+ ETuple tup;
+ if ((tup = args[3].asTuple()) != null) {
+ if (tup.nth(1) == INTEGER_ATOM
+ && tup.nth(2).asInt() <= 32) {
+ current = setType(current, args[5], Type.INT_TYPE);
+ return current;
+ }
+ }
+
+ current = setType(current, args[5], ENUMBER_TYPE);
+ return current;
+ }
+
+ case bs_get_binary2: {
+ if (!EMATCHSTATE_TYPE.equals(getType(current, args[0]))) {
+ throw new Error("matching without a state");
+ }
+
+ current = setType(current, args[5], EBINARY_TYPE);
+ return current;
+ }
+
+ case bs_get_float2: {
+ if (!EMATCHSTATE_TYPE.equals(getType(current, args[0]))) {
+ throw new Error("matching without a state");
+ }
+
+ current = setType(current, args[5], Type.DOUBLE_TYPE);
+ return current;
+ }
+
+ // these bit string matchers don't modify registers
+
+ case bs_test_tail2:
+ case bs_test_unit:
+ case bs_skip_bits2:
+
+ if (!EMATCHSTATE_TYPE.equals(getType(current, args[0]))) {
+ throw new Error("matching without a state");
+ }
return current;
@@ -779,6 +1236,12 @@ private TypeMap analyze_test(TypeMap current, ETuple insn,
}
+ private void check(TypeMap current, EObject src) {
+ if (getType(current, src) == null) {
+ throw new Error("argument has no type");
+ }
+ }
+
private TypeMap branch(TypeMap current, EObject nth, int idx) {
if (nth != NOFAIL_ATOM) {
@@ -879,6 +1342,8 @@ private Type getType(TypeMap current, EObject src) {
}
} else if (tup.elem1 == FLOAT_ATOM) {
return Type.DOUBLE_TYPE;
+ } else if (tup.elem1 == FIELD_FLAGS_ATOM) {
+ return Type.INT_TYPE;
}
} else if (src == NIL_ATOM) {
@@ -891,8 +1356,120 @@ private Type getType(TypeMap current, EObject src) {
throw new Error("unknown " + src);
}
+ @Override
+ public BeamInstruction[] getInstructions() {
+
+ BeamInstruction[] res = new BeamInstruction[insns.size()];
+ for (int i = 0; i < insns.size(); i++) {
+ res[i] = new BInsn(insns.get(i), this.map[i]);
+ }
+
+ return res;
+ }
+
+ @Override
+ public int getLabel() {
+ return this.block_label;
+ }
+
+ class BInsn implements BeamInstruction {
+
+ private final ETuple insn;
+ private final TypeMap current;
+
+ public BInsn(ETuple insn, TypeMap current) {
+ this.insn = insn;
+ this.current = current;
+ }
+
+ @Override
+ public BeamOpcode opcode() {
+ return BeamOpcode.get(insn.nth(1).asAtom());
+ }
+
+ @Override
+ public String toString() {
+ return insn.toString();
+ }
+ }
+ }
+
+ @Override
+ public int getArity() {
+ return arity;
}
+ @Override
+ public String getName() {
+ return name.getName();
+ }
+
+ @Override
+ public String getModuleName() {
+ return moduleName.getName();
+ }
+
+ @Override
+ public boolean isExported() {
+ String externalName = getName() + "/" + getArity();
+ return exports.contains(externalName);
+ }
+
+ @Override
+ public int getFregCount() {
+ return max_freg;
+ }
+
+ @Override
+ public int getXregCount() {
+ return max_xreg;
+ }
+
+ @Override
+ public int getYregCount() {
+ return max_stack;
+ }
+
+ @Override
+ public BeamCodeBlock[] getCodeBlocks() {
+
+ BeamCodeBlock[] blocks = this.lbs.values().toArray(
+ new BeamCodeBlock[0]);
+
+ return blocks;
+ }
+
+ @Override
+ public int getEntryLabel() {
+ return startLabel;
+ }
+
+ }
+
+ public void visitModule(EAtom name) {
+ this.moduleName = name;
+ super.visitModule(name);
+ }
+
+ Set exports = new HashSet();
+
+ /** list of {Fun,Arity,Entry} */
+ public void visitExport(EAtom fun, int arity, int entry) {
+ exports.add(fun.getName() + "/" + arity);
+ super.visitExport(fun, arity, entry);
+ }
+
+ /** list of {Atom,Value} */
+ public void visitAttribute(EAtom att, EObject value) {
+ super.visitAttribute(att, value);
+ }
+
+ public String getModuleName() {
+ return this.moduleName.getName();
+ }
+
+ public BeamFunction[] functions() {
+ return functions.toArray(new BeamFunction[functions.size()]);
}
}
diff --git a/src/erjang/beam/analysis/TypeMap.java b/src/erjang/beam/analysis/TypeMap.java
index b4e4fef5..22d8c0d8 100644
--- a/src/erjang/beam/analysis/TypeMap.java
+++ b/src/erjang/beam/analysis/TypeMap.java
@@ -1,18 +1,33 @@
/**
- *
- */
-package org.erlang.beam;
+ * This file is part of Erjang - A JVM-based Erlang VM
+ *
+ * Copyright (c) 2009 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.analysis;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Set;
import java.util.TreeSet;
-import org.erlang.EObject;
-import org.erlang.ETuple;
-import org.erlang.ETuple2;
import org.objectweb.asm.Type;
+import erjang.EObject;
+import erjang.ETuple;
+import erjang.ETuple2;
+
class TypeMap {
private static Type TYPE_EOBJECT = Type.getType(EObject.class);
private static Type TYPE_ETUPLE = Type.getType(ETuple.class);
@@ -20,15 +35,15 @@ class TypeMap {
private static Type[] NO_TYPES = new Type[0];
private Type[] xregs, yregs, fregs;
- private int stacksize; // number of y-regs
+ final int stacksize; // number of y-regs
final BasicBlock bb;
-
public TypeMap(BasicBlock bb) {
xregs = NO_TYPES;
yregs = NO_TYPES;
fregs = NO_TYPES;
+ stacksize = 0;
this.bb = bb;
}
@@ -103,7 +118,8 @@ private String shortName(Type type) {
}
}
- private TypeMap(Type[] xregs, Type[] yregs, Type[] fregs, int stacksize, BasicBlock bb) {
+ private TypeMap(Type[] xregs, Type[] yregs, Type[] fregs, int stacksize,
+ BasicBlock bb) {
super();
this.xregs = xregs;
this.yregs = yregs;
@@ -124,6 +140,9 @@ public boolean equals(Object obj) {
}
private static boolean eqy(TypeMap me, TypeMap other) {
+ if (me.stacksize != other.stacksize)
+ return false;
+
int stacksize = Math.min(me.stacksize, other.stacksize);
for (int i = 0; i < stacksize; i++) {
if (!eq(me.gety(i), other.gety(i)))
@@ -158,11 +177,20 @@ public TypeMap mergeFrom(TypeMap other) {
Type[] new_y = yregs;
int new_stacksize = stacksize;
if (!eqy(this, other)) {
- new_stacksize = Math.min(stacksize, other.stacksize);
- new_y = new Type[new_stacksize];
- for (int i = 0; i < new_stacksize; i++) {
- new_y[new_stacksize - i - 1] = merge(this.gety(i), other
- .gety(i));
+
+ if (stacksize != other.stacksize) {
+ // yank stack!
+ new_stacksize = 0;
+ new_y = NO_TYPES;
+ } else {
+
+ // the smaller stack-size wins
+ new_stacksize = Math.min(stacksize, other.stacksize);
+ new_y = new Type[new_stacksize];
+ for (int i = 0; i < new_stacksize; i++) {
+ new_y[new_stacksize - i - 1] = merge(this.gety(i), other
+ .gety(i));
+ }
}
}
@@ -212,7 +240,7 @@ public TypeMap setx(int reg, Type t) {
if (eq(getx(reg), t))
return this;
-
+
Type[] new_xregs;
if (xregs.length <= reg) {
new_xregs = grow(xregs, reg);
@@ -332,5 +360,22 @@ public void touchx(int from, int to) {
}
}
+ public int max_xreg() {
+ int max = 0;
+ for (int i = 0; i < xregs.length; i++) {
+ if (xregs[i] != null)
+ max = i;
+ }
+ return max + 1;
+ }
+
+ public int max_freg() {
+ int max = 0;
+ for (int i = 0; i < fregs.length; i++) {
+ if (fregs[i] != null)
+ max = i;
+ }
+ return max + 1;
+ }
}
\ No newline at end of file
diff --git a/src/erjang/jbeam/README b/src/erjang/jbeam/README
index 30cdc7e9..e6f6cacc 100644
--- a/src/erjang/jbeam/README
+++ b/src/erjang/jbeam/README
@@ -1 +1,6 @@
-This directory contains an earlier version
+This directory contains an earlier version, which could actually compile to .class files;
+but it was badly broken.
+
+I just keep it around because I intend to grab some snippets of code.
+
+
diff --git a/src/erjang/jbeam/ops/AllocateZero.java b/src/erjang/jbeam/ops/AllocateZero.java
index 1a08e95f..06d717d6 100644
--- a/src/erjang/jbeam/ops/AllocateZero.java
+++ b/src/erjang/jbeam/ops/AllocateZero.java
@@ -1,4 +1,4 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
public class AllocateZero extends Insn {
diff --git a/src/erjang/jbeam/ops/AttributesDecl.java b/src/erjang/jbeam/ops/AttributesDecl.java
index 63b86851..25755074 100644
--- a/src/erjang/jbeam/ops/AttributesDecl.java
+++ b/src/erjang/jbeam/ops/AttributesDecl.java
@@ -1,6 +1,6 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
-import org.erlang.ECons;
+import erjang.ECons;
public class AttributesDecl {
diff --git a/src/erjang/jbeam/ops/BasicBlock.java b/src/erjang/jbeam/ops/BasicBlock.java
index 805afb3c..ca3e141e 100644
--- a/src/erjang/jbeam/ops/BasicBlock.java
+++ b/src/erjang/jbeam/ops/BasicBlock.java
@@ -1,4 +1,4 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/erjang/jbeam/ops/Call.java b/src/erjang/jbeam/ops/Call.java
index a651f3a8..e49cf219 100644
--- a/src/erjang/jbeam/ops/Call.java
+++ b/src/erjang/jbeam/ops/Call.java
@@ -1,9 +1,10 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
-import org.erlang.EAtom;
import com.sun.xml.internal.ws.org.objectweb.asm.Opcodes;
+import erjang.EAtom;
+
public class Call extends Insn {
private final int nargs;
diff --git a/src/erjang/jbeam/ops/CallExtOnly.java b/src/erjang/jbeam/ops/CallExtOnly.java
index 338b3f4a..10ffe780 100644
--- a/src/erjang/jbeam/ops/CallExtOnly.java
+++ b/src/erjang/jbeam/ops/CallExtOnly.java
@@ -1,9 +1,10 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
-import org.erlang.EFun;
-import org.erlang.ETerm;
import org.objectweb.asm.Type;
+import erjang.EFun;
+import erjang.ETerm;
+
public class CallExtOnly extends Insn {
private static final Type EFUN_TYPE = Type.getType(EFun.class);
diff --git a/src/erjang/jbeam/ops/CodeAdapter.java b/src/erjang/jbeam/ops/CodeAdapter.java
index e9c71022..2ac24a82 100644
--- a/src/erjang/jbeam/ops/CodeAdapter.java
+++ b/src/erjang/jbeam/ops/CodeAdapter.java
@@ -1,12 +1,13 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
-import org.erlang.EObject;
-import org.erlang.ETerm;
-import org.erlang.jbeam.BEAMFile;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
+import erjang.EObject;
+import erjang.ETerm;
+import erjang.jbeam.BEAMFile;
+
public class CodeAdapter extends MethodAdapter {
private final BEAMFile beam;
diff --git a/src/erjang/jbeam/ops/CompilationInfo.java b/src/erjang/jbeam/ops/CompilationInfo.java
index 5c69c09c..834e7c06 100644
--- a/src/erjang/jbeam/ops/CompilationInfo.java
+++ b/src/erjang/jbeam/ops/CompilationInfo.java
@@ -1,6 +1,6 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
-import org.erlang.ECons;
+import erjang.ECons;
public class CompilationInfo extends Stmt {
diff --git a/src/erjang/jbeam/ops/Deallocate.java b/src/erjang/jbeam/ops/Deallocate.java
index 2d2e7ae1..cc553a3b 100644
--- a/src/erjang/jbeam/ops/Deallocate.java
+++ b/src/erjang/jbeam/ops/Deallocate.java
@@ -1,7 +1,7 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
-import org.erlang.jbeam.ops.FunctionAdapter;
-import org.erlang.jbeam.ops.Insn;
+import erjang.jbeam.ops.FunctionAdapter;
+import erjang.jbeam.ops.Insn;
public class Deallocate extends Insn {
diff --git a/src/erjang/jbeam/ops/ExportsDecl.java b/src/erjang/jbeam/ops/ExportsDecl.java
index 7af969a3..44a60abb 100644
--- a/src/erjang/jbeam/ops/ExportsDecl.java
+++ b/src/erjang/jbeam/ops/ExportsDecl.java
@@ -1,6 +1,6 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
-import org.erlang.ECons;
+import erjang.ECons;
public class ExportsDecl {
diff --git a/src/erjang/jbeam/ops/Expr.java b/src/erjang/jbeam/ops/Expr.java
index 9f084bad..b8381f77 100644
--- a/src/erjang/jbeam/ops/Expr.java
+++ b/src/erjang/jbeam/ops/Expr.java
@@ -1,4 +1,4 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
diff --git a/src/erjang/jbeam/ops/ExternalFunction.java b/src/erjang/jbeam/ops/ExternalFunction.java
index 140d807a..b1ad0faf 100644
--- a/src/erjang/jbeam/ops/ExternalFunction.java
+++ b/src/erjang/jbeam/ops/ExternalFunction.java
@@ -1,9 +1,9 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
-import org.erlang.EAtom;
-import org.erlang.EInteger;
-import org.erlang.ETerm;
-import org.erlang.ETuple;
+import erjang.EAtom;
+import erjang.EInteger;
+import erjang.ETerm;
+import erjang.ETuple;
public class ExternalFunction {
diff --git a/src/erjang/jbeam/ops/FileDecl.java b/src/erjang/jbeam/ops/FileDecl.java
index e4802314..12af6c1d 100644
--- a/src/erjang/jbeam/ops/FileDecl.java
+++ b/src/erjang/jbeam/ops/FileDecl.java
@@ -1,6 +1,6 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
-import org.erlang.EString;
+import erjang.EString;
public class FileDecl extends Stmt {
diff --git a/src/erjang/jbeam/ops/FuncInfo.java b/src/erjang/jbeam/ops/FuncInfo.java
index dfe0ee3e..dfafb04d 100644
--- a/src/erjang/jbeam/ops/FuncInfo.java
+++ b/src/erjang/jbeam/ops/FuncInfo.java
@@ -1,10 +1,11 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
-import org.erlang.ERT;
-import org.erlang.EAtom;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method;
+import erjang.EAtom;
+import erjang.ERT;
+
public class FuncInfo extends Insn {
diff --git a/src/erjang/jbeam/ops/FunctionAdapter.java b/src/erjang/jbeam/ops/FunctionAdapter.java
index a41e55ed..0b76b1a6 100644
--- a/src/erjang/jbeam/ops/FunctionAdapter.java
+++ b/src/erjang/jbeam/ops/FunctionAdapter.java
@@ -1,18 +1,19 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
import java.util.HashMap;
import java.util.Map;
-import org.erlang.EAtom;
-import org.erlang.ETerm;
-import org.erlang.Tail;
-import org.erlang.jbeam.BEAMFile;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
+import erjang.EAtom;
+import erjang.ETerm;
+import erjang.Tail;
+import erjang.jbeam.BEAMFile;
+
public class FunctionAdapter extends CodeAdapter {
private static final Type TAIL_TYPE = Type.getType(Tail.class);
diff --git a/src/erjang/jbeam/ops/FunctionDecl.java b/src/erjang/jbeam/ops/FunctionDecl.java
index 6e2d176d..99e6ef40 100644
--- a/src/erjang/jbeam/ops/FunctionDecl.java
+++ b/src/erjang/jbeam/ops/FunctionDecl.java
@@ -1,12 +1,8 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
import java.util.ArrayList;
import java.util.List;
-import org.erlang.EAtom;
-import org.erlang.ETerm;
-import org.erlang.Tail;
-import org.erlang.jbeam.BEAMFile;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
@@ -14,6 +10,11 @@
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
+import erjang.EAtom;
+import erjang.ETerm;
+import erjang.Tail;
+import erjang.jbeam.BEAMFile;
+
public class FunctionDecl extends Stmt implements Opcodes {
private static final Type TAIL_TYPE = Type.getType(Tail.class);
diff --git a/src/erjang/jbeam/ops/GCBif.java b/src/erjang/jbeam/ops/GCBif.java
index 62894a88..3a616cbc 100644
--- a/src/erjang/jbeam/ops/GCBif.java
+++ b/src/erjang/jbeam/ops/GCBif.java
@@ -1,16 +1,17 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
-import org.erlang.EBIF;
-import org.erlang.EAtom;
-import org.erlang.ETerm;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
+import erjang.EAtom;
+import erjang.ETerm;
+import erjang.modules.ErlangModule;
+
public class GCBif extends Insn {
private static final Type EXCEPTION_TYPE = Type.getType(Exception.class);
- private static final Type BIF_TYPE = Type.getType(EBIF.class);
+ private static final Type BIF_TYPE = Type.getType(ErlangModule.class);
private static final Type ETERM_TYPE = Type.getType(ETerm.class);
diff --git a/src/erjang/jbeam/ops/Insn.java b/src/erjang/jbeam/ops/Insn.java
index 268400f1..019d0833 100644
--- a/src/erjang/jbeam/ops/Insn.java
+++ b/src/erjang/jbeam/ops/Insn.java
@@ -1,9 +1,10 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
-import org.erlang.ETerm;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
+import erjang.ETerm;
+
public abstract class Insn extends Stmt implements Opcodes {
Type emit_push(FunctionAdapter ma, Object value) {
diff --git a/src/erjang/jbeam/ops/ModuleDecl.java b/src/erjang/jbeam/ops/ModuleDecl.java
index 528d5771..8192e776 100644
--- a/src/erjang/jbeam/ops/ModuleDecl.java
+++ b/src/erjang/jbeam/ops/ModuleDecl.java
@@ -1,6 +1,6 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
-import org.erlang.EAtom;
+import erjang.EAtom;
public class ModuleDecl extends Stmt {
diff --git a/src/erjang/jbeam/ops/Move.java b/src/erjang/jbeam/ops/Move.java
index 9255fa53..2083d702 100644
--- a/src/erjang/jbeam/ops/Move.java
+++ b/src/erjang/jbeam/ops/Move.java
@@ -1,4 +1,4 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
public class Move extends Insn {
diff --git a/src/erjang/jbeam/ops/PutInsn.java b/src/erjang/jbeam/ops/PutInsn.java
index 9fcb3ff3..7594e399 100644
--- a/src/erjang/jbeam/ops/PutInsn.java
+++ b/src/erjang/jbeam/ops/PutInsn.java
@@ -1,4 +1,4 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
import org.objectweb.asm.Opcodes;
diff --git a/src/erjang/jbeam/ops/PutToupleInsn.java b/src/erjang/jbeam/ops/PutToupleInsn.java
index e057607e..766de346 100644
--- a/src/erjang/jbeam/ops/PutToupleInsn.java
+++ b/src/erjang/jbeam/ops/PutToupleInsn.java
@@ -1,4 +1,4 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
import org.objectweb.asm.Opcodes;
diff --git a/src/erjang/jbeam/ops/Register.java b/src/erjang/jbeam/ops/Register.java
index 4f55b932..da420c22 100644
--- a/src/erjang/jbeam/ops/Register.java
+++ b/src/erjang/jbeam/ops/Register.java
@@ -1,4 +1,4 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
import org.objectweb.asm.Type;
diff --git a/src/erjang/jbeam/ops/RegisterX.java b/src/erjang/jbeam/ops/RegisterX.java
index e41cc644..fbb6288d 100644
--- a/src/erjang/jbeam/ops/RegisterX.java
+++ b/src/erjang/jbeam/ops/RegisterX.java
@@ -1,4 +1,4 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
public class RegisterX extends Register {
diff --git a/src/erjang/jbeam/ops/RegisterY.java b/src/erjang/jbeam/ops/RegisterY.java
index 658cc743..83a1b7f4 100644
--- a/src/erjang/jbeam/ops/RegisterY.java
+++ b/src/erjang/jbeam/ops/RegisterY.java
@@ -1,4 +1,4 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
public class RegisterY extends Register {
diff --git a/src/erjang/jbeam/ops/Return.java b/src/erjang/jbeam/ops/Return.java
index 5669143c..0586e633 100644
--- a/src/erjang/jbeam/ops/Return.java
+++ b/src/erjang/jbeam/ops/Return.java
@@ -1,4 +1,4 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
public class Return extends Insn {
diff --git a/src/erjang/jbeam/ops/Stmt.java b/src/erjang/jbeam/ops/Stmt.java
index a0925e8a..0becd899 100644
--- a/src/erjang/jbeam/ops/Stmt.java
+++ b/src/erjang/jbeam/ops/Stmt.java
@@ -1,4 +1,4 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
public class Stmt {
diff --git a/src/erjang/jbeam/ops/Test.java b/src/erjang/jbeam/ops/Test.java
index f576e708..933710bd 100644
--- a/src/erjang/jbeam/ops/Test.java
+++ b/src/erjang/jbeam/ops/Test.java
@@ -1,17 +1,18 @@
-package org.erlang.jbeam.ops;
+package erjang.jbeam.ops;
-import org.erlang.EBIF;
-import org.erlang.EAtom;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
+import erjang.EAtom;
+import erjang.modules.ErlangModule;
+
public class Test extends Insn {
private final EAtom how;
private final Label failto;
private final Object[] args;
- private static final Type BIF_TYPE = Type.getType(EBIF.class);
+ private static final Type BIF_TYPE = Type.getType(ErlangModule.class);
public Test(EAtom how, Label failto, Object[] args) {
this.how = how;
diff --git a/src/erjang/modules/ErlangModule.java b/src/erjang/modules/ErlangModule.java
index a2efe65b..a3bdccec 100644
--- a/src/erjang/modules/ErlangModule.java
+++ b/src/erjang/modules/ErlangModule.java
@@ -1,15 +1,40 @@
-package org.erlang;
-
-import org.erlang.bif.Type;
-
-public class EBIF {
-
- @bif
+package erjang.modules;
+
+import java.math.BigInteger;
+
+import erjang.BIF;
+import erjang.EAtom;
+import erjang.EBig;
+import erjang.ECons;
+import erjang.EDouble;
+import erjang.EInteger;
+import erjang.ENode;
+import erjang.ENumber;
+import erjang.EObject;
+import erjang.EPID;
+import erjang.ERT;
+import erjang.ESeq;
+import erjang.ETuple;
+import erjang.ETuple3;
+import erjang.ErlFun;
+import erjang.Module;
+import erjang.BIF.Type;
+
+@Module("erlang")
+public class ErlangModule {
+
+ static final EAtom ATOM_TRUE = EAtom.intern("true");
+ static final EAtom ATOM_FALSE = EAtom.intern("false");
+
+ static {
+ }
+
+ @BIF @ErlFun(export=true)
static public EPID self() {
return null;
}
- @bif
+ @BIF @ErlFun(export=true)
static public EObject element(EInteger idx, EObject obj) {
ETuple tup;
if ((tup = obj.asTuple()) != null && tup.arity() >= idx.value) {
@@ -18,7 +43,7 @@ static public EObject element(EInteger idx, EObject obj) {
throw ERT.badarg("erlang", "element", idx, obj);
}
- @bif
+ @BIF
static public EObject element(EInteger idx, ETuple tup) {
if (tup.arity() >= idx.value) {
return tup.nth(idx.value);
@@ -26,7 +51,7 @@ static public EObject element(EInteger idx, ETuple tup) {
throw ERT.badarg("erlang", "element", idx, tup);
}
- @bif
+ @BIF
static public EObject element(int idx, ETuple tup) {
if (tup.arity() >= idx) {
return tup.nth(idx);
@@ -34,7 +59,7 @@ static public EObject element(int idx, ETuple tup) {
throw ERT.badarg("erlang", "element", idx, tup);
}
- @bif
+ @BIF
static public EObject element(int idx, EObject obj) {
ETuple tup;
if ((tup = obj.asTuple()) != null && tup.arity() >= idx) {
@@ -43,12 +68,12 @@ static public EObject element(int idx, EObject obj) {
throw ERT.badarg("erlang", "element", idx, obj);
}
- @bif
+ @BIF
static public EObject hd(ECons cell) {
return cell.head();
}
- @bif
+ @BIF
static public EObject hd(EObject cell) {
ECons cons;
if ((cons = cell.asCons()) != null) {
@@ -57,7 +82,7 @@ static public EObject hd(EObject cell) {
throw ERT.badarg("erlang", "hd", cell);
}
- @bif
+ @BIF
static public int length(EObject list) {
ESeq seq;
if ((seq = list.asSeq()) != null) {
@@ -66,12 +91,12 @@ static public int length(EObject list) {
throw ERT.badarg("erlang", "length", list);
}
- @bif
+ @BIF
static public int length(ESeq list) {
return list.length();
}
- @bif(name="length", type=Type.GUARD)
+ @BIF(name="length", type=Type.GUARD)
static public EInteger length$guard(EObject list) {
ESeq seq;
if ((seq = list.asSeq()) != null) {
@@ -80,31 +105,31 @@ static public int length(ESeq list) {
return null;
}
- @bif
+ @BIF @ErlFun(export=true)
static public ENode node() {
return null;
}
- @bif
+ @BIF @ErlFun(export=true)
static public ENode node(EObject name) {
return null;
}
// process dict
- @bif
+ @BIF @ErlFun(export=true)
static public ECons get() {
return null;
}
- @bif
+ @BIF @ErlFun(export=true)
static public EObject get(EObject key) {
return null;
}
// floats
- @bif(type=Type.ARITHBIF)
+ @BIF(type=Type.ARITHBIF)
static public double fdiv(double v1, double v2) {
if (v2 == 0.0)
throw ERT.badarith("erlang", "/", v1, v2);
@@ -112,34 +137,58 @@ static public double fdiv(double v1, double v2) {
return v1 / v2;
}
- @bif(type=Type.ARITHBIF)
+ @BIF(type=Type.ARITHBIF)
static public double fsub(double v1, double v2) {
return v1 - v2;
}
- @bif(type=Type.ARITHBIF)
+ @BIF(type=Type.ARITHBIF)
static public double fadd(double v1, double v2) {
return v1 + v2;
}
- @bif(type=Type.ARITHBIF)
+ @BIF(type=Type.ARITHBIF)
static public double fmul(double v1, double v2) {
return v1 * v2;
}
// arithmetic
- @bif(name="-")
- static public ENumber $minus$(EObject v1, int v2) {
+ @BIF(name="div")
+ static public ENumber div(EObject v1, int v2) {
+ ENumber n1;
+ if ((n1 = v1.asNumber()) != null) {
+ return n1.div(v2);
+ }
+ throw ERT.badarg();
+ }
+
+ @BIF(name="div")
+ static public ENumber div(ENumber n1, int v2) {
+ return n1.div(v2);
+ }
+
+ @BIF(name="-")
+ static public ENumber minus(EObject v1, int v2) {
ENumber n1;
if ((n1 = v1.asNumber()) != null) {
return n1.minus(v2);
}
- throw ERT.badarg((Throwable) null, "erlang", "-", v1, v2);
+ throw ERT.badarg("erlang", "-", v1, v2);
+ }
+
+ @BIF(name="-")
+ static public ENumber minus(int v1, int v2) {
+ long res = (long)v1 - (long)v2;
+ int intres = (int) res;
+ if (res == intres)
+ return new EInteger(intres);
+ else
+ return new EBig(BigInteger.valueOf(res));
}
- @bif(name="-")
- static public ENumber $minus$(EObject v1, EObject v2) {
+ @BIF(name="-") @ErlFun(name="-", export=true)
+ static public ENumber minus(EObject v1, EObject v2) {
ENumber n1;
if ((n1 = v1.asNumber()) != null) {
ENumber n2;
@@ -150,7 +199,7 @@ static public double fmul(double v1, double v2) {
throw ERT.badarg((Throwable) null, "erlang", "-", v1, v2);
}
- @bif(name="-", type=Type.GUARD)
+ @BIF(name="-", type=Type.GUARD)
static public ENumber subtract$guard(EObject v1, EObject v2) {
ENumber n1;
if ((n1 = v1.asNumber()) != null) {
@@ -162,7 +211,49 @@ static public double fmul(double v1, double v2) {
return null;
}
- @bif(name = "+")
+ @BIF(name="/", type=Type.GUARD)
+ static public ENumber divide$guard(EObject v1, EObject v2) {
+ ENumber n1;
+ if ((n1 = v1.asNumber()) != null) {
+ ENumber n2;
+ if ((n2 = v2.asNumber()) != null) {
+ if (n2.intValue() == 0) return null;
+ return n1.divide(v2);
+ }
+ }
+ return null;
+ }
+
+ @BIF(name="/", type=Type.GUARD)
+ static public ENumber divide$guard(EObject v1, double d2) {
+ ENumber n1;
+ if (d2 != 0.0 && (n1 = v1.asNumber()) != null) {
+ return n1.divide(d2);
+ }
+ return null;
+ }
+
+
+
+ @BIF(name = "+", type=Type.GUARD)
+ static public ENumber plus$guard(EObject v1, EObject v2) {
+ ENumber n1;
+ if ((n1 = v1.asNumber()) != null) {
+ ENumber n2;
+ if ((n2 = v2.asNumber()) != null) {
+ return n1.add(n2);
+ }
+ }
+ return null;
+ }
+
+
+ @BIF(name="+")
+ static public ENumber plus(int v1, int v2) {
+ return ENumber.valueFor((long)v1 + (long)v2);
+ }
+
+ @BIF(name = "+")
static public ENumber plus(EObject v1, EObject v2) {
ENumber n1;
if ((n1 = v1.asNumber()) != null) {
@@ -174,8 +265,17 @@ static public ENumber plus(EObject v1, EObject v2) {
throw ERT.badarg((Throwable) null, "erlang", "+", v1, v2);
}
- @bif(name = "*")
- static public ENumber $multiply$(EObject v1, EObject v2) {
+ @BIF(name = "+")
+ static public ENumber plus(EObject v1, int i2) {
+ ENumber n1;
+ if ((n1 = v1.asNumber()) != null) {
+ return n1.add(i2);
+ }
+ throw ERT.badarg(v1, i2);
+ }
+
+ @BIF(name = "*")
+ static public ENumber multiply(EObject v1, EObject v2) {
ENumber n1;
if ((n1 = v1.asNumber()) != null) {
ENumber n2;
@@ -186,7 +286,12 @@ static public ENumber plus(EObject v1, EObject v2) {
throw ERT.badarg((Throwable) null, "erlang", "+", v1, v2);
}
- @bif(name = "trunc")
+ @BIF(name = "*")
+ static public ENumber multiply(int v1, int v2) {
+ return ENumber.valueFor((long)v1 * (long)v2);
+ }
+
+ @BIF(name = "trunc") @ErlFun(export=true)
static public ENumber trunc(EObject v1) {
ENumber n1;
if ((n1 = v1.asNumber()) != null) {
@@ -195,17 +300,27 @@ static public ENumber trunc(EObject v1) {
throw ERT.badarg((Throwable) null, "erlang", "trunc", v1);
}
- @bif(name = "trunc")
+ @BIF(name = "trunc")
static public double trunc(double d) {
return Math.floor(d);
}
- @bif(name="round")
+ @BIF(name = "trunc")
+ static public double trunc(EDouble d1) {
+ return Math.floor(d1.value);
+ }
+
+ @BIF(name="round")
static public double round(double d) {
return Math.round(d);
}
- @bif(name = "rem")
+ @BIF(name="round")
+ static public double round(EDouble d) {
+ return Math.round(d.value);
+ }
+
+ @BIF @ErlFun(export=true)
static public ENumber rem(EObject v1, EObject v2) {
ENumber n1;
if ((n1 = v1.asNumber()) != null) {
@@ -217,7 +332,7 @@ static public ENumber rem(EObject v1, EObject v2) {
throw ERT.badarg("erlang", "rem", v1, v2);
}
- @bif(name="trunc", type=Type.GUARD)
+ @BIF(name="rem", type=Type.GUARD)
static public ENumber rem$guard(EObject v1, EObject v2) {
ENumber n1;
if ((n1 = v1.asNumber()) != null) {
@@ -229,7 +344,7 @@ static public ENumber rem(EObject v1, EObject v2) {
return null;
}
- @bif(name = "rem")
+ @BIF(name = "rem")
static public ENumber rem(EObject v1, int v2) {
ENumber n1;
if ((n1 = v1.asNumber()) != null) {
@@ -238,7 +353,7 @@ static public ENumber rem(EObject v1, int v2) {
throw ERT.badarg("erlang", "rem", v1, v2);
}
- @bif(name="abs", type=Type.GUARD)
+ @BIF(name="abs", type=Type.GUARD)
static public ENumber abs$guard(EObject v1) {
ENumber num;
if ((num = v1.asNumber()) != null) {
@@ -247,7 +362,7 @@ static public ENumber rem(EObject v1, int v2) {
return null;
}
- @bif(name = "abs")
+ @BIF(name = "abs") @ErlFun(export=true)
static public ENumber abs(EObject v1) {
ENumber num;
if ((num = v1.asNumber()) != null) {
@@ -256,12 +371,12 @@ static public ENumber abs(EObject v1) {
throw ERT.badarg("erlang", "abs", v1);
}
- @bif(name = "abs")
+ @BIF(name = "abs")
static public ENumber abs(ENumber v1) {
return v1.asb();
}
- @bif(name = "now")
+ @BIF(name = "now") @ErlFun(export=true)
static public ETuple3 now() {
long now = System.currentTimeMillis();
@@ -278,4 +393,12 @@ static public ETuple3 now() {
return res;
}
+ // tests
+
+ @BIF(name="is_eq",type=Type.GUARD)
+ public static final EAtom is_eq$g(EObject a1, EObject a2) { return a1.equals(a2) ? ATOM_TRUE : null; }
+
+ @BIF
+ public static final EAtom is_eq(EObject a1, EObject a2) { return a1.equals(a2) ? ATOM_TRUE : ATOM_FALSE; }
+
}