Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * Copyright The Sett Ltd, 2005 to 2014.
    *
    * 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 com.thesett.aima.logic.fol.wam.machine;
  
  import java.util.Set;
  
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.ALLOCATE;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.ALLOCATE_N;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.CALL;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.CON;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.DEALLOCATE;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.EXECUTE;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.GET_CONST;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.GET_LIST;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.GET_STRUC;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.GET_VAL;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.GET_VAR;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.LIS;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.PROCEED;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.PUT_CONST;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.PUT_LIST;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.PUT_STRUC;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.PUT_UNSAFE_VAL;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.PUT_VAL;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.PUT_VAR;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.REF;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.RETRY_ME_ELSE;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.SET_CONST;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.SET_LOCAL_VAL;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.SET_VAL;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.SET_VAR;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.SET_VOID;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.STACK_ADDR;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.STR;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.SUSPEND;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.TRUST_ME;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.TRY_ME_ELSE;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.UNIFY_CONST;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.UNIFY_LOCAL_VAL;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.UNIFY_VAL;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.UNIFY_VAR;
  import static com.thesett.aima.logic.fol.wam.compiler.WAMInstruction.UNIFY_VOID;
WAMResolvingJavaMachine is a byte code interpreter for WAM written in java. This is a direct implementation of the instruction interpretations given in "Warren's Abstract Machine: A Tutorial Reconstruction". The pseudo algorithm presented there can be read in the comments interspersed with the code. There are a couple of challenges to be solved that are not presented in the book:

  • The book describes a STORE[addr] operation that loads or stores a heap, register or stack address. In the L1 and L0 machines, only heap and register addresses had to be catered for. This made things easier because the registers could be held at the top of the heap and a single common address range used for both. With increasing numbers of data areas in the machine, and Java unable to use direct pointers into memory, a choice between having separate arrays for each data area, or building all data areas within a single array has to be made. The single array approach was chosen, because otherwise the addressing mode would need to be passed down into the 'deref' and 'unify' operations, which would be complicated by having to choose amongst which of several arrays to operate on. An addressing mode has had to be added to the instruction set, so that instructions loading data from registers or stack, can specify which. Once addresses are resolved relative to the register or stack basis, the plain addresses offset to the base of the whole data area are used, and it is these addresses that are passed to the 'deref' and 'unify' operations.
  • The memory layout for the WAM is described in Appendix B.3. of the book. The same layout is usd for this machine with the exception that the code area is held in a separate array. This follows the x86 machine convention of separating code and data segments in memory, and also caters well for the sharing of the code area with the JVM as a byte buffer.
  • The deref operation is presented in the book as a recursive function. It was turned into an equivalent iterative looping function instead. The deref operation returns multiple parameters, but as Java only supports single return types, a choice had to be made between creating a simple class to hold the return types, or storing the return values in member variables, and reading them from there. The member variables solution was chosen.

CRC Card
Responsibilities Collaborations
Execute compiled WAM programs and queries.
Provide access to the heap.

Author(s):
Rupert Smith
Todo:
Think about unloading of byte code as well as insertion of of byte code. For example, would it be possible to unload a program, and replace it with a different one? This would require re-linking of any references to the original. So maybe want to add an index to reverse references. Call instructions should have their jumps pre-calculated for speed, but perhaps should also put the bare f/n into them, for the case where they may need to be updated. Also, add a semaphore to all call instructions, or at the entry point of all programs, this would be used to synchronize live updates to programs in a running machine, as well as to add debugging break points.
Todo:
Think about ability to grow (and shrink?) the heap. Might be best to do this at the same time as the first garbage collector.
 
 {
    
Used for debugging.
 
     /* private static final Logger log = Logger.getLogger(WAMResolvingJavaMachine.class.getName()); */

    
Used for tracing instruction executions.
 
     private static final java.util.logging.Logger trace =
         java.util.logging.Logger.getLogger("TRACE.WAMResolvingJavaMachine");

    
The mask to extract an address from a tagged heap cell.
 
     public static final int AMASK = 0x3FFFFFFF;

    
The mask to extract a constant from a tagged heap cell. Arity of atomic constants is always zero, so just the functor name needs to be stored and loaded to the heap cell.
 
     public static final int CMASK = 0xFFFFFFF;

    
The shift to position the tag within a tagged heap cell.
 
     public static final int TSHIFT = 30;

    
Defines the register capacity for the virtual machine.
 
     private static final int REG_SIZE = 256;

    
Defines the heap size to use for the virtual machine.
 
     private static final int HEAP_SIZE = 10000;

    
Defines the offset of the base of the heap in the data area.
 
     private static final int HEAP_BASE = ;

    
Defines the stack size to use for the virtual machine.
 
     private static final int STACK_SIZE = 10000;

    
Defines the offset of the base of the stack in the data area.
 
     private static final int STACK_BASE =  + ;

    
Defines the trail size to use for the virtual machine.
 
     private static final int TRAIL_SIZE = 10000;

    
Defines the offset of the base of the trail in the data area.
 
     private static final int TRAIL_BASE =  +  + ;

    
Defines the max unification stack depth for the virtual machine.
 
     private static final int PDL_SIZE = 1000;

    
Defines the highest address in the data area of the virtual machine.
 
     private static final int TOP =  +  +  +  + ;

    
Defines the initial code area size for the virtual machine.
 
     private static final int CODE_SIZE = 10000;

    
Holds the current instruction pointer into the code.
 
     private int ip;

    
Holds the entire data segment of the machine. All registers, heaps and stacks are held in here.
 
     private IntBuffer data;

    
Holds the heap pointer.
 
     private int hp;

    
Holds the top of heap at the latest choice point.
 
     private int hbp;

    
Holds the secondary heap pointer, used for the heap address of the next term to match.
 
     private int sp;

    
Holds the unification stack pointer.
 
     private int up;

    
Holds the environment base pointer.
 
     private int ep;

    
Holds the choice point base pointer.
 
     private int bp;

    
Holds the last call choice point pointer.
 
     private int b0;

    
Holds the trail pointer.
 
     private int trp;

    
Used to record whether the machine is in structure read or write mode.
 
     private boolean writeMode;

    
Holds the heap cell tag from the most recent dereference.
 
     private byte derefTag;

    
Holds the heap call value from the most recent dereference.
 
     private int derefVal;

    
Indicates that the machine has been suspended, upon finding a solution.
 
     private boolean suspended;

    
Creates a unifying virtual machine for WAM with default heap sizes.

Parameters:
symbolTable The symbol table for the machine.
 
     public WAMResolvingJavaMachine(SymbolTable<IntegerStringObjectsymbolTable)
     {
         super(symbolTable);
 
         // Reset the machine to its initial state.
         reset();
     }

    
Resets the machine, to its initial state. This clears any programs from the machine, and clears all of its stacks and heaps.
 
     public void reset()
     {
         // Create fresh heaps, code areas and stacks.
          = ByteBuffer.allocateDirect( << 2).order(.).asIntBuffer();
          = ByteBuffer.allocateDirect();
 
         // Registers are on the top of the data area, the heap comes next.
          = ;
          = ;
          = ;
 
         // The stack comes after the heap. Pointers are zero initially, since no stack frames exist yet.
          = 0;
          = 0;
          = 0;
 
         // The trail comes after the stack.
          = ;
 
         // The unification stack (PDL) is a push down stack at the end of the data area.
          = ;
 
         // Turn off write mode.
          = false;
 
         // Reset the instruction pointer to that start of the code area, ready for fresh code to be loaded there.
          = 0;
 
         // Could probably not bother resetting these, but will do it anyway just to be sure.
          = 0;
          = 0;
 
         // The machine is initially not suspended.
          = false;
 
         // Ensure that the overridden reset method of WAMBaseMachine is run too, to clear the call table.
         super.reset();
 
         // Notify any debug monitor that the machine has been reset.
         if ( != null)
         {
             .onReset(this);
         }
     }

    
Provides an iterator that generates all solutions on demand as a sequence of variable bindings.

Returns:
An iterator that generates all solutions on demand as a sequence of variable bindings.
 
     public Iterator<Set<Variable>> iterator()
     {
         return new SequenceIterator<Set<Variable>>()
             {
                 public Set<VariablenextInSequence()
                 {
                     return resolve();
                 }
             };
     }

    
Sets the maximum number of search steps that a search method may take. If it fails to find a solution before this number of steps has been reached its search method should fail and return null. What exactly constitutes a single step, and the granularity of the step size, is open to different interpretation by different search algorithms. The guideline is that this is the maximum number of states on which the goal test should be performed.

Parameters:
max The maximum number of states to goal test. If this is zero or less then the maximum number of steps will not be checked for.
 
     public void setMaxSteps(int max)
     {
         throw new UnsupportedOperationException("WAMResolvingJavaMachine does not support max steps limit on search.");
     }

    
 
     public IntBuffer getDataBuffer()
     {
         return ;
     }

    
 
     {
         return new WAMInternalRegisters();
     }

    
 
     public WAMMemoryLayout getMemoryLayout()
     {
              - );
     }

    

Does nothing.

 
     protected void codeAdded(ByteBuffer codeBufferint codeOffsetint length)
     {
     }

    
 
     protected int derefStack(int a)
     {
         /*log.fine("Stack deref from " + (a + ep + 3) + ", ep = " + ep);*/
 
         return deref(a +  + 3);
     }

    
 
     protected boolean execute(WAMCallPoint callPoint)
     {
         /*log.fine("protected boolean execute(WAMCallPoint callPoint): called");*/
 
         boolean failed;
 
         // Check if the machine is being woken up from being suspended, in which case immediately fail in order to
         // trigger back-tracking to find more solutions.
         if ()
         {
             failed = true;
              = false;
         }
         else
         {
              = callPoint.entryPoint;
             uClear();
             failed = false;
         }
 
         int numOfArgs = 0;
 
         // Holds the current continuation point.
         int cp = .position();
 
         // Notify any debug monitor that execution is starting.
         if ( != null)
         {
             .onExecute(this);
         }
 
         //while (!failed && (ip < code.length))
         while (true)
         {
             // Attempt to backtrack on failure.
             if (failed)
             {
                 failed = backtrack();
 
                 if (failed)
                 {
                     break;
                 }
             }
 
             // Grab next instruction and switch on it.
             byte instruction = .get();
 
             switch (instruction)
             {
             // put_struc Xi, f/n:
             case :
             {
                 // grab addr, f/n
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
                 int fn = .getInt( + 3);
 
                 .fine( + ": PUT_STRUC " + printSlot(ximode) + ", " + fn);
 
                 // heap[h] <- STR, h + 1
                 .put(fn);
 
                 // Xi <- heap[h]
                 .put(xistructureAt());
 
                 // h <- h + 2
                  += 1;
 
                 // P <- instruction_size(P)
                  += 7;
 
                 break;
             }
 
             // set_var Xi:
             case :
             {
                 // grab addr
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
 
                 .fine( + ": SET_VAR " + printSlot(ximode));
 
                 // heap[h] <- REF, h
                 .put(refTo());
 
                 // Xi <- heap[h]
                 .put(xi.get());
 
                 // h <- h + 1
                 ++;
 
                 // P <- instruction_size(P)
                  += 3;
 
                 break;
             }
 
             // set_val Xi:
             case :
             {
                 // grab addr
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
 
                 .fine( + ": SET_VAL " + printSlot(ximode));
 
                 // heap[h] <- Xi
                 .put(.get(xi));
 
                 // h <- h + 1
                 ++;
 
                 // P <- instruction_size(P)
                  += 3;
 
                 break;
             }
 
             // get_struc Xi,
             case :
             {
                 // grab addr, f/n
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
                 int fn = .getInt( + 3);
 
                 .fine( + ": GET_STRUC " + printSlot(ximode) + ", " + fn);
 
                 // addr <- deref(Xi);
                 int addr = deref(xi);
                 byte tag = ;
                 int a = ;
 
                 // switch STORE[addr]
                 switch (tag)
                 {
                 // case REF:
                 case :
                 {
                     // heap[h] <- STR, h + 1
                     .put(structureAt( + 1));
 
                     // heap[h+1] <- f/n
                     .put( + 1, fn);
 
                     // bind(addr, h)
                     bind(addr);
 
                     // h <- h + 2
                      += 2;
 
                     // mode <- write
                      = true;
                     .fine("-> write mode");
 
                     break;
                 }
 
                 // case STR, a:
                 case :
                 {
                     // if heap[a] = f/n
                     if (.get(a) == fn)
                     {
                         // s <- a + 1
                          = a + 1;
 
                         // mode <- read
                          = false;
                         .fine("-> read mode");
                     }
                     else
                     {
                         // fail
                         failed = true;
                     }
 
                     break;
                 }
 
                 default:
                 {
                     // fail
                     failed = true;
                 }
                 }
 
                 // P <- instruction_size(P)
                  += 7;
 
                 break;
             }
 
             // unify_var Xi:
             case :
             {
                 // grab addr
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
 
                 .fine( + ": UNIFY_VAR " + printSlot(ximode));
 
                 // switch mode
                 if (!)
                 {
                     // case read:
                     // Xi <- heap[s]
                     .put(xi.get());
                 }
                 else
                 {
                     // case write:
                     // heap[h] <- REF, h
                     .put(refTo());
 
                     // Xi <- heap[h]
                     .put(xi.get());
 
                     // h <- h + 1
                     ++;
                 }
 
                 // s <- s + 1
                 ++;
 
                 // P <- P + instruction_size(P)
                  += 3;
 
                 break;
             }
 
             // unify_val Xi:
             case :
             {
                 // grab addr
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
 
                 .fine( + ": UNIFY_VAL " + printSlot(ximode));
 
                 // switch mode
                 if (!)
                 {
                     // case read:
                     // unify (Xi, s)
                     failed = !unify(xi);
                 }
                 else
                 {
                     // case write:
                     // heap[h] <- Xi
                     .put(.get(xi));
 
                     // h <- h + 1
                     ++;
                 }
 
                 // s <- s + 1
                 ++;
 
                 // P <- P + instruction_size(P)
                  += 3;
 
                 break;
             }
 
             // put_var Xn, Ai:
             case :
             {
                 // grab addr, Ai
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
                 byte ai = .get( + 3);
 
                 .fine( + ": PUT_VAR " + printSlot(ximode) + ", A" + ai);
 
                 if (mode == .)
                 {
                     // heap[h] <- REF, H
                     .put(refTo());
 
                     // Xn <- heap[h]
                     .put(xi.get());
 
                     // Ai <- heap[h]
                     .put(ai.get());
                 }
                 else
                 {
                     // STACK[addr] <- REF, addr
                     .put(xirefTo(xi));
 
                     // Ai <- STACK[addr]
                     .put(ai.get(xi));
                 }
 
                 // h <- h + 1
                 ++;
 
                 // P <- P + instruction_size(P)
                  += 4;
 
                 break;
             }
 
             // put_val Xn, Ai:
             case :
             {
                 // grab addr, Ai
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
                 byte ai = .get( + 3);
 
                 .fine( + ": PUT_VAL " + printSlot(ximode) + ", A" + ai);
 
                 // Ai <- Xn
                 .put(ai.get(xi));
 
                 // P <- P + instruction_size(P)
                  += 4;
 
                 break;
             }
 
             // get var Xn, Ai:
             case :
             {
                 // grab addr, Ai
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
                 byte ai = .get( + 3);
 
                 .fine( + ": GET_VAR " + printSlot(ximode) + ", A" + ai);
 
                 // Xn <- Ai
                 .put(xi.get(ai));
 
                 // P <- P + instruction_size(P)
                  += 4;
 
                 break;
             }
 
             // get_val Xn, Ai:
             case :
             {
                 // grab addr, Ai
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
                 byte ai = .get( + 3);
 
                 .fine( + ": GET_VAL " + printSlot(ximode) + ", A" + ai);
 
                 // unify (Xn, Ai)
                 failed = !unify(xiai);
 
                 // P <- P + instruction_size(P)
                  += 4;
 
                 break;
             }
 
             case :
             {
                 // grab addr, f/n
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
                 int fn = .getInt( + 3);
 
                 .fine( + ": PUT_CONST " + printSlot(ximode) + ", " + fn);
 
                 // Xi <- heap[h]
                 .put(xiconstantCell(fn));
 
                 // P <- instruction_size(P)
                  += 7;
 
                 break;
             }
 
             case :
             {
                 // grab addr, Ai
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
                 int fn = .getInt( + 3);
 
                 .fine( + ": GET_CONST " + printSlot(ximode) + ", " + fn);
 
                 // addr <- deref(Xi)
                 int addr = deref(xi);
                 int tag = ;
                 int val = ;
 
                 failed = !unifyConst(fnxi);
 
                 // P <- P + instruction_size(P)
                  += 7;
 
                 break;
             }
 
             case :
             {
                 int fn = .getInt( + 1);
 
                 .fine( + ": SET_CONST " + fn);
 
                 // heap[h] <- <CON, c>
                 .put(constantCell(fn));
 
                 // h <- h + 1
                 ++;
 
                 // P <- instruction_size(P)
                  += 5;
 
                 break;
             }
 
             case :
             {
                 int fn = .getInt( + 1);
 
                 .fine( + ": UNIFY_CONST " + fn);
 
                 // switch mode
                 if (!)
                 {
                     // case read:
                     // addr <- deref(S)
 
                     // unifyConst(fn, addr)
                     failed = !unifyConst(fn);
                 }
                 else
                 {
                     // case write:
                     // heap[h] <- <CON, c>
                     .put(constantCell(fn));
 
                     // h <- h + 1
                     ++;
                 }
 
                 // s <- s + 1
                 ++;
 
                 // P <- P + instruction_size(P)
                  += 5;
 
                 break;
             }
 
             case :
             {
                 // grab addr
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
 
                 .fine( + ": PUT_LIST " + printSlot(ximode));
 
                 // Xi <- <LIS, H>
                 .put(xilistCell());
 
                 // P <- P + instruction_size(P)
                  += 3;
 
                 break;
             }
 
             case :
             {
                 // grab addr
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
 
                 .fine( + ": GET_LIST " + printSlot(ximode));
 
                 int addr = deref(xi);
                 int tag = ;
                 int val = ;
 
                 // case STORE[addr] of
                 switch (tag)
                 {
                 case :
                 {
                     // <REF, _> :
                     // HEAP[H] <- <LIS, H+1>
                     .put(listCell( + 1));
 
                     // bind(addr, H)
                     bind(addr);
 
                     // H <- H + 1
                      += 1;
 
                     // mode <- write
                      = true;
                     .fine("-> write mode");
 
                     break;
                 }
 
                 case :
                 {
                     // <LIS, a> :
                     // S <- a
                      = val;
 
                     // mode <- read
                      = false;
                     .fine("-> read mode");
 
                     break;
                 }
 
                 default:
                 {
                     // other: fail <- true;
                     failed = true;
                 }
                 }
 
                 // P <- P + instruction_size(P)
                  += 3;
 
                 break;
             }
 
             case :
             {
                 // grab N
                 int n = (int.get( + 1);
 
                 .fine( + ": SET_VOID " + n);
 
                 // for i <- H to H + n - 1 do
                 //  HEAP[i] <- <REF, i>
                 for (int addr = addr < ( + n); addr++)
                 {
                     .put(addrrefTo(addr));
                 }
 
                 // H <- H + n
                  += n;
 
                 // P <- P + instruction_size(P)
                  += 2;
 
                 break;
             }
 
             case :
             {
                 // grab N
                 int n = (int.get( + 1);
 
                 .fine( + ": UNIFY_VOID " + n);
 
                 // case mode of
                 if (!)
                 {
                     //  read: S <- S + n
                      += n;
                 }
                 else
                 {
                     //  write:
                     //   for i <- H to H + n -1 do
                     //    HEAP[i] <- <REF, i>
                     for (int addr = addr < ( + n); addr++)
                     {
                         .put(addrrefTo(addr));
                     }
 
                     //   H <- H + n
                      += n;
                 }
 
                 // P <- P + instruction_size(P)
                  += 2;
 
                 break;
             }
 
             // put_unsafe_val Yn, Ai:
             case :
             {
                 // grab addr, Ai
                 byte mode = .get( + 1);
                 int yi = (int.get( + 2) + ( + 3);
                 byte ai = .get( + 3);
 
                 .fine( + ": PUT_UNSAFE_VAL " + printSlot(yi.) + ", A" + ai);
 
                 int addr = deref(yi);
 
                 if (addr < )
                 {
                     // Ai <- Xn
                     .put(ai.get(addr));
                 }
                 else
                 {
                     .put(refTo());
                     bind(addr);
                     .put(ai.get());
                     ++;
                 }
 
                 // P <- P + instruction_size(P)
                  += 4;
 
                 break;
             }
 
             // set_local_val Xi:
             case :
             {
                 // grab addr
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
 
                 .fine( + ": SET_LOCAL_VAL " + printSlot(ximode));
 
                 int addr = deref(xi);
 
                 if (addr < )
                 {
                     .put(.get(addr));
                 }
                 else
                 {
                     .put(refTo());
                     bind(addr);
                 }
 
                 // h <- h + 1
                 ++;
 
                 // P <- P + instruction_size(P)
                  += 3;
 
                 break;
             }
 
             // unify_local_val Xi:
             case :
             {
                 // grab addr
                 byte mode = .get( + 1);
                 int xi = getRegisterOrStackSlot(mode);
 
                 .fine( + ": UNIFY_LOCAL_VAL " + printSlot(ximode));
 
                 // switch mode
                 if (!)
                 {
                     // case read:
                     // unify (Xi, s)
                     failed = !unify(xi);
                 }
                else
                {
                    // case write:
                    int addr = deref(xi);
                    if (addr < )
                    {
                        .put(.get(addr));
                    }
                    else
                    {
                        .put(refTo());
                        bind(addr);
                    }
                    // h <- h + 1
                    ++;
                }
                // s <- s + 1
                ++;
                // P <- P + instruction_size(P)
                 += 3;
                break;
            }
            // call @(p/n), perms:
            case :
            {
                // grab @(p/n), perms
                int pn = .getInt( + 1);
                int n = .get( + 5);
                int numPerms = (int.get( + 6);
                // num_of_args <- n
                numOfArgs = n;
                // Ensure that the predicate to call is known and linked in, otherwise fail.
                if (pn == -1)
                {
                    failed = true;
                    break;
                }
                // STACK[E + 2] <- numPerms
                .put( + 2, numPerms);
                // CP <- P + instruction_size(P)
                cp =  + 7;
                .fine( + ": CALL " + pn + "/" + n + ", " + numPerms + " (cp = " + cp + ")]");
                // B0 <- B
                 = ;
                // P <- @(p/n)
                 = pn;
                break;
            }
            // execute @(p/n):
            case :
            {
                // grab @(p/n)
                int pn = .getInt( + 1);
                int n = .get( + 5);
                // num_of_args <- n
                numOfArgs = n;
                .fine( + ": EXECUTE " + pn + "/" + n + " (cp = " + cp + ")]");
                // Ensure that the predicate to call is known and linked in, otherwise fail.
                if (pn == -1)
                {
                    failed = true;
                    break;
                }
                // B0 <- B
                 = ;
                // P <- @(p/n)
                 = pn;
                break;
            }
            // proceed:
            case :
            {
                .fine( + ": PROCEED" + " (cp = " + cp + ")]");
                // P <- CP
                 = cp;
                break;
            }
            // allocate:
            case :
            {
                // if E > B
                //  then newB <- E + STACK[E + 2] + 3
                // else newB <- B + STACK[B] + 7
                int esp = nextStackFrame();
                // STACK[newE] <- E
                .put(esp);
                // STACK[E + 1] <- CP
                .put(esp + 1, cp);
                // STACK[E + 2] <- N
                .put(esp + 2, 0);
                // E <- newE
                // newE <- E + n + 3
                 = esp;
                .fine( + ": ALLOCATE");
                .fine("-> env @ " +  + " " + traceEnvFrame());
                // P <- P + instruction_size(P)
                 += 1;
                break;
            }
            // allocate N:
            case :
            {
                // grab N
                int n = (int.get( + 1);
                // if E > B
                //  then newB <- E + STACK[E + 2] + 3
                // else newB <- B + STACK[B] + 7
                int esp = nextStackFrame();
                // STACK[newE] <- E
                .put(esp);
                // STACK[E + 1] <- CP
                .put(esp + 1, cp);
                // STACK[E + 2] <- N
                .put(esp + 2, n);
                // E <- newE
                // newE <- E + n + 3
                 = esp;
                .fine( + ": ALLOCATE_N " + n);
                .fine("-> env @ " +  + " " + traceEnvFrame());
                // P <- P + instruction_size(P)
                 += 2;
                break;
            }
            // deallocate:
            case :
            {
                int newip = .get( + 1);
                // E <- STACK[E]
                 = .get();
                .fine( + ": DEALLOCATE");
                .fine("<- env @ " +  + " " + traceEnvFrame());
                // CP <- STACK[E + 1]
                cp = newip;
                // P <- P + instruction_size(P)
                 += 1;
                break;
            }
            // try me else L:
            case :
            {
                // grab L
                int l = .getInt( + 1);
                // if E > B
                //  then newB <- E + STACK[E + 2] + 3
                // else newB <- B + STACK[B] + 7
                int esp = nextStackFrame();
                // STACK[newB] <- num_of_args
                // n <- STACK[newB]
                int n = numOfArgs;
                .put(espn);
                // for i <- 1 to n do STACK[newB + i] <- Ai
                for (int i = 0; i < ni++)
                {
                    .put(esp + i + 1, .get(i));
                }