major refactoring of edu.berkeley.fleet.loops, includes renaming Context to CodeBag
[fleet.git] / src / edu / berkeley / fleet / loops / CodeBag.java
index 6478802..d8b078f 100644 (file)
 package edu.berkeley.fleet.loops;
-import edu.berkeley.fleet.api.*;
 import java.util.*;
 import java.net.*;
+import edu.berkeley.fleet.two.*;
+import edu.berkeley.fleet.api.*;
+import edu.berkeley.fleet.api.Instruction.*;
+import edu.berkeley.fleet.api.Instruction.Set;
+import edu.berkeley.fleet.api.Instruction.Set.*;
+import static edu.berkeley.fleet.util.BitManipulations.*;
+
+
+// QUESTION: does each dock mentioned by a context have a linear chain
+// of loops, or can it branch?
+
+//    - or should we use "sub-contexts" for that
+//        - advantage: it lets us convey the fact that a bunch of loops are dispatched together
+//    - should loops have an "invoke context" opcode?
 
 /**
- *  A CodeBag represents the instructions of a Context along with
- *  (compile-time) knowledge of where it resides.  Consequently, it is
- *  meaningful to say "give me the sequence of instructions which will
- *  invoke this CodeBag".
+ *  A CodeBag is a collection of Loops which obey these rules:
+ *
+ *    - A CodeBag has exclusive control of all docks mentioned by any of its Loops.
+ *    - A CodeBag includes a "starting loop" for every dock it mentions.
+ *    - When a CodeBag is spawned, it starts the "starting loop" on all of its docks.
+ *    - A loop may or may not have a successor.
+ *    - Control may transfer only two ways:
+ *        - If a loop has a successor, control will transfer to the successor when the loop finishes.
+ *        - A loop may explicitly transfer control to another loop via abortAndInvoke().  The
+ *          invoked loop must belong to the same Dock and the same CodeBag.
+ *    - A CodeBag finishes when all of its docks have finished executing a loop with no successor.
+ *
+ *  Definitions:
+ *    - A Move instruction is a blocking instruction if either its   tokenIn or dataIn bits are set.
+ *    - All other instructions  are non-blocking.
+ *    - A dock is quiescent if its instruction ring is empty.
+ *    - A dock is pre-quiescent if 
+ *        - all instructions which remain in the target dock's instruction
+ *          fifo are nonblocking instructions,
+ *        - either the docks' OLC=0 or all instructions which remain
+ *          in its instruction fifo are one-shot instructions
+ *        - after executing these remaining instructions, the dock's hatch is open
+ */
+
+/*
+ *                          SF         works       works @diff    ok for non   size    ships
+ * Dispatch Method       Crossings     @inbox?       docks?       tail call?   limit   consumed
+ * ------------------------------------------------------------------------------------------
+ * 
+ * Inline                    0           Y              N             N        Small  None
+ * 
+ * Inline literals           1           N              Y             Y        Tiny   None
+ *  w/ "dispatch"
+ * 
+ * Send CBD to               2+          N              Y             Y        None   None (mem ship)
+ * memory ship
+ * 
+ * Send token to             3+          Y              Y             Y        None   One Output Dock
+ * assistant outbox first
+ * 
+ * Release from FIFO         2           Y              Y             Y        Med    1x FIFO, but can be shared
+ * 
  */
+
 public class CodeBag {
 
-    /*
-     *                          SF         works       works @diff    ok for non   size    ships
-     * Dispatch Method       Crossings     @inbox?       docks?       tail call?   limit   consumed
-     * ------------------------------------------------------------------------------------------
-     * 
-     * Inline                    0           Y              N             N        Small  None
-     * 
-     * Inline literals           1           N              Y             Y        Tiny   None
-     *  w/ "dispatch"
-     * 
-     * Send CBD to               2+          N              Y             Y        None   None (mem ship)
-     * memory ship
-     * 
-     * Send token to             3+          Y              Y             Y        None   One Output Dock
-     * assistant outbox first
-     * 
-     * Release from FIFO         2           Y              Y             Y        Med    1x FIFO, but can be shared
-     * 
-     */
-
-    final Program program;
-    final Instruction[] instructions;
-    final long baseAddress;
-
-    /**
-     *  Given a Context, creates a CodeBag which will live in the
-     *  Memory ship memoryShip at the address given by baseAddress.
-     */
-    CodeBag(Program program, Instruction[] instructions, long baseAddress) {
-        int MAX_BAG_SIZE = (1<<7)-1;
-        if (instructions.length > MAX_BAG_SIZE)
-            throw new RuntimeException("warning: code bag size is "+instructions.length+
-                                       ", which exceeds maximum of "+MAX_BAG_SIZE+
-                                       "; breaking into multiple bags");
-        this.program = program;
-        this.instructions = instructions;
-        this.baseAddress = baseAddress;
+    public final Fleet fleet;
+
+    private Program program = null;
+    private BitVector descriptor = null;
+    public DeferredBitVector getDescriptor() {
+        return new DeferredBitVector() {
+            public BitVector getBitVector() {
+                if (program==null) throw new RuntimeException();
+                seal();
+                return descriptor;
+            } };
+    }
+
+    LinkedHashMap<Dock,LoopFactory> startupLoopFactories = new LinkedHashMap<Dock,LoopFactory>();
+    ArrayList<LoopFactory> loopFactories = new ArrayList<LoopFactory>();
+
+    // FIXME: currently not used
+    private boolean sealed = false;
+    public boolean isSealed() { return sealed; }
+    public void seal() {
+        if (sealed) return;
+        for(LoopFactory lf : loopFactories) lf.flush_pending();
+        sealed = true;
+        if (program!=null) descriptor = program.addInstructions(emit());
+    }
+
+    public CodeBag(Fleet fleet) { this(fleet, null); }
+    public CodeBag(Program prog) { this(prog.fleet, prog); }
+    public CodeBag(Fleet fleet, Program prog) {
+        this.fleet = fleet;
+        this.program = prog;
+    }
+
+    public LoopFactory loopFactory(Dock dock, int count) { return loopFactory(dock, count, count==0); }
+    public LoopFactory loopFactory(Dock dock, int count, boolean torpedoable) {
+        LoopFactory ret = startupLoopFactories.get(dock);
+        if (ret == null) return new LoopFactory(this, dock, count, torpedoable);
+        while (ret.getNext()!=null)
+            ret = ret.getNext();
+        return ret.makeNext(count, torpedoable);
+    }
+
+    boolean autoflush = false;
+    public void setAutoflush(boolean a) { this.autoflush = a; }
+    public boolean getAutoflush() { return autoflush; }
+
+    public void emit(ArrayList<Instruction> ic) {
+        seal();
+        for(LoopFactory lf : startupLoopFactories.values())
+            lf.emit(ic);
+    }
+
+    private LoopFactory hack = null;
+    public void sendTorpedo(Dock dock) {
+        if (hack==null) hack = loopFactory(fleet.getShip("Timer",0).getDock("out"), 1);
+        hack.sendToken(dock.getInstructionDestination());
+    }
+    public void sendWord(DeferredBitVector bv, Destination dest) {
+        // problem: this isn't actually atomic -- two uncoordinated
+        // actors might invoke these commands at the same time
+        if (hack==null) hack = loopFactory(fleet.getShip("Timer",0).getDock("out"), 1);
+        hack.literal(bv);
+        hack.sendWord(dest);
+    }
+
+    public Instruction[] emit() {
+        ArrayList<Instruction> ic = new ArrayList<Instruction>();
+        emit(ic);
+        return (Instruction[])ic.toArray(new Instruction[0]);
+    }
+
+    public void dispatch(FleetProcess fp) { dispatch(fp, false); }
+    public void dispatch(FleetProcess fp, boolean flushWhenDone) {
+        ArrayList<Instruction> ai;
+        emit(ai = new ArrayList<Instruction>());
+        for(Instruction ins : ai)
+            fp.sendInstruction(ins);
+        if (flushWhenDone) fp.flush();
+    }
+
+    public void append(CodeBag ctx) {
+        if (sealed) throw new RuntimeException("already sealed");
+        // how to handle ship pools?
+        throw new RuntimeException("not implemented");
     }
 
 }