com.thesett.aima.logic.fol.l3.L3ResolvingJavaMachine Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of l3 Show documentation
Show all versions of l3 Show documentation
Implementation of the L0 machine described in "Warren's Abstact Machine, A Tutorial Reconstruction, by Hassan Ait-Kaci"
The newest version!
/*
* 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.l3;
import java.util.Iterator;
import java.util.Set;
import com.thesett.aima.logic.fol.LinkageException;
import com.thesett.aima.logic.fol.Variable;
import static com.thesett.aima.logic.fol.l3.L3Instruction.ALLOCATE;
import static com.thesett.aima.logic.fol.l3.L3Instruction.CALL;
import static com.thesett.aima.logic.fol.l3.L3Instruction.DEALLOCATE;
import static com.thesett.aima.logic.fol.l3.L3Instruction.GET_STRUC;
import static com.thesett.aima.logic.fol.l3.L3Instruction.GET_VAL;
import static com.thesett.aima.logic.fol.l3.L3Instruction.GET_VAR;
import static com.thesett.aima.logic.fol.l3.L3Instruction.PROCEED;
import static com.thesett.aima.logic.fol.l3.L3Instruction.PUT_STRUC;
import static com.thesett.aima.logic.fol.l3.L3Instruction.PUT_VAL;
import static com.thesett.aima.logic.fol.l3.L3Instruction.PUT_VAR;
import static com.thesett.aima.logic.fol.l3.L3Instruction.REF;
import static com.thesett.aima.logic.fol.l3.L3Instruction.RETRY_ME_ELSE;
import static com.thesett.aima.logic.fol.l3.L3Instruction.SET_VAL;
import static com.thesett.aima.logic.fol.l3.L3Instruction.SET_VAR;
import static com.thesett.aima.logic.fol.l3.L3Instruction.STACK_ADDR;
import static com.thesett.aima.logic.fol.l3.L3Instruction.STR;
import static com.thesett.aima.logic.fol.l3.L3Instruction.SUSPEND;
import static com.thesett.aima.logic.fol.l3.L3Instruction.TRUST_ME;
import static com.thesett.aima.logic.fol.l3.L3Instruction.TRY_ME_ELSE;
import static com.thesett.aima.logic.fol.l3.L3Instruction.UNIFY_VAL;
import static com.thesett.aima.logic.fol.l3.L3Instruction.UNIFY_VAR;
import com.thesett.common.util.ByteBufferUtils;
import com.thesett.common.util.SequenceIterator;
import com.thesett.common.util.doublemaps.SymbolTable;
/**
* L3ResolvingJavaMachine is a byte code interpreter for L3 written in java. This is a direct implementation of the
* instruction interpretations given in "Warren's Abstract Machine: A Tutorial Reconstruction". The pseudo algorithm
* presented there can be read in the comments interspersed with the code. There are a couple of challenges to be solved
* that are not presented in the book:
*
*
*
* - The book describes a STORE[addr] operation that loads or stores a heap, register or stack address. In the L1 and
* L0 machines, only heap and register addresses had to be catered for. This made things easier because the registers
* could be held at the top of the heap and a single common address range used for both. With increasing numbers of data
* areas in the machine, and Java unable to use direct pointers into memory, a choice between having separate arrays for
* each data area, or building all data areas within a single array has to be made. The single array approach was
* chosen, because otherwise the addressing mode would need to be passed down into the 'deref' and 'unify' operations,
* which would be complicated by having to choose amongst which of several arrays to operate on. An addressing mode has
* had to be added to the instruction set, so that instructions loading data from registers or stack, can specify which.
* Once addresses are resolved relative to the register or stack basis, the plain addresses offset to the base of the
* whole data area are used, and it is these addresses that are passed to the 'deref' and 'unify' operations.
*
- The memory layout for the WAM is described in Appendix B.3. of the book. The same layout is usd for this machine
* with the exception that the code area is held in a separate array. This follows the x86 machine convention of
* separating code and data segments in memory, and also caters well for the sharing of the code area with the JVM as a
* byte buffer.
*
- The deref operation is presented in the book as a recursive function. It was turned into an equivalent iterative
* looping function instead. The deref operation returns multiple parameters, but as Java only supports single return
* types, a choice had to be made between creating a simple class to hold the return types, or storing the return values
* in member variables, and reading them from there. The member variables solution was chosen.
*
*
*
CRC Card
* Responsibilities Collaborations
* Execute compiled L3 programs and queries.
* Provide access to the heap.
*
*
* @author Rupert Smith
* @todo Think about unloading of byte code as well as insertion of of byte code. For example, would it be possible to
* unload a program, and replace it with a different one? This would require re-linking of any references to the
* original. So maybe want to add an index to reverse references. Call instructions should have their jumps
* pre-calculated for speed, but perhaps should also put the bare f/n into them, for the case where they may
* need to be updated. Also, add a semaphore to all call instructions, or at the entry point of all programs,
* this would be used to synchronize live updates to programs in a running machine, as well as to add debugging
* break points.
* @todo Think about ability to grow (and shrink?) the heap. Might be best to do this at the same time as the first
* garbage collector.
*/
public class L3ResolvingJavaMachine extends L3ResolvingMachine
{
/** Used for debugging. */
/* private static final Logger log = Logger.getLogger(L3ResolvingJavaMachine.class.getName()); */
/** Used for tracing instruction executions. */
/* private static final Logger trace = Logger.getLogger("TRACE.L3ResolvingJavaMachine"); */
/** Defines the register capacity for the virtual machine. */
private static final int REG_SIZE = 10;
/** Defines the heap size to use for the virtual machine. */
private static final int HEAP_SIZE = 10000;
/** Defines the offset of the base of the heap in the data area. */
private static final int HEAP_BASE = REG_SIZE;
/** Defines the stack size to use for the virtual machine. */
private static final int STACK_SIZE = 10000;
/** Defines the offset of the base of the stack in the data area. */
private static final int STACK_BASE = REG_SIZE + HEAP_SIZE;
/** Defines the trail size to use for the virtual machine. */
private static final int TRAIL_SIZE = 10000;
/** Defines the offset of the base of the trail in the data area. */
private static final int TRAIL_BASE = REG_SIZE + HEAP_SIZE + STACK_SIZE;
/** Defines the max unification stack depth for the virtual machine. */
private static final int PDL_SIZE = 1000;
/** Defines the highest address in the data area of the virtual machine. */
private static final int TOP = REG_SIZE + HEAP_SIZE + STACK_SIZE + TRAIL_SIZE + PDL_SIZE;
/** Defines the initial code area size for the virtual machine. */
private static final int CODE_SIZE = 10000;
/** Holds the byte code. */
private byte[] code;
/** Holds the current load offset within the code area. */
private int loadPoint;
/** Holds the current instruction pointer into the code. */
private int ip;
/** Holds the entire data segment of the machine. All registers, heaps and stacks are held in here. */
private int[] data;
/** Holds the heap pointer. */
private int hp;
/** Holds the top of heap at the latest choice point. */
private int hbp;
/** Holds the secondary heap pointer, used for the heap address of the next term to match. */
private int sp;
/** Holds the unification stack pointer. */
private int up;
/** Holds the environment base pointer. */
private int ep;
/** Holds the choice point base pointer. */
private int bp;
/** Holds the trail pointer. */
private int trp;
/** Used to record whether the machine is in structure read or write mode. */
private boolean writeMode;
/** Holds the heap cell tag from the most recent dereference. */
private byte derefTag;
/** Holds the heap call value from the most recent dereference. */
private int derefVal;
/** Indicates that the machine has been suspended, upon finding a solution. */
private boolean suspended;
/**
* Creates a unifying virtual machine for L3 with default heap sizes.
*
* @param symbolTable The symbol table for the machine.
*/
public L3ResolvingJavaMachine(SymbolTable