/*
* Copyright (c) 2006 Thomas Weise
*
* E-Mail : tweise@gmx.de
* Creation Date : 2006-06-26 08:21:11
* Original Filename: org.dgpf.gp.vm.instructions.ctrl.Call.java
* Version : 1.0.0
* Last modification: 2006-07-15
* 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.instructions.ctrl;
import org.dgpf.gp.vm.base.Conventions;
import org.dgpf.gp.vm.base.IInstructionHandler;
import org.dgpf.gp.vm.base.Instruction;
import org.dgpf.gp.vm.base.VM;
import org.dgpf.gp.vm.instructions.BasicCosts;
import org.dgpf.gp.vm.instructions.InstructionCache;
/**
* The procedure call operation.
*
* @author Thomas Weise
*/
public class Call extends Instruction
{
/**
* The serial version uid.
*/
private static final long serialVersionUID = 1;
/**
* The procedure to be called.
*/
private final int m_index;
/**
* true
if and only if this is an unconditional jump.
*/
private final boolean m_unconditional ;
/**
* The 1st hidden instruction cache.
*/
private static final InstructionCache C_CACHE
= new InstructionCache(10)
{
/**
* Internally create a new instruction.
* @param p_index The index property.
* @return The new instruction.
*/
@Override
protected final Call create(final int p_index)
{
if(p_index >= 100) return null;
return new Call(p_index, false);
}
};
/**
* The 2nd hidden instruction cache.
*/
private static final InstructionCache UNC_CACHE
= new InstructionCache(10)
{
/**
* Internally create a new instruction.
* @param p_index The index property.
* @return The new instruction.
*/
@Override
protected final Call create(final int p_index)
{
if(p_index >= 100) return null;
return new Call(p_index, true);
}
};
/**
* Create a new push-c instruction.
* @param p_index The indexant to be pushed.
* @param p_unconditional true
if and only if this is an
* unconditional call.
*/
Call (final int p_index,
final boolean p_unconditional)
{
super();
this.m_index = p_index;
this.m_unconditional = p_unconditional;
}
/**
* Obtain a call instance.
* @param p_index The indexant value to use.
* @param p_unconditional true
if and only if this is an
* unconditional call.
* @return The new call instance.
*/
public static final Call create(final int p_index,
final boolean p_unconditional)
{
Call l_c;
l_c = (p_unconditional ? UNC_CACHE : C_CACHE).get(p_index);
if(l_c != null) return l_c;
return new Call(p_index, p_unconditional);
}
/**
* Returns true
if and only if this is an unconditional jump.
* @return true
if and only if this is an unconditional jump.
*/
public final boolean is_unconditional()
{
return this.m_unconditional;
}
/**
* Execute this instruction on a virtual machine.
* @param p_machine The virtual machine to execute on.
* @return The cost of the execution of the last instruction.
*/
@Override
protected final double execute (final VM p_machine)
{
p_machine.call(this.m_index);
return BasicCosts.CALL_COSTS;
}
/**
* Obtain the call target.
* @return The call target.
*/
public final int get_index()
{
return this.m_index;
}
/**
* Store this objects content into a string builder.
* @param p_sb The string builder to store stuff into.
*/
@Override
public final void to_string (final StringBuilder p_sb)
{
if(this.m_unconditional) p_sb.append("call ");
else p_sb.append("if zf then call ");
p_sb.append(Conventions.PROC_PREFIX);
p_sb.append(this.m_index);
}
/**
* Perform a write replace of this object.
* @return The object to store.
*/
private final Object writeReplace()
{
Object l_o;
l_o = (this.m_unconditional ? UNC_CACHE : C_CACHE).get(this.m_index);
if(l_o != null) return l_o;
return this;
}
/**
* Deserialize to the proper instance.
* @return The globally shared instance.
*/
private final Object readResolve()
{
return this.writeReplace();
}
/**
* Obtain the instruction handler to be used for this sort of instructions.
* @return The instruction handler to be used for this sort of instructions.
*/
@Override
public final IInstructionHandler get_handler()
{
return CallHandler.INSTANCE;
}
/**
* Check whether this instruction equals to a specified object, called
* internally.
* @param p_o The object to compare with, which is of the same class as
* this instruction.
* @return true
if and only if this instruction equals
* the specified object.
*/
@Override
protected boolean does_equal (final Object p_o)
{
return (((Call)p_o).m_index == this.m_index);
}
/**
* Get a string that can be copy-pasted into a java file an that creates
* this instruction.
* @param p_b The string builder to add with.
*/
@Override
public final void to_creation_string (final StringBuilder p_b)
{
p_b.append("Call.create(");
p_b.append(this.m_index);
p_b.append(')');
}
}