Logo
Distributed Genetic Programming Framework
print print

File org.dgpf.gp.vm.base.VM.java

Here you can find all the information about the file org.dgpf.gp.vm.base.VM.java. You may explore it here or download it onto your local disk.
/*
 * Copyright (c) 2006 Thomas Weise
 * 
 * E-Mail           : tweise@gmx.de
 * Creation Date    : 2006-06-08 08:25:29
 * Original Filename: org.dgpf.gp.vm.VM.java
 * Version          : 1.0.0
 * Last modification: 2006-06-08
 *                by: Thomas Weise
 * 
 * License          : GNU LESSER GENERAL PUBLIC LICENSE
 *                    Version 2.1, February 1999
 *                    You should have received a copy of this license along
 *                    with this library; if not, write to the Free Software
 *                    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *                    MA 02111-1307, USA or download the license under
 *                    http://www.gnu.org/copyleft/lesser.html.
 *                    
 * Warranty         : This software is provided "as is" without any
 *                    warranty; without even the implied warranty of
 *                    merchantability or fitness for a particular purpose.
 *                    See the Gnu Lesser General Public License for more
 *                    details.
 */

 
package org.dgpf.gp.vm.base;

import org.sfc.collections.Arrays;
import org.sfc.text.Text;

/**
 * A extensible virtual machine for executing small programs.
 *
 * @author Thomas Weise
 */

public class VM  extends Program  implements  IVMInformation
  {
/**
 * The serial version uid.
 */

  private static final long serialVersionUID = 1;
  
/**
 * The total costs of the execution until now.
 */

  private       double          m_costs ;
/**
 * The count of ticks performed.
 */

  private       long            m_ticks ;
/**
 * The table with the running hardware interrupts.
 */

  private       boolean[]       m_interrupts  ;
/**
 * The automatons memory.
 */

  private       VMMemory        m_memory  ;
/**
 * The vm memory context to be used.
 */

  private final VMContext       m_context ;
/**
 * The current frame.
 */

  private       VMFrame         m_frame   ;
/**
 * The maximum memory size aquired during the simulation.
 * @see #get_peak_memory()
 */

  private       int             m_peak_mem_size;
/**
 * The current count of execution frames.
 */

  private       int             m_frame_count ;
/**
 * The peak frame count.
 * @see #get_peak_frames()
 */

  private       int             m_peak_frame_count   ;
/**
 * <code>true</code> if and only if a call failed due to insufficient
 * memory.
 * @see #has_frame_error()
 * @see #get_frame_errors()
 */

  private       boolean         m_frame_error   ;
/**
 * The count of errors induced by memory allocation.
 */

  private       long            m_mem_errors  ;
  
/**
 * Create a new random access machine.
 * @param p_context   The memory context used.
 */

  public  VM (final VMContext   p_context)
    {
    super(); 
    this.m_interrupts  = new boolean[8];    
    this.m_context     = p_context;
    this.m_memory      = p_context.allocate_mem();
    }
  
/**
 * Dispose this vm. You may override this method to provide additional
 * cleanup. This method should not be called directly.
 * @see #dispose()
 */

  protected void  do_dispose()
    {
    this.dispose_frames();
    this.m_context.dispose_mem(this.m_memory);    
    }
  
/**
 * Dispose the whole virtual machine. You must not use the automaton
 * anymore afterwards.
 * @see #do_dispose()
 */

  public  final void  dispose ()
    {
    if(this.m_memory != null)
      {
      this.do_dispose();
      this.m_memory = null;
      }
    }
  
/**
 * Internally dispose all frames.
 */

  private final void  dispose_frames  ()
    {
    VMFrame   l_f, l_f2;
    VMContext l_m;
    
    l_m = this.m_context;
    for(l_f = this.m_frame; l_f != null; l_f = l_f2)
      {
      l_f2 = l_f.m_prev;
      l_m.dispose_frame(l_f);
      }
    
    this.m_frame       = null;
    this.m_frame_count = 0;
    }
  
/**
 * Initialize the state of this virtual machine.
 * @param p_program The program to run on this machine.
 */

  @Override
  public  void  init(final Program p_program)
    {   
    VMFrame         l_f;
    VMContext       l_mm;
    boolean[]       l_ii;
    Instruction[][] l_c;
    int             l_cl;
    
    super.init(p_program);
    
    this.dispose_frames();
    
    l_mm         = this.m_context;
    l_c          = this.m_code;
    l_cl         = l_c.length;    
    this.m_costs = 0.0d;
    this.m_ticks = 0L;    
    l_ii         = this.m_interrupts;
    
    if(l_ii.length >= l_c.length)
      {
      Arrays.fill(l_ii, false, 0, l_cl);
      }
    else
      {
      this.m_interrupts = l_ii = new boolean[l_cl];
      }
    
//    this.m_memory.clear();
    this.m_memory.m_size    = 0;
    
    l_f                     = l_mm.allocate_frame();
    l_f.m_parameters        = l_mm.allocate_mem();    
    this.m_frame            = l_f;    
    l_f.m_code              = this.m_code[0];
    l_f.m_ci                = 0;
        
    this.m_peak_mem_size    = 0;
    this.m_peak_frame_count = 1;
    this.m_frame_count      = 1;
    this.m_frame_error      = false;
    }
  
/**
 * Check whether a new ip address leads to a return.
 * @param p_f   The current frame.
 * @param p_ip  The new instruction pointer for that frame.
 */

  private final void  check_return (final VMFrame p_f,
                                    final int     p_ip)
    {
    VMFrame  l_f2;
    
    p_f.m_ip = p_ip;
      
// we've reached the end of the current frame's code
    if( (p_ip >= p_f.m_code.length) || (p_ip < 0) )
      {        
// denote that the current frame's code can now be again called by hardware
      this.m_interrupts[p_f.m_ci] ^= p_f.m_hw;
      this.m_frame_count--;
        
      l_f2 = p_f.m_prev;
// the instruction might have been an interrupt call - if so, the current
// will not any longer be the same as at the beginning of this tick
      if(this.m_frame != p_f)
        {
// if the call returns, it shall return to the calling frame
        this.m_frame.m_prev = l_f2;
        }
      else
        {
        this.m_frame = l_f2;
          
// ok, it was no call
// so check if this was a called frame
        if(l_f2 != null)
          {            
          if(!(p_f.m_hw))
            {
//the called frame's return value
            l_f2.m_stack.append(p_f.m_stack);
//            l_m = p_f.m_stack;
//            if(l_m.m_size > 0) l_f2.m_stack.push(l_m.pop());
            }                        
          }          
        }
      
      this.m_context.dispose_frame(p_f);
      }
    }
  
/**
 * Perform a single clock tick.
 * @return  <code>true</code> if and only if the program wasn't terminated
 *          yet and an instruction was executed.
 */

  public  boolean tick  ()
    {
    VMFrame       l_f;
    Instruction[] l_ii;
    int           l_ip;
    
// has the simulation already terminated?
    l_f  = this.m_frame;

// this will only happen if we reached in the main program's (int 0's) end.
    if(l_f == null) return false;
    
    l_ip = l_f.m_ip;
    l_ii = l_f.m_code;

// execute the current istruction
    this.m_costs += l_ii[l_ip].execute(this);
    this.m_ticks++;  
    
// only modify ip if the instruction was non-blocking
    if(l_f.m_non_blocked)
      {
      this.check_return(l_f, l_ip+1);
      }
    else
      {
      l_f.m_non_blocked = true;
      }
    
    return true;
    }
  
  
/**
 * Goto to a specified instruction.
 * @param p_ip  The new instruction's index. This instruction will be
 *              executed next.
 */

  public  final void  jump  (final int p_ip)
    {
    VMFrame l_f;
    
    l_f               = this.m_frame;
    if(l_f != null)
      {
      l_f.m_non_blocked = false;
      this.check_return(l_f, p_ip);
      }
    }
  
/**
 * Call this to put the automaton into blocking mode which will cause the
 * current (or next, if not currenlty executing one) instruction to be
 * repeated.
 */

  public  final void  block ()
    {
    if(this.m_frame != null) this.m_frame.m_non_blocked = false;
    }
  
  
/**
 * Obtain the accumulated costs of the program execution.
 * @return The accumulated costs of the program execution.
 */

  public  final double  get_consumed_costs ()
    {
    return this.m_costs;
    }
  
/**
 * Return the total count of ticks ellapsed, that is, the total count of
 * instructions executed.
 * @return The total count of ticks ellapsed, that is, the total count of
 *         instructions executed.
 */

  public  final long    get_consumed_ticks ()
    {
    return this.m_ticks;
    }
  
/**
 * Read a value from the memory.
 * @param p_addr  The address to read from. If this value is >= 0, the
 *                static memory will be addressed. If the address is < 0,
 *                it will be used to index the current execution frame's
 *                parameter memory.
 * @return  The value stored at the specified address, or <code>0</code> if
 *          the address is out of range.
 */

  public  final int read  (int p_addr)
    {
    VMMemory  l_v;
    boolean   l_b;
    
    if(p_addr >= 0)
      {
      l_b = true;
      l_v = this.m_memory;
      }
    else
      {
      if(this.m_frame == null) return 0;
      l_v = this.m_frame.m_parameters;
//      if(l_v.m_size <= 0) l_v = this.m_memory; //??
      l_b = false;
      p_addr = (-(1+p_addr));
      }
    
    if(p_addr >= l_v.m_size)
      {
      p_addr -= l_v.m_data.length;
      return ((p_addr > 0) ? (l_b ? p_addr : (-p_addr)) : 0);
      }
    
    return l_v.m_data[p_addr];
    
//    if(p_addr >= 0)
//      {
//      return this.m_memory.read(p_addr);
//      }
//    
//    return ((this.m_frame != null)
//                ? this.m_frame.m_parameters.read(-(1+p_addr)) : 0);
    }
  
/**
 * Store a value to the memory.
 * @param p_addr  The address to write to. If this value is >= 0, the
 *                static memory will be addressed. If the translated
 *                address is out of range, nothing will be done.
 * @param p_value The value to be stored at the specified address.
 */

  public  final void  write (      int p_addr,
                             final int p_value)
    {            
//    if(p_addr >= 0)
//      {
//      switch(this.m_memory.write(p_addr, p_value))
//        {
//        case 1:
//          {
//          this.check_mem_peak();
//          break;
//          }
//        case 2:
//          {
//          this.m_mem_errors++;
//          break;
//          }
//        }
//      }
//    else
//      {
//      this.m_mem_errors++;
//      }
    
    
    VMMemory l_vm;
    VMFrame  l_f;
    
    l_f = this.m_frame;
        
    if(p_addr >= 0)
      {
      l_vm = this.m_memory;
      }
    else
      {
      if(l_f == null) return;
      l_vm   = l_f.m_parameters;
      p_addr = (-(1+p_addr));
      }
    
    switch(l_vm.write(p_addr, p_value))
      {
      case 1:
        {
        this.check_mem_peak();
        break;
        }
      case 2:
        {
        this.m_mem_errors++;
        break;
        }
      }
    }
  
  
/**
 * Read a value from the memory using the addressed memory cell as index.
 * @param p_addr  The address to read the address from from.
 * @return  The value stored at the specified address, or <code>0</code> if
 *          the address is out of range.
 * @see #read(int)
 */

  public  final int read_rel  (final int p_addr)
    {
    return this.read(this.read(p_addr));
    }
  
/**
 * Store a value to the memory using relative addressing mode.
 * @param p_addr  The address to read the adress to write to from.
 * @param p_value The value to be stored at the specified address.
 * @see #write(int, int)
 */

  public  final void  write_rel (final int p_addr,
                                 final int p_value)
    {
    this.write(this.read(p_addr), p_value);
    }
  
/**
 * Check for a memory peak.
 */

  private final void check_mem_peak()
    {
    int l_i;    
    l_i = (this.m_memory.m_size + this.m_frame.m_parameters.m_size
                                + this.m_frame.m_stack.m_size);
    if(l_i > this.m_peak_mem_size) this.m_peak_mem_size = l_i;
    }
  
/**
 * Obtain the stack currently in use.
 * @return The stack currently in use or <code>null</code> if no stack is
 *         currently in use.
 */

  public  final VMMemory  remove_stack()
    {
    VMFrame  l_f;
    VMMemory l_v;
    
    l_f         = this.m_frame;
    if(l_f != null)
      {
      l_v         = l_f.m_stack;
      if(l_v.m_size <= 0) return null;
      l_f.m_stack = this.m_context.allocate_mem();
      
      return l_v;
      }
    
    return null;
    }
  
/**
 * Push something onto the stack.
 * @param p_value   The value to be pushed.
 */

  public  final void  push  (final int p_value)
    {
    if(this.m_frame != null)
      {
      if(this.m_frame.m_stack.push(p_value)) this.check_mem_peak();
      }
    }
  
/**
 * Pop something from the stack.
 * @return The item popped, or <code>0</code> if the stack was empty.
 */

  public  final int  pop()
    {    
    return ((this.m_frame != null) ? this.m_frame.m_stack.pop() : 0);
    }
  
/**
 * Call an interrupt.
 * @param p_number      The number of the interrupt to be called.
 * @param p_parameters  The interrupt's parameter data. This can be
 *                      <code>null</code> if no parameter data is needed.
 * @param p_hardware  <code>true</code> if and only if the interrupt is a
 *                    hardware interrupt, <code>false</code> otherwise.
 * @return  <code>true</code> if the interrupt call was successful. 
 */

  private final boolean do_interrupt (final int      p_number,
                                      final VMMemory p_parameters,
                                      final boolean  p_hardware)
    {
    boolean[] l_ints;
    int       l_fc;
    VMFrame   l_f;
    
    l_ints = this.m_interrupts;
    
    if((p_number < 0) || (p_number >= l_ints.length))
      {
      return false;
      }
    
    l_fc   = (this.m_frame_count+1);
    
    if(l_fc > this.m_context.m_max_frame_count)
      {
      if(this.m_frame != null)
        {
        this.m_frame.m_non_blocked = false;
        this.dispose_frames();
        }
      Arrays.fill(this.m_interrupts, true);
      this.m_frame_error = true;
      return false;
      }
    
    if(p_hardware)
      {
      if(l_ints[p_number])
        {
        return false;
        }
      l_ints[p_number] = true;
      }    
    
    this.m_frame_count = l_fc;
    if(l_fc > this.m_peak_frame_count) this.m_peak_frame_count = l_fc;
    
    l_f        = this.m_context.allocate_frame();
    l_f.m_ci   = p_number;
    l_f.m_code = this.m_code[p_number];
        
    l_f.m_parameters = ((p_parameters != null) ? p_parameters
                                         : this.m_context.allocate_mem());
    l_f.m_prev   = this.m_frame;
    l_f.m_hw     = p_hardware;
    this.m_frame = l_f;
    
    if(p_parameters != null) this.check_mem_peak();
    
    return true;
    }
  
/**
 * Call an interrupt via software.
 * @param p_number      The number of the interrupt to be called.
 * @return  <code>true</code> if the interrupt call was successful. In the
 *          case that the interrupt could not be called successful, the
 *          parameter <code>p_parameters</code> set will automatically be
 *          disposed. 
 */

  public  final boolean call  (final int      p_number)
    {
    VMFrame  l_f;
    VMMemory l_m;
    
    l_f         = this.m_frame;
    
    if(l_f != null)
      {
      l_m         = l_f.m_stack;
       
      if(this.do_interrupt(p_number, l_m, false))
        {
        l_f.m_stack = this.m_context.allocate_mem();
        return true;
        }
      }
    
    return false;
    }
  
/**
 * Call a hardware interrupt.
 * @param p_number      The number of the interrupt to be called.
 * @param p_parameters  The interrupt's parameter data. This can be
 *                      <code>null</code> if no parameter data is needed.
 * @return  <code>true</code> if and only if the interrupt call was
 *          successful. 
 */

  public  final boolean interrupt(final int      p_number,
                                  final VMMemory p_parameters)
    { 
    return (this.do_interrupt(p_number, p_parameters, true));
    }
  
/**
 * Set or clear the zero_flag register.
 * @param p_set   <code>true</code> if the zero_flag should be set,
 *                <code>false</code> if it should be cleared.
 */

  public  final void  set_zero_flag (final boolean p_set)
    {
    if(this.m_frame != null) this.m_frame.m_zero_flag = p_set;
    }
  
/**
 * Obtain the zero_flag value.
 * @return The zero_flag value.
 */

  public  final boolean get_zero_flag()
    {
    return (this.m_frame != null) ? this.m_frame.m_zero_flag : false;
    }
  
/**
 * Store this objects content into a string builder.
 * @param p_sb  The string builder to store stuff into.
 */

  @Override
  public  void  to_string (final StringBuilder p_sb)
    {
    VMFrame l_f;
    int     l_c;
    
    super.to_string(p_sb);
    p_sb.append(Text.LINE_BREAK_CHARS);
    p_sb.append(Text.LINE_BREAK_CHARS);
    
    p_sb.append("ticks       : ");    
    p_sb.append(this.m_ticks);
    p_sb.append(Text.LINE_BREAK_CHARS);
    p_sb.append("costs       : ");    
    p_sb.append(this.m_costs);
    p_sb.append(Text.LINE_BREAK_CHARS);
    
    p_sb.append("peak frames : ");    
    p_sb.append(this.m_peak_frame_count);
    p_sb.append(Text.LINE_BREAK_CHARS);
    p_sb.append("peak mem    : ");    
    p_sb.append(this.m_peak_mem_size);
    p_sb.append(Text.LINE_BREAK_CHARS);
    
    p_sb.append("memory      : ");
    this.m_memory.to_string(p_sb);
    
    l_c = 0;
    for(l_f = this.m_frame; l_f != null; l_f = l_f.m_prev)
      {
      p_sb.append(Text.LINE_BREAK_CHARS);
      p_sb.append(Text.LINE_BREAK_CHARS);
      p_sb.append("frame ");
      p_sb.append(l_c++);
      p_sb.append(':');
      p_sb.append(Text.LINE_BREAK_CHARS);
      l_f.to_string(p_sb);      
      }
    }
  
/**
 * Finalize this vm.
 * @throws  Throwable If something fails.
 */

  @Override
  protected final void finalize() throws Throwable
    {
    this.dispose();
    super.finalize();
    }
  
/**
 * Obtain the vm context this virtual machine belongs to.
 * @return The vm context this virtual machine belongs to.
 */

  public  final VMContext get_context()
    {
    return this.m_context;
    }
  
/**
 * Obtain the peak memory size.
 * @return The peak memory size.
 */

  public  final int get_peak_memory ()
    {
    return this.m_peak_mem_size;
    }
  
/**
 * Obtain the peak frame count.
 * @return The peak frame count.
 */

  public  final int get_peak_frames()
    {
    return this.m_peak_frame_count;
    }
  
/**
 * Check whether a procedure call failed due to insufficient free frames
 * which reflects a stack overflow in normal programming environments.
 * @return <code>true</code> if a procedure call failed due to insufficient
 *         free frames which reflects a stack overflow in normal
 *         programming environments.
 */

  public  final boolean has_frame_error  ()
    {
    return this.m_frame_error;
    }
  
/**
 * Obtain the count of invalid write operations, that is, write operations
 * that surpass the maximum memory address available.
 * @return The count of invalid write operations, that is, write operations
 * that surpass the maximum memory address available.
 */

  public  final long get_mem_errors  ()
    {
    return this.m_mem_errors;
    }
  

/**
 * Obtain the count a procedure call failed due to insufficient free frames
 * which reflects a stack overflow in normal programming environments.
 * For a single virtual machine, this is either 0 (if no such error
 * appeared) or 1 (if the execution stopped due to a stack overflow).
 * @return The count a procedure call failed due to insufficient free
 *         frames which reflects a stack overflow in normal programming
 *         environments.
 */

  public  final long get_frame_errors  ()
    {
    return (this.m_frame_error ? 1L : 0L);
    }
  }

File Information:

file name:VM.java
package:org.dgpf.gp.vm.base
qualified name:org.dgpf.gp.vm.base.VM.java
file type:Java Source File
download location:download http://dgpf.sourceforge.net/source/org/dgpf/gp/vm/base/VM.java
size:20.201 KB (20686 B)
uploaded: 2015-07-22 04:10:56 GMT+0000
last update: 2006-07-13 03:55:45 GMT+0000
last access: 2017-11-24 00:14:59 GMT+0000

statistics online since 2006-01-02.   RSS Feed
Contact us by sending an email to tweise@gmx.de to receive further information, to report errors, or to join our project.
All content on this site (http://dgpf.sourceforge.net/) is LGPL-licensed.
http://dgpf.sourceforge.net/scripts/source/source.php last modified at 2015-07-22 04:10:53 GMT+0000 served at 2017-11-24 00:14:59 GMT+0000.
Valid CSS Valid XHTML 1.1
Valid RSS SourceForge.net Logo