Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.compiler;
import java.nio.ByteBuffer;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.thesett.aima.logic.fol.Functor;
import com.thesett.aima.logic.fol.FunctorName;
import com.thesett.aima.logic.fol.LinkageException;
import com.thesett.aima.logic.fol.Term;
import com.thesett.aima.logic.fol.VariableAndFunctorInterner;
import com.thesett.aima.logic.fol.wam.machine.WAMCodeView;
import com.thesett.aima.logic.fol.wam.machine.WAMMachine;
import com.thesett.common.util.Pair;
import com.thesett.common.util.Sizeable;
import com.thesett.common.util.SizeableLinkedList;
import com.thesett.common.util.SizeableList;
import com.thesett.common.util.doublemaps.SymbolKey;
/**
* WAMInstruction provides a structured in-memory representation of the WAM instruction set, as well as utilities to
* emmit the instructions as byte code, disassemble them back into the structured representation, and pretty print them.
*
* Instructions implement {@link Sizeable} reporting their length in bytes as their 'size of'.
*
*
CRC Card
*
Responsibilities
Collaborations
*
Provide the translation of the WAM instruction set down to bytes.
*
Provide dissasembly of byte encoded instructions back into structured instructions.
*
Calculate the length of an instruction in bytes.
{@link com.thesett.common.util.Sizeable}
*
*
* @author Rupert Smith
*/
public class WAMInstruction implements Sizeable
{
/** Instruction to write out a struc onto the heap. */
public static final byte PUT_STRUC = 0x01;
/** The instruction to set a register as a variable. */
public static final byte SET_VAR = 0x02;
/** The instruction to set a register to a heap location. */
public static final byte SET_VAL = 0x03;
/** The instruction to compare a register to a structure on the heap. */
public static final byte GET_STRUC = 0x04;
/** The instruction to unify a register with a variable. */
public static final byte UNIFY_VAR = 0x05;
/** The instruction to unify a register with a location on the heap. */
public static final byte UNIFY_VAL = 0x06;
/** The instruction to copy a heap location into an argument register. */
public static final byte PUT_VAR = 0x07;
/** The instruction to copy a register into an argument register. */
public static final byte PUT_VAL = 0x08;
/** The instruction to unify an argument register with a variable. */
public static final byte GET_VAR = 0x09;
/** The instruction to unify a register with a location on the heap. */
public static final byte GET_VAL = 0x0a;
/** The instruction to copy a constant into an argument register. */
public static final byte PUT_CONST = 0x12;
/** The instruction to compare or bind a reference from a register to a constant. */
public static final byte GET_CONST = 0x13;
/** The instruction to write a constant onto the heap. */
public static final byte SET_CONST = 0x14;
/** The instruction to unify the heap with a constant. */
public static final byte UNIFY_CONST = 0x15;
/** The instruction to copy a list pointer into an argument register. */
public static final byte PUT_LIST = 0x16;
/** The instruction to compare or bind a reference from a register to a list pointer. */
public static final byte GET_LIST = 0x17;
/** The instruction to write an anonymous variable onto the heap. */
public static final byte SET_VOID = 0x18;
/** The instruction to unify with anonymous variables on the heap. */
public static final byte UNIFY_VOID = 0x19;
/** The instruction to initialize an argument register, ensuring the stack variable it references is globalized. */
public static final byte PUT_UNSAFE_VAL = 0x1c;
/** The instruction to set a register, ensuring the stack variable it references is globalized. */
public static final byte SET_LOCAL_VAL = 0x1d;
/** The instruction to unify a register, ensuring any stack variable it references is globalized. */
public static final byte UNIFY_LOCAL_VAL = 0x1e;
/** The instruction to call a predicate. */
public static final byte CALL = 0x0b;
/** The instruction to tail call a predicate. */
public static final byte EXECUTE = 0x1a;
/** The instruction to return from a called predicate. */
public static final byte PROCEED = 0x0c;
/** The stack frame allocation instruction. */
public static final byte ALLOCATE = 0x1b;
/** The stack frame allocation instruction for queries. */
public static final byte ALLOCATE_N = 0x0d;
/** The stack frame de-allocation instruction. */
public static final byte DEALLOCATE = 0x0e;
/** The first clause try instruction. */
public static final byte TRY_ME_ELSE = 0x0f;
/** The middle clause retry instruction. */
public static final byte RETRY_ME_ELSE = 0x10;
/** The final clause trust or fail instruction. */
public static final byte TRUST_ME = 0x11;
/** The first clause indexing try instruction. */
public static final byte TRY = 0x1f;
/** The middle clause indexing retry instruction. */
public static final byte RETRY = 0x20;
/** The final clause indexing trust or fail instruction. */
public static final byte TRUST = 0x21;
/** The second level indexing instruction. */
public static final byte SWITCH_ON_TERM = 0x22;
/** The third level indexing instruction for constants. */
public static final byte SWITCH_ON_CONST = 0x23;
/** The third level indexing instruction for structures. */
public static final byte SWITCH_ON_STRUC = 0x24;
/** The simpler neck-cut instruction. */
public static final byte NECK_CUT = 0x25;
/** The get level instruction for cuts. */
public static final byte GET_LEVEL = 0x26;
/** The full deep cut instruction. */
public static final byte CUT = 0x27;
/** The continue instruction for inline choice points. */
public static final byte CONTINUE = 0x28;
/** The no-op instruction, useful for inserting labels into the code. */
public static final byte NO_OP = 0x29;
/** The internal call instruction for intrinsics. */
public static final byte CALL_INTERNAL = 0x2a;
/** The suspend operation. */
public static final byte SUSPEND = 0x7f;
// === Defines the addressing modes.
/** Used to specify addresses relative to registers. */
public static final byte REG_ADDR = 0x01;
/** Used to specify addresses relative to the current stack frame. */
public static final byte STACK_ADDR = 0x02;
// === Defines the heap cell marker types.
/** Indicates a reference data type. */
public static final byte REF = 0x00;
/** Indicates a structure data type. */
public static final byte STR = 0x01;
/** Indicates a constant atom data type. */
public static final byte CON = 0x02;
/** Indicates a list data type. */
public static final byte LIS = 0x03;
/** Defines the L0 virtual machine instruction set as constants. */
public enum WAMInstructionSet
{
/** Instruction to write out a struc onto the heap. */
PutStruc(PUT_STRUC, "put_struc", 7, 0xb)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleReg1Fn(codeBuf, ip, instruction, interner);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
emmitCodeReg1Fn(codeBuf, code, instruction, machine);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return toStringReg1Fn(pretty, instruction);
}
},
/** The instruction to set a register as a variable. */
SetVar(SET_VAR, "set_var", 3, 0x3),
/** The instruction to set a register to a heap location. */
SetVal(SET_VAL, "set_val", 3, 0x3),
/** The instruction to set a register, ensuring the stack variable it references is globalized. */
SetLocalVal(SET_LOCAL_VAL, "set_local_val", 3, 0x3),
/** The instruction to compare a register to a structure on the heap. */
GetStruc(GET_STRUC, "get_struc", 7, 0xb)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleReg1Fn(codeBuf, ip, instruction, interner);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
emmitCodeReg1Fn(codeBuf, code, instruction, machine);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return toStringReg1Fn(pretty, instruction);
}
},
/** The instruction to unify a register with a variable. */
UnifyVar(UNIFY_VAR, "unify_var", 3, 0x3),
/** The instruction to unify a register with a location on the heap. */
UnifyVal(UNIFY_VAL, "unify_val", 3, 0x3),
/** The instruction to unify a register, ensuring any stack variable it references is globalized. */
UnifyLocalVal(UNIFY_LOCAL_VAL, "unify_local_val", 3, 0x3),
/** The instruction to copy a heap location into an argument register. */
PutVar(PUT_VAR, "put_var", 4, 0x7)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleReg1Reg2(codeBuf, ip, instruction);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
emmitCodeReg1Reg2(codeBuf, code, instruction);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return toStringReg1Reg2(pretty, instruction);
}
},
/** The instruction to copy a register into an argument register. */
PutVal(PUT_VAL, "put_val", 4, 0x7)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleReg1Reg2(codeBuf, ip, instruction);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
emmitCodeReg1Reg2(codeBuf, code, instruction);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return toStringReg1Reg2(pretty, instruction);
}
},
/**
* The instruction to initialize an argument register, ensuring the stack variable it references is globalized.
*/
PutUnsafeVal(PUT_UNSAFE_VAL, "put_unsafe_val", 4, 0x7)
{
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
emmitCodeReg1Reg2(codeBuf, code, instruction);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return toStringReg1Reg2(pretty, instruction);
}
},
/** The instruction to unify an argument register with a variable. */
GetVar(GET_VAR, "get_var", 4, 0x7)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleReg1Reg2(codeBuf, ip, instruction);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
emmitCodeReg1Reg2(codeBuf, code, instruction);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return toStringReg1Reg2(pretty, instruction);
}
},
/** The instruction to unify a register with a location on the heap. */
GetVal(GET_VAL, "get_val", 4, 0x7)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleReg1Reg2(codeBuf, ip, instruction);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
emmitCodeReg1Reg2(codeBuf, code, instruction);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return toStringReg1Reg2(pretty, instruction);
}
},
/** The instruction to copy a constant into an argument register. */
PutConstant(PUT_CONST, "put_const", 7, 0xb)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleReg1Fn(codeBuf, ip, instruction, interner);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
emmitCodeReg1Fn(codeBuf, code, instruction, machine);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return toStringReg1Fn(pretty, instruction);
}
},
/** The instruction to compare or bind a reference from a register to a constant. */
GetConstant(GET_CONST, "get_const", 7, 0xb)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleReg1Fn(codeBuf, ip, instruction, interner);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
emmitCodeReg1Fn(codeBuf, code, instruction, machine);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return toStringReg1Fn(pretty, instruction);
}
},
/** The instruction to write a constant onto the heap. */
SetConstant(SET_CONST, "set_const", 5, 0x8)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleFn(codeBuf, ip, instruction, interner);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
emmitCodeFn(codeBuf, code, instruction, machine);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return toStringFn(pretty, instruction);
}
},
/** The instruction to unify the heap with a constant. */
UnifyConstant(UNIFY_CONST, "unify_const", 5, 0x8)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleFn(codeBuf, ip, instruction, interner);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
emmitCodeFn(codeBuf, code, instruction, machine);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return toStringFn(pretty, instruction);
}
},
/** The instruction to copy a list pointer into an argument register. */
PutList(PUT_LIST, "put_list", 3, 0x3),
/** The instruction to compare or bind a reference from a register to a list pointer. */
GetList(GET_LIST, "get_list", 3, 0x3),
/** The instruction to write an anonymous variable onto the heap. */
SetVoid(SET_VOID, "set_void", 2, 0x2)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleReg1NoMode(codeBuf, ip, instruction);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
emmitCodeReg1NoMode(codeBuf, code, instruction);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty + " " + instruction.reg1;
}
},
/** The instruction to unify with anonymous variables on the heap. */
UnifyVoid(UNIFY_VOID, "unify_void", 2, 0x2)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleReg1NoMode(codeBuf, ip, instruction);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
emmitCodeReg1NoMode(codeBuf, code, instruction);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty + " " + instruction.reg1;
}
},
/** The instruction to call a predicate. */
Call(CALL, "call", 7, 0xa)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
int entryPoint = codeBuf.getInt(ip + 1);
int arity = codeBuf.get(ip + 5);
instruction.reg1 = codeBuf.get(ip + 6);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
int toCall = machine.internFunctorName(instruction.fn);
WAMCallPoint callPointToCall = machine.resolveCallPoint(toCall);
// Ensure that a valid call point was returned, otherwise a linkage error has occurred.
if (callPointToCall == null)
{
throw new LinkageException("Could not resolve call to " + instruction.fn + ".", null, null,
"Unable to resolve call to " + instruction.fn.getName() + "/" + instruction.fn.getArity() +
".");
}
int entryPoint = callPointToCall.entryPoint;
codeBuf.put(code);
codeBuf.putInt(entryPoint);
codeBuf.put((byte) instruction.fn.getArity());
codeBuf.put(instruction.reg1);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty + " " +
((instruction.fn != null) ? (instruction.fn.getName() + "/" + instruction.fn.getArity()) : "") +
(", " + instruction.reg1);
}
},
/** The instruction to tail call a predicate. */
Execute(EXECUTE, "execute", 6, 0x8)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
int entryPoint = codeBuf.getInt(ip + 1);
int arity = codeBuf.get(ip + 5);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
int toCall = machine.internFunctorName(instruction.fn);
WAMCallPoint callPointToCall = machine.resolveCallPoint(toCall);
// Ensure that a valid call point was returned, otherwise a linkage error has occurred.
if (callPointToCall == null)
{
throw new LinkageException("Could not resolve call to " + instruction.fn + ".", null, null,
"Unable to resolve call to " + instruction.fn.getName() + "/" + instruction.fn.getArity() +
".");
}
int entryPoint = callPointToCall.entryPoint;
codeBuf.put(code);
codeBuf.putInt(entryPoint);
codeBuf.put((byte) instruction.fn.getArity());
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty + " " +
((instruction.fn != null) ? (instruction.fn.getName() + "/" + instruction.fn.getArity()) : "");
}
},
/** The instruction to return from a called predicate. */
Proceed(PROCEED, "proceed", 1, 0x0)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
// Do nothing as this instruction takes no arguments.
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
codeBuf.put(code);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty;
}
},
/** The stack frame allocation instruction. */
Allocate(ALLOCATE, "allocate", 1, 0x0)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
// Do nothing as this instruction takes no arguments.
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
codeBuf.put(code);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty;
}
},
/** The stack frame allocation instruction for queries. */
AllocateN(ALLOCATE_N, "allocate_n", 2, 0x2)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleReg1NoMode(codeBuf, ip, instruction);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
emmitCodeReg1NoMode(codeBuf, code, instruction);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty + " " + instruction.reg1;
}
},
/** The stack frame deallocation instruction. */
Deallocate(DEALLOCATE, "deallocate", 1, 0x0)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
// Do nothing as this instruction takes no arguments.
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
codeBuf.put(code);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty;
}
},
/** The first clause try instruction. */
TryMeElse(TRY_ME_ELSE, "try_me_else", 5, 0x10)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
int label = codeBuf.getInt(ip + 1);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
int ip = codeBuf.position();
// Intern the alternative forward label, and write it out as zero initially, for later completion.
int toCall = machine.internFunctorName(instruction.target1);
machine.reserveReferenceToLabel(toCall, ip + 1);
codeBuf.put(code);
codeBuf.putInt(0);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
WAMLabel label = instruction.target1;
return pretty + " " + ((label != null) ? label.toPrettyString() : "");
}
},
/** The middle clause retry instruction. */
RetryMeElse(RETRY_ME_ELSE, "retry_me_else", 5, 0x10)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
int label = codeBuf.getInt(ip + 1);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
int ip = codeBuf.position();
// Resolve any forward reference to the label for this instruction.
int label = machine.internFunctorName(instruction.label);
machine.resolveLabelPoint(label, ip);
// Intern the alternative forward label, and write it out as zero initially, for later completion.
int toCall = machine.internFunctorName(instruction.target1);
machine.reserveReferenceToLabel(toCall, ip + 1);
codeBuf.put(code);
codeBuf.putInt(0);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
WAMLabel label = instruction.target1;
return pretty + " " + ((label != null) ? label.toPrettyString() : "");
}
},
/** The final clause trust or fail instruction. */
TrustMe(TRUST_ME, "trust_me", 1, 0x0)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
// Do nothing as this instruction takes no arguments.
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
int ip = codeBuf.position();
// Resolve any forward reference to the label for this instruction.
int label = machine.internFunctorName(instruction.label);
machine.resolveLabelPoint(label, ip);
codeBuf.put(code);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty;
}
},
/** The first clause indexing try instruction. */
Try(TRY, "try", 5, 0x10)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
int label = codeBuf.getInt(ip + 1);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
int ip = codeBuf.position();
// Resolve any forward reference to the label for this instruction.
if (instruction.label != null)
{
int label = machine.internFunctorName(instruction.label);
machine.resolveLabelPoint(label, ip);
}
// Intern the forward label, and write it out as zero initially, for later completion.
int toCall = machine.internFunctorName(instruction.target1);
machine.reserveReferenceToLabel(toCall, ip + 1);
codeBuf.put(code);
codeBuf.putInt(0);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
WAMLabel label = instruction.target1;
return pretty + " " + ((label != null) ? label.toPrettyString() : "");
}
},
/** The middle clause indexing retry instruction. */
Retry(RETRY, "retry", 5, 0x10)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
int label = codeBuf.getInt(ip + 1);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
int ip = codeBuf.position();
// Resolve any forward reference to the label for this instruction.
if (instruction.label != null)
{
int label = machine.internFunctorName(instruction.label);
machine.resolveLabelPoint(label, ip);
}
// Intern the forward label, and write it out as zero initially, for later completion.
int toCall = machine.internFunctorName(instruction.target1);
machine.reserveReferenceToLabel(toCall, ip + 1);
codeBuf.put(code);
codeBuf.putInt(0);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
WAMLabel label = instruction.target1;
return pretty + " " + ((label != null) ? label.toPrettyString() : "");
}
},
/** The final clause indexing trust or fail instruction. */
Trust(TRUST, "trust", 5, 0x10)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
int label = codeBuf.getInt(ip + 1);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
int ip = codeBuf.position();
// Resolve any forward reference to the label for this instruction.
if (instruction.label != null)
{
int label = machine.internFunctorName(instruction.label);
machine.resolveLabelPoint(label, ip);
}
// Intern the forward label, and write it out as zero initially, for later completion.
int toCall = machine.internFunctorName(instruction.target1);
machine.reserveReferenceToLabel(toCall, ip + 1);
codeBuf.put(code);
codeBuf.putInt(0);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty;
}
},
/** The second level indexing instruction. */
SwitchOnTerm(SWITCH_ON_TERM, "switch_on_term", 17, 0x0)
{
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
int ip = codeBuf.position();
// Resolve any forward reference to the label for this instruction.
int label = machine.internFunctorName(instruction.label);
machine.resolveLabelPoint(label, ip);
// Intern the alternative forward labels, and write them out as zero initially, for later completion.
int jump = machine.internFunctorName(instruction.target1);
machine.reserveReferenceToLabel(jump, ip + 1);
jump = machine.internFunctorName(instruction.target2);
machine.reserveReferenceToLabel(jump, ip + 5);
jump = machine.internFunctorName(instruction.target3);
machine.reserveReferenceToLabel(jump, ip + 9);
jump = machine.internFunctorName(instruction.target4);
machine.reserveReferenceToLabel(jump, ip + 13);
codeBuf.put(code);
codeBuf.putInt(0);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty + " " + labelToString(instruction.target1) + " / " + labelToString(instruction.target2) +
" / " + labelToString(instruction.target3) + " / " + labelToString(instruction.target4);
}
},
/** The third level indexing instruction for constants. */
SwitchOnConst(SWITCH_ON_CONST, "switch_on_const", 9, 0x0)
{
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
int ip = codeBuf.position();
// Resolve any forward reference to the label for this instruction.
int label = machine.internFunctorName(instruction.label);
machine.resolveLabelPoint(label, ip);
// Intern the alternative forward labels, and write them out as zero initially, for later completion.
int jump = machine.internFunctorName(instruction.target1);
machine.reserveReferenceToLabel(jump, ip + 1);
jump = machine.internFunctorName(instruction.target2);
machine.reserveReferenceToLabel(jump, ip + 5);
codeBuf.put(code);
codeBuf.putInt(0);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty + " " + labelToString(instruction.target1) + " / " + labelToString(instruction.target2);
}
},
/** The third level indexing instruction for structures. */
SwitchOnStruc(SWITCH_ON_STRUC, "switch_on_struc", 9, 0x0)
{
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
int ip = codeBuf.position();
// Resolve any forward reference to the label for this instruction.
int label = machine.internFunctorName(instruction.label);
machine.resolveLabelPoint(label, ip);
// Intern the alternative forward labels, and write them out as zero initially, for later completion.
int jump = machine.internFunctorName(instruction.target1);
machine.reserveReferenceToLabel(jump, ip + 1);
jump = machine.internFunctorName(instruction.target2);
machine.reserveReferenceToLabel(jump, ip + 5);
codeBuf.put(code);
codeBuf.putInt(0);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty + " " + labelToString(instruction.target1) + " / " + labelToString(instruction.target2);
}
},
/** The simpler neck-cut instruction. */
NeckCut(NECK_CUT, "neck_cut", 1, 0x0)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
// Do nothing as this instruction takes no arguments.
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
codeBuf.put(code);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty;
}
},
/** The get level instruction for cuts. */
GetLevel(GET_LEVEL, "get_level", 2, 0x2)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleReg1NoMode(codeBuf, ip, instruction);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
emmitCodeReg1NoMode(codeBuf, code, instruction);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty + " " + instruction.reg1;
}
},
/** The full deep cut instruction. */
Cut(CUT, "cut", 2, 0x2)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleReg1NoMode(codeBuf, ip, instruction);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
emmitCodeReg1NoMode(codeBuf, code, instruction);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty + " " + instruction.reg1;
}
},
/** The continue instruction for inline choice points. */
Continue(CONTINUE, "continue", 5, 0x10)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
int label = codeBuf.getInt(ip + 1);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
int ip = codeBuf.position();
// Intern the forward label, and write it out as zero initially, for later completion.
int toCall = machine.internFunctorName(instruction.target1);
machine.reserveReferenceToLabel(toCall, ip + 1);
codeBuf.put(code);
codeBuf.putInt(0);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
WAMLabel label = instruction.target1;
return pretty + " " + ((label != null) ? label.toPrettyString() : "");
}
},
/** The no-op instruction, useful for inserting labels into the code. */
NoOp(NO_OP, "no_op", 1, 0x0)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
// Do nothing as this instruction takes no arguments.
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
int ip = codeBuf.position();
// Resolve any forward reference to the label for this instruction.
int label = machine.internFunctorName(instruction.label);
machine.resolveLabelPoint(label, ip);
codeBuf.put(code);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty;
}
},
/** The instruction to call a predicate. */
CallInternal(CALL_INTERNAL, "call_internal", 7, 0xa)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
int entryPoint = codeBuf.getInt(ip + 1);
int arity = codeBuf.get(ip + 5);
instruction.reg1 = codeBuf.get(ip + 6);
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
int toCall = machine.internFunctorName(instruction.fn);
WAMCallPoint callPointToCall = machine.resolveCallPoint(toCall);
// Ensure that a valid call point was returned, otherwise a linkage error has occurred.
if (callPointToCall == null)
{
throw new LinkageException("Could not resolve internal call to " + instruction.fn + ".", null, null,
"Unable to resolve internal call to " + instruction.fn.getName() + "/" +
instruction.fn.getArity() + ".");
}
int entryPoint = callPointToCall.entryPoint;
codeBuf.put(code);
codeBuf.putInt(entryPoint);
codeBuf.put((byte) instruction.fn.getArity());
codeBuf.put(instruction.reg1);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty + " " +
((instruction.fn != null) ? (instruction.fn.getName() + "/" + instruction.fn.getArity()) : "") +
(", " + instruction.reg1);
}
},
/** The suspend on success instruction. */
Suspend(SUSPEND, "suspend", 1, 0x0)
{
/** {@inheritDoc} */
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
// Do nothing as this instruction takes no arguments.
}
/** {@inheritDoc} */
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
{
codeBuf.put(code);
}
/** {@inheritDoc} */
public String toString(WAMInstruction instruction)
{
return pretty;
}
};
/** Holds a mapping of the instruction by byte code. */
private static Map codeToValue = new HashMap();
static
{
for (WAMInstructionSet instruction : EnumSet.allOf(WAMInstructionSet.class))
{
codeToValue.put(instruction.code, instruction);
}
}
/** Holds the byte representation of the instruction. */
protected byte code;
/** Holds the human readable form of the instruction. */
protected String pretty;
/** Holds the length of the instruction in bytes. */
protected int length;
/**
* Holds a bit mask defining which argument fields this op-code uses. The correspondence between bits and fields
* is:
*
*
Bits to Fields
*
Bit
Field
*
0
{@link WAMInstruction#mode1}
*
1
{@link WAMInstruction#reg1}
*
2
{@link WAMInstruction#reg2}
*
3
{@link WAMInstruction#fn}
*
4
{@link WAMInstruction#target1}
*
*/
protected int fieldMask;
/**
* Creates a new L0 instruction with the specified byte code.
*
* @param i The byte code for the instruction.
* @param pretty The human readable form of the instruction.
* @param length The length of the instruction plus arguments in bytes.
*/
private WAMInstructionSet(byte i, String pretty, int length, int fieldMask)
{
this.code = i;
this.pretty = pretty;
this.length = length;
this.fieldMask = fieldMask;
}
/**
* Creates an instruction from a byte code.
*
* @param code The byte coded form of the instruction.
*
* @return An instruction matching the byte code, or null if no instruction matches the code.
*/
public static WAMInstructionSet fromCode(byte code)
{
return codeToValue.get(code);
}
/**
* Provides the base name of register 1, "X" for register addressing, "Y" for stack mode addressing.
*
* @param instruction The instruction to get the base register name from;
*
* @return The base name of register 1, "X" for register addressing, "Y" for stack mode addressing.
*/
public static String reg1Name(WAMInstruction instruction)
{
return (instruction.mode1 == STACK_ADDR) ? "Y" : "X";
}
/**
* Writes out the instruction plus arguments in the byte code format to the specified location within a code
* buffer.
*
* @param instruction The instruction, including its arguments.
* @param codeBuf The code buffer to write to.
* @param machine The binary machine to write the code into.
*
* @throws LinkageException If required symbols to link to cannot be found in the binary machine.
*/
public void emmitCode(WAMInstruction instruction, ByteBuffer codeBuf, WAMMachine machine)
throws LinkageException
{
emmitCodeReg1(codeBuf, code, instruction);
}
/**
* Provides the field mask describing which argument fields this instruction uses.
*
* @return The field mask describing which argument fields this instruction uses.
*/
public int getFieldMask()
{
return fieldMask;
}
/**
* Provides the human readable form of the instruction.
*
* @return The human readable form of the instruction.
*/
public String getPretty()
{
return pretty;
}
/**
* Prints the human readable form of the instruction for debugging purposes.
*
* @param instruction The instruction, including its arguments.
*
* @return The human readable form of the instruction for debugging purposes.
*/
public String toString(WAMInstruction instruction)
{
return toStringReg1(pretty, instruction);
}
/**
* Gets the byte coded representation of the instruction.
*
* @return The byte coded representation of the instruction.
*/
public byte getCode()
{
return code;
}
/**
* Calculates the length of this instruction in bytes.
*
* @return The length of this instruction in bytes.
*/
public int length()
{
return length;
}
/**
* Disassembles the arguments of an instruction. This is a default implementation to handle the most common
* case; instructions with one register argument.
*
* @param instruction The instruction, including its arguments.
* @param ip The start of the instruction within the buffer.
* @param codeBuf The code buffer.
* @param interner The interner to look up function and variable names against.
*/
protected void disassembleArguments(WAMInstruction instruction, int ip, ByteBuffer codeBuf,
VariableAndFunctorInterner interner)
{
disassembleReg1(codeBuf, ip, instruction);
}
/**
* Writes out the instruction plus arguments in the byte code format to the specified location within a code
* buffer.
*
* @param codeBuf The code buffer to write to.
* @param code The instruction mnemonic.
* @param instruction The instruction, including its arguments.
*/
private static void emmitCodeReg1(ByteBuffer codeBuf, byte code, WAMInstruction instruction)
{
codeBuf.put(code);
codeBuf.put(instruction.mode1);
codeBuf.put(instruction.reg1);
}
/**
* Writes out the instruction plus arguments in the byte code format to the specified location within a code
* buffer.
*
* @param codeBuf The code buffer to write to.
* @param code The instruction mnemonic.
* @param instruction The instruction, including its arguments.
*/
private static void emmitCodeReg1NoMode(ByteBuffer codeBuf, byte code, WAMInstruction instruction)
{
codeBuf.put(code);
codeBuf.put(instruction.reg1);
}
/**
* Writes out the instruction plus arguments in the byte code format to the specified location within a code
* buffer.
*
* @param codeBuf The code buffer to write to.
* @param code The instruction mnemonic.
* @param instruction The instruction, including its arguments.
*/
private static void emmitCodeReg1Reg2(ByteBuffer codeBuf, byte code, WAMInstruction instruction)
{
codeBuf.put(code);
codeBuf.put(instruction.mode1);
codeBuf.put(instruction.reg1);
codeBuf.put(instruction.reg2);
}
/**
* Writes out the instruction plus arguments in the byte code format to the specified location within a code
* buffer.
*
* @param codeBuf The code buffer to write to.
* @param code The instruction mnemonic.
* @param instruction The instruction, including its arguments.
* @param interner The binary machine to write the code into.
*/
private static void emmitCodeReg1Fn(ByteBuffer codeBuf, byte code, WAMInstruction instruction,
WAMMachine interner)
{
codeBuf.put(code);
codeBuf.put(instruction.mode1);
codeBuf.put(instruction.reg1);
int arity = instruction.fn.getArity() << 24;
int name = interner.internFunctorName(instruction.fn) & 0x00ffffff;
codeBuf.putInt(arity | name);
}
/**
* Writes out the instruction plus arguments in the byte code format to the specified location within a code
* buffer.
*
* @param codeBuf The code buffer to write to.
* @param code The instruction mnemonic.
* @param instruction The instruction, including its arguments.
* @param interner The binary machine to write the code into.
*/
private static void emmitCodeFn(ByteBuffer codeBuf, byte code, WAMInstruction instruction, WAMMachine interner)
{
codeBuf.put(code);
int arity = instruction.fn.getArity() << 24;
int name = interner.internFunctorName(instruction.fn) & 0x00ffffff;
codeBuf.putInt(arity | name);
}
/**
* Helper print function that prints an instruction with one register argument.
*
* @param pretty The pretty printed instruction mnenomic.
* @param instruction The instruction data.
*
* @return A pretty printed instruction.
*/
private static String toStringReg1(String pretty, WAMInstruction instruction)
{
return pretty + " " + reg1Name(instruction) + instruction.reg1;
}
/**
* Helper print function that prints an instruction with two register arguments.
*
* @param pretty The pretty printed instruction mnenomic.
* @param instruction The instruction data.
*
* @return A pretty printed instruction.
*/
private static String toStringReg1Reg2(String pretty, WAMInstruction instruction)
{
return pretty + " " + reg1Name(instruction) + instruction.reg1 + ", A" + instruction.reg2;
}
/**
* Helper print function that prints an instruction with one register argument and a functor reference.
*
* @param pretty The pretty printed instruction mnenomic.
* @param instruction The instruction data.
*
* @return A pretty printed instruction.
*/
private static String toStringReg1Fn(String pretty, WAMInstruction instruction)
{
return pretty + " " +
((instruction.fn != null) ? (instruction.fn.getName() + "/" + instruction.fn.getArity()) : "") + ", A" +
instruction.reg1;
}
/**
* Helper print function that prints an instruction with one functor reference.
*
* @param pretty The pretty printed instruction mnenomic.
* @param instruction The instruction data.
*
* @return A pretty printed instruction.
*/
private static String toStringFn(String pretty, WAMInstruction instruction)
{
return pretty + " " +
((instruction.fn != null) ? (instruction.fn.getName() + "/" + instruction.fn.getArity()) : "");
}
/**
* Disassembles the arguments to an instruction that takes one register and one functor reference.
*
* @param codeBuf The code buffer to disassemble from.
* @param ip The instruction pointer within the code buffer.
* @param instruction The instruction to store the disassembles arguments in.
* @param interner The interner to look up function and variable names against.
*/
private static void disassembleReg1Fn(ByteBuffer codeBuf, int ip, WAMInstruction instruction,
VariableAndFunctorInterner interner)
{
instruction.mode1 = codeBuf.get(ip + 1);
instruction.reg1 = codeBuf.get(ip + 2);
int fn = codeBuf.getInt(ip + 3);
int f = fn & 0x00ffffff;
instruction.fn = interner.getDeinternedFunctorName(f);
}
/**
* Disassembles the arguments to an instruction that takes one functor reference.
*
* @param codeBuf The code buffer to disassemble from.
* @param ip The instruction pointer within the code buffer.
* @param instruction The instruction to store the disassembles arguments in.
* @param interner The interner to look up function and variable names against.
*/
private static void disassembleFn(ByteBuffer codeBuf, int ip, WAMInstruction instruction,
VariableAndFunctorInterner interner)
{
int fn = codeBuf.getInt(ip + 1);
int f = fn & 0x00ffffff;
instruction.fn = interner.getDeinternedFunctorName(f);
}
/**
* Disassembles the arguments to an instruction that takes one register argument.
*
* @param codeBuf The code buffer to disassemble from.
* @param ip The instruction pointer within the code buffer.
* @param instruction The instruction to store the disassembles arguments in.
*/
private static void disassembleReg1(ByteBuffer codeBuf, int ip, WAMInstruction instruction)
{
instruction.mode1 = codeBuf.get(ip + 1);
instruction.reg1 = codeBuf.get(ip + 2);
}
/**
* Disassembles the arguments to an instruction that takes one register argument and no mode flag.
*
* @param codeBuf The code buffer to disassemble from.
* @param ip The instruction pointer within the code buffer.
* @param instruction The instruction to store the disassembles arguments in.
*/
private static void disassembleReg1NoMode(ByteBuffer codeBuf, int ip, WAMInstruction instruction)
{
instruction.reg1 = codeBuf.get(ip + 1);
}
/**
* Disassembles the arguments to an instruction that takes one register argument.
*
* @param codeBuf The code buffer to disassemble from.
* @param ip The instruction pointer within the code buffer.
* @param instruction The instruction to store the disassembles arguments in.
*/
private static void disassembleReg1Reg2(ByteBuffer codeBuf, int ip, WAMInstruction instruction)
{
instruction.mode1 = codeBuf.get(ip + 1);
instruction.reg1 = codeBuf.get(ip + 2);
instruction.reg2 = codeBuf.get(ip + 3);
}
}
/** The optional address label of the instruction. */
protected WAMLabel label;
/** The instruction. */
protected WAMInstructionSet mnemonic;
/** Holds the addressing mode of the first register argument to the instruction. */
protected byte mode1;
/** Holds the first register argument to the instruction. */
protected byte reg1;
/** Holds the second register argument to the instruction. */
protected byte reg2;
/** Holds the functor argument to the instruction. */
protected FunctorName fn;
/** An optional target address label. */
protected WAMLabel target1;
/** An optional target address label. */
protected WAMLabel target2;
/** An optional target address label. */
protected WAMLabel target3;
/** An optional target address label. */
protected WAMLabel target4;
/** Holds the symbol key of the argument that is held in the first register of this instruction. */
private SymbolKey symbolKeyReg1;
/** Holds the functor name of the argument that is assigned to the first register of this instruction. */
private Integer functorNameReg1;
/** An optional list of entries for an indexing table. */
protected List> indexTable;
/**
* Creates an instruction for the specified mnemonic.
*
* @param mnemonic The instruction mnemonic.
*/
public WAMInstruction(WAMInstructionSet mnemonic)
{
this.mnemonic = mnemonic;
}
/**
* Creates an instruction with the mnemonic resolved from its byte encoded form.
*
* @param code The byte encoded form of the instruction mnemonic.
*/
public WAMInstruction(byte code)
{
this.mnemonic = WAMInstructionSet.fromCode(code);
}
/**
* Creates an instruction for the specified mnemonic that takes one register and one functor argument.
*
* @param mnemonic The instruction mnemonic.
* @param mode1 The addressing mode to use with the register argument.
* @param reg1 The register argument.
* @param fn The functor argument.
* @param reg1Term The term that is assigned or associated with reg1.
*/
public WAMInstruction(WAMInstructionSet mnemonic, byte mode1, byte reg1, FunctorName fn, Term reg1Term)
{
this.mnemonic = mnemonic;
this.mode1 = mode1;
this.reg1 = reg1;
this.fn = fn;
// Record the symbol keys of the term that resulted in the creation of the instruction, and are associated
// with reg1 of the instruction.
symbolKeyReg1 = reg1Term.getSymbolKey();
functorNameReg1 = reg1Term.isFunctor() ? ((Functor) reg1Term).getName() : null;
}
/**
* Creates an instruction for the specified mnemonic that takes one register and one functor argument.
*
* @param mnemonic The instruction mnemonic.
* @param mode1 The addressing mode to use with the register argument.
* @param reg1 The register argument.
* @param fn The functor argument.
*/
public WAMInstruction(WAMInstructionSet mnemonic, byte mode1, byte reg1, FunctorName fn)
{
this.mnemonic = mnemonic;
this.mode1 = mode1;
this.reg1 = reg1;
this.fn = fn;
}
/**
* Creates an instruction for the specified mnemonic that takes two register arguments.
*
* @param mnemonic The instruction mnemonic.
* @param mode1 The addressing mode to use with the first register argument.
* @param reg1 The first register argument.
* @param reg2 The second register argument.
*/
public WAMInstruction(WAMInstructionSet mnemonic, byte mode1, byte reg1, byte reg2)
{
this.mnemonic = mnemonic;
this.mode1 = mode1;
this.reg1 = reg1;
this.reg2 = reg2;
}
/**
* Creates an instruction for the specified mnemonic that takes a single register argument.
*
* @param mnemonic The instruction mnemonic.
* @param mode1 The addressing mode to use with the register argument.
* @param reg1 The single register argument.
* @param reg1Term The term that is assigned or associated with reg1.
*/
public WAMInstruction(WAMInstructionSet mnemonic, byte mode1, byte reg1, Term reg1Term)
{
this.mnemonic = mnemonic;
this.mode1 = mode1;
this.reg1 = reg1;
// Record the symbol keys of the term that resulted in the creation of the instruction, and are associated
// with reg1 of the instruction.
symbolKeyReg1 = reg1Term.getSymbolKey();
functorNameReg1 = reg1Term.isFunctor() ? ((Functor) reg1Term).getName() : null;
}
/**
* Creates an instruction for the specified mnemonic that takes a single register argument.
*
* @param mnemonic The instruction mnemonic.
* @param mode1 The addressing mode to use with the register argument.
* @param reg1 The single register argument.
*/
public WAMInstruction(WAMInstructionSet mnemonic, byte mode1, byte reg1)
{
this.mnemonic = mnemonic;
this.mode1 = mode1;
this.reg1 = reg1;
}
/**
* Creates an instruction for the specified mnemonic that takes a single register argument, and no addressing mode,
* for situations where the addressing mode is already inferred by the instruction type.
*
* @param mnemonic The instruction mnemonic.
* @param reg1 The single register argument.
*/
public WAMInstruction(WAMInstructionSet mnemonic, byte reg1)
{
this.mnemonic = mnemonic;
this.reg1 = reg1;
}
/**
* Creates an instruction for the specified mnemonic that takes a single functor argument.
*
* @param mnemonic The instruction mnemonic.
* @param fn The functor argument.
*/
public WAMInstruction(WAMInstructionSet mnemonic, FunctorName fn)
{
this.mnemonic = mnemonic;
this.fn = fn;
}
/**
* Creates an instruction for the specified mnemonic that takes a single functor argument and a single register.
*
* @param mnemonic The instruction mnemonic.
* @param reg1 The single register argument.
* @param fn The functor argument.
*/
public WAMInstruction(WAMInstructionSet mnemonic, byte reg1, FunctorName fn)
{
this.mnemonic = mnemonic;
this.reg1 = reg1;
this.fn = fn;
}
/**
* Creates a labelled instruction for the specified mnemonic that takes a single functor argument.
*
* @param label The instructions address label.
* @param mnemonic The instruction mnemonic.
* @param fn The functor argument.
*/
public WAMInstruction(WAMLabel label, WAMInstructionSet mnemonic, WAMLabel fn)
{
this.label = label;
this.mnemonic = mnemonic;
this.target1 = fn;
}
/**
* Creates a labelled instruction for the specified mnemonic.
*
* @param label The instructions address label.
* @param mnemonic The instruction mnemonic.
*/
public WAMInstruction(WAMLabel label, WAMInstructionSet mnemonic)
{
this.label = label;
this.mnemonic = mnemonic;
}
/**
* Disassembles the instructions from the specified byte buffer, starting at a given location (ip). An interner for
* the functor names encountered in the instruction buffer must also be supplied, in order to look up the functor
* names by encoded value.
*
* @param start The start offset into the buffer to disassemble.
* @param length The length of data in the buffer to disassemble.
* @param codeBuf The code buffer.
* @param interner The interner to look up interned names with.
* @param codeView A view onto the machines code buffer.
*
* @return A list of instructions disassembles from the code buffer.
*/
public static SizeableList disassemble(int start, int length, ByteBuffer codeBuf,
VariableAndFunctorInterner interner, WAMCodeView codeView)
{
SizeableList result = new SizeableLinkedList();
int ip = start;
while (ip < (start + length))
{
// Decode the instruction and its arguments.
byte iCode = codeBuf.get(ip);
WAMInstruction instruction = new WAMInstruction(iCode);
instruction.mnemonic.disassembleArguments(instruction, ip, codeBuf, interner);
// Restore any label on the instruction.
Integer label = codeView.getNameForAddress(ip);
if (label != null)
{
FunctorName name = interner.getDeinternedFunctorName(label);
if (name instanceof WAMLabel)
{
instruction.label = (WAMLabel) name;
}
}
result.add(instruction);
ip += instruction.mnemonic.length();
}
return result;
}
/**
* Gets the instruction mnemonic.
*
* @return The instruction mnemonic.
*/
public WAMInstructionSet getMnemonic()
{
return mnemonic;
}
/**
* Gets the addressing mode of the first register argument to the instruction.
*
* @return The addressing mode of the first register argument to the instruction.
*/
public byte getMode1()
{
return mode1;
}
/**
* Gets the first register to which the instruction applies.
*
* @return The first register to which the instruction applies.
*/
public byte getReg1()
{
return reg1;
}
/**
* Sets the first register to which the instruction applies.
*
* @param reg1 The first register to which the instruction applies.
*/
public void setReg1(byte reg1)
{
this.reg1 = reg1;
}
/**
* Gets the second register to which the instruction applies.
*
* @return The second register to which the instruction applies.
*/
public byte getReg2()
{
return reg2;
}
/**
* Sets the second register to which the instruction applies.
*
* @param reg2 The second register to which the instruction applies.
*/
public void setReg2(byte reg2)
{
this.reg2 = reg2;
}
/**
* Provides the symbol key of the argument that is assigned to the first register of this instruction.
*
* @return The symbol key, or null if none was associated with reg1.
*/
public SymbolKey getSymbolKeyReg1()
{
return symbolKeyReg1;
}
/**
* Provides the functor name of the argument that is assigned to the first register of this instruction.
*
* @return The functor name, or null if none was associated with reg1.
*/
public Integer getFunctorNameReg1()
{
return functorNameReg1;
}
/**
* Gets the functor argument, if any, to which the instruction applies.
*
* @return The functor argument to which the instruction applies, or null if there is none.
*/
public FunctorName getFn()
{
return fn;
}
/**
* Provides the target label argument, if any, to which the instruction applies.
*
* @return The target label argument to which the instruction applies, or null if there is none.
*/
public WAMLabel getTarget1()
{
return target1;
}
/**
* Sets the functor argument to which the instruction applies.
*
* @param fn The functor argument to which the instruction applies.
*/
public void setFn(FunctorName fn)
{
this.fn = fn;
}
/**
* Gets the label for the instruction, if any is set.
*
* @return The label for the instruction, or null if none is set.
*/
public WAMLabel getLabel()
{
return label;
}
/**
* Writes out the instruction plus arguments in the byte code format to the specified location within a code buffer.
*
* @param codeBuffer The code buffer to write to.
* @param machine The binary machine to write the code into.
*
* @throws LinkageException If required symbols to link to cannot be found in the binary machine.
*/
public void emmitCode(ByteBuffer codeBuffer, WAMMachine machine) throws LinkageException
{
mnemonic.emmitCode(this, codeBuffer, machine);
}
/**
* Calculates the length of this instruction in bytes.
*
* @return The length of this instruction in bytes.
*/
public long sizeof()
{
return mnemonic.length();
}
/**
* Prints the human readable form of the instruction for debugging purposes.
*
* @return The human readable form of the instruction for debugging purposes.
*/
public String toString()
{
return mnemonic.toString(this);
}
/**
* Pretty prints a label as a string.
*
* @param label The label to print.
*
* @return A pretty version of the label.
*/
private static String labelToString(WAMLabel label)
{
return ((label != null) ? label.toPrettyString() : "");
}
}