lojix/wam_prolog/src/main/com/thesett/aima/logic/fol/wam/machine/WAMResolvingJavaMachine.java
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 (suspended)
        {
            failed = true;
            suspended = false;
        }
        else
        {
            ip = callPoint.entryPoint;
            uClear();
            failed = false;
        }

        int numOfArgs = 0;

        // Holds the current continuation point.
        cp = codeBuffer.position();

        // Notify any debug monitor that execution is starting.
        if (monitor != null)
        {
            monitor.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 = codeBuffer.get(ip);

            switch (instruction)
            {
            // put_struc Xi, f/n:
            case PUT_STRUC:
            {
                // grab addr, f/n
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                int fn = codeBuffer.getInt(ip + 3);

                /*trace.fine(ip + ": PUT_STRUC " + printSlot(xi, mode) + ", " + fn);*/

                // heap[h] <- STR, h + 1
                data.put(hp, fn);

                // Xi <- heap[h]
                data.put(xi, structureAt(hp));

                // h <- h + 2
                hp += 1;

                // P <- instruction_size(P)
                ip += 7;

                break;
            }

            // set_var Xi:
            case SET_VAR:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": SET_VAR " + printSlot(xi, mode));*/

                // heap[h] <- REF, h
                data.put(hp, refTo(hp));

                // Xi <- heap[h]
                data.put(xi, data.get(hp));

                // h <- h + 1
                hp++;

                // P <- instruction_size(P)
                ip += 3;

                break;
            }

            // set_val Xi:
            case SET_VAL:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": SET_VAL " + printSlot(xi, mode));*/

                // heap[h] <- Xi
                data.put(hp, data.get(xi));

                // h <- h + 1
                hp++;

                // P <- instruction_size(P)
                ip += 3;

                break;
            }

            // get_struc Xi,
            case GET_STRUC:
            {
                // grab addr, f/n
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                int fn = codeBuffer.getInt(ip + 3);

                /*trace.fine(ip + ": GET_STRUC " + printSlot(xi, mode) + ", " + fn);*/

                // addr <- deref(Xi);
                int addr = deref(xi);
                byte tag = derefTag;
                int a = derefVal;

                // switch STORE[addr]
                switch (tag)
                {
                // case REF:
                case REF:
                {
                    // heap[h] <- STR, h + 1
                    data.put(hp, structureAt(hp + 1));

                    // heap[h+1] <- f/n
                    data.put(hp + 1, fn);

                    // bind(addr, h)
                    bind(addr, hp);

                    // h <- h + 2
                    hp += 2;

                    // mode <- write
                    writeMode = true;
                    /*trace.fine("-> write mode");*/

                    break;
                }

                // case STR, a:
                case STR:
                {
                    // if heap[a] = f/n
                    if (data.get(a) == fn)
                    {
                        // s <- a + 1
                        sp = a + 1;

                        // mode <- read
                        writeMode = false;
                        /*trace.fine("-> read mode");*/
                    }
                    else
                    {
                        // fail
                        failed = true;
                    }

                    break;
                }

                default:
                {
                    // fail
                    failed = true;
                }
                }

                // P <- instruction_size(P)
                ip += 7;

                break;
            }

            // unify_var Xi:
            case UNIFY_VAR:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": UNIFY_VAR " + printSlot(xi, mode));*/

                // switch mode
                if (!writeMode)
                {
                    // case read:
                    // Xi <- heap[s]
                    data.put(xi, data.get(sp));
                }
                else
                {
                    // case write:
                    // heap[h] <- REF, h
                    data.put(hp, refTo(hp));

                    // Xi <- heap[h]
                    data.put(xi, data.get(hp));

                    // h <- h + 1
                    hp++;
                }

                // s <- s + 1
                sp++;

                // P <- P + instruction_size(P)
                ip += 3;

                break;
            }

            // unify_val Xi:
            case UNIFY_VAL:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": UNIFY_VAL " + printSlot(xi, mode));*/

                // switch mode
                if (!writeMode)
                {
                    // case read:
                    // unify (Xi, s)
                    failed = !unify(xi, sp);
                }
                else
                {
                    // case write:
                    // heap[h] <- Xi
                    data.put(hp, data.get(xi));

                    // h <- h + 1
                    hp++;
                }

                // s <- s + 1
                sp++;

                // P <- P + instruction_size(P)
                ip += 3;

                break;
            }

            // put_var Xn, Ai:
            case PUT_VAR:
            {
                // grab addr, Ai
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                byte ai = codeBuffer.get(ip + 3);

                /*trace.fine(ip + ": PUT_VAR " + printSlot(xi, mode) + ", A" + ai);*/

                if (mode == WAMInstruction.REG_ADDR)
                {
                    // heap[h] <- REF, H
                    data.put(hp, refTo(hp));

                    // Xn <- heap[h]
                    data.put(xi, data.get(hp));

                    // Ai <- heap[h]
                    data.put(ai, data.get(hp));
                }
                else
                {
                    // STACK[addr] <- REF, addr
                    data.put(xi, refTo(xi));

                    // Ai <- STACK[addr]
                    data.put(ai, data.get(xi));
                }

                // h <- h + 1
                hp++;

                // P <- P + instruction_size(P)
                ip += 4;

                break;
            }

            // put_val Xn, Ai:
            case PUT_VAL:
            {
                // grab addr, Ai
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                byte ai = codeBuffer.get(ip + 3);

                /*trace.fine(ip + ": PUT_VAL " + printSlot(xi, mode) + ", A" + ai);*/

                // Ai <- Xn
                data.put(ai, data.get(xi));

                // P <- P + instruction_size(P)
                ip += 4;

                break;
            }

            // get var Xn, Ai:
            case GET_VAR:
            {
                // grab addr, Ai
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                byte ai = codeBuffer.get(ip + 3);

                /*trace.fine(ip + ": GET_VAR " + printSlot(xi, mode) + ", A" + ai);*/

                // Xn <- Ai
                data.put(xi, data.get(ai));

                // P <- P + instruction_size(P)
                ip += 4;

                break;
            }

            // get_val Xn, Ai:
            case GET_VAL:
            {
                // grab addr, Ai
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                byte ai = codeBuffer.get(ip + 3);

                /*trace.fine(ip + ": GET_VAL " + printSlot(xi, mode) + ", A" + ai);*/

                // unify (Xn, Ai)
                failed = !unify(xi, ai);

                // P <- P + instruction_size(P)
                ip += 4;

                break;
            }

            case PUT_CONST:
            {
                // grab addr, f/n
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                int fn = codeBuffer.getInt(ip + 3);

                /*trace.fine(ip + ": PUT_CONST " + printSlot(xi, mode) + ", " + fn);*/

                // Xi <- heap[h]
                data.put(xi, constantCell(fn));

                // P <- instruction_size(P)
                ip += 7;

                break;
            }

            case GET_CONST:
            {
                // grab addr, Ai
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                int fn = codeBuffer.getInt(ip + 3);

                /*trace.fine(ip + ": GET_CONST " + printSlot(xi, mode) + ", " + fn);*/

                // addr <- deref(Xi)
                int addr = deref(xi);
                int tag = derefTag;
                int val = derefVal;

                failed = !unifyConst(fn, xi);

                // P <- P + instruction_size(P)
                ip += 7;

                break;
            }

            case SET_CONST:
            {
                int fn = codeBuffer.getInt(ip + 1);

                /*trace.fine(ip + ": SET_CONST " + fn);*/

                // heap[h] <- <CON, c>
                data.put(hp, constantCell(fn));

                // h <- h + 1
                hp++;

                // P <- instruction_size(P)
                ip += 5;

                break;
            }

            case UNIFY_CONST:
            {
                int fn = codeBuffer.getInt(ip + 1);

                /*trace.fine(ip + ": UNIFY_CONST " + fn);*/

                // switch mode
                if (!writeMode)
                {
                    // case read:
                    // addr <- deref(S)

                    // unifyConst(fn, addr)
                    failed = !unifyConst(fn, sp);
                }
                else
                {
                    // case write:
                    // heap[h] <- <CON, c>
                    data.put(hp, constantCell(fn));

                    // h <- h + 1
                    hp++;
                }

                // s <- s + 1
                sp++;

                // P <- P + instruction_size(P)
                ip += 5;

                break;
            }

            case PUT_LIST:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": PUT_LIST " + printSlot(xi, mode));*/

                // Xi <- <LIS, H>
                data.put(xi, listCell(hp));

                // P <- P + instruction_size(P)
                ip += 3;

                break;
            }

            case GET_LIST:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": GET_LIST " + printSlot(xi, mode));*/

                int addr = deref(xi);
                int tag = derefTag;
                int val = derefVal;

                // case STORE[addr] of
                switch (tag)
                {
                case REF:
                {
                    // <REF, _> :
                    // HEAP[H] <- <LIS, H+1>
                    data.put(hp, listCell(hp + 1));

                    // bind(addr, H)
                    bind(addr, hp);

                    // H <- H + 1
                    hp += 1;

                    // mode <- write
                    writeMode = true;
                    /*trace.fine("-> write mode");*/

                    break;
                }

                case LIS:
                {
                    // <LIS, a> :
                    // S <- a
                    sp = val;

                    // mode <- read
                    writeMode = false;
                    /*trace.fine("-> read mode");*/

                    break;
                }

                default:
                {
                    // other: fail <- true;
                    failed = true;
                }
                }

                // P <- P + instruction_size(P)
                ip += 3;

                break;
            }

            case SET_VOID:
            {
                // grab N
                int n = (int) codeBuffer.get(ip + 1);

                /*trace.fine(ip + ": SET_VOID " + n);*/

                // for i <- H to H + n - 1 do
                //  HEAP[i] <- <REF, i>
                for (int addr = hp; addr < (hp + n); addr++)
                {
                    data.put(addr, refTo(addr));
                }

                // H <- H + n
                hp += n;

                // P <- P + instruction_size(P)
                ip += 2;

                break;
            }

            case UNIFY_VOID:
            {
                // grab N
                int n = (int) codeBuffer.get(ip + 1);

                /*trace.fine(ip + ": UNIFY_VOID " + n);*/

                // case mode of
                if (!writeMode)
                {
                    //  read: S <- S + n
                    sp += n;
                }
                else
                {
                    //  write:
                    //   for i <- H to H + n -1 do
                    //    HEAP[i] <- <REF, i>
                    for (int addr = hp; addr < (hp + n); addr++)
                    {
                        data.put(addr, refTo(addr));
                    }

                    //   H <- H + n
                    hp += n;
                }

                // P <- P + instruction_size(P)
                ip += 2;

                break;
            }

            // put_unsafe_val Yn, Ai:
            case PUT_UNSAFE_VAL:
            {
                // grab addr, Ai
                byte mode = codeBuffer.get(ip + 1);
                int yi = (int) codeBuffer.get(ip + 2) + (ep + 3);
                byte ai = codeBuffer.get(ip + 3);

                /*trace.fine(ip + ": PUT_UNSAFE_VAL " + printSlot(yi, WAMInstruction.STACK_ADDR) + ", A" + ai);*/

                int addr = deref(yi);

                if (addr < ep)
                {
                    // Ai <- Xn
                    data.put(ai, data.get(addr));
                }
                else
                {
                    data.put(hp, refTo(hp));
                    bind(addr, hp);
                    data.put(ai, data.get(hp));
                    hp++;
                }

                // P <- P + instruction_size(P)
                ip += 4;

                break;
            }

            // set_local_val Xi:
            case SET_LOCAL_VAL:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": SET_LOCAL_VAL " + printSlot(xi, mode));*/

                int addr = deref(xi);

                if (addr < ep)
                {
                    data.put(hp, data.get(addr));
                }
                else
                {
                    data.put(hp, refTo(hp));
                    bind(addr, hp);
                }

                // h <- h + 1
                hp++;

                // P <- P + instruction_size(P)
                ip += 3;

                break;
            }

            // unify_local_val Xi:
            case UNIFY_LOCAL_VAL:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": UNIFY_LOCAL_VAL " + printSlot(xi, mode));*/

                // switch mode
                if (!writeMode)
                {
                    // case read:
                    // unify (Xi, s)
                    failed = !unify(xi, sp);
                }
                else
                {
                    // case write:
                    int addr = deref(xi);

                    if (addr < ep)
                    {
                        data.put(hp, data.get(addr));
                    }
                    else
                    {
                        data.put(hp, refTo(hp));
                        bind(addr, hp);
                    }

                    // h <- h + 1
                    hp++;
                }

                // s <- s + 1
                sp++;

                // P <- P + instruction_size(P)
                ip += 3;

                break;
            }

            // call @(p/n), perms:
            case CALL:
            {
                // grab @(p/n), perms
                int pn = codeBuffer.getInt(ip + 1);
                int n = codeBuffer.get(ip + 5);
                int numPerms = (int) codeBuffer.get(ip + 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
                data.put(ep + 2, numPerms);

                // CP <- P + instruction_size(P)
                cp = ip + 7;

                /*trace.fine(ip + ": CALL " + pn + "/" + n + ", " + numPerms + " (cp = " + cp + ")]");*/

                // B0 <- B
                b0 = bp;

                // P <- @(p/n)
                ip = pn;

                break;
            }

            // execute @(p/n):
            case EXECUTE:
            {
                // grab @(p/n)
                int pn = codeBuffer.getInt(ip + 1);
                int n = codeBuffer.get(ip + 5);

                // num_of_args <- n
                numOfArgs = n;

                /*trace.fine(ip + ": 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
                b0 = bp;

                // P <- @(p/n)
                ip = pn;

                break;
            }

            // proceed:
            case PROCEED:
            {
                /*trace.fine(ip + ": PROCEED" + " (cp = " + cp + ")]");*/

                // P <- CP
                ip = cp;

                break;
            }

            // allocate:
            case ALLOCATE:
            {
                // if E > B
                //  then newB <- E + STACK[E + 2] + 3
                // else newB <- B + STACK[B] + 7
                int esp = nextStackFrame();

                // STACK[newE] <- E
                data.put(esp, ep);

                // STACK[E + 1] <- CP
                data.put(esp + 1, cp);

                // STACK[E + 2] <- N
                data.put(esp + 2, 0);

                // E <- newE
                // newE <- E + n + 3
                ep = esp;

                /*trace.fine(ip + ": ALLOCATE");*/
                /*trace.fine("-> env @ " + ep + " " + traceEnvFrame());*/

                // P <- P + instruction_size(P)
                ip += 1;

                break;
            }

            // allocate N:
            case ALLOCATE_N:
            {
                // grab N
                int n = (int) codeBuffer.get(ip + 1);

                // if E > B
                //  then newB <- E + STACK[E + 2] + 3
                // else newB <- B + STACK[B] + 7
                int esp = nextStackFrame();

                // STACK[newE] <- E
                data.put(esp, ep);

                // STACK[E + 1] <- CP
                data.put(esp + 1, cp);

                // STACK[E + 2] <- N
                data.put(esp + 2, n);

                // E <- newE
                // newE <- E + n + 3
                ep = esp;

                /*trace.fine(ip + ": ALLOCATE_N " + n);*/
                /*trace.fine("-> env @ " + ep + " " + traceEnvFrame());*/

                // P <- P + instruction_size(P)
                ip += 2;

                break;
            }

            // deallocate:
            case DEALLOCATE:
            {
                int newip = data.get(ep + 1);

                // E <- STACK[E]
                ep = data.get(ep);

                /*trace.fine(ip + ": DEALLOCATE");*/
                /*trace.fine("<- env @ " + ep + " " + traceEnvFrame());*/

                // CP <- STACK[E + 1]
                cp = newip;

                // P <- P + instruction_size(P)
                ip += 1;

                break;
            }

            // try me else L:
            case TRY_ME_ELSE:
            {
                // grab L
                int l = codeBuffer.getInt(ip + 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;
                data.put(esp, n);

                // for i <- 1 to n do STACK[newB + i] <- Ai
                for (int i = 0; i < n; i++)
                {
                    data.put(esp + i + 1, data.get(i));
                }

                // STACK[newB + n + 1] <- E
                data.put(esp + n + 1, ep);

                // STACK[newB + n + 2] <- CP
                data.put(esp + n + 2, cp);

                // STACK[newB + n + 3] <- B
                data.put(esp + n + 3, bp);

                // STACK[newB + n + 4] <- L
                data.put(esp + n + 4, l);

                // STACK[newB + n + 5] <- TR
                data.put(esp + n + 5, trp);

                // STACK[newB + n + 6] <- H
                data.put(esp + n + 6, hp);

                // STACK[newB + n + 7] <- B0
                data.put(esp + n + 7, b0);

                // B <- new B
                bp = esp;

                // HB <- H
                hbp = hp;

                /*trace.fine(ip + ": TRY_ME_ELSE");*/
                /*trace.fine("-> chp @ " + bp + " " + traceChoiceFrame());*/

                // P <- P + instruction_size(P)
                ip += 5;

                break;
            }

            // retry me else L:
            case RETRY_ME_ELSE:
            {
                // grab L
                int l = codeBuffer.getInt(ip + 1);

                // n <- STACK[B]
                int n = data.get(bp);

                // for i <- 1 to n do Ai <- STACK[B + i]
                for (int i = 0; i < n; i++)
                {
                    data.put(i, data.get(bp + i + 1));
                }

                // E <- STACK[B + n + 1]
                ep = data.get(bp + n + 1);

                // CP <- STACK[B + n + 2]
                cp = data.get(bp + n + 2);

                // STACK[B + n + 4] <- L
                data.put(bp + n + 4, l);

                // unwind_trail(STACK[B + n + 5], TR)
                unwindTrail(data.get(bp + n + 5), trp);

                // TR <- STACK[B + n + 5]
                trp = data.get(bp + n + 5);

                // H <- STACK[B + n + 6]
                hp = data.get(bp + n + 6);

                // HB <- H
                hbp = hp;

                /*trace.fine(ip + ": RETRY_ME_ELSE");*/
                /*trace.fine("-- chp @ " + bp + " " + traceChoiceFrame());*/

                // P <- P + instruction_size(P)
                ip += 5;

                break;
            }

            // trust me (else fail):
            case TRUST_ME:
            {
                // n <- STACK[B]
                int n = data.get(bp);

                // for i <- 1 to n do Ai <- STACK[B + i]
                for (int i = 0; i < n; i++)
                {
                    data.put(i, data.get(bp + i + 1));
                }

                // E <- STACK[B + n + 1]
                ep = data.get(bp + n + 1);

                // CP <- STACK[B + n + 2]
                cp = data.get(bp + n + 2);

                // unwind_trail(STACK[B + n + 5], TR)
                unwindTrail(data.get(bp + n + 5), trp);

                // TR <- STACK[B + n + 5]
                trp = data.get(bp + n + 5);

                // H <- STACK[B + n + 6]
                hp = data.get(bp + n + 6);

                // HB <- STACK[B + n + 6]
                hbp = hp;

                // B <- STACK[B + n + 3]
                bp = data.get(bp + n + 3);

                /*trace.fine(ip + ": TRUST_ME");*/
                /*trace.fine("<- chp @ " + bp + " " + traceChoiceFrame());*/

                // P <- P + instruction_size(P)
                ip += 1;

                break;
            }

            case SWITCH_ON_TERM:
            {
                // grab labels
                int v = codeBuffer.getInt(ip + 1);
                int c = codeBuffer.getInt(ip + 5);
                int l = codeBuffer.getInt(ip + 9);
                int s = codeBuffer.getInt(ip + 13);

                int addr = deref(1);
                int tag = derefTag;

                // case STORE[deref(A1)] of
                switch (tag)
                {
                case REF:

                    // <REF, _> : P <- V
                    ip = v;
                    break;

                case CON:

                    // <CON, _> : P <- C
                    ip = c;
                    break;

                case LIS:

                    // <LIS, _> : P <- L
                    ip = l;
                    break;

                case STR:

                    // <STR, _> : P <- S
                    ip = s;
                    break;
                }

                break;
            }

            case SWITCH_ON_CONST:
            {
                // grab labels
                int t = codeBuffer.getInt(ip + 1);
                int n = codeBuffer.getInt(ip + 5);

                // <tag, val> <- STORE[deref(A1)]
                deref(1);

                int val = derefVal;

                // <found, inst> <- get_hash(val, T, N)
                int inst = getHash(val, t, n);

                // if found
                if (inst > 0)
                {
                    // then P <- inst
                    ip = inst;
                }
                else
                {
                    // else backtrack
                    failed = true;
                }

                break;
            }

            case SWITCH_ON_STRUC:
            {
                // grab labels
                int t = codeBuffer.getInt(ip + 1);
                int n = codeBuffer.getInt(ip + 5);

                // <tag, val> <- STORE[deref(A1)]
                deref(1);

                int val = derefVal;

                // <found, inst> <- get_hash(val, T, N)
                int inst = getHash(val, t, n);

                // if found
                if (inst > 0)
                {
                    // then P <- inst
                    ip = inst;
                }
                else
                {
                    // else backtrack
                    failed = true;
                }

                break;
            }

            case TRY:
            {
                // grab L
                int l = codeBuffer.getInt(ip + 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;
                data.put(esp, n);

                // for i <- 1 to n do STACK[newB + i] <- Ai
                for (int i = 0; i < n; i++)
                {
                    data.put(esp + i + 1, data.get(i));
                }

                // STACK[newB + n + 1] <- E
                data.put(esp + n + 1, ep);

                // STACK[newB + n + 2] <- CP
                data.put(esp + n + 2, cp);

                // STACK[newB + n + 3] <- B
                data.put(esp + n + 3, bp);

                // STACK[newB + n + 4] <- L
                data.put(esp + n + 4, ip + 5);

                // STACK[newB + n + 5] <- TR
                data.put(esp + n + 5, trp);

                // STACK[newB + n + 6] <- H
                data.put(esp + n + 6, hp);

                // STACK[newB + n + 7] <- B0
                data.put(esp + n + 7, b0);

                // B <- new B
                bp = esp;

                // HB <- H
                hbp = hp;

                /*trace.fine(ip + ": TRY");*/
                /*trace.fine("-> chp @ " + bp + " " + traceChoiceFrame());*/

                // P <- L
                ip = l;

                break;
            }

            case RETRY:
            {
                // grab L
                int l = codeBuffer.getInt(ip + 1);

                // n <- STACK[B]
                int n = data.get(bp);

                // for i <- 1 to n do Ai <- STACK[B + i]
                for (int i = 0; i < n; i++)
                {
                    data.put(i, data.get(bp + i + 1));
                }

                // E <- STACK[B + n + 1]
                ep = data.get(bp + n + 1);

                // CP <- STACK[B + n + 2]
                cp = data.get(bp + n + 2);

                // STACK[B + n + 4] <- L
                data.put(bp + n + 4, ip + 5);

                // unwind_trail(STACK[B + n + 5], TR)
                unwindTrail(data.get(bp + n + 5), trp);

                // TR <- STACK[B + n + 5]
                trp = data.get(bp + n + 5);

                // H <- STACK[B + n + 6]
                hp = data.get(bp + n + 6);

                // HB <- H
                hbp = hp;

                /*trace.fine(ip + ": RETRY");*/
                /*trace.fine("-- chp @ " + bp + " " + traceChoiceFrame());*/

                // P <- L
                ip = l;

                break;
            }

            case TRUST:
            {
                // grab L
                int l = codeBuffer.getInt(ip + 1);

                // n <- STACK[B]
                int n = data.get(bp);

                // for i <- 1 to n do Ai <- STACK[B + i]
                for (int i = 0; i < n; i++)
                {
                    data.put(i, data.get(bp + i + 1));
                }

                // E <- STACK[B + n + 1]
                ep = data.get(bp + n + 1);

                // CP <- STACK[B + n + 2]
                cp = data.get(bp + n + 2);

                // unwind_trail(STACK[B + n + 5], TR)
                unwindTrail(data.get(bp + n + 5), trp);

                // TR <- STACK[B + n + 5]
                trp = data.get(bp + n + 5);

                // H <- STACK[B + n + 6]
                hp = data.get(bp + n + 6);

                // HB <- STACK[B + n + 6]
                hbp = hp;

                // B <- STACK[B + n + 3]
                bp = data.get(bp + n + 3);

                /*trace.fine(ip + ": TRUST");*/
                /*trace.fine("<- chp @ " + bp + " " + traceChoiceFrame());*/

                // P <- L
                ip = l;

                break;
            }

            case NECK_CUT:
            {
                if (bp > b0)
                {
                    bp = b0;
                    tidyTrail();
                }

                /*trace.fine(ip + ": NECK_CUT");*/
                /*trace.fine("<- chp @ " + bp + " " + traceChoiceFrame());*/

                ip += 1;

                break;
            }

            case GET_LEVEL:
            {
                int yn = (int) codeBuffer.get(ip + 1) + (ep + 3);

                data.put(yn, b0);

                /*trace.fine(ip + ": GET_LEVEL " + codeBuffer.get(ip + 1));*/

                ip += 2;

                break;
            }

            case CUT:
            {
                int yn = (int) codeBuffer.get(ip + 1) + (ep + 3);

                int cbp = data.get(yn);

                if (bp > cbp)
                {
                    bp = cbp;
                    tidyTrail();
                }

                /*trace.fine(ip + ": CUT " + codeBuffer.get(ip + 1));*/
                /*trace.fine("<- chp @ " + bp + " " + traceChoiceFrame());*/

                ip += 2;

                break;
            }

            case CONTINUE:
            {
                // grab L
                int l = codeBuffer.getInt(ip + 1);

                /*trace.fine(ip + ": CONTINUE " + l);*/

                ip = l;

                break;
            }

            case NO_OP:
            {
                /*trace.fine(ip + ": NO_OP");*/

                ip += 1;

                break;
            }

            // call_internal @(p/n), perms:
            case CALL_INTERNAL:
            {
                // grab @(p/n), perms
                int pn = codeBuffer.getInt(ip + 1);
                int n = codeBuffer.get(ip + 5);
                int numPerms = (int) codeBuffer.get(ip + 6);

                // num_of_args <- n
                numOfArgs = n;

                /*trace.fine(ip + ": CALL_INTERNAL " + pn + "/" + n + ", " + numPerms + " (cp = " + cp + ")]");*/

                boolean callOk = callInternal(pn, n, numPerms);

                failed = !callOk;

                break;
            }

            // suspend on success:
            case SUSPEND:
            {
                /*trace.fine(ip + ": SUSPEND");*/
                ip += 1;
                suspended = true;

                return true;
            }
            }

            // Notify any debug monitor that the machine has been stepped.
            if (monitor != null)
            {
                monitor.onStep(this);
            }
        }

        return !failed;
    }
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 (suspended)
        {
            failed = true;
            suspended = false;
        }
        else
        {
            ip = callPoint.entryPoint;
            uClear();
            failed = false;
        }

        int numOfArgs = 0;

        // Holds the current continuation point.
        cp = codeBuffer.position();

        // Notify any debug monitor that execution is starting.
        if (monitor != null)
        {
            monitor.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 = codeBuffer.get(ip);

            switch (instruction)
            {
            // put_struc Xi, f/n:
            case PUT_STRUC:
            {
                // grab addr, f/n
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                int fn = codeBuffer.getInt(ip + 3);

                /*trace.fine(ip + ": PUT_STRUC " + printSlot(xi, mode) + ", " + fn);*/

                // heap[h] <- STR, h + 1
                data.put(hp, fn);

                // Xi <- heap[h]
                data.put(xi, structureAt(hp));

                // h <- h + 2
                hp += 1;

                // P <- instruction_size(P)
                ip += 7;

                break;
            }

            // set_var Xi:
            case SET_VAR:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": SET_VAR " + printSlot(xi, mode));*/

                // heap[h] <- REF, h
                data.put(hp, refTo(hp));

                // Xi <- heap[h]
                data.put(xi, data.get(hp));

                // h <- h + 1
                hp++;

                // P <- instruction_size(P)
                ip += 3;

                break;
            }

            // set_val Xi:
            case SET_VAL:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": SET_VAL " + printSlot(xi, mode));*/

                // heap[h] <- Xi
                data.put(hp, data.get(xi));

                // h <- h + 1
                hp++;

                // P <- instruction_size(P)
                ip += 3;

                break;
            }

            // get_struc Xi,
            case GET_STRUC:
            {
                // grab addr, f/n
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                int fn = codeBuffer.getInt(ip + 3);

                /*trace.fine(ip + ": GET_STRUC " + printSlot(xi, mode) + ", " + fn);*/

                // addr <- deref(Xi);
                int addr = deref(xi);
                byte tag = derefTag;
                int a = derefVal;

                // switch STORE[addr]
                switch (tag)
                {
                // case REF:
                case REF:
                {
                    // heap[h] <- STR, h + 1
                    data.put(hp, structureAt(hp + 1));

                    // heap[h+1] <- f/n
                    data.put(hp + 1, fn);

                    // bind(addr, h)
                    bind(addr, hp);

                    // h <- h + 2
                    hp += 2;

                    // mode <- write
                    writeMode = true;
                    /*trace.fine("-> write mode");*/

                    break;
                }

                // case STR, a:
                case STR:
                {
                    // if heap[a] = f/n
                    if (data.get(a) == fn)
                    {
                        // s <- a + 1
                        sp = a + 1;

                        // mode <- read
                        writeMode = false;
                        /*trace.fine("-> read mode");*/
                    }
                    else
                    {
                        // fail
                        failed = true;
                    }

                    break;
                }

                default:
                {
                    // fail
                    failed = true;
                }
                }

                // P <- instruction_size(P)
                ip += 7;

                break;
            }

            // unify_var Xi:
            case UNIFY_VAR:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": UNIFY_VAR " + printSlot(xi, mode));*/

                // switch mode
                if (!writeMode)
                {
                    // case read:
                    // Xi <- heap[s]
                    data.put(xi, data.get(sp));
                }
                else
                {
                    // case write:
                    // heap[h] <- REF, h
                    data.put(hp, refTo(hp));

                    // Xi <- heap[h]
                    data.put(xi, data.get(hp));

                    // h <- h + 1
                    hp++;
                }

                // s <- s + 1
                sp++;

                // P <- P + instruction_size(P)
                ip += 3;

                break;
            }

            // unify_val Xi:
            case UNIFY_VAL:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": UNIFY_VAL " + printSlot(xi, mode));*/

                // switch mode
                if (!writeMode)
                {
                    // case read:
                    // unify (Xi, s)
                    failed = !unify(xi, sp);
                }
                else
                {
                    // case write:
                    // heap[h] <- Xi
                    data.put(hp, data.get(xi));

                    // h <- h + 1
                    hp++;
                }

                // s <- s + 1
                sp++;

                // P <- P + instruction_size(P)
                ip += 3;

                break;
            }

            // put_var Xn, Ai:
            case PUT_VAR:
            {
                // grab addr, Ai
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                byte ai = codeBuffer.get(ip + 3);

                /*trace.fine(ip + ": PUT_VAR " + printSlot(xi, mode) + ", A" + ai);*/

                if (mode == WAMInstruction.REG_ADDR)
                {
                    // heap[h] <- REF, H
                    data.put(hp, refTo(hp));

                    // Xn <- heap[h]
                    data.put(xi, data.get(hp));

                    // Ai <- heap[h]
                    data.put(ai, data.get(hp));
                }
                else
                {
                    // STACK[addr] <- REF, addr
                    data.put(xi, refTo(xi));

                    // Ai <- STACK[addr]
                    data.put(ai, data.get(xi));
                }

                // h <- h + 1
                hp++;

                // P <- P + instruction_size(P)
                ip += 4;

                break;
            }

            // put_val Xn, Ai:
            case PUT_VAL:
            {
                // grab addr, Ai
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                byte ai = codeBuffer.get(ip + 3);

                /*trace.fine(ip + ": PUT_VAL " + printSlot(xi, mode) + ", A" + ai);*/

                // Ai <- Xn
                data.put(ai, data.get(xi));

                // P <- P + instruction_size(P)
                ip += 4;

                break;
            }

            // get var Xn, Ai:
            case GET_VAR:
            {
                // grab addr, Ai
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                byte ai = codeBuffer.get(ip + 3);

                /*trace.fine(ip + ": GET_VAR " + printSlot(xi, mode) + ", A" + ai);*/

                // Xn <- Ai
                data.put(xi, data.get(ai));

                // P <- P + instruction_size(P)
                ip += 4;

                break;
            }

            // get_val Xn, Ai:
            case GET_VAL:
            {
                // grab addr, Ai
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                byte ai = codeBuffer.get(ip + 3);

                /*trace.fine(ip + ": GET_VAL " + printSlot(xi, mode) + ", A" + ai);*/

                // unify (Xn, Ai)
                failed = !unify(xi, ai);

                // P <- P + instruction_size(P)
                ip += 4;

                break;
            }

            case PUT_CONST:
            {
                // grab addr, f/n
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                int fn = codeBuffer.getInt(ip + 3);

                /*trace.fine(ip + ": PUT_CONST " + printSlot(xi, mode) + ", " + fn);*/

                // Xi <- heap[h]
                data.put(xi, constantCell(fn));

                // P <- instruction_size(P)
                ip += 7;

                break;
            }

            case GET_CONST:
            {
                // grab addr, Ai
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);
                int fn = codeBuffer.getInt(ip + 3);

                /*trace.fine(ip + ": GET_CONST " + printSlot(xi, mode) + ", " + fn);*/

                // addr <- deref(Xi)
                int addr = deref(xi);
                int tag = derefTag;
                int val = derefVal;

                failed = !unifyConst(fn, xi);

                // P <- P + instruction_size(P)
                ip += 7;

                break;
            }

            case SET_CONST:
            {
                int fn = codeBuffer.getInt(ip + 1);

                /*trace.fine(ip + ": SET_CONST " + fn);*/

                // heap[h] <- <CON, c>
                data.put(hp, constantCell(fn));

                // h <- h + 1
                hp++;

                // P <- instruction_size(P)
                ip += 5;

                break;
            }

            case UNIFY_CONST:
            {
                int fn = codeBuffer.getInt(ip + 1);

                /*trace.fine(ip + ": UNIFY_CONST " + fn);*/

                // switch mode
                if (!writeMode)
                {
                    // case read:
                    // addr <- deref(S)

                    // unifyConst(fn, addr)
                    failed = !unifyConst(fn, sp);
                }
                else
                {
                    // case write:
                    // heap[h] <- <CON, c>
                    data.put(hp, constantCell(fn));

                    // h <- h + 1
                    hp++;
                }

                // s <- s + 1
                sp++;

                // P <- P + instruction_size(P)
                ip += 5;

                break;
            }

            case PUT_LIST:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": PUT_LIST " + printSlot(xi, mode));*/

                // Xi <- <LIS, H>
                data.put(xi, listCell(hp));

                // P <- P + instruction_size(P)
                ip += 3;

                break;
            }

            case GET_LIST:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": GET_LIST " + printSlot(xi, mode));*/

                int addr = deref(xi);
                int tag = derefTag;
                int val = derefVal;

                // case STORE[addr] of
                switch (tag)
                {
                case REF:
                {
                    // <REF, _> :
                    // HEAP[H] <- <LIS, H+1>
                    data.put(hp, listCell(hp + 1));

                    // bind(addr, H)
                    bind(addr, hp);

                    // H <- H + 1
                    hp += 1;

                    // mode <- write
                    writeMode = true;
                    /*trace.fine("-> write mode");*/

                    break;
                }

                case LIS:
                {
                    // <LIS, a> :
                    // S <- a
                    sp = val;

                    // mode <- read
                    writeMode = false;
                    /*trace.fine("-> read mode");*/

                    break;
                }

                default:
                {
                    // other: fail <- true;
                    failed = true;
                }
                }

                // P <- P + instruction_size(P)
                ip += 3;

                break;
            }

            case SET_VOID:
            {
                // grab N
                int n = (int) codeBuffer.get(ip + 1);

                /*trace.fine(ip + ": SET_VOID " + n);*/

                // for i <- H to H + n - 1 do
                //  HEAP[i] <- <REF, i>
                for (int addr = hp; addr < (hp + n); addr++)
                {
                    data.put(addr, refTo(addr));
                }

                // H <- H + n
                hp += n;

                // P <- P + instruction_size(P)
                ip += 2;

                break;
            }

            case UNIFY_VOID:
            {
                // grab N
                int n = (int) codeBuffer.get(ip + 1);

                /*trace.fine(ip + ": UNIFY_VOID " + n);*/

                // case mode of
                if (!writeMode)
                {
                    //  read: S <- S + n
                    sp += n;
                }
                else
                {
                    //  write:
                    //   for i <- H to H + n -1 do
                    //    HEAP[i] <- <REF, i>
                    for (int addr = hp; addr < (hp + n); addr++)
                    {
                        data.put(addr, refTo(addr));
                    }

                    //   H <- H + n
                    hp += n;
                }

                // P <- P + instruction_size(P)
                ip += 2;

                break;
            }

            // put_unsafe_val Yn, Ai:
            case PUT_UNSAFE_VAL:
            {
                // grab addr, Ai
                byte mode = codeBuffer.get(ip + 1);
                int yi = (int) codeBuffer.get(ip + 2) + (ep + 3);
                byte ai = codeBuffer.get(ip + 3);

                /*trace.fine(ip + ": PUT_UNSAFE_VAL " + printSlot(yi, WAMInstruction.STACK_ADDR) + ", A" + ai);*/

                int addr = deref(yi);

                if (addr < ep)
                {
                    // Ai <- Xn
                    data.put(ai, data.get(addr));
                }
                else
                {
                    data.put(hp, refTo(hp));
                    bind(addr, hp);
                    data.put(ai, data.get(hp));
                    hp++;
                }

                // P <- P + instruction_size(P)
                ip += 4;

                break;
            }

            // set_local_val Xi:
            case SET_LOCAL_VAL:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": SET_LOCAL_VAL " + printSlot(xi, mode));*/

                int addr = deref(xi);

                if (addr < ep)
                {
                    data.put(hp, data.get(addr));
                }
                else
                {
                    data.put(hp, refTo(hp));
                    bind(addr, hp);
                }

                // h <- h + 1
                hp++;

                // P <- P + instruction_size(P)
                ip += 3;

                break;
            }

            // unify_local_val Xi:
            case UNIFY_LOCAL_VAL:
            {
                // grab addr
                byte mode = codeBuffer.get(ip + 1);
                int xi = getRegisterOrStackSlot(mode);

                /*trace.fine(ip + ": UNIFY_LOCAL_VAL " + printSlot(xi, mode));*/

                // switch mode
                if (!writeMode)
                {
                    // case read:
                    // unify (Xi, s)
                    failed = !unify(xi, sp);
                }
                else
                {
                    // case write:
                    int addr = deref(xi);

                    if (addr < ep)
                    {
                        data.put(hp, data.get(addr));
                    }
                    else
                    {
                        data.put(hp, refTo(hp));
                        bind(addr, hp);
                    }

                    // h <- h + 1
                    hp++;
                }

                // s <- s + 1
                sp++;

                // P <- P + instruction_size(P)
                ip += 3;

                break;
            }

            // call @(p/n), perms:
            case CALL:
            {
                // grab @(p/n), perms
                int pn = codeBuffer.getInt(ip + 1);
                int n = codeBuffer.get(ip + 5);
                int numPerms = (int) codeBuffer.get(ip + 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
                data.put(ep + 2, numPerms);

                // CP <- P + instruction_size(P)
                cp = ip + 7;

                /*trace.fine(ip + ": CALL " + pn + "/" + n + ", " + numPerms + " (cp = " + cp + ")]");*/

                // B0 <- B
                b0 = bp;

                // P <- @(p/n)
                ip = pn;

                break;
            }

            // execute @(p/n):
            case EXECUTE:
            {
                // grab @(p/n)
                int pn = codeBuffer.getInt(ip + 1);
                int n = codeBuffer.get(ip + 5);

                // num_of_args <- n
                numOfArgs = n;

                /*trace.fine(ip + ": 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
                b0 = bp;

                // P <- @(p/n)
                ip = pn;

                break;
            }

            // proceed:
            case PROCEED:
            {
                /*trace.fine(ip + ": PROCEED" + " (cp = " + cp + ")]");*/

                // P <- CP
                ip = cp;

                break;
            }

            // allocate:
            case ALLOCATE:
            {
                // if E > B
                //  then newB <- E + STACK[E + 2] + 3
                // else newB <- B + STACK[B] + 7
                int esp = nextStackFrame();

                // STACK[newE] <- E
                data.put(esp, ep);

                // STACK[E + 1] <- CP
                data.put(esp + 1, cp);

                // STACK[E + 2] <- N
                data.put(esp + 2, 0);

                // E <- newE
                // newE <- E + n + 3
                ep = esp;

                /*trace.fine(ip + ": ALLOCATE");*/
                /*trace.fine("-> env @ " + ep + " " + traceEnvFrame());*/

                // P <- P + instruction_size(P)
                ip += 1;

                break;
            }

            // allocate N:
            case ALLOCATE_N:
            {
                // grab N
                int n = (int) codeBuffer.get(ip + 1);

                // if E > B
                //  then newB <- E + STACK[E + 2] + 3
                // else newB <- B + STACK[B] + 7
                int esp = nextStackFrame();

                // STACK[newE] <- E
                data.put(esp, ep);

                // STACK[E + 1] <- CP
                data.put(esp + 1, cp);

                // STACK[E + 2] <- N
                data.put(esp + 2, n);

                // E <- newE
                // newE <- E + n + 3
                ep = esp;

                /*trace.fine(ip + ": ALLOCATE_N " + n);*/
                /*trace.fine("-> env @ " + ep + " " + traceEnvFrame());*/

                // P <- P + instruction_size(P)
                ip += 2;

                break;
            }

            // deallocate:
            case DEALLOCATE:
            {
                int newip = data.get(ep + 1);

                // E <- STACK[E]
                ep = data.get(ep);

                /*trace.fine(ip + ": DEALLOCATE");*/
                /*trace.fine("<- env @ " + ep + " " + traceEnvFrame());*/

                // CP <- STACK[E + 1]
                cp = newip;

                // P <- P + instruction_size(P)
                ip += 1;

                break;
            }

            // try me else L:
            case TRY_ME_ELSE:
            {
                // grab L
                int l = codeBuffer.getInt(ip + 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;
                data.put(esp, n);

                // for i <- 1 to n do STACK[newB + i] <- Ai
                for (int i = 0; i < n; i++)
                {
                    data.put(esp + i + 1, data.get(i));
                }

                // STACK[newB + n + 1] <- E
                data.put(esp + n + 1, ep);

                // STACK[newB + n + 2] <- CP
                data.put(esp + n + 2, cp);

                // STACK[newB + n + 3] <- B
                data.put(esp + n + 3, bp);

                // STACK[newB + n + 4] <- L
                data.put(esp + n + 4, l);

                // STACK[newB + n + 5] <- TR
                data.put(esp + n + 5, trp);

                // STACK[newB + n + 6] <- H
                data.put(esp + n + 6, hp);

                // STACK[newB + n + 7] <- B0
                data.put(esp + n + 7, b0);

                // B <- new B
                bp = esp;

                // HB <- H
                hbp = hp;

                /*trace.fine(ip + ": TRY_ME_ELSE");*/
                /*trace.fine("-> chp @ " + bp + " " + traceChoiceFrame());*/

                // P <- P + instruction_size(P)
                ip += 5;

                break;
            }

            // retry me else L:
            case RETRY_ME_ELSE:
            {
                // grab L
                int l = codeBuffer.getInt(ip + 1);

                // n <- STACK[B]
                int n = data.get(bp);

                // for i <- 1 to n do Ai <- STACK[B + i]
                for (int i = 0; i < n; i++)
                {
                    data.put(i, data.get(bp + i + 1));
                }

                // E <- STACK[B + n + 1]
                ep = data.get(bp + n + 1);

                // CP <- STACK[B + n + 2]
                cp = data.get(bp + n + 2);

                // STACK[B + n + 4] <- L
                data.put(bp + n + 4, l);

                // unwind_trail(STACK[B + n + 5], TR)
                unwindTrail(data.get(bp + n + 5), trp);

                // TR <- STACK[B + n + 5]
                trp = data.get(bp + n + 5);

                // H <- STACK[B + n + 6]
                hp = data.get(bp + n + 6);

                // HB <- H
                hbp = hp;

                /*trace.fine(ip + ": RETRY_ME_ELSE");*/
                /*trace.fine("-- chp @ " + bp + " " + traceChoiceFrame());*/

                // P <- P + instruction_size(P)
                ip += 5;

                break;
            }

            // trust me (else fail):
            case TRUST_ME:
            {
                // n <- STACK[B]
                int n = data.get(bp);

                // for i <- 1 to n do Ai <- STACK[B + i]
                for (int i = 0; i < n; i++)
                {
                    data.put(i, data.get(bp + i + 1));
                }

                // E <- STACK[B + n + 1]
                ep = data.get(bp + n + 1);

                // CP <- STACK[B + n + 2]
                cp = data.get(bp + n + 2);

                // unwind_trail(STACK[B + n + 5], TR)
                unwindTrail(data.get(bp + n + 5), trp);

                // TR <- STACK[B + n + 5]
                trp = data.get(bp + n + 5);

                // H <- STACK[B + n + 6]
                hp = data.get(bp + n + 6);

                // HB <- STACK[B + n + 6]
                hbp = hp;

                // B <- STACK[B + n + 3]
                bp = data.get(bp + n + 3);

                /*trace.fine(ip + ": TRUST_ME");*/
                /*trace.fine("<- chp @ " + bp + " " + traceChoiceFrame());*/

                // P <- P + instruction_size(P)
                ip += 1;

                break;
            }

            case SWITCH_ON_TERM:
            {
                // grab labels
                int v = codeBuffer.getInt(ip + 1);
                int c = codeBuffer.getInt(ip + 5);
                int l = codeBuffer.getInt(ip + 9);
                int s = codeBuffer.getInt(ip + 13);

                int addr = deref(1);
                int tag = derefTag;

                // case STORE[deref(A1)] of
                switch (tag)
                {
                case REF:

                    // <REF, _> : P <- V
                    ip = v;
                    break;

                case CON:

                    // <CON, _> : P <- C
                    ip = c;
                    break;

                case LIS:

                    // <LIS, _> : P <- L
                    ip = l;
                    break;

                case STR:

                    // <STR, _> : P <- S
                    ip = s;
                    break;
                }

                break;
            }

            case SWITCH_ON_CONST:
            {
                // grab labels
                int t = codeBuffer.getInt(ip + 1);
                int n = codeBuffer.getInt(ip + 5);

                // <tag, val> <- STORE[deref(A1)]
                deref(1);

                int val = derefVal;

                // <found, inst> <- get_hash(val, T, N)
                int inst = getHash(val, t, n);

                // if found
                if (inst > 0)
                {
                    // then P <- inst
                    ip = inst;
                }
                else
                {
                    // else backtrack
                    failed = true;
                }

                break;
            }

            case SWITCH_ON_STRUC:
            {
                // grab labels
                int t = codeBuffer.getInt(ip + 1);
                int n = codeBuffer.getInt(ip + 5);

                // <tag, val> <- STORE[deref(A1)]
                deref(1);

                int val = derefVal;

                // <found, inst> <- get_hash(val, T, N)
                int inst = getHash(val, t, n);

                // if found
                if (inst > 0)
                {
                    // then P <- inst
                    ip = inst;
                }
                else
                {
                    // else backtrack
                    failed = true;
                }

                break;
            }

            case TRY:
            {
                // grab L
                int l = codeBuffer.getInt(ip + 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;
                data.put(esp, n);

                // for i <- 1 to n do STACK[newB + i] <- Ai
                for (int i = 0; i < n; i++)
                {
                    data.put(esp + i + 1, data.get(i));
                }

                // STACK[newB + n + 1] <- E
                data.put(esp + n + 1, ep);

                // STACK[newB + n + 2] <- CP
                data.put(esp + n + 2, cp);

                // STACK[newB + n + 3] <- B
                data.put(esp + n + 3, bp);

                // STACK[newB + n + 4] <- L
                data.put(esp + n + 4, ip + 5);

                // STACK[newB + n + 5] <- TR
                data.put(esp + n + 5, trp);

                // STACK[newB + n + 6] <- H
                data.put(esp + n + 6, hp);

                // STACK[newB + n + 7] <- B0
                data.put(esp + n + 7, b0);

                // B <- new B
                bp = esp;

                // HB <- H
                hbp = hp;

                /*trace.fine(ip + ": TRY");*/
                /*trace.fine("-> chp @ " + bp + " " + traceChoiceFrame());*/

                // P <- L
                ip = l;

                break;
            }

            case RETRY:
            {
                // grab L
                int l = codeBuffer.getInt(ip + 1);

                // n <- STACK[B]
                int n = data.get(bp);

                // for i <- 1 to n do Ai <- STACK[B + i]
                for (int i = 0; i < n; i++)
                {
                    data.put(i, data.get(bp + i + 1));
                }

                // E <- STACK[B + n + 1]
                ep = data.get(bp + n + 1);

                // CP <- STACK[B + n + 2]
                cp = data.get(bp + n + 2);

                // STACK[B + n + 4] <- L
                data.put(bp + n + 4, ip + 5);

                // unwind_trail(STACK[B + n + 5], TR)
                unwindTrail(data.get(bp + n + 5), trp);

                // TR <- STACK[B + n + 5]
                trp = data.get(bp + n + 5);

                // H <- STACK[B + n + 6]
                hp = data.get(bp + n + 6);

                // HB <- H
                hbp = hp;

                /*trace.fine(ip + ": RETRY");*/
                /*trace.fine("-- chp @ " + bp + " " + traceChoiceFrame());*/

                // P <- L
                ip = l;

                break;
            }

            case TRUST:
            {
                // grab L
                int l = codeBuffer.getInt(ip + 1);

                // n <- STACK[B]
                int n = data.get(bp);

                // for i <- 1 to n do Ai <- STACK[B + i]
                for (int i = 0; i < n; i++)
                {
                    data.put(i, data.get(bp + i + 1));
                }

                // E <- STACK[B + n + 1]
                ep = data.get(bp + n + 1);

                // CP <- STACK[B + n + 2]
                cp = data.get(bp + n + 2);

                // unwind_trail(STACK[B + n + 5], TR)
                unwindTrail(data.get(bp + n + 5), trp);

                // TR <- STACK[B + n + 5]
                trp = data.get(bp + n + 5);

                // H <- STACK[B + n + 6]
                hp = data.get(bp + n + 6);

                // HB <- STACK[B + n + 6]
                hbp = hp;

                // B <- STACK[B + n + 3]
                bp = data.get(bp + n + 3);

                /*trace.fine(ip + ": TRUST");*/
                /*trace.fine("<- chp @ " + bp + " " + traceChoiceFrame());*/

                // P <- L
                ip = l;

                break;
            }

            case NECK_CUT:
            {
                if (bp > b0)
                {
                    bp = b0;
                    tidyTrail();
                }

                /*trace.fine(ip + ": NECK_CUT");*/
                /*trace.fine("<- chp @ " + bp + " " + traceChoiceFrame());*/

                ip += 1;

                break;
            }

            case GET_LEVEL:
            {
                int yn = (int) codeBuffer.get(ip + 1) + (ep + 3);

                data.put(yn, b0);

                /*trace.fine(ip + ": GET_LEVEL " + codeBuffer.get(ip + 1));*/

                ip += 2;

                break;
            }

            case CUT:
            {
                int yn = (int) codeBuffer.get(ip + 1) + (ep + 3);

                int cbp = data.get(yn);

                if (bp > cbp)
                {
                    bp = cbp;
                    tidyTrail();
                }

                /*trace.fine(ip + ": CUT " + codeBuffer.get(ip + 1));*/
                /*trace.fine("<- chp @ " + bp + " " + traceChoiceFrame());*/

                ip += 2;

                break;
            }

            case CONTINUE:
            {
                // grab L
                int l = codeBuffer.getInt(ip + 1);

                /*trace.fine(ip + ": CONTINUE " + l);*/

                ip = l;

                break;
            }

            case NO_OP:
            {
                /*trace.fine(ip + ": NO_OP");*/

                ip += 1;

                break;
            }

            // call_internal @(p/n), perms:
            case CALL_INTERNAL:
            {
                // grab @(p/n), perms
                int pn = codeBuffer.getInt(ip + 1);
                int n = codeBuffer.get(ip + 5);
                int numPerms = (int) codeBuffer.get(ip + 6);

                // num_of_args <- n
                numOfArgs = n;

                /*trace.fine(ip + ": CALL_INTERNAL " + pn + "/" + n + ", " + numPerms + " (cp = " + cp + ")]");*/

                boolean callOk = callInternal(pn, n, numPerms);

                failed = !callOk;

                break;
            }

            // suspend on success:
            case SUSPEND:
            {
                /*trace.fine(ip + ": SUSPEND");*/
                ip += 1;
                suspended = true;

                return true;
            }
            }

            // Notify any debug monitor that the machine has been stepped.
            if (monitor != null)
            {
                monitor.onStep(this);
            }
        }

        return !failed;
    }
{@inheritDoc}