Logo Search packages:      
Sourcecode: kaffe version File versions  Download package

icode.c

/* icode.c
 * Define the instructions.
 *
 * Copyright (c) 1996, 1997
 *    Transvirtual Technologies, Inc.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file.
 */

#include "config.h"
#include "config-std.h"
#include "config-mem.h"
#include "gtypes.h"
#include "slots.h"
#include "seq.h"
#include "md.h"
#include "registers.h"
#include "basecode.h"
#include "labels.h"
#include "constpool.h"
#include "icode.h"
#include "soft.h"
#include "access.h"
#include "object.h"
#include "constants.h"
#include "classMethod.h"
#include "gc.h"
#include "itypes.h"
#include "locks.h"
#include "machine.h"
#include "codeproto.h"
#include "thread.h"
#include "jthread.h"
#include "support.h"
#include "code-analyse.h"
#include "funcs.h"
#include "kaffe_jni.h"
#include "fp.h"
#include "global-regs.h"

#if defined(HAVE_branch_and_link)
#define blink 0x8000000
#else
#define blink 0
#endif

/*
 * This flag can turn off array bounds checking.
 *  - for experimental purposes only.
 */
int noArrayBoundsChecks = 0;

#if defined(WORDS_BIGENDIAN)
#define     LSLOT(_s)   ((_s)+1)
#define     HSLOT(_s)   (_s)
#else
#define     LSLOT(_s)   (_s)
#define     HSLOT(_s)   ((_s)+1)
#endif

bool used_ieee_rounding;
bool used_ieee_division;

sequence* lastSpill;

#define     MAXLABTAB   64
label* labtab[MAXLABTAB];

static void _call_soft(void *routine, int profiled);

/* ----------------------------------------------------------------------- */
/* Register loads and spills.                                  */
/*                                                       */

#if defined(HAVE_spill_int)

void
spill_int(SlotData* src)
{
      sequence s;
      seq_dst(&s) = src;
      seq_value(&s, 1) = slotOffsetNoSpill(src, Rint);
      HAVE_spill_int(&s);
}
#endif

#if defined(HAVE_reload_int)

void
reload_int(SlotData* dst)
{
      sequence s;
      seq_dst(&s) = dst;
      seq_value(&s, 1) = slotOffsetNoSpill(dst, Rint);
      HAVE_reload_int(&s);
}
#endif

#if defined(HAVE_spill_ref)

void
spill_ref(SlotData* src)
{
      sequence s;
      seq_dst(&s) = src;
      seq_value(&s, 1) = slotOffsetNoSpill(src, Rref);
      HAVE_spill_ref(&s);
}
#endif

#if defined(HAVE_reload_ref)

void
reload_ref(SlotData* dst)
{
      sequence s;
      seq_dst(&s) = dst;
      seq_value(&s, 1) = slotOffsetNoSpill(dst, Rref);
      HAVE_reload_ref(&s);
}
#endif

#if defined(HAVE_spill_long)

void
spill_long(SlotData* src)
{
      sequence s;
      seq_dst(&s) = src;
      seq_value(&s, 1) = slotOffsetNoSpill(src, Rlong);
      HAVE_spill_long(&s);
}
#endif

#if defined(HAVE_reload_long)

void
reload_long(SlotData* dst)
{
      sequence s;
      seq_dst(&s) = dst;
      seq_value(&s, 1) = slotOffsetNoSpill(dst, Rlong);
      HAVE_reload_long(&s);
}
#endif

#if defined(HAVE_spill_float)

void
spill_float(SlotData* src)
{
      sequence s;
      seq_dst(&s) = src;
      seq_value(&s, 1) = slotOffsetNoSpill(src, Rfloat);
      HAVE_spill_float(&s);
}
#endif

#if defined(HAVE_reload_float)

void
reload_float(SlotData* dst)
{
      sequence s;
      seq_dst(&s) = dst;
      seq_value(&s, 1) = slotOffsetNoSpill(dst, Rfloat);
      HAVE_reload_float(&s);
}
#endif

#if defined(HAVE_spill_double)

void
spill_double(SlotData* src)
{
      sequence s;
      seq_dst(&s) = src;
      seq_value(&s, 1) = slotOffsetNoSpill(src, Rdouble);
      HAVE_spill_double(&s);
}
#endif

#if defined(HAVE_reload_double)

void
reload_double(SlotData* dst)
{
      sequence s;
      seq_dst(&s) = dst;
      seq_value(&s, 1) = slotOffsetNoSpill(dst, Rdouble);
      HAVE_reload_double(&s);
}
#endif

void
copyslots(SlotInfo* dst, SlotInfo* src, int type)
{
      slot_slot_slot(dst, NULL, src, slotAlias, Tcopy);
      activeSeq->u[1].value.i = type;
}

void
copylslots(SlotInfo* dst, SlotInfo* src, int type)
{
      lslot_lslot_lslot(dst, NULL, src, slotAlias, Tcopy);
      activeSeq->u[1].value.i = type;
}

/* ----------------------------------------------------------------------- */
/* Prologues and epilogues.                                    */
/*                                                       */

void
prologue(Method* meth)
{
      label* l;

      used_ieee_rounding = false;
      used_ieee_division = false;

      l = KaffeJIT3_newLabel();
      l->type = Lnull;
      l->at = 0;
      l->to = 0;
      l->from = 0;

      setupSlotsForBasicBlock();
#if defined(NR_GLOBALS)
      setupGlobalRegisters();
#endif
      setupArgumentRegisters();

      /* Emit prologue code */
      slot_const_const(NULL, (jword)l, (jword)meth, HAVE_prologue, Tnull);
        slot_const_const(NULL, (jword)createSpillMask(), SR_START, doReload, Tnull);
      
#if defined(ENABLE_JVMPI)
      {
            SlotInfo *tmp;

            slot_alloctmp(tmp);
            if( METHOD_IS_STATIC(meth) )
                  move_ref_const(tmp, NULL);
            else
                  move_ref(tmp, local(0));
            softcall_enter_method(tmp, meth);
            slot_freetmp(tmp);
      }
#endif
}

void
check_stack_limit(void)
{
#if defined(STACK_LIMIT)
#if defined(HAVE_check_stack_limit_constpool)
      label* l;
      constpool* c;

      l = KaffeJIT3_newLabel();
      c = KaffeJIT3_newConstant(CPref, soft_stackoverflow);
      l->type = Lexternal;
      l->at = 0;
      l->to = (uintp)c;
      l->from = 0;

      slot_slot_const(NULL, stack_limit, (jword)l, HAVE_check_stack_limit_constpool, Tnull);
#elif defined(HAVE_check_stack_limit)
      label* l;

      l = KaffeJIT3_newLabel();
      l->type = Lexternal;
      l->at = 0;
      l->to = (uintp)soft_stackoverflow;
      l->from = 0;

      slot_slot_const(NULL, stack_limit, (jword)l, HAVE_check_stack_limit, Tnull);
#endif
#endif /* STACK_LIMIT */
}

void
exception_prologue(void)
{
      label* l;

      l = KaffeJIT3_newLabel();
      l->type = Lnull;
      l->at = 0;
      l->to = 0;
      l->from = 0;

      /* Emit exception prologue code */
      slot_const_const(NULL, (jword)l, 0, HAVE_exception_prologue, Tnull);
        slot_const_const(NULL, (jword)createSpillMask(), SR_EXCEPTION, doReload, Tnull);
}

void
epilogue(Method* meth UNUSED)
{
      label* l;
      
      l = KaffeJIT3_newLabel();
      l->type = Lnull;  /* Lnegframe|Labsolute|Lgeneral */
      l->at = 0;
      l->to = 0;
      l->from = 0;
#if defined(TRACE_METHOD_END)
      if (Kaffe_JavaVMArgs.enableVerboseCall != 0) {
                begin_func_sync();
                call_soft(soft_end);
                popargs();
                end_func_sync();
        }
#endif

      slot_const_const(NULL, (jword)l, 0, HAVE_epilogue, Tnull);
}

void
exit_method(void)
{
#if defined(ENABLE_JVMPI)
      softcall_exit_method(globalMethod);
#endif
}

void
ret(void)
{
      label *l;

      l = KaffeJIT3_newLabel();
      l->at = 0;
      l->to = 0;
      l->from = 0;

      /* Jump to epilogue */
      l->type = Lepilogue;
      branch (l, ba);
}


/* ----------------------------------------------------------------------- */
/* Conditional monitor management.                             */
/*                                                       */

void
mon_enter(methods* meth, SlotInfo* obj)
{
      /* Emit monitor entry if required */
      if ((meth->accflags & ACC_SYNCHRONISED) == 0) {
            return;
      }
#if defined(HAVE_mon_enter)
      {
            label* l;

            begin_func_sync();
            l = KaffeJIT3_newLabel();
            l->type = Lexternal;
            l->at = 0;
            l->to = (uintp)slowLockObject;
            l->from = 0;
            if (METHOD_IS_STATIC(meth) == 0) {
                  meth = NULL;
            }
            else {
                  obj = NULL;
            }
            slot_slot_slot_const_const(NULL, NULL, obj, (jword)meth, (jword)l, HAVE_mon_enter, Tnull);
            end_func_sync();
      }
#else
      begin_func_sync();
      if ((meth->accflags & ACC_STATIC) != 0) {
            pusharg_class_const(meth->class, 0);
      }
      else {
            pusharg_ref(obj, 0);
      }
      call_soft(lockObject);
      popargs();
      end_func_sync();
#endif
}

void
mon_exit(methods* meth, SlotInfo* obj)
{
      /* Emit monitor entry if required */
      if ((meth->accflags & ACC_SYNCHRONISED) == 0) {
            return;
      }
#if defined(HAVE_mon_exit)
      {
            label* l;

            begin_func_sync();
            l = KaffeJIT3_newLabel();
            l->type = Lexternal;
            l->at = 0;
            l->to = (uintp)slowUnlockObject;
            l->from = 0;
            if (METHOD_IS_STATIC(meth) == 0) {
                  meth = NULL;
            }
            else {
                  obj = NULL;
            }
            slot_slot_slot_const_const(NULL, NULL, obj, (jword)meth, (jword)l, HAVE_mon_exit, Tnull);
            end_func_sync();
      }
#else
      begin_func_sync();
      if (METHOD_IS_STATIC(meth) != 0) {
            pusharg_class_const(meth->class, 0);
      }
      else {
            pusharg_ref(obj, 0);
      }
      call_soft(unlockObject);
      popargs();
      end_func_sync();
#endif
}

void
softcall_monitorenter(SlotInfo* mon)
{
#if defined(HAVE_mon_enter)
      label* l;

      l = KaffeJIT3_newLabel();
      l->type = Lexternal;
      l->at = 0;
      l->to = (uintp)slowLockObject;
      l->from = 0;
      slot_slot_slot_const_const(NULL, NULL, mon, 0, (jword)l, HAVE_mon_enter, Tnull);
#else
      pusharg_ref(mon, 0);
      call_soft(lockObject);
      popargs();
#endif
}

void
softcall_monitorexit(SlotInfo* mon)
{
#if defined(HAVE_mon_exit)
      label* l;

      l = KaffeJIT3_newLabel();
      l->type = Lexternal;
      l->at = 0;
      l->to = (uintp)slowUnlockObject;
      l->from = 0;
      slot_slot_slot_const_const(NULL, NULL, mon, 0, (jword)l, HAVE_mon_exit, Tnull);
#else
      pusharg_ref(mon, 0);
      call_soft(unlockObject);
      popargs();
#endif
}

/* ----------------------------------------------------------------------- */
/* Basic block and instruction management.                           */
/*                                                       */

void
mark_all_writes(void)
{
      int i;
      SlotData* sd;

      /* We must reference all slots sequence since they may be used */
      for (i = maxslot - 1; i >= 0; i--) {
            sd = slotinfo[i].slot;
            if (sd->wseq != 0) {
                  sd->wseq->refed = 1;
            }
      }
}

void
_start_sub_block(void)
{
      slot_const_const(NULL, (jword)createSpillMask(), SR_SUBBASIC, doReload, Tnull);
      setupSlotsForBasicBlock();
}

void
_start_basic_block(void)
{
      slot_const_const(NULL, (jword)createSpillMask(), SR_BASIC, doReload, Tnull);
      setupSlotsForBasicBlock();
}

void
_end_sub_block(void)
{
      mark_all_writes();
      slot_const_const(NULL, (jword)createSpillMask(), SR_SUBBASIC, doSpill, Tnull);
}

void
_end_basic_block(void)
{
      mark_all_writes();
      slot_const_const(NULL, (jword)createSpillMask(), SR_BASIC, doSpill, Tnull);
}

void
_syncRegisters(uintp stk UNUSED, uintp temp UNUSED)
{
      slot_const_const(NULL, (jword)createSpillMask(), SR_SYNC, doSpill, Tnull);
}

void
_start_instruction(uintp _pc)
{
      slot_const_const(NULL, 0, _pc, startInsn, Tnull);
}

void
_start_exception_block(uintp stk)
{
      /* Exception blocks act like function returns - the return
       * value is the exception object.
       */
      start_basic_block();
      exception_prologue();
      return_ref(&localinfo[stk]);
}

/*
 * Begin a register/slot syncronization - this is the point we will
 * store all our cached values back to where they belong.  We don't know
 * which values to store yet - this is decided at the end_sync point.
 */
void
begin_sync(void)
{
      assert(lastSpill == 0);
      slot_const_const(NULL, 0, SR_BASIC, doSpill, Tnull);
      lastSpill = activeSeq;
}

void
end_sync(void)
{
      /* Make sure a sync is in progress */
      assert(lastSpill != 0);
      lastSpill->u[1].smask = createSpillMask();
      lastSpill = NULL;
      mark_all_writes();
}

void
begin_func_sync(void)
{
      assert(lastSpill == 0);
      slot_const_const(NULL, 0, SR_FUNCTION, doSpill, Tnull);
      lastSpill = activeSeq;

      /* If we might throw and catch and exception we better make everything
       * is written which should be.
       */
      if (canCatch(ANY)) {
            mark_all_writes();
      }
}

void
end_func_sync(void)
{
      SlotData** mask;

      /* Build a mask of the slots to spill and reload */
      mask = createSpillMask();

      /* Save the slots to spill */
      assert(lastSpill != 0);
      lastSpill->u[1].smask = mask;
      lastSpill = NULL;

      /* Create a reload and save the slots to reload */
      slot_const_const(NULL, (jword)mask, SR_FUNCTION, doReload, Tnull);
}


/* ----------------------------------------------------------------------- */
/* Moves.                                                */
/*                                                       */

void
move_int_const(SlotInfo* dst, jint val)
{
#if defined(HAVE_move_int_const)
      if (HAVE_move_int_const_rangecheck(val)) {
            slot_slot_const(dst, NULL, val, HAVE_move_int_const, Tconst);
      }
      else
#endif
      {
            constpool *c;
            label* l;

            c = KaffeJIT3_newConstant(CPint, val);
            l = KaffeJIT3_newLabel();
            l->type = Lconstant;
            l->at = 0;
            l->to = (uintp)c;
            l->from = 0;

#if defined(HAVE_load_constpool_int)
            slot_slot_const(dst, 0, (jword)l, HAVE_load_constpool_int, Tnull);
#else
            {
                  SlotInfo* tmp;
                  slot_alloctmp(tmp);
                  move_label_const(tmp, l);
                  load_int(dst, tmp);
                  slot_freetmp(tmp);
            }
#endif
      }
}

void
move_ref_const(SlotInfo* dst, void *val)
{
#if defined(HAVE_move_ref_const)
      if (HAVE_move_ref_const_rangecheck(val)) {
            slot_slot_const(dst, NULL, (jword)val, HAVE_move_ref_const, Tconst);
      }
      else
#endif
      {
            constpool *c;
            label* l;

            c = KaffeJIT3_newConstant(CPref, val);
            l = KaffeJIT3_newLabel();
            l->type = Lconstant;
            l->at = 0;
            l->to = (uintp)c;
            l->from = 0;

#if defined(HAVE_load_constpool_ref)
            slot_slot_const(dst, 0, (jword)l, HAVE_load_constpool_ref, Tnull);
#else
            {
                  SlotInfo* tmp;
                  slot_alloctmp(tmp);
                  move_label_const(tmp, l);
                  load_ref(dst, tmp);
                  slot_freetmp(tmp);
            }
#endif
      }
}

void
move_string_const(SlotInfo* dst, void *val)
{
#if 1
      move_ref_const(dst, val);
#else
      label* l;
      constpool *c;
      SlotInfo* tmp;

      c = KaffeJIT3_newConstant(CPstring, val);
      l = KaffeJIT3_newLabel();
      l->type = Lconstant;
      l->at = 0;
      l->to = (uintp)c;
      l->from = 0;

#if defined(HAVE_load_constpool_ref)
      slot_slot_const(dst, 0, (jword)l, HAVE_load_constpool_ref, Tnull);
#else
      slot_alloctmp(tmp);
      move_label_const(tmp, l);
      load_ref(dst, tmp);
      slot_freetmp(tmp);
#endif

#endif
}

void
move_long_const(SlotInfo* dst, jlong val)
{
#if defined(HAVE_move_long_const)
      if (HAVE_move_long_const_rangecheck(val)) {
            lslot_slot_lconst(dst, 0, val, HAVE_move_long_const, Tconst);
      }
      else {
            constpool *c;
            label* l;
            SlotInfo* tmp;

            c = KaffeJIT3_newConstant(CPlong, val);
            l = KaffeJIT3_newLabel();
            l->type = Lconstant;
            l->at = 0;
            l->to = (uintp)c;
            l->from = 0;


#if defined(HAVE_load_constpool_long)
            slot_slot_const(dst, 0, (jword)l, HAVE_load_constpool_long, Tnull);
#else
            slot_alloctmp(tmp);
            move_label_const(tmp, l);
            load_long(dst, tmp);
            slot_freetmp(tmp);
#endif
      }
#else

#if defined(WORDS_BIGENDIAN)
      /*
       * Switch the ordering so that we get a better register allocation
       * ordering and don't have to swap immediately afterwards.  (sigh)
       */
      move_int_const(HSLOT(dst), (jint)((val >> 32) & 0xFFFFFFFF));
      move_int_const(LSLOT(dst), (jint)(val & 0xFFFFFFFF));
#else
      move_int_const(LSLOT(dst), (jint)(val & 0xFFFFFFFF));
      move_int_const(HSLOT(dst), (jint)((val >> 32) & 0xFFFFFFFF));
#endif
      
#endif
}

void
move_float_const(SlotInfo* dst, float val)
{
#if defined(HAVE_move_float_const)
      if (HAVE_move_float_const_rangecheck(val)) {
            slot_slot_fconst(dst, NULL, val, HAVE_move_float_const, Tconst);
      }
      else
#endif
      {
            constpool *c;
            label* l;

            c = KaffeJIT3_newConstant(CPfloat, val);
            l = KaffeJIT3_newLabel();
            l->type = Lconstant;
            l->at = 0;
            l->to = (uintp)c;
            l->from = 0;

#if defined(HAVE_load_constpool_float)
            slot_slot_const(dst, NULL, (jword)l, HAVE_load_constpool_float, Tnull);
#else
            {
                  SlotInfo* tmp;
                  slot_alloctmp(tmp);
                  move_label_const(tmp, l);
                  load_float(dst, tmp);
                  slot_freetmp(tmp);
            }
#endif
      }
}

void
move_double_const(SlotInfo* dst, jdouble val)
{
#if defined(HAVE_move_double_const)
      if (HAVE_move_double_const_rangecheck(val)) {
            lslot_slot_fconst(dst, NULL, val, HAVE_move_double_const, Tconst);
      }
      else
#endif
      {
            constpool *c;
            label* l;

            c = KaffeJIT3_newConstant(CPdouble, val);
            l = KaffeJIT3_newLabel();
            l->type = Lconstant;
            l->at = 0;
            l->to = (uintp)c;
            l->from = 0;

#if defined(HAVE_load_constpool_double)
            lslot_lslot_const(dst, 0, (jword)l, HAVE_load_constpool_double, Tnull);
#else
            {
                  SlotInfo* tmp;
                  slot_alloctmp(tmp);
                  move_label_const(tmp, l);
                  load_double(dst, tmp);
                  slot_freetmp(tmp);
            }
#endif
      }
}

#if defined(HAVE_move_any)
void
move_any(SlotInfo* dst, SlotInfo* src)
{
      if (dst == src) {
      }
      else if (isGlobal(dst->slot)) {
            slot_slot_slot(dst, NULL, src, HAVE_move_any, Tcopy);
      }
      else {
            copyslots(dst, src, Rref);
      }
}
#endif

#if defined(HAVE_move_int)
void
move_int(SlotInfo* dst, SlotInfo* src)
{
      if (dst == src) {
      }
#if defined(HAVE_move_int_const)
      else if (slot_type(src) == Tconst) {
            move_int_const(dst, slot_value(src)->i);
      }
#endif
      else if (isGlobal(dst->slot)) {
            slot_slot_slot(dst, NULL, src, HAVE_move_int, Tcopy);
      }
      else {
            copyslots(dst, src, Rint);
      }
}
#endif

void
move_ref(SlotInfo* dst, SlotInfo* src)
{
      if (dst == src) {
      }
#if defined(HAVE_move_ref_const)
      else if (slot_type(src) == Tconst) {
            move_ref_const(dst, slot_value(src)->l);
      }
#endif
      else if (isGlobal(dst->slot)) {
            slot_slot_slot(dst, NULL, src, HAVE_move_ref, Tcopy);
      }
      else {
            copyslots(dst, src, Rref);
      }
}

void
move_anylong(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_move_anylong)
      lslot_lslot_lslot(dst, 0, src, HAVE_move_anylong, Tcopy);
#else
      assert(LSLOT(dst) != HSLOT(src));
      move_any(LSLOT(dst), LSLOT(src));
      move_any(HSLOT(dst), HSLOT(src));
#endif
}

void
move_long(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_move_long)
      lslot_lslot_lslot(dst, 0, src, HAVE_move_long, Tcopy);
#else
      assert(LSLOT(dst) != HSLOT(src));
      move_int(LSLOT(dst), LSLOT(src));
      move_int(HSLOT(dst), HSLOT(src));
#endif
}

void
move_float(SlotInfo* dst, SlotInfo* src)
{
      if (dst == src) {
      }
#if defined(HAVE_move_float_const)
      else if (slot_type(src) == Tconst) {
            move_float_const(dst, slot_value(src)->f);
      }
#endif
      else if (isGlobal(dst->slot)) {
#if defined(HAVE_move_float)
            slot_slot_slot(dst, NULL, src, HAVE_move_float, Tcopy);
#elif defined(HAVE_NO_FLOATING_POINT)
            move_int(dst, src);
#else
      KAFFEVM_ABORT();
#endif
      }
      else {
            copyslots(dst, src, Rfloat);
      }
}

void
move_double(SlotInfo* dst, SlotInfo* src)
{
      if (dst == src) {
      }
#if defined(HAVE_move_double_const)
      else if (slot_type(src) == Tconst) {
            move_double_const(dst, slot_value(src)->d);
      }
#endif
      else if (isGlobal(dst->slot)) {
#if defined(HAVE_move_double)
            lslot_lslot_lslot(dst, NULL, src, HAVE_move_double, Tcopy);
#elif defined(HAVE_NO_FLOATING_POINT) || defined(PS2LINUX)
            move_long(dst, src);
#else
            KAFFEVM_ABORT();
#endif
      }
      else {
            copylslots(dst, src, Rdouble);
      }
}

#if defined(HAVE_move_label_const)
void
move_label_const(SlotInfo* dst, label* lab)
{
      slot_slot_const(dst, NULL, (jword)lab, HAVE_move_label_const, Tnull);
}
#endif

void
swap_any(SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_swap_any)
      slot_slot_slot(src, 0, src2, HAVE_swap_any, Tcomplex);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref(tmp, src);
      move_ref(src, src2);
      move_ref(src2, tmp);
      slot_freetmp(tmp);
#endif
}

/* ----------------------------------------------------------------------- */
/* Arithmetic operators - add, sub, etc.                       */
/*                                                       */


#if defined(HAVE_adc_int)
void
adc_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      slot_slot_slot(dst, src, src2, HAVE_adc_int, Tcomplex);
}
#endif

#if defined(HAVE_add_int)
void
_add_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      slot_slot_slot(dst, src, src2, HAVE_add_int, Tcomm);
}

void
add_int_const(SlotInfo* dst, SlotInfo* src, jint val)
{
#if defined(HAVE_add_int_const)
      if (HAVE_add_int_const_rangecheck(val)) {
            slot_slot_const(dst, src, val, HAVE_add_int_const, Tcomplex);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            _add_int(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

void
add_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_add_int_const)
      if (slot_type(src) == Tconst) {
#if 0
            /* Disabled as it does not clear Carry and breaks
                   add_long() on ARM */
            if (slot_type(src2) == Tconst) {
                  move_int_const(dst, slot_value(src)->i + slot_value(src2)->i);
            }
            else
#endif
            {
                  add_int_const(dst, src2, slot_value(src)->i);
            }
      }
      else if (slot_type(src2) == Tconst) {
            add_int_const(dst, src, slot_value(src2)->i);
      }
      else
#endif
      _add_int(dst, src, src2);
}
#endif

#if defined(HAVE_add_ref)
void
_add_ref(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      slot_slot_slot(dst, src, src2, HAVE_add_ref, Tcomm);
}

void
add_ref_const(SlotInfo* dst, SlotInfo* src, jint val)
{
#if defined(HAVE_add_ref_const)
      if (HAVE_add_ref_const_rangecheck(val)) {
            slot_slot_const(dst, src, val, HAVE_add_ref_const, Tcomplex);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            _add_ref(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

void
add_ref(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      _add_ref(dst, src, src2);
}
#endif

#if defined(HAVE_set_lt_int)
void
set_lt_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      slot_slot_slot(dst, src, src2, HAVE_set_lt_int, Tcomplex);
}
#endif

#if defined(HAVE_set_lt_int_const)
void
set_lt_int_const(SlotInfo* dst, SlotInfo* src, jint val)
{
      slot_slot_const(dst, src, val, HAVE_set_lt_int_const, Tcomplex);
}
#endif

void
add_long(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_add_long)
      lslot_lslot_lslot(dst, src, src2, HAVE_add_long, Tcomplex);
#elif defined(HAVE_adc_int)
      add_int(LSLOT(dst), LSLOT(src), LSLOT(src2));
      adc_int(HSLOT(dst), HSLOT(src), HSLOT(src2));
#elif defined(HAVE_set_lt_int)
      SlotInfo* res,*carry;

      slot_alloctmp(res);
      slot_alloctmp(carry);

      add_int(res, LSLOT(src), LSLOT(src2));
      set_lt_int(carry, res, LSLOT(src2));
      add_int(carry, HSLOT(src), carry);
      add_int(HSLOT(dst), carry, HSLOT(src2));
      move_int(LSLOT(dst),res);

      slot_freetmp(res);
      slot_freetmp(carry);
#else
      KAFFEVM_ABORT();
#endif
}

#if defined(HAVE_add_long_const)
void
add_long_const(SlotInfo* dst, SlotInfo* src, jlong val)
{
      if (HAVE_add_long_const_rangecheck(val)) {
            lslot_lslot_lconst(dst, src, val, HAVE_add_long_const, Tcomplex);
      }
      else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_long_const(tmp, val);
            add_long(dst, src, tmp);
            slot_freetmp(tmp);
      }
}
#endif

void
add_float(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_add_float)
      slot_slot_slot(dst, src, src2, HAVE_add_float, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_float(src, 0);
      pusharg_float(src2, 1);
#else
      pusharg_float(src2, 1);
      pusharg_float(src, 0);
#endif
      call_soft(soft_fadd);
      popargs();
      end_func_sync();
      return_float(dst);
#endif
}

void
add_double(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_add_double)
      lslot_lslot_lslot(dst, src, src2, HAVE_add_double, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_double(src, 0);
      pusharg_double(src2, pusharg_long_idx_inc);
#else
      pusharg_double(src2, pusharg_long_idx_inc);
      pusharg_double(src, 0);
#endif
      call_soft(soft_faddl);
      popargs();
      end_func_sync();
      return_double(dst);
#endif
}

#if defined(HAVE_sbc_int)
void
sbc_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      slot_slot_slot(dst, src, src2, HAVE_sbc_int, Tcomplex);
}
#endif

#if defined(HAVE_sub_int)
void
_sub_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      slot_slot_slot(dst, src, src2, HAVE_sub_int, Tcomplex);
}

void
sub_int_const(SlotInfo* dst, SlotInfo* src, jint val)
{
#if defined(HAVE_sub_int_const)
      if (HAVE_sub_int_const_rangecheck(val)) {
            slot_slot_const(dst, src, val, HAVE_sub_int_const, Tcomplex);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            _sub_int(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

void
sub_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_sub_int_const)
      if (slot_type(src2) == Tconst) {
            sub_int_const(dst, src, slot_value(src2)->i);
      }
      else
#endif
      _sub_int(dst, src, src2);
}
#endif

void
sub_long(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_sub_long)
      lslot_lslot_lslot(dst, src, src2, HAVE_sub_long, Tcomplex);
#elif defined(HAVE_sbc_int)
      sub_int(LSLOT(dst), LSLOT(src), LSLOT(src2));
      sbc_int(HSLOT(dst), HSLOT(src), HSLOT(src2));
#elif defined(HAVE_set_lt_int)
        SlotInfo* carry;

        slot_alloctmp(carry);

        set_lt_int(carry, LSLOT(src), LSLOT(src2));
        sub_int(carry, HSLOT(src), carry);
        sub_int(HSLOT(dst), carry, HSLOT(src2));
        sub_int(LSLOT(dst), LSLOT(src), LSLOT(src2));

      slot_freetmp(carry);
#else
      KAFFEVM_ABORT();
#endif
}

#if defined(HAVE_sub_long_const)
void
sub_long_const(SlotInfo* dst, SlotInfo* src, jlong val)
{
      if (HAVE_sub_long_const_rangecheck(val)) {
            lslot_lslot_lconst(dst, src, val, HAVE_sub_long_const, Tcomplex);
      }
      else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_long_const(tmp, val);
            sub_long(dst, src, tmp);
            slot_freetmp(tmp);
      }
}
#endif

void
sub_float(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_sub_float)
      slot_slot_slot(dst, src, src2, HAVE_sub_float, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_float(src, 0);
      pusharg_float(src2, 1);
#else
      pusharg_float(src2, 1);
      pusharg_float(src, 0);
#endif
      call_soft(soft_fsub);
      popargs();
      end_func_sync();
      return_float(dst);
#endif
}

void
sub_double(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_sub_double)
      lslot_lslot_lslot(dst, src, src2, HAVE_sub_double, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_double(src, 0);
      pusharg_double(src2, pusharg_long_idx_inc);
#else
      pusharg_double(src2, pusharg_long_idx_inc);
      pusharg_double(src, 0);
#endif
      call_soft(soft_fsubl);
      popargs();
      end_func_sync();
      return_double(dst);
#endif
}

int
mul_int_const_optimize(SlotInfo* dst, SlotInfo* src, jint val)
{
      switch (val) {
      case 2:
            lshl_int_const(dst, src, 1);
            break;
      case 4:
            lshl_int_const(dst, src, 2);
            break;
      case 8:
            lshl_int_const(dst, src, 3);
            break;
      case 16:
            lshl_int_const(dst, src, 4);
            break;
      default:
            return (0);
      }
      return (1);
}

void
_mul_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_mul_int)
      slot_slot_slot(dst, src, src2, HAVE_mul_int, Tcomplex);
#else
      begin_func_sync();
#  if defined(PUSHARG_FORWARDS)
      pusharg_int(src, 0);
      pusharg_int(src2, 1);
#  else
      pusharg_int(src2, 1);
      pusharg_int(src, 0);
#  endif
      call_soft(soft_mul);
      popargs();
      end_func_sync();
      return_int(dst);
#endif
}

void
mul_int_const(SlotInfo* dst, SlotInfo* src, jint val)
{
      if (mul_int_const_optimize(dst, src, val) != 0) {
            return;
      }
#if defined(HAVE_mul_int_const)
      if (HAVE_mul_int_const_rangecheck(val)) {
            slot_slot_const(dst, src, val, HAVE_mul_int_const, Tcomplex);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            _mul_int(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

void
mul_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      if (slot_type(src2) == Tconst) {
            if (mul_int_const_optimize(dst, src, slot_value(src2)->i) != 0) {
                  return;
            }
      }
#if defined(HAVE_mul_int) && defined(HAVE_mul_int_const)
      if (slot_type(src) == Tconst) {
            mul_int_const(dst, src2, slot_value(src)->i);
      }
      else if (slot_type(src2) == Tconst) {
            mul_int_const(dst, src, slot_value(src2)->i);
      }
      else
#endif
      _mul_int(dst, src, src2);
}

void
mul_long(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_mul_long)
      lslot_lslot_lslot(dst, src, src2, HAVE_mul_long, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_long(src, 0);
      pusharg_long(src2, pusharg_long_idx_inc);
#else
      pusharg_long(src2, pusharg_long_idx_inc);
      pusharg_long(src, 0);
#endif
      call_soft(soft_lmul);
      popargs();
      end_func_sync();
      return_long(dst);
#endif
}

#if defined(HAVE_mul_long_const)
void
mul_long_const(SlotInfo* dst, SlotInfo* src, jlong val)
{
      if (HAVE_mul_long_const_rangecheck(val)) {
            lslot_lslot_lconst(dst, src, val, HAVE_mul_long_const, Tcomplex);
      }
      else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_long_const(tmp, val);
            mul_long(dst, src, tmp);
            slot_freetmp(tmp);
      }
}
#endif

void
mul_float(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_mul_float)
      slot_slot_slot(dst, src, src2, HAVE_mul_float, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_float(src, 0);
      pusharg_float(src2, 1);
#else
      pusharg_float(src2, 1);
      pusharg_float(src, 0);
#endif
      call_soft(soft_fmul);
      popargs();
      end_func_sync();
      return_float(dst);
#endif
}

void
mul_double(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_mul_double)
      lslot_lslot_lslot(dst, src, src2, HAVE_mul_double, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_double(src, 0);
      pusharg_double(src2, pusharg_long_idx_inc);
#else
      pusharg_double(src2, pusharg_long_idx_inc);
      pusharg_double(src, 0);
#endif
      call_soft(soft_fmull);
      popargs();
      end_func_sync();
      return_double(dst);
#endif
}

int
div_int_const_optimize(SlotInfo* dst, SlotInfo* src, jint val)
{
      SlotInfo* tmp;
      
      switch (val) {
      case 2:
            slot_alloctmp(tmp);
            lshr_int_const(tmp, src, (sizeof(int) * 8 - 1));
            add_int(tmp, tmp, src);
            ashr_int_const(dst, tmp, 1);
            slot_freetmp(tmp);
            break;
      case 4:
            slot_alloctmp(tmp);
            ashr_int_const(tmp, src, 1);
            lshr_int_const(tmp, tmp, (sizeof(int) * 8 - 2));
            add_int(tmp, tmp, src);
            ashr_int_const(dst, tmp, 2);
            slot_freetmp(tmp);
            break;
      case 8:
            slot_alloctmp(tmp);
            ashr_int_const(tmp, src, 2);
            lshr_int_const(tmp, tmp, (sizeof(int) * 8 - 3));
            add_int(tmp, tmp, src);
            ashr_int_const(dst, tmp, 3);
            slot_freetmp(tmp);
            break;
      case 16:
            slot_alloctmp(tmp);
            ashr_int_const(tmp, src, 3);
            lshr_int_const(tmp, tmp, (sizeof(int) * 8 - 4));
            add_int(tmp, tmp, src);
            ashr_int_const(dst, tmp, 4);
            slot_freetmp(tmp);
            break;
      default:
            return (0);
      }
      return (1);
}

void
_div_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_div_int)
      slot_slot_slot(dst, src, src2, HAVE_div_int, Tcomplex);
#else
      begin_func_sync();
#  if defined(PUSHARG_FORWARDS)
      pusharg_int(src, 0);
      pusharg_int(src2, 1);
#  else
      pusharg_int(src2, 1);
      pusharg_int(src, 0);
#  endif
      call_soft(soft_div);
      popargs();
      end_func_sync();
      return_int(dst);
#endif
}

void
div_int_const(SlotInfo* dst, SlotInfo* src, jint val)
{
      if (div_int_const_optimize(dst, src, val) != 0) {
            return;
      }
#if defined(HAVE_div_int_const)
      if (HAVE_div_int_const_rangecheck(val)) {
            slot_slot_const(dst, src, val, HAVE_div_int_const, Tcomplex);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            _div_int(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

void
div_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      if (slot_type(src2) == Tconst) {
            if (div_int_const_optimize(dst, src, slot_value(src2)->i) != 0) {
                  return;
            }
      }
      _div_int(dst, src, src2);
}

void
div_long(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_div_long)
      lslot_lslot_lslot(dst, src, src2, HAVE_div_long, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_long(src, 0);
      pusharg_long(src2, pusharg_long_idx_inc);
#else
      pusharg_long(src2, pusharg_long_idx_inc);
      pusharg_long(src, 0);
#endif
      call_soft(soft_ldiv);
      popargs();
      end_func_sync();
      return_long(dst);
#endif
}

void
div_float(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      used_ieee_division = true;
#if defined(HAVE_div_float)
      slot_slot_slot(dst, src, src2, HAVE_div_float, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_float(src, 0);
      pusharg_float(src2, 1);
#else
      pusharg_float(src2, 1);
      pusharg_float(src, 0);
#endif
      call_soft(soft_fdiv);
      popargs();
      end_func_sync();
      return_float(dst);
#endif
}

void
div_double(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      used_ieee_division = true;
#if defined(HAVE_div_double)
      lslot_lslot_lslot(dst, src, src2, HAVE_div_double, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_double(src, 0);
      pusharg_double(src2, pusharg_long_idx_inc);
#else
      pusharg_double(src2, pusharg_long_idx_inc);
      pusharg_double(src, 0);
#endif
      call_soft(soft_fdivl);
      popargs();
      end_func_sync();
      return_double(dst);
#endif
}

void
rem_int_const(SlotInfo* dst, SlotInfo* src, jint val)
{
#if defined(HAVE_rem_int_const)
      if (HAVE_rem_int_const_rangecheck(val)) {
            slot_slot_const(dst, src, val, HAVE_rem_int_const, Tcomplex);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            rem_int(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

void
rem_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_rem_int)
      slot_slot_slot(dst, src, src2, HAVE_rem_int, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_int(src, 0);
      pusharg_int(src2, 1);
#else
      pusharg_int(src2, 1);
      pusharg_int(src, 0);
#endif
      call_soft(soft_rem);
      popargs();
      end_func_sync();
      return_int(dst);
#endif
}

void
rem_long(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_rem_long)
      lslot_lslot_lslot(dst, src, src2, HAVE_rem_long, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_long(src, 0);
      pusharg_long(src2, pusharg_long_idx_inc);
#else
      pusharg_long(src2, pusharg_long_idx_inc);
      pusharg_long(src, 0);
#endif
      call_soft(soft_lrem);
      popargs();
      end_func_sync();
      return_long(dst);
#endif
}

void
rem_float(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      used_ieee_division = true;
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_float(src, 0);
      pusharg_float(src2, 1);
#else
      pusharg_float(src2, 1);
      pusharg_float(src, 0);
#endif
      call_soft(soft_frem);
      popargs();
      end_func_sync();
      return_float(dst);
}

void
rem_double(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      used_ieee_division = true;
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_double(src, 0);
      pusharg_double(src2, pusharg_long_idx_inc);
#else
      pusharg_double(src2, pusharg_long_idx_inc);
      pusharg_double(src, 0);
#endif
      call_soft(soft_freml);
      popargs();
      end_func_sync();
      return_double(dst);
}

void
neg_int(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_neg_int)
      slot_slot_slot(dst, NULL, src, HAVE_neg_int, Tcomplex);
#else
      SlotInfo* zero;
      slot_alloctmp(zero);
      move_int_const(zero, NULL);
      sub_int(dst, zero, src);
      slot_freetmp(zero);
#endif
}

#if defined(HAVE_ngc_int)
void
ngc_int(SlotInfo* dst, SlotInfo* src)
{
      slot_slot_slot(dst, 0, src, HAVE_ngc_int, Tcomplex);
}
#endif

void
neg_long(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_neg_long)
      lslot_lslot_lslot(dst, 0, src, HAVE_neg_long, Tcomplex);
#elif defined(HAVE_ngc_int)
      neg_int(LSLOT(dst), LSLOT(src));
      ngc_int(HSLOT(dst), HSLOT(src));
#elif defined(HAVE_sbc_int)
      SlotInfo* zero;
      slot_alloctmp(zero);
      move_int_const(zero, 0);
      sub_int(LSLOT(dst), zero, LSLOT(src));
      sbc_int(HSLOT(dst), zero, HSLOT(src));
      slot_freetmp(zero);
#elif defined(HAVE_adc_int_const)
      neg_int(LSLOT(dst), LSLOT(src));
      adc_int_const(HSLOT(dst), HSLOT(src), 0);
      neg_int(HSLOT(dst), HSLOT(dst));
#elif defined(HAVE_set_lt_int_const) && defined(HAVE_nor_int)
        SlotInfo* zero;
        SlotInfo* carry;

        slot_alloctmp(zero);
        slot_alloctmp(carry);

        move_int_const(zero, 0);
        set_lt_int_const(carry,LSLOT(src),1);
        sub_int(LSLOT(dst),zero,LSLOT(src));
        nor_int(HSLOT(dst),zero,HSLOT(src));
        add_int(HSLOT(dst),HSLOT(dst),carry);

      slot_freetmp(zero);
      slot_freetmp(carry);
#else
      KAFFEVM_ABORT();
#endif
}

void
neg_float(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_neg_float)
      slot_slot_slot(dst, NULL, src, HAVE_neg_float, Tcomplex);
#else
      SlotInfo* zero;
      slot_alloctmp(zero);
      move_float_const(zero, 0);
      sub_float(dst, zero, src);
      slot_freetmp(zero);
#endif
}

void
neg_double(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_neg_double)
      lslot_lslot_lslot(dst, NULL, src, HAVE_neg_double, Tcomplex);
#else
      SlotInfo* zero;
      slot_alloc2tmp(zero);
      move_double_const(zero, 0);
      sub_double(dst, zero, src);
      slot_free2tmp(zero);
#endif
}


/* ----------------------------------------------------------------------- */
/* Logical operators - and, or, etc.                                 */
/*                                                       */

#if defined(HAVE_and_int)
void
_and_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      slot_slot_slot(dst, src, src2, HAVE_and_int, Tcomplex);
}

void
and_int_const(SlotInfo* dst, SlotInfo* src, jint val)
{
      if (val == -1) {
            move_int(dst, src);
      }
      else if (val == 0) {
            move_int_const(dst, 0);
      }
#if defined(HAVE_and_int_const)
      else if (HAVE_and_int_const_rangecheck(val)) {
            slot_slot_const(dst, src, val, HAVE_and_int_const, Tcomplex);
      }
#endif
      else {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            _and_int(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

void
and_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_and_int_const)
      if (slot_type(src) == Tconst) {
            and_int_const(dst, src2, slot_value(src)->i);
      }
      else if (slot_type(src2) == Tconst) {
            and_int_const(dst, src, slot_value(src2)->i);
      }
      else
#endif
      _and_int(dst, src, src2);
}
#endif

void
and_long(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_and_long)
      lslot_lslot_lslot(dst, src, src2, HAVE_and_long, Tcomplex);
#else
      and_int(LSLOT(dst), LSLOT(src), LSLOT(src2));
      and_int(HSLOT(dst), HSLOT(src), HSLOT(src2));
#endif
}

void
and_long_const(SlotInfo* dst, SlotInfo* src, jlong val)
{
#if defined(HAVE_and_long_const)
      if (HAVE_and_long_const_rangecheck(val)) {
            lslot_lslot_lconst(dst, src, val, HAVE_and_long_const, Tcomplex);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_long_const(tmp, val);
            and_long(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

#if defined(HAVE_or_int)
void
_or_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      slot_slot_slot(dst, src, src2, HAVE_or_int, Tcomplex);
}

void
or_int_const(SlotInfo* dst, SlotInfo* src, jint val)
{
      if (val == -1) {
            move_int_const(dst, -1);
      }
      else if (val == 0) {
            move_int(dst, src);
      }
#if defined(HAVE_or_int_const)
      if (HAVE_or_int_const_rangecheck(val)) {
            slot_slot_const(dst, src, val, HAVE_or_int_const, Tcomplex);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            _or_int(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

void
or_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_or_int_const)
      if (slot_type(src) == Tconst) {
            or_int_const(dst, src2, slot_value(src)->i);
      }
      else if (slot_type(src2) == Tconst) {
            or_int_const(dst, src, slot_value(src2)->i);
      }
      else
#endif
      _or_int(dst, src, src2);
}
#endif

#if defined(HAVE_nor_int)
void
nor_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      slot_slot_slot(dst, src, src2, HAVE_nor_int, Tcomplex);
}
#endif

void
or_long(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_or_long)
      lslot_lslot_lslot(dst, src, src2, HAVE_or_long, Tcomplex);
#else
      or_int(LSLOT(dst), LSLOT(src), LSLOT(src2));
      or_int(HSLOT(dst), HSLOT(src), HSLOT(src2));
#endif
}

#if defined(HAVE_xor_int)
void
_xor_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      slot_slot_slot(dst, src, src2, HAVE_xor_int, Tcomplex);
}

void
xor_int_const(SlotInfo* dst, SlotInfo* src, jint val)
{
#if defined(HAVE_xor_int_const)
      if (HAVE_xor_int_const_rangecheck(val)) {
            slot_slot_const(dst, src, val, HAVE_xor_int_const, Tcomplex);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            _xor_int(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

void
xor_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_xor_int_const)
      if (slot_type(src) == Tconst) {
            xor_int_const(dst, src2, slot_value(src)->i);
      }
      else if (slot_type(src2) == Tconst) {
            xor_int_const(dst, src, slot_value(src2)->i);
      }
      else
#endif
      _xor_int(dst, src, src2);
}
#endif

void
xor_long(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_xor_long)
      lslot_lslot_lslot(dst, src, src2, HAVE_xor_long, Tcomplex);
#else
      xor_int(LSLOT(dst), LSLOT(src), LSLOT(src2));
      xor_int(HSLOT(dst), HSLOT(src), HSLOT(src2));
#endif
}

#if defined(HAVE_lshl_int)
void
_lshl_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      slot_slot_slot(dst, src, src2, HAVE_lshl_int, Tcomplex);
}

void
lshl_int_const(SlotInfo* dst, SlotInfo* src, jint val)
{
#if defined(HAVE_lshl_int_const)
      if (HAVE_lshl_int_const_rangecheck(val)) {
            slot_slot_const(dst, src, val, HAVE_lshl_int_const, Tcomplex);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            _lshl_int(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

void
lshl_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_lshl_int_const)
      if (slot_type(src2) == Tconst) {
            lshl_int_const(dst, src, slot_value(src2)->i);
      }
      else
#endif
      _lshl_int(dst, src, src2);
}
#endif

#if defined(HAVE_lshl_long_const)
void
lshl_long_const(SlotInfo* dst, SlotInfo* src, jint val)
{
      if (HAVE_lshl_long_const_rangecheck(val)) {
            slot_slot_const(dst, src, val, HAVE_lshl_long_const, Tcomplex);
      }
      else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            lshl_int(dst, src, tmp);
            slot_freetmp(tmp);
      }
}
#endif

void
lshl_long(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_lshl_long)
      lslot_lslot_slot(dst, src, src2, HAVE_lshl_long, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_long(src, 0);
      pusharg_int(src2, pusharg_long_idx_inc);
#else
      pusharg_int(src2, pusharg_long_idx_inc);
      pusharg_long(src, 0);
#endif
      call_soft(soft_lshll);
      popargs();
      end_func_sync();
      return_long(dst);
#endif
}

#if defined(HAVE_ashr_int)
void
_ashr_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      slot_slot_slot(dst, src, src2, HAVE_ashr_int, Tcomplex);
}

void
ashr_int_const(SlotInfo* dst, SlotInfo* src, jint val)
{
#if defined(HAVE_ashr_int_const)
      if (HAVE_ashr_int_const_rangecheck(val)) {
            slot_slot_const(dst, src, val, HAVE_ashr_int_const, Tcomplex);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            _ashr_int(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

void
ashr_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_ashr_int_const)
      if (slot_type(src2) == Tconst) {
            ashr_int_const(dst, src, slot_value(src2)->i);
      }
      else
#endif
      _ashr_int(dst, src, src2);
}
#endif

void
ashr_long(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_ashr_long)
      lslot_lslot_slot(dst, src, src2, HAVE_ashr_long, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_long(src, 0);
      pusharg_int(src2, pusharg_long_idx_inc);
#else
      pusharg_int(src2, pusharg_long_idx_inc);
      pusharg_long(src, 0);
#endif
      call_soft(soft_ashrl);
      popargs();
      end_func_sync();
      return_long(dst);
#endif
}

#if defined(HAVE_lshr_int)
void
_lshr_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      slot_slot_slot(dst, src, src2, HAVE_lshr_int, Tcomplex);
}

void
lshr_int_const(SlotInfo* dst, SlotInfo* src, jint val)
{
#if defined(HAVE_lshr_int_const)
      if (HAVE_lshr_int_const_rangecheck(val)) {
            slot_slot_const(dst, src, val, HAVE_lshr_int_const, Tcomplex);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            _lshr_int(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

void
lshr_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_lshr_int_const)
      if (slot_type(src2) == Tconst) {
            lshr_int_const(dst, src, slot_value(src2)->i);
      }
      else
#endif
      _lshr_int(dst, src, src2);
}
#endif

void
lshr_long(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_lshr_long)
      lslot_lslot_slot(dst, src, src2, HAVE_lshr_long, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_long(src, 0);
      pusharg_int(src2, pusharg_long_idx_inc);
#else
      pusharg_int(src2, pusharg_long_idx_inc);
      pusharg_long(src, 0);
#endif
      call_soft(soft_lshrl);
      popargs();
      end_func_sync();
      return_long(dst);
#endif
}




/* ----------------------------------------------------------------------- */
/* Load and store.                                             */
/*                                                       */

#if defined(HAVE_load_int)
void
load_int(SlotInfo* dst, SlotInfo* src)
{
      slot_slot_slot(dst, NULL, src, HAVE_load_int, Tload);
}
#endif

void
load_offset_int(SlotInfo* dst, SlotInfo* src, jint offset)
{
      if (offset == 0) {
            load_int(dst, src);
      }
      else
#if defined(HAVE_load_offset_int)
      if (HAVE_load_offset_int_rangecheck(offset)) {
            slot_slot_const(dst, src, offset, HAVE_load_offset_int, Tload);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref_const(tmp, src, offset);
            load_int(dst, tmp);
            slot_freetmp(tmp);
      }
}

void
load_addr_int(SlotInfo* dst, void* addr)
{
#if defined(HAVE_load_addr_int)
      slot_slot_const(dst, NULL, (uintp)addr, HAVE_load_addr_int, Tload);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      load_int(dst, tmp);
      slot_freetmp(tmp);
#endif
}

#if defined(HAVE_load_ref)
void
load_ref(SlotInfo* dst, SlotInfo* src)
{
      slot_slot_slot(dst, NULL, src, HAVE_load_ref, Tload);
}
#endif

void
load_offset_ref(SlotInfo* dst, SlotInfo* src, jint offset)
{
      if (offset == 0) {
            load_ref(dst, src);
      }
      else
#if defined(HAVE_load_offset_ref)
      if (HAVE_load_offset_ref_rangecheck(offset)) {
            slot_slot_const(dst, src, offset, HAVE_load_offset_ref, Tload);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref_const(tmp, src, offset);
            load_ref(dst, tmp);
            slot_freetmp(tmp);
      }
}

void
load_addr_ref(SlotInfo* dst, void* addr)
{
#if defined(HAVE_load_addr_ref)
      slot_slot_const(dst, NULL, (uintp)addr, HAVE_load_addr_ref, Tload);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      load_ref(dst, tmp);
      slot_freetmp(tmp);
#endif
}

void
load_long(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_load_long)
      lslot_lslot_lslot(dst, 0, src, HAVE_load_long, Tload);
#else
      SlotInfo* tmp;

      slot_alloctmp(tmp);
      add_ref_const(tmp, src, 4);
      /* Don't use LSLOT & HSLOT here */
      load_int(dst, src);
      load_int(dst+1, tmp);
      slot_freetmp(tmp);
#endif
}

void
load_addr_long(SlotInfo* dst, void* addr)
{
#if defined(HAVE_load_addr_long)
      slot_slot_const(dst, 0, (uintp)addr, HAVE_load_addr_long, Tload);
#else
      load_addr_int(dst, addr);
      load_addr_int(dst+1, (void*)((uintp)addr+4));
#endif
}

void
load_float(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_load_float)
      slot_slot_slot(dst, NULL, src, HAVE_load_float, Tload);
#elif defined(HAVE_NO_FLOATING_POINT)
      load_int(dst, src);
#else
      KAFFEVM_ABORT();
#endif
}

void
load_addr_float(SlotInfo* dst, void* addr)
{
#if defined(HAVE_load_addr_float)
      slot_slot_const(dst, NULL, (uintp)addr, HAVE_load_addr_float, Tload);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      load_float(dst, tmp);
      slot_freetmp(tmp);
#endif
}

void
load_double(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_load_double)
      lslot_lslot_slot(dst, NULL, src, HAVE_load_double, Tload);
#elif defined(HAVE_NO_FLOATING_POINT) || defined(PS2LINUX)
      load_long(dst, src);
#else
      KAFFEVM_ABORT();
#endif
}

void
load_addr_double(SlotInfo* dst, void* addr)
{
#if defined(HAVE_load_addr_double)
      lslot_lslot_const(dst, 0, (uintp)addr, HAVE_load_addr_double, Tload);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      load_double(dst, tmp);
      slot_freetmp(tmp);
#endif
}

void
load_byte(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_load_byte)
      slot_slot_slot(dst, NULL, src, HAVE_load_byte, Tload);
#else
      load_int(dst, src);
      lshl_int_const(dst, dst, 8 * (sizeof(jint) - sizeof(jbyte)));
      ashr_int_const(dst, dst, 8 * (sizeof(jint) - sizeof(jbyte)));
#endif
}

void
load_char(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_load_char)
      slot_slot_slot(dst, NULL, src, HAVE_load_char, Tload);
#else
      load_int(dst, src);
      and_int_const(dst, dst, (1 << (8 * sizeof(jchar))) - 1);
#endif
}

void
load_short(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_load_short)
      slot_slot_slot(dst, NULL, src, HAVE_load_short, Tload);
#else
      load_int(dst, src);
      lshl_int_const(dst, dst, 8 * (sizeof(jint) - sizeof(jshort)));
      ashr_int_const(dst, dst, 8 * (sizeof(jint) - sizeof(jshort)));
#endif
}

void
load_addr_char(SlotInfo* dst, void* addr)
{
#if defined(HAVE_load_addr_char)
      slot_slot_const(dst, 0, (uintp)addr, HAVE_load_addr_char, Tload);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      load_char(dst, tmp);
      slot_freetmp(tmp);
#endif
}

void
load_addr_byte(SlotInfo* dst, void* addr)
{
#if defined(HAVE_load_addr_byte)
      slot_slot_const(dst, 0, (uintp)addr, HAVE_load_addr_byte, Tload);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      load_byte(dst, tmp);
      slot_freetmp(tmp);
#endif
}

void
load_addr_short(SlotInfo* dst, void* addr)
{
#if defined(HAVE_load_addr_short)
      slot_slot_const(dst, 0, (uintp)addr, HAVE_load_addr_short, Tload);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      load_short(dst, tmp);
      slot_freetmp(tmp);
#endif
}

void
load_offset_long(SlotInfo* dst, SlotInfo* src, jint offset)
{
      if (offset == 0) {
            load_long(dst, src);
      }
      else
#if defined(HAVE_load_offset_long)
      if (HAVE_load_offset_long_rangecheck(offset)) {
            lslot_slot_const(dst, src, offset, HAVE_load_offset_long, Tload);
      }
      else
#endif
      {
                /* Don't use LSLOT & HSLOT here */
            load_offset_int(dst, src, offset);
            load_offset_int(dst+1, src, offset+4);
      }
}

void
load_offset_byte(SlotInfo* dst, SlotInfo* src, jint offset)
{
      if (offset == 0) {
            load_byte(dst, src);
      }
      else
#if defined(HAVE_load_offset_byte)
      if (HAVE_load_offset_byte_rangecheck(offset)) {
            slot_slot_const(dst, src, offset, HAVE_load_offset_byte, Tload);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref_const(tmp, src, offset);
            load_byte(dst, tmp);
            slot_freetmp(tmp);
      }
}

void
load_offset_char(SlotInfo* dst, SlotInfo* src, jint offset)
{
      if (offset == 0) {
            load_char(dst, src);
      }
      else
#if defined(HAVE_load_offset_char)
      if (HAVE_load_offset_char_rangecheck(offset)) {
            slot_slot_const(dst, src, offset, HAVE_load_offset_char, Tload);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref_const(tmp, src, offset);
            load_char(dst, tmp);
            slot_freetmp(tmp);
      }
}

void
load_offset_short(SlotInfo* dst, SlotInfo* src, jint offset)
{
      if (offset == 0) {
            load_short(dst, src);
      }
      else
#if defined(HAVE_load_offset_short)
      if (HAVE_load_offset_short_rangecheck(offset)) {
            slot_slot_const(dst, src, offset, HAVE_load_offset_short, Tload);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref_const(tmp, src, offset);
            load_short(dst, tmp);
            slot_freetmp(tmp);
      }
}

void
load_offset_float(SlotInfo* dst, SlotInfo* src, jint offset)
{
      if (offset == 0) {
            load_float(dst, src);
      }
      else
#if defined(HAVE_load_offset_float)
      if (HAVE_load_offset_float_rangecheck(offset)) {
            slot_slot_const(dst, src, offset, HAVE_load_offset_float, Tload);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref_const(tmp, src, offset);
            load_float(dst, tmp);
            slot_freetmp(tmp);
      }
}

void
load_offset_double(SlotInfo* dst, SlotInfo* src, jint offset)
{
      if (offset == 0) {
            load_double(dst, src);
      }
      else
#if defined(HAVE_load_offset_double)
      if (HAVE_load_offset_double_rangecheck(offset)) {
            lslot_slot_const(dst, src, offset, HAVE_load_offset_double, Tload);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref_const(tmp, src, offset);
            load_double(dst, tmp);
            slot_freetmp(tmp);
      }
}

void
load_offset_scaled_int(SlotInfo* dst, SlotInfo* src, SlotInfo* idx, int offset)
{
      if (slot_type(idx) == Tconst) {
            load_offset_int(dst, src, (jint)(slot_value(idx)->i * sizeof(jint) + offset));
      }
      else
#if defined(HAVE_load_offset_scaled_int)
      slot_slot_slot_const_const(dst, src, idx, offset, 0, HAVE_load_offset_scaled_int, Tload);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            lshl_int_const(tmp, idx, SHIFT_jint);
            add_ref(tmp, src, tmp);
            load_offset_int(dst, tmp, offset);
            slot_freetmp(tmp);
      }
#endif
}

void
load_offset_scaled_ref(SlotInfo* dst, SlotInfo* src, SlotInfo* idx, int offset)
{
      if (slot_type(idx) == Tconst) {
            load_offset_ref(dst, src, (jint)(slot_value(idx)->i * sizeof(jref) + offset));
      }
      else
#if defined(HAVE_load_offset_scaled_ref)
      slot_slot_slot_const_const(dst, src, idx, offset, 0, HAVE_load_offset_scaled_ref, Tload);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            lshl_int_const(tmp, idx, SHIFT_jref);
            add_ref(tmp, src, tmp);
            load_offset_ref(dst, tmp, offset);
            slot_freetmp(tmp);
      }
#endif
}

void
load_offset_scaled_long(SlotInfo* dst, SlotInfo* src, SlotInfo* idx, int offset)
{
      if (slot_type(idx) == Tconst) {
            load_offset_long(dst, src, (jint)(slot_value(idx)->i * sizeof(jlong) + offset));
      }
      else
#if defined(HAVE_load_offset_scaled_long)
      slot_slot_slot_const_const(dst, src, idx, offset, 0, HAVE_load_offset_scaled_long, Tload);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            lshl_int_const(tmp, idx, SHIFT_jlong);
            add_ref(tmp, src, tmp);
            load_offset_long(dst, tmp, offset);
            slot_freetmp(tmp);
      }
#endif
}

void
load_offset_scaled_float(SlotInfo* dst, SlotInfo* src, SlotInfo* idx, int offset)
{
      if (slot_type(idx) == Tconst) {
            load_offset_float(dst, src, (jint)(slot_value(idx)->i * sizeof(jfloat) + offset));
      }
      else
#if defined(HAVE_load_offset_scaled_float)
      slot_slot_slot_const_const(dst, src, idx, offset, 0, HAVE_load_offset_scaled_float, Tload);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            lshl_int_const(tmp, idx, SHIFT_jfloat);
            add_ref(tmp, src, tmp);
            load_offset_float(dst, tmp, offset);
            slot_freetmp(tmp);
      }
#endif
}

void
load_offset_scaled_double(SlotInfo* dst, SlotInfo* src, SlotInfo* idx, int offset)
{
      if (slot_type(idx) == Tconst) {
            load_offset_double(dst, src, (jint)(slot_value(idx)->i * sizeof(jdouble) + offset));
      }
      else
#if defined(HAVE_load_offset_scaled_double)
      lslot_slot_slot_const_const(dst, src, idx, offset, 0, HAVE_load_offset_scaled_double, Tload);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            lshl_int_const(tmp, idx, SHIFT_jdouble);
            add_ref(tmp, src, tmp);
            load_offset_double(dst, tmp, offset);
            slot_freetmp(tmp);
      }
#endif
}

void
load_offset_scaled_byte(SlotInfo* dst, SlotInfo* src, SlotInfo* idx, int offset)
{
      if (slot_type(idx) == Tconst) {
            load_offset_byte(dst, src, (jint)(slot_value(idx)->i * sizeof(jbyte) + offset));
      }
      else
#if defined(HAVE_load_offset_scaled_byte)
      slot_slot_slot_const_const(dst, src, idx, offset, 0, HAVE_load_offset_scaled_byte, Tload);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref(tmp, src, idx);
            load_offset_byte(dst, tmp, offset);
            slot_freetmp(tmp);
      }
#endif
}

void
load_offset_scaled_char(SlotInfo* dst, SlotInfo* src, SlotInfo* idx, int offset)
{
      if (slot_type(idx) == Tconst) {
            load_offset_char(dst, src, (jint)(slot_value(idx)->i * sizeof(jchar) + offset));
      }
      else
#if defined(HAVE_load_offset_scaled_char)
      slot_slot_slot_const_const(dst, src, idx, offset, 0, HAVE_load_offset_scaled_char, Tload);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            lshl_int_const(tmp, idx, SHIFT_jchar);
            add_ref(tmp, src, tmp);
            load_offset_char(dst, tmp, offset);
            slot_freetmp(tmp);
      }
#endif
}

void
load_offset_scaled_short(SlotInfo* dst, SlotInfo* src, SlotInfo* idx, int offset)
{
      if (slot_type(idx) == Tconst) {
            load_offset_short(dst, src, (jint)(slot_value(idx)->i * sizeof(jshort) + offset));
      }
      else
#if defined(HAVE_load_offset_scaled_short)
      slot_slot_slot_const_const(dst, src, idx, offset, 0, HAVE_load_offset_scaled_short, Tload);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            lshl_int_const(tmp, idx, SHIFT_jshort);
            add_ref(tmp, src, tmp);
            load_offset_short(dst, tmp, offset);
            slot_freetmp(tmp);
      }
#endif
}

void
load_code_ref(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_load_code_ref)
      slot_slot_slot(dst, 0, src, HAVE_load_code_ref, Tload);
#else
      load_ref(dst, src);
#endif
}

void
load_key(SlotInfo* dst, SlotInfo* src)
{
      load_int(dst, src);
}

#if defined(HAVE_store_int)
void
store_int(SlotInfo* dst, SlotInfo* src)
{
      slot_slot_slot(NULL, dst, src, HAVE_store_int, Tstore);
}
#endif

void
store_offset_int(SlotInfo* dst, jint offset, SlotInfo* src)
{
      if (offset == 0) {
            store_int(dst, src);
      }
      else
#if defined(HAVE_store_const_offset_int)
      if (slot_type(src) == Tconst) {
            store_const_offset_int(dst, offset, slot_value(src)->i);
      }
      else
#endif
#if defined(HAVE_store_offset_int)
      if (HAVE_store_offset_int_rangecheck(offset)) {
            slot_slot_const(src, dst, offset, HAVE_store_offset_int, Tstore);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref_const(tmp, dst, offset);
            store_int(tmp, src);
            slot_freetmp(tmp);
      }
}

void
store_addr_int(void* addr, SlotInfo* src)
{
#if defined(HAVE_store_addr_int)
      slot_slot_const(NULL, src, (uintp)addr, HAVE_store_addr_int, Tstore);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      store_int(tmp, src);
      slot_freetmp(tmp);
#endif
}

#if defined(HAVE_store_ref)
void
store_ref(SlotInfo* dst, SlotInfo* src)
{
      slot_slot_slot(NULL, dst, src, HAVE_store_ref, Tstore);
}
#endif

void
store_offset_ref(SlotInfo* dst, jint offset, SlotInfo* src)
{
      if (offset == 0) {
            store_ref(dst, src);
      }
      else
#if defined(HAVE_store_offset_ref)
      if (HAVE_store_offset_ref_rangecheck(offset)) {
            slot_slot_const(src, dst, offset, HAVE_store_offset_ref, Tstore);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref_const(tmp, dst, offset);
            store_ref(tmp, src);
            slot_freetmp(tmp);
      }
}

void
store_addr_ref(void* addr, SlotInfo* src)
{
#if defined(HAVE_store_addr_ref)
      slot_slot_const(NULL, src, (uintp)addr, HAVE_store_addr_ref, Tstore);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      store_ref(tmp, src);
      slot_freetmp(tmp);
#endif
}

void
store_long(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_store_long)
      lslot_slot_lslot(0, dst, src, HAVE_store_long, Tstore);
#else
      SlotInfo* tmp;

      slot_alloctmp(tmp);
      add_ref_const(tmp, dst, 4);
      /* Don't use LSLOT & HSLOT here */
      store_int(dst, src);
      store_int(tmp, src+1);
      slot_freetmp(tmp);
#endif
}

void
store_offset_long(SlotInfo* dst, jint offset, SlotInfo* src)
{
      if (offset == 0) {
            store_long(dst, src);
      }
      else
#if defined(HAVE_store_offset_long)
      if (HAVE_store_offset_long_rangecheck(offset)) {
            lslot_slot_const(src, dst, offset, HAVE_store_offset_long, Tstore);
      }
      else
#endif
      {
                /* Don't use LSLOT & HSLOT here */
            store_offset_int(dst, offset, src);
            store_offset_int(dst, offset+4, src+1);
      }
}

void
store_addr_long(void* addr, SlotInfo* src)
{
#if defined(HAVE_store_addr_long)
      slot_slot_const(0, src, (uintp)addr, HAVE_store_addr_long, Tstore);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      store_long(tmp, src);
      slot_freetmp(tmp);
#endif
}

void
store_float(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_store_float)
      slot_slot_slot(NULL, dst, src, HAVE_store_float, Tstore);
#elif defined(HAVE_NO_FLOATING_POINT)
      store_int(dst, src);
#else
      KAFFEVM_ABORT();
#endif
}

void
store_offset_float(SlotInfo* dst, jint offset, SlotInfo* src)
{
      if (offset == 0) {
            store_float(dst, src);
      }
      else
#if defined(HAVE_store_offset_float)
      if (HAVE_store_offset_float_rangecheck(offset)) {
            slot_slot_const(src, dst, offset, HAVE_store_offset_float, Tstore);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref_const(tmp, dst, offset);
            store_float(tmp, src);
            slot_freetmp(tmp);
      }
}

void
store_addr_float(void* addr, SlotInfo* src)
{
#if defined(HAVE_store_addr_float)
      slot_slot_const(0, src, (uintp)addr, HAVE_store_addr_float, Tstore);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      store_float(tmp, src);
      slot_freetmp(tmp);
#endif
}

void
store_double(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_store_double)
      slot_slot_lslot(NULL, dst, src, HAVE_store_double, Tstore);
#elif defined(HAVE_NO_FLOATING_POINT) || defined(PS2LINUX)
      store_long(dst, src);
#else
      KAFFEVM_ABORT();
#endif
}

void
store_offset_double(SlotInfo* dst, jint offset, SlotInfo* src)
{
      if (offset == 0) {
            store_double(dst, src);
      }
      else
#if defined(HAVE_store_offset_double)
      if (HAVE_store_offset_double_rangecheck(offset)) {
            lslot_slot_const(src, dst, offset, HAVE_store_offset_double, Tstore);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref_const(tmp, dst, offset);
            store_double(tmp, src);
            slot_freetmp(tmp);
      }
}

void
store_addr_double(void* addr, SlotInfo* src)
{
#if defined(HAVE_store_addr_double)
      lslot_lslot_const(0, src, (uintp)addr, HAVE_store_addr_double, Tstore);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      store_double(tmp, src);
      slot_freetmp(tmp);
#endif
}

void
store_byte(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_store_byte)
      slot_slot_slot(NULL, dst, src, HAVE_store_byte, Tstore);
#else
      /* FIXME -- this is unlikely to work as-is as it doesn't
         allow for alignment requirements on the integer load.  */
      SlotInfo* tmp;
      SlotInfo* tmp2;
      slot_alloctmp(tmp);
      slot_alloctmp(tmp2);
      and_int_const(tmp, src, (1 << (8 * sizeof(jbyte))) - 1);
      load_int(tmp2, dst);
      and_int_const(tmp2, tmp2, -(1 << (8 * sizeof(jbyte))));
      or_int(tmp2, tmp2, tmp);
      store_int(dst, tmp2);
      slot_freetmp(tmp);
      slot_freetmp(tmp2);
#endif
}

void
store_offset_byte(SlotInfo* dst, jint offset, SlotInfo* src)
{
      if (offset == 0) {
            store_byte(dst, src);
      }
      else
#if defined(HAVE_store_const_offset_byte)
      if (slot_type(src) == Tconst) {
            store_const_offset_byte(dst, offset, slot_value(src)->i);
      }
      else
#endif
#if defined(HAVE_store_offset_byte)
      if (HAVE_store_offset_byte_rangecheck(offset)) {
            slot_slot_const(src, dst, offset, HAVE_store_offset_byte, Tstore);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref_const(tmp, dst, offset);
            store_byte(tmp, src);
            slot_freetmp(tmp);
      }
}

void
store_addr_byte(void* addr, SlotInfo* src)
{
#if defined(HAVE_store_addr_byte)
      slot_slot_const(0, src, (uintp)addr, HAVE_store_addr_byte, Tstore);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      store_byte(tmp, src);
      slot_freetmp(tmp);
#endif
}

void
store_char(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_store_char)
      slot_slot_slot(NULL, dst, src, HAVE_store_char, Tstore);
#else
      /* FIXME -- this is unlikely to work as-is as it doesn't
         allow for alignment requirements on the integer load.  */
      SlotInfo* tmp;
      SlotInfo* tmp2;
      slot_alloctmp(tmp);
      slot_alloctmp(tmp2);
      and_int_const(tmp, src, (1 << (8 * sizeof(jchar))) - 1);
      load_int(tmp2, dst);
      and_int_const(tmp2, tmp2, -(1 << (8 * sizeof(jchar))));
      or_int(tmp2, tmp2, tmp);
      store_int(dst, tmp2);
      slot_freetmp(tmp);
      slot_freetmp(tmp2);
#endif
}

void
store_offset_char(SlotInfo* dst, jint offset, SlotInfo* src)
{
      if (offset == 0) {
            store_char(dst, src);
      }
      else
#if defined(HAVE_store_offset_char)
      if (HAVE_store_offset_char_rangecheck(offset)) {
            slot_slot_const(src, dst, offset, HAVE_store_offset_char, Tstore);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref_const(tmp, dst, offset);
            store_char(tmp, src);
            slot_freetmp(tmp);
      }
}

void
store_addr_char(void* addr, SlotInfo* src)
{
#if defined(HAVE_store_addr_char)
      slot_slot_const(0, src, (uintp)addr, HAVE_store_addr_char, Tstore);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      store_char(tmp, src);
      slot_freetmp(tmp);
#endif
}

void
store_short(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_store_short)
      slot_slot_slot(NULL, dst, src, HAVE_store_short, Tstore);
#else
      /* FIXME -- this is unlikely to work as-is as it doesn't
         allow for alignment requirements on the integer load.  */
      SlotInfo* tmp;
      SlotInfo* tmp2;
      slot_alloctmp(tmp);
      slot_alloctmp(tmp2);
      and_int_const(tmp, src, (1 << (8 * sizeof(jshort))) - 1);
      load_int(tmp2, dst);
      and_int_const(tmp2, tmp2, -(1 << (8 * sizeof(jshort))));
      or_int(tmp2, tmp2, tmp);
      store_int(dst, tmp2);
      slot_freetmp(tmp);
      slot_freetmp(tmp2);
#endif
}

void
store_offset_short(SlotInfo* dst, jint offset, SlotInfo* src)
{
      if (offset == 0) {
            store_short(dst, src);
      }
      else
#if defined(HAVE_store_offset_short)
      if (HAVE_store_offset_short_rangecheck(offset)) {
            slot_slot_const(src, dst, offset, HAVE_store_offset_short, Tstore);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref_const(tmp, dst, offset);
            store_short(tmp, src);
            slot_freetmp(tmp);
      }
}

void
store_addr_short(void* addr, SlotInfo* src)
{
#if defined(HAVE_store_addr_short)
      slot_slot_const(0, src, (uintp)addr, HAVE_store_addr_short, Tstore);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      move_ref_const(tmp, addr);
      store_short(tmp, src);
      slot_freetmp(tmp);
#endif
}

void
store_offset_scaled_int(SlotInfo* dst, SlotInfo* idx, int offset, SlotInfo* src)
{
      if (slot_type(idx) == Tconst) {
            store_offset_int(dst, (jint)(slot_value(idx)->i * sizeof(jint) + offset), src);
      }
      else
#if defined(HAVE_store_offset_scaled_int)
      slot_slot_slot_const_const(dst, idx, src, offset, 0, HAVE_store_offset_scaled_int, Tstore);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            lshl_int_const(tmp, idx, SHIFT_jint);
            add_ref(tmp, dst, tmp);
            store_offset_int(tmp, offset, src);
            slot_freetmp(tmp);
      }
#endif
}

void
store_offset_scaled_ref(SlotInfo* dst, SlotInfo* idx, int offset, SlotInfo* src)
{
      if (slot_type(idx) == Tconst) {
            store_offset_ref(dst, (jint)(slot_value(idx)->i * sizeof(jref) + offset), src);
      }
      else
#if defined(HAVE_store_offset_scaled_ref)
      slot_slot_slot_const_const(dst, idx, src, offset, 0, HAVE_store_offset_scaled_ref, Tstore);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            lshl_int_const(tmp, idx, SHIFT_jref);
            add_ref(tmp, dst, tmp);
            store_offset_ref(tmp, offset, src);
            slot_freetmp(tmp);
      }
#endif
}

void
store_offset_scaled_long(SlotInfo* dst, SlotInfo* idx, int offset, SlotInfo* src)
{
      if (slot_type(idx) == Tconst) {
            store_offset_long(dst, (jint)(slot_value(idx)->i * sizeof(jlong) + offset), src);
      }
      else
#if defined(HAVE_store_offset_scaled_long)
      slot_slot_slot_const_const(dst, idx, src, offset, 0, HAVE_store_offset_scaled_long, Tstore);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            lshl_int_const(tmp, idx, SHIFT_jlong);
            add_ref(tmp, dst, tmp);
            store_offset_long(tmp, offset, src);
            slot_freetmp(tmp);
      }
#endif
}

void
store_offset_scaled_float(SlotInfo* dst, SlotInfo* idx, int offset, SlotInfo* src)
{
      if (slot_type(idx) == Tconst) {
            store_offset_float(dst, (jint)(slot_value(idx)->i * sizeof(jfloat) + offset), src);
      }
      else
#if defined(HAVE_store_offset_scaled_float)
      slot_slot_slot_const_const(dst, idx, src, offset, 0, HAVE_store_offset_scaled_float, Tstore);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            lshl_int_const(tmp, idx, SHIFT_jfloat);
            add_ref(tmp, dst, tmp);
            store_offset_float(tmp, offset, src);
            slot_freetmp(tmp);
      }
#endif
}

void
store_offset_scaled_double(SlotInfo* dst, SlotInfo* idx, int offset, SlotInfo* src)
{
      if (slot_type(idx) == Tconst) {
            store_offset_double(dst, (jint)(slot_value(idx)->i * sizeof(jdouble) + offset), src);
      }
      else
#if defined(HAVE_store_offset_scaled_double)
      slot_slot_lslot_const_const(dst, idx, src, offset, 0, HAVE_store_offset_scaled_double, Tstore);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            lshl_int_const(tmp, idx, SHIFT_jdouble);
            add_ref(tmp, dst, tmp);
            store_offset_double(tmp, offset, src);
            slot_freetmp(tmp);
      }
#endif
}

void
store_offset_scaled_byte(SlotInfo* dst, SlotInfo* idx, int offset, SlotInfo* src)
{
      if (slot_type(idx) == Tconst) {
            store_offset_byte(dst, (jint)(slot_value(idx)->i * sizeof(jbyte) + offset), src);
      }
      else
#if defined(HAVE_store_offset_scaled_byte)
#if defined(HAVE_store_const_offset_scaled_byte)
      if (slot_type(src) == Tconst) {
            store_const_offset_scaled_byte(dst, idx, offset, slot_value(src)->i);
      }
      else
#endif
      slot_slot_slot_const_const(dst, idx, src, offset, 0, HAVE_store_offset_scaled_byte, Tstore);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            add_ref(tmp, dst, idx);
            store_offset_byte(tmp, offset, src);
            slot_freetmp(tmp);
      }
#endif
}

#if defined(HAVE_store_const_offset_scaled_byte)
void
store_const_offset_scaled_byte(SlotInfo* dst, SlotInfo* idx, int offset, jint src)
{
      slot_slot_const_const_const(dst, idx, offset, src, 0, HAVE_store_const_offset_scaled_byte, Tstore);
}
#endif

void
store_offset_scaled_char(SlotInfo* dst, SlotInfo* idx, int offset, SlotInfo* src)
{
      if (slot_type(idx) == Tconst) {
            store_offset_char(dst, (jint)(slot_value(idx)->i * sizeof(jchar) + offset), src);
      }
      else
#if defined(HAVE_store_offset_scaled_char)
      slot_slot_slot_const_const(dst, idx, src, offset, 0, HAVE_store_offset_scaled_char, Tstore);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            lshl_int_const(tmp, idx, SHIFT_jchar);
            add_ref(tmp, dst, tmp);
            store_offset_char(tmp, offset, src);
            slot_freetmp(tmp);
      }
#endif
}

void
store_offset_scaled_short(SlotInfo* dst, SlotInfo* idx, int offset, SlotInfo* src)
{
      if (slot_type(idx) == Tconst) {
            store_offset_short(dst, (jint)(slot_value(idx)->i * sizeof(jshort) + offset), src);
      }
      else
#if defined(HAVE_store_offset_scaled_short)
      slot_slot_slot_const_const(dst, idx, src, offset, 0, HAVE_store_offset_scaled_short, Tstore);
#else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            lshl_int_const(tmp, idx, SHIFT_jshort);
            add_ref(tmp, dst, tmp);
            store_offset_short(tmp, offset, src);
            slot_freetmp(tmp);
      }
#endif
}

#if defined(HAVE_store_const_offset_int)
void
store_const_offset_int(SlotInfo* dst, jint offset, jint val)
{
      if (HAVE_store_const_offset_int_rangecheck(offset)) {
            slot_const_const(dst, offset, val, HAVE_store_const_offset_int, Tstore);
      }
      else
      {
            SlotInfo* tmp;
            SlotInfo* tmp2;
            slot_alloctmp(tmp);
            slot_alloctmp(tmp2);
            add_ref_const(tmp, dst, offset);
            move_int_const(tmp2, val);
            store_int(tmp, tmp2);
            slot_freetmp(tmp);
            slot_freetmp(tmp2);
      }
}
#endif

#if defined(HAVE_store_const_offset_byte)
void
store_const_offset_byte(SlotInfo* dst, jint offset, jint val)
{
      if (HAVE_store_const_offset_byte_rangecheck(offset)) {
            slot_const_const(dst, offset, val, HAVE_store_const_offset_byte, Tstore);
      }
      else
      {
            SlotInfo* tmp;
            SlotInfo* tmp2;
            slot_alloctmp(tmp);
            slot_alloctmp(tmp2);
            add_ref_const(tmp, dst, offset);
            move_int_const(tmp2, val);
            store_byte(tmp, tmp2);
            slot_freetmp(tmp);
            slot_freetmp(tmp2);
      }
}
#endif


/* ----------------------------------------------------------------------- */
/* Function argument management.                               */
/*                                                       */

void
pusharg_int_const(int val, int idx)
{
#if defined(HAVE_pusharg_int_const)
      if (HAVE_pusharg_int_const_rangecheck(val)) {
            slot_const_const(NULL, val, idx, HAVE_pusharg_int_const, Tnull);
            argcount += 1;
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            pusharg_int(tmp, idx);
            slot_freetmp(tmp);
      }
}

#if defined(HAVE_pusharg_int)
void
pusharg_int(SlotInfo* src, int idx)
{
#if defined(HAVE_pusharg_int_const)
      if (slot_type(src) == Tconst) {
            pusharg_int_const(slot_value(src)->i, idx);
      }
      else
#endif
      {
            slot_slot_const(NULL, src, idx, HAVE_pusharg_int, Tnull);
            argcount += 1;
      }
}
#endif

#if defined(HAVE_pusharg_ref)
void
pusharg_ref(SlotInfo* src, int idx)
{
#if defined(HAVE_pusharg_ref_const)
      if (slot_type(src) == Tconst) {
            pusharg_ref_const(slot_value(src)->l, idx);
      }
      else
#endif
      {
            slot_slot_const(NULL, src, idx, HAVE_pusharg_ref, Tnull);
            argcount += 1;
      }
}
#endif

void
pusharg_ref_const(void* val, int idx)
{
#if defined(HAVE_pusharg_ref_const)
      if (HAVE_pusharg_ref_const_rangecheck((jword)val)) {
            slot_const_const(NULL, (jword)val, idx, HAVE_pusharg_ref_const, Tnull);
            argcount += 1;
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_ref_const(tmp, val);
            pusharg_ref(tmp, idx);
            slot_freetmp(tmp);
      }
}

void
pusharg_class_const(Hjava_lang_Class* cls, int idx)
{
#if 1
      pusharg_ref_const(cls, idx);
#else
      ???
#endif
}

void
pusharg_utf8_const(Utf8Const* val, int idx)
{
#if 1
      pusharg_ref_const(val, idx);
#else
      ???
#endif
}

void
pusharg_float(SlotInfo* src, int idx)
{
#if defined(HAVE_pusharg_float)
      slot_slot_const(NULL, src, idx, HAVE_pusharg_float, Tnull);
      argcount += 1;
#elif defined(HAVE_NO_FLOATING_POINT)
      pusharg_int(src, idx);
#else
      KAFFEVM_ABORT();
#endif
}

void
pusharg_double(SlotInfo* src, int idx)
{
#if defined(HAVE_pusharg_double)
      lslot_lslot_const(NULL, src, idx, HAVE_pusharg_double, Tnull);
      argcount += pusharg_long_idx_inc;
#elif defined(HAVE_NO_FLOATING_POINT) || defined(PS2LINUX)
      pusharg_long(src, idx);
#else
      KAFFEVM_ABORT();
#endif
}

void
pusharg_long(SlotInfo* src, int idx)
{
#if defined(HAVE_pusharg_long)
      lslot_lslot_const(0, src, idx, HAVE_pusharg_long, Tnull);
      argcount += pusharg_long_idx_inc;
#elif defined(PUSHARG_FORWARDS)
      /* Don't use LSLOT & HSLOT here */
      pusharg_int(src, idx);
      pusharg_int(src+1, idx+1);
#else
      /* Don't use LSLOT & HSLOT here */
      pusharg_int(src+1, idx+1);
      pusharg_int(src, idx);
#endif
}

void
popargs_internal(int does_return UNUSED)
{
      if (argcount != 0) {
#if defined(HAVE_popargs)
            /*
             * Must always call popargs so the backend can do cleanup.
             *
             * Might be able to get away with sending an argcount of zero,
             * but, well just send the whole thing for now.  Alternatively,
             * it might be better to add a new back end call to
             * end_func_sync.
             */
            slot_slot_const(NULL, NULL, argcount, HAVE_popargs, Tnull);
#endif
            if (argcount > maxPush) {
                  maxPush = argcount;
            }
            argcount = 0;
      }
}



/* ----------------------------------------------------------------------- */
/* Control flow changes.                                       */
/*                                                       */

#if defined(HAVE_branch_and_link)
void
branch_and_link(label* dst, int type)
{
      slot_const_const(NULL, (jword)dst, type & ~blink, HAVE_branch_and_link, Tnull);
}
#endif

#if defined(HAVE_branch)
void
branch(label* dst, int type)
{
#if defined(HAVE_branch_and_link)
      if( type & blink )
      {
            branch_and_link(dst, type);
      }
      else
#endif
      {
            slot_const_const(NULL, (jword)dst, type & ~blink, HAVE_branch, Tnull);
      }
}
#endif

void
cbranch_int(SlotInfo* s1, SlotInfo* s2, label* dst, int type)
{
#if defined(HAVE_cbranch_int)
      slot_slot_slot_const_const(NULL, s1, s2, (jword)dst, type,
                           HAVE_cbranch_int, Tcomplex);
#else
      cmp_int(NULL, s1, s2);
      branch(dst, type);
#endif
}

void
cbranch_offset_int(SlotInfo* s1, SlotInfo* s2, jint s3, label* dst, int type)
{
#if defined(HAVE_cmp_int)
      cmp_offset_int(NULL, s1, s2, s3);
      branch(dst, type);
#else
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      load_offset_int(tmp, s2, s3);
      cbranch_int(s1, tmp, dst, type);
      slot_freetmp(tmp);
#endif
}

void
cbranch_int_const(SlotInfo* s1, jint val, label* dst, int type)
{
#if defined(HAVE_cbranch_int_const)
      if (HAVE_cbranch_int_const_rangecheck(val)) {
            slot_slot_const_const_const(NULL, s1, val, (jword)dst, type, HAVE_cbranch_int_const, Tcomplex);
      }
      else {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            cbranch_int(s1, tmp, dst, type);
            slot_freetmp(tmp);
      }
#else
      cmp_int_const(NULL, s1, val);
      branch(dst, type);
#endif
}

void
cbranch_ref(SlotInfo* s1, SlotInfo* s2, label* dst, int type)
{
#if defined(HAVE_cbranch_ref)
      slot_slot_slot_const_const(0, s1, s2, (jword)dst, type,
                           HAVE_cbranch_ref, Tcomplex);
#else
      cmp_ref(NULL, s1, s2);
      branch(dst, type);
#endif
}

void
cbranch_ref_const(SlotInfo* s1, void *val, label* dst, int type)
{
#if defined(HAVE_cbranch_ref_const)
      if (HAVE_cbranch_ref_const_rangecheck((jword)val)) {
            slot_slot_const_const_const(NULL, s1, (jword)val, (jword)dst, type,
                                  HAVE_cbranch_ref_const, Tcomplex);
      }
      else
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_ref_const(tmp, val);
            cbranch_ref(s1, tmp, dst, type);
            slot_freetmp(tmp);
      }
#else
      cmp_ref_const(NULL, s1, val);
      branch(dst, type);
#endif
}

void
branch_indirect(SlotInfo* dst)
{
#if defined(HAVE_branch_indirect)
      slot_slot_const(NULL, dst, ba, HAVE_branch_indirect, Tnull);
#else
      load_ref(dst, dst);
      call(dst);
#endif
}

#if defined(HAVE_call)
void
call(SlotInfo* dst)
{
      slot_slot_const(NULL, dst, ba, HAVE_call, Tnull);
}
#endif

void
call_indirect_method(Method *meth)
{
      void* ptr;

      if (METHOD_TRANSLATED(meth)) {
            _call_soft(METHOD_NATIVECODE(meth), 1);
      }
      else {
            ptr = PMETHOD_NATIVECODE(meth);

#if defined(HAVE_call_indirect_const)
            slot_const_const(NULL, (jword)ptr, ba, HAVE_call_indirect_const, Tnull);
#else
            {
                  SlotInfo* tmp;
                  slot_alloctmp(tmp);
                  move_ref_const(tmp, ptr);
                  load_ref(tmp, tmp);
                  call(tmp);
                  slot_freetmp(tmp);
            }
#endif
      }
}

static void
_call_soft(void *routine, int profiled)
{
#if defined(HAVE_call_soft)
      label* l = KaffeJIT3_newLabel();
      l->type = Labsolute|Lexternal | (profiled ? 0 : Lnoprofile);
      l->at = 0;
      l->to = (uintp)routine; /* What place does it goto */
      l->from = 0;

      slot_const_const(0, (jword)l, ba, HAVE_call_soft, Tnull);
#elif defined(HAVE_call_ref)
      label* l;
      l = KaffeJIT3_newLabel();
      l->type = Lexternal | (profiled ? 0 : Lnoprofile);
      l->at = 0;
      l->to = (uintp)routine; /* What place does it goto */
      l->from = 0;

      slot_const_const(NULL, (jword)l, ba, HAVE_call_ref, Tnull);
#else
      label* l;
      constpool* c;
      SlotInfo* tmp;

      l = KaffeJIT3_newLabel();
      c = KaffeJIT3_newConstant(CPref, routine);
      l->type = Lconstant;
      l->at = 0;
      l->to = (uintp)c;
      l->from = 0;

      slot_alloctmp(tmp);
#if defined(HAVE_load_constpool_ref)
      slot_slot_const(tmp, 0, (jword)l, HAVE_load_constpool_ref, Tnull);
#else
      move_label_const(tmp, l);
      load_ref(tmp, tmp);
#endif
      call(tmp);
      slot_freetmp(tmp);
#endif
}

void
call_soft(void *routine)
{
      _call_soft(routine, 0);
}

#if defined(HAVE_return_int)
void
return_int(SlotInfo* dst)
{
      slot_slot_slot(dst, NULL, NULL, HAVE_return_int, Tnull);
}
#endif

#if defined(HAVE_return_ref)
void
return_ref(SlotInfo* dst)
{
      slot_slot_slot(dst, NULL, NULL, HAVE_return_ref, Tnull);
}
#endif

#if defined(HAVE_return_long)
void
return_long(SlotInfo* dst)
{
      lslot_lslot_lslot(dst, NULL, NULL, HAVE_return_long, Tnull);
}
#endif

void
return_float(SlotInfo* dst)
{
#if defined(HAVE_return_float)
      slot_slot_slot(dst, NULL, NULL, HAVE_return_float, Tnull);
#if defined(HAVE_FLOATING_POINT_STACK)
      begin_sync();
      end_sync();
#endif
#elif defined(HAVE_NO_FLOATING_POINT)
      return_int(dst);
#else
      KAFFEVM_ABORT();
#endif
}

void
return_double(SlotInfo* dst)
{
#if defined(HAVE_return_double)
      lslot_lslot_lslot(dst, NULL, NULL, HAVE_return_double, Tnull);
#if defined(HAVE_FLOATING_POINT_STACK)
      begin_sync();
      end_sync();
#endif
#elif defined(HAVE_NO_FLOATING_POINT) || defined(PS2LINUX)
      return_long(dst);
#else
      KAFFEVM_ABORT();
#endif
}

#if defined(HAVE_returnarg_int)
void
returnarg_int(SlotInfo* src)
{
      slot_slot_slot(NULL, NULL, src, HAVE_returnarg_int, Tcopy);
}
#endif

#if defined(HAVE_returnarg_ref)
void
returnarg_ref(SlotInfo* src)
{
      slot_slot_slot(NULL, NULL, src, HAVE_returnarg_ref, Tcopy);
}
#endif

#if defined(HAVE_returnarg_long)
void
returnarg_long(SlotInfo* src)
{
      lslot_lslot_lslot(NULL, NULL, src, HAVE_returnarg_long, Tcopy);
}
#endif

void
returnarg_float(SlotInfo* src)
{
#if defined(HAVE_returnarg_float)
      slot_slot_slot(NULL, NULL, src, HAVE_returnarg_float, Tcopy);
#elif defined(HAVE_NO_FLOATING_POINT)
      returnarg_int(src);
#else
      KAFFEVM_ABORT();
#endif
}

void
returnarg_double(SlotInfo* src)
{
#if defined(HAVE_returnarg_double)
      lslot_lslot_lslot(NULL, NULL, src, HAVE_returnarg_double, Tcopy);
#elif defined(HAVE_NO_FLOATING_POINT) || defined(PS2LINUX)
      returnarg_long(src);
#else
      KAFFEVM_ABORT();
#endif
}

/* ----------------------------------------------------------------------- */
/* Labels.                                               */
/*                                                       */

label*
reference_label(int32 i UNUSED, int32 n)
{
      label* l;

      assert(n < MAXLABTAB);
      if (labtab[n] == 0) {
            l = KaffeJIT3_newLabel();
            labtab[n] = l;
            l->type = Lnull;
            l->at = 0;
            l->from = 0;
            l->to = 0;
      }
      else {
            l = labtab[n];
            labtab[n] = NULL;
      }
      return (l);
}

label*
reference_code_label(uintp offset)
{
      label* l = KaffeJIT3_newLabel();
      l->at = 0;        /* Where is the jump */
      l->to = offset;         /* What place does it goto */
      l->from = 0;
      l->type = Lcode;
      return (l);
}

label*
reference_table_label(int32 n)
{
      label* l;

      assert(n < MAXLABTAB);
      if (labtab[n] == 0) {
            l = KaffeJIT3_newLabel();
            labtab[n] = l;
            l->type = Lnull;
            l->at = 0;
            l->from = 0;
            l->to = 0;
      }
      else {
            l = labtab[n];
            labtab[n] = NULL;
      }
      return (l);
}

SlotInfo*
stored_code_label(SlotInfo* dst)
{
      return (dst);
}

SlotInfo*
table_code_label(SlotInfo* dst)
{
      return (dst);
}

#if defined(HAVE_set_label)
void
set_label(int i UNUSED, int n)
{
      assert(n < MAXLABTAB);
      if (labtab[n] == 0) {
            labtab[n] = KaffeJIT3_newLabel();
            labtab[n]->type = Linternal;
            labtab[n]->at = 0;
            labtab[n]->from = 0;
            labtab[n]->to = 0;
            slot_slot_const(NULL, NULL, (jword)labtab[n], HAVE_set_label, Tnull);
      }
      else {
            assert(labtab[n]->type == Lnull);
            labtab[n]->type = Linternal;
            slot_slot_const(NULL, NULL, (jword)labtab[n], HAVE_set_label, Tnull);
            labtab[n] = NULL;
      }
}
#endif

#if defined(HAVE_build_code_ref)
label*
build_code_ref(uint8* pos, uintp _pc)
{
      label* l;
      jint offset;

      offset = (pos[0] * 0x01000000 + pos[1] * 0x00010000 +
              pos[2] * 0x00000100 + pos[3] * 0x00000001);
      l = reference_code_label(_pc+offset);

      slot_slot_const(NULL, NULL, (jword)l, HAVE_build_code_ref, Tnull);
      return (l);
}
#endif

#if defined(HAVE_build_key)
void
build_key(uint8* pos)
{
      jint val = (pos[0] * 0x01000000 + pos[1] * 0x00010000 +
                pos[2] * 0x00000100 + pos[3] * 0x00000001);

      slot_slot_const(NULL, NULL, val, HAVE_build_key, Tnull);
}
#endif


/* ----------------------------------------------------------------------- */
/* Comparisons.                                                */
/*                                                       */

#if defined(HAVE_cmp_int)
void
_cmp_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
      slot_slot_slot(dst, src, src2, HAVE_cmp_int, Tcomplex);
}

void
cmp_int_const(SlotInfo* dst, SlotInfo* src, jint val)
{
#if defined(HAVE_cmp_int_const)
      if (HAVE_cmp_int_const_rangecheck(val)) {
            slot_slot_const(dst, src, val, HAVE_cmp_int_const, Tcomplex);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_int_const(tmp, val);
            _cmp_int(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

void
cmp_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_cmp_int_const)
      if (slot_type(src2) == Tconst) {
            cmp_int_const(dst, src, slot_value(src2)->i);
      }
      else
#endif
      _cmp_int(dst, src, src2);
}
#endif

void
cmp_offset_int(SlotInfo* dst, SlotInfo* src, SlotInfo* src2, jint off)
{
#if defined(HAVE_cmp_offset_int)
      slot_slot_slot_const_const(dst, src, src2, off, 0, HAVE_cmp_offset_int, Tcomplex);
#elif defined(HAVE_cmpl_int)
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      load_offset_int(tmp, src2, off);
      slot_slot_slot(dst, src, tmp, HAVE_cmpl_int, Tcomplex);
      slot_freetmp(tmp);
#elif defined(HAVE_cmp_int)
      SlotInfo* tmp;
      slot_alloctmp(tmp);
      load_offset_int(tmp, src2, off);
      cmp_int(dst, src, tmp);
      slot_freetmp(tmp);
#else
      KAFFEVM_ABORT();
#endif
}

#if defined(HAVE_cmp_ref)
void
cmp_ref_const(SlotInfo* dst, SlotInfo* src, void* val)
{
#if defined(HAVE_cmp_ref_const)
      if (HAVE_cmp_ref_const_rangecheck((jword)val)) {
            slot_slot_const(dst, src, (jword)val, HAVE_cmp_ref_const, Tcomplex);
      }
      else
#endif
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            move_ref_const(tmp, val);
            cmp_ref(dst, src, tmp);
            slot_freetmp(tmp);
      }
}

void
cmp_ref(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_cmp_ref_const)
      /* Note: This optimization assumes that we only ever check pointer
       * equality.
       */
      if (slot_type(src2) == Tconst) {
            cmp_ref_const(dst, src, slot_value(src2)->l);
      }
      else if (slot_type(src) == Tconst) {
            cmp_ref_const(dst, src2, slot_value(src)->l);
      }
      else
#endif
      slot_slot_slot(dst, src, src2, HAVE_cmp_ref, Tcomplex);
}
#endif

void
lcmp(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_lcmp)
      slot_lslot_lslot(dst, src, src2, HAVE_lcmp, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_long(src, 0);
      pusharg_long(src2, pusharg_long_idx_inc);
#else
      pusharg_long(src2, pusharg_long_idx_inc);
      pusharg_long(src, 0);
#endif
      call_soft(soft_lcmp);
      popargs();
      end_func_sync();
      return_int(dst);
#endif
}

void
cmpl_float(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_cmpl_float)
      slot_slot_slot(dst, src, src2, HAVE_cmpl_float, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_float(src, 0);
      pusharg_float(src2, 1);
#else
      pusharg_float(src2, 1);
      pusharg_float(src, 0);
#endif
      call_soft(soft_fcmpl);
      popargs();
      end_func_sync();
      return_int(dst);
#endif
}

void
cmpl_double(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_cmpl_double)
      slot_lslot_lslot(dst, src, src2, HAVE_cmpl_double, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_double(src, 0);
      pusharg_double(src2, pusharg_long_idx_inc);
#else
      pusharg_double(src2, pusharg_long_idx_inc);
      pusharg_double(src, 0);
#endif
      call_soft(soft_dcmpl);
      popargs();
      end_func_sync();
      return_int(dst);
#endif
}

void
cmpg_float(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_cmpg_float)
      slot_slot_slot(dst, src, src2, HAVE_cmpg_float, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_float(src, 0);
      pusharg_float(src2, 1);
#else
      pusharg_float(src2, 1);
      pusharg_float(src, 0);
#endif
      call_soft(soft_fcmpg);
      popargs();
      end_func_sync();
      return_int(dst);
#endif
}

void
cmpg_double(SlotInfo* dst, SlotInfo* src, SlotInfo* src2)
{
#if defined(HAVE_cmpg_double)
      slot_lslot_lslot(dst, src, src2, HAVE_cmpg_double, Tcomplex);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_double(src, 0);
      pusharg_double(src2, pusharg_long_idx_inc);
#else
      pusharg_double(src2, pusharg_long_idx_inc);
      pusharg_double(src, 0);
#endif
      call_soft(soft_dcmpg);
      popargs();
      end_func_sync();
      return_int(dst);
#endif
}

/* ----------------------------------------------------------------------- */
/* Conversions.                                                */
/*                                                       */

void
cvt_int_long(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_cvt_int_long)
      lslot_lslot_slot(dst, 0, src, HAVE_cvt_int_long, Tcomplex);
#else
      move_int(LSLOT(dst), src);
      ashr_int_const(HSLOT(dst), src, (8 * sizeof(jint)) - 1);
#endif
}

void
cvt_int_float(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_cvt_int_float)
      slot_slot_slot(dst, NULL, src, HAVE_cvt_int_float, Tcomplex);
#else
      begin_func_sync();
      pusharg_int(src, NULL);
      call_soft(soft_cvtif);
      popargs();
      end_func_sync();
      return_float(dst);
#endif
}

void
cvt_int_double(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_cvt_int_double)
      lslot_lslot_slot(dst, NULL, src, HAVE_cvt_int_double, Tcomplex);
#else
      begin_func_sync();
      pusharg_int(src, NULL);
      call_soft(soft_cvtid);
      popargs();
      end_func_sync();
      return_double(dst);
#endif
}

void
cvt_long_int(SlotInfo* dst, SlotInfo* src)
{
      move_int(dst, LSLOT(src));
}

void
cvt_long_float(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_cvt_long_float)
      slot_slot_lslot(dst, 0, src, HAVE_cvt_long_float, Tcomplex);
#else
      begin_func_sync();
      pusharg_long(src, 0);
      call_soft(soft_cvtlf);
      popargs();
      end_func_sync();
      return_float(dst);
#endif
}

void
cvt_long_double(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_cvt_long_double)
      lslot_lslot_lslot(dst, 0, src, HAVE_cvt_long_double, Tcomplex);
#else
      begin_func_sync();
      pusharg_long(src, 0);
      call_soft(soft_cvtld);
      popargs();
      end_func_sync();
      return_double(dst);
#endif
}

void
cvt_float_int(SlotInfo* dst, SlotInfo* src)
{
      used_ieee_rounding = true;
#if defined(HAVE_cvt_float_int)
      slot_slot_slot(dst, 0, src, HAVE_cvt_float_int, Tcomplex);
#elif defined(HAVE_cvt_float_int_ieee)
      {
        SlotInfo *tmp;
        
        slot_alloctmp(tmp);

        end_sub_block();
        and_int_const(tmp, src, FEXPMASK);
        cbranch_int_const_ne(tmp, FEXPMASK, reference_label(1, 1));
        
        and_int_const(tmp, src, FMANMASK);
        cbranch_int_const_eq(tmp, 0, reference_label(1, 2));

          start_sub_block();
        move_int_const(dst, 0);
        end_sub_block();
        branch_a(reference_label(1, 3));

        set_label(1, 1);
        set_label(1, 2);
        start_sub_block();
        slot_slot_lslot(dst, 0, src, HAVE_cvt_float_int_ieee, Tcomplex);
        end_sub_block();

        set_label(1, 3);

        start_sub_block();

        slot_freetmp(tmp);
      }
#else
      begin_func_sync();
      pusharg_float(src, 0);
      call_soft(soft_cvtfi);
      popargs();
      end_func_sync();
      return_int(dst);
#endif
}

void
cvt_float_long(SlotInfo* dst, SlotInfo* src)
{
      used_ieee_rounding = true;
#if defined(HAVE_cvt_float_long)
      lslot_lslot_slot(dst, 0, src, HAVE_cvt_float_long, Tcomplex);
#else
      begin_func_sync();
      pusharg_float(src, 0);
      call_soft(soft_cvtfl);
      popargs();
      end_func_sync();
      return_long(dst);
#endif
}

void
cvt_float_double(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_cvt_float_double)
      lslot_lslot_slot(dst, NULL, src, HAVE_cvt_float_double, Tcomplex);
#else
      begin_func_sync();
      pusharg_float(src, 0);
      call_soft(soft_cvtfd);
      popargs();
      end_func_sync();
      return_double(dst);
#endif
}

void
cvt_double_int(SlotInfo* dst, SlotInfo* src)
{
      used_ieee_rounding = true;
#if defined(HAVE_cvt_double_int)
      slot_slot_lslot(dst, NULL, src, HAVE_cvt_double_int, Tcomplex);
#elif defined(HAVE_cvt_double_int_ieee)
      {
        SlotInfo *tmp;

        end_sub_block();
        slot_alloc2tmp(tmp);

        and_long_const(tmp, src, DEXPMASK);
        cbranch_int_const_ne(LSLOT(tmp), (jint)(DEXPMASK & 0xffffffff), reference_label(1, 1));
        cbranch_int_const_ne(HSLOT(tmp), (jint)((DEXPMASK >> 32) & 0xffffffff), reference_label(1, 2));
        
        and_long_const(tmp, src, DMANMASK);
        cbranch_int_const_ne(LSLOT(tmp), 0, reference_label(1, 3));
        cbranch_int_const_eq(HSLOT(tmp), 0, reference_label(1, 4));

        set_label(1, 3);
        start_sub_block();
        move_int_const(dst, 0);
        end_sub_block();
        branch_a(reference_label(1, 5));

        set_label(1, 4);
        set_label(1, 1);
        set_label(1, 2);
        start_sub_block();
        slot_slot_lslot(dst, 0, src, HAVE_cvt_double_int_ieee, Tcomplex);
        end_sub_block();

        set_label(1, 5);
        slot_free2tmp(tmp);
        start_sub_block();
      }
#else
      begin_func_sync();
      pusharg_double(src, 0);
      call_soft(soft_cvtdi);
      popargs();
      end_func_sync();
      return_int(dst);
#endif
}

void
cvt_double_long(SlotInfo* dst, SlotInfo* src)
{
      used_ieee_rounding = true;
#if defined(HAVE_cvt_double_long)
      lslot_lslot_lslot(dst, 0, src, HAVE_cvt_double_long, Tcomplex);
#else
      begin_func_sync();
      pusharg_double(src, 0);
      call_soft(soft_cvtdl);
      popargs();
      end_func_sync();
      return_long(dst);
#endif
}

void
cvt_double_float(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_cvt_double_float)
      slot_slot_lslot(dst, NULL, src, HAVE_cvt_double_float, Tcomplex);
#else
      begin_func_sync();
      pusharg_double(src, 0);
      call_soft(soft_cvtdf);
      popargs();
      end_func_sync();
      return_float(dst);
#endif
}

void
cvt_int_byte(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_cvt_int_byte)
      slot_slot_slot(dst, NULL, src, HAVE_cvt_int_byte, Tcomplex);
#else
      lshl_int_const(dst, src, 8 * (sizeof(jint) - sizeof(jbyte)));
      ashr_int_const(dst, dst, 8 * (sizeof(jint) - sizeof(jbyte)));
#endif
}

void
cvt_int_char(SlotInfo* dst, SlotInfo* src)
{
      and_int_const(dst, src, (1 << (8 * sizeof(jchar))) - 1);
}

void
cvt_int_short(SlotInfo* dst, SlotInfo* src)
{
#if defined(HAVE_cvt_int_short)
      slot_slot_slot(dst, 0, src, HAVE_cvt_int_short, Tcomplex);
#else
      lshl_int_const(dst, src, 8 * (sizeof(jint) - sizeof(jshort)));
      ashr_int_const(dst, dst, 8 * (sizeof(jint) - sizeof(jshort)));
#endif
}



/* ----------------------------------------------------------------------- */
/* Breakpoints.                                                */
/*                                                       */

void
softcall_breakpoint(void)
{
      KAFFEVM_ABORT();
}

/* ----------------------------------------------------------------------- */
/* Build call frame.                                           */
/*                                                       */

void
build_call_frame(Utf8Const* sig, SlotInfo* obj, int sp_idx)
{
      struct pusharg_info {
            char type;
            uint16 arg_idx;
            uint16 sp_idx;
      };
      static struct pusharg_info* args;
      static int sz_args = 0;
      int arg_idx;
      int idx;
      int limit;
      const char* sigptr;

      /* Make sure we have enough argument space */
      if (sp_idx + 2 > sz_args) {
            sz_args = sp_idx + 2;

            args = gc_realloc(args,
                          sizeof(struct pusharg_info) * sz_args,
                          KGC_ALLOC_JIT_ARGS);
            if( !args )
            {
                  /* XXX We should be a little more graceful */
                  KAFFEVM_ABORT();
            }
      }

      /* If we've got an object ... */
      idx = 0;
      if (obj != 0) {
            args[idx].type = 'O';
            args[idx].arg_idx = idx;
            args[idx].sp_idx = sp_idx;
            idx++;
      }
      sp_idx--;
      arg_idx = idx;

      sigptr = sig->data;
      assert(sigptr[0] == '(');
      for (sigptr++; *sigptr != ')'; sigptr++) {

            args[idx].arg_idx = arg_idx;
            args[idx].sp_idx = sp_idx;
            args[idx].type = *sigptr;

            switch (*sigptr) {
            case '[':
                  while (*++sigptr == '[')
                        ;
                  if (*sigptr == 'L') {
                        sigptr = strchr(sigptr, ';');
                  }
                  break;

            case 'L':
                  sigptr = strchr(sigptr, ';');
                  break;

            case 'I':
            case 'Z':
            case 'S':
            case 'B':
            case 'C':
            case 'F':
                  break;

            case 'J':
            case 'D':
                  sp_idx--;
                  args[idx].sp_idx = sp_idx;
                  arg_idx += pusharg_long_idx_inc - 1;
                  break;

            case 'V':
            default:
                  KAFFEVM_ABORT();
            }

            sp_idx--;
            arg_idx++;
            idx++;
      }

#if defined(STACK_LIMIT)
      args[idx].type = 'K';
      args[idx].arg_idx = arg_idx;
      args[idx].sp_idx = sp_idx;
      idx++;
#endif

      limit = idx;

#if defined(PUSHARG_FORWARDS)
      for (idx = 0; idx < limit; idx++) {
#else
      for (idx = limit-1; idx >= 0; idx--) {
#endif
            sp_idx = args[idx].sp_idx;
            arg_idx = args[idx].arg_idx;
            switch (args[idx].type) {
            case 'L':
            case '[':
                  pusharg_ref(stack(sp_idx), arg_idx);
                  break;
            case 'O':
                  /* Special: object we've invoking on */
                  pusharg_ref(obj, arg_idx);
                  break;
#if defined(STACK_LIMIT)
            case 'K':
                  /* Special: push stack limit */
                  pusharg_ref(stack_limit, arg_idx);
                  break;
#endif
            case 'I':
            case 'Z':
            case 'S':
            case 'B':
            case 'C':
                  pusharg_int(stack(sp_idx), arg_idx);
                  break;
            case 'J':
                  pusharg_long(stack_long(sp_idx), arg_idx);
                  break;
            case 'F':
                  pusharg_float(stack_float(sp_idx), arg_idx);
                  break;
            case 'D':
                  pusharg_double(stack_double(sp_idx), arg_idx);
                  break;
            default:
                  break;
            }
      }
}

/* ----------------------------------------------------------------------- */
/* Soft calls.                                                 */
/*                                                       */

#if 0
void
/* Custom edition */ softcall_lookupmethod(SlotInfo* dst, Method* meth, SlotInfo* obj)
{
      /* 'obj' must be written back since it will be reused */
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_ref(obj, 0);
      pusharg_utf8_const(meth->name, 1);
      pusharg_utf8_const(meth->sig, 2);
#else
      pusharg_utf8_const(meth->sig, 2);
      pusharg_utf8_const(meth->name, 1);
      pusharg_ref(obj, 0);
#endif
      /* Custom edition */ call_soft(soft_lookupmethod);
      popargs();
      end_func_sync();
      return_ref(dst);
}
#endif

void
softcall_lookupinterfacemethod(SlotInfo* dst, Method* meth, SlotInfo* obj)
{
      /* 'obj' must be written back since it will be reused */
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
        pusharg_ref(obj, 0);
        pusharg_class_const(meth->class, 1);
        pusharg_ref_const((void*)(int)meth->idx, 2);
#else
        pusharg_ref_const((void*)(int)meth->idx, 2);
        pusharg_class_const(meth->class, 1);
        pusharg_ref(obj, 0);
#endif
      call_soft(soft_lookupinterfacemethod);
      popargs();
      end_func_sync();
      return_ref(dst);
}

void
check_array_index(SlotInfo* obj, SlotInfo* idx)
{
      if (noArrayBoundsChecks != 0) {
            return;
      }
#if defined(HAVE_ccall)
      {
            SlotInfo* tmp;
            slot_alloctmp(tmp);
            load_offset_int(tmp, obj, object_array_length);
            ccall_soft_int_ugt(tmp, idx, soft_badarrayindex);
            slot_freetmp(tmp);
      }
#else
#if defined(HAVE_fakecall) || defined(HAVE_fakecall_constpool)
      if (!canCatch(BADARRAYINDEX)) {
            cbranch_offset_int(idx, obj, object_array_length, newFakeCall(soft_badarrayindex, pc), buge | blink);
      }
      else
#endif
      {
            end_sub_block();
            cbranch_offset_int_ult(idx, obj, object_array_length, reference_label(1, 1));
            call_soft(soft_badarrayindex);
            start_sub_block();
            set_label(1, 1);
      }
#endif
}

void
check_array_store(SlotInfo* array, SlotInfo* obj)
{
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_ref(array, 0);
      pusharg_ref(obj, 1);
#else
      pusharg_ref(obj, 1);
      pusharg_ref(array, 0);
#endif
      call_soft(soft_checkarraystore);
      popargs();
      end_func_sync();
}

void
explicit_check_null(int x, SlotInfo* obj, int y)
{
#if 0
#if defined(HAVE_fakecall) || defined(HAVE_fakecall_constpool)
      if (!canCatch(ANY)) {
            cbranch_ref_const(obj, 0, newFakeCall(soft_nullpointer, pc), eq | blink);
      }
      else
#endif
#endif
      {
            end_sub_block();
            cbranch_ref_const_ne(obj, NULL, reference_label(x, y));
            softcall_nullpointer();
            start_sub_block();
            set_label(x, y);
      }
}

#if defined(CREATE_NULLPOINTER_CHECKS)
void
check_null(int x, SlotInfo* obj, int y)
{
      explicit_check_null(x, obj, y);
}
#else
void
check_null(int x UNUSED, SlotInfo* obj UNUSED, int y UNUSED)
{
      if (canCatch(ANY)) {
            begin_func_sync();
            end_func_sync();
      }
}
#endif

#if defined(CREATE_DIVZERO_CHECKS)
void
check_div(int x, SlotInfo* obj, int y)
{
#if defined(HAVE_fakecall) || defined(HAVE_fakecall_constpool)
      if (!canCatch(ANY)) {
            cbranch_int_const(obj, 0, newFakeCall(soft_divzero, pc), beq | blink);
      }
      else
#endif
      {
            end_sub_block();
            cbranch_int_const_ne(obj, 0, reference_label(x, y));
            softcall_divzero();
            start_sub_block();
            set_label(x, y);
      }
}
#else
void
check_div(int x UNUSED, SlotInfo* obj UNUSED, int y UNUSED)
{
      if (canCatch(ANY)) {
            begin_func_sync();
            end_func_sync();
      }
}
#endif

#if defined(CREATE_DIVZERO_CHECKS)
void
check_div_long(int x, SlotInfo* obj, int y)
{
#if 0
      THE CODE BELOW DOES NOT WORK - !!! FIX ME !!!
#if defined(HAVE_fakecall) || defined(HAVE_fakecall_constpool)
      if (!canCatch(ANY)) {
            cbranch_int_const(LSLOT(obj), 0, newFakeCall(soft_divzero, pc), eq | blink);
            cbranch_int_const(HSLOT(obj), 0, newFakeCall(soft_divzero, pc), eq | blink);
      }
      else
#endif
#endif
      {
            end_sub_block();
            cbranch_int_const_ne(LSLOT(obj), 0, reference_label(x, y+0));
            cbranch_int_const_ne(HSLOT(obj), 0, reference_label(x, y+1));
            softcall_divzero();
            start_sub_block();
            set_label(x, y+1);
            set_label(x, y+0);
      }
}
#else
void
check_div_long(int x UNUSED, SlotInfo* obj UNUSED, int y UNUSED)
{
      if (canCatch(ANY)) {
            begin_sync();
            end_sync();
      }
}
#endif

#if defined(HAVE_ccall)
void
ccall_ugt(SlotInfo* dst)
{
      slot_slot_const(0, dst, bugt, HAVE_ccall, Tnull);
}

void
ccall_soft_ugt(void* routine)
{
      label* l;
      constpool* c;
      SlotInfo* tmp;

      l = KaffeJIT3_newLabel();
      c = KaffeJIT3_newConstant(CPref, routine);
      l->type = Lconstant;
      l->at = 0;
      l->to = (uintp)c;
      l->from = 0;

      slot_alloctmp(tmp);
#if defined(HAVE_load_constpool_ref)
      slot_slot_const(tmp, 0, (jword)l, HAVE_load_constpool_ref, Tnull);
#else
      move_label_const(tmp, l);
      load_ref(tmp, tmp);
#endif
      ccall(tmp);
      slot_freetmp(tmp);
}

void
ccall_soft_int_ugt(SlotInfo* s1, SlotInfo* s2, void* func)
{
      cmp_int(0, s1, s2);
      ccall_soft_ugt(func);
}

void
ccall_int_const_ugt(SlotInfo* s1, jint s2, void* func)
{
      cmp_int_const(0, s1, s2);
      ccall_ugt(func);
}
#endif

void
softcall_nullpointer(void)
{
      if (canCatch(ANY)) {
            begin_func_sync();
            end_func_sync();
      }
      call_soft(soft_nullpointer);
}

void
softcall_divzero(void)
{
      if (canCatch(ANY)) {
            begin_func_sync();
            end_func_sync();
      }
      call_soft(soft_divzero);
}

void
softcall_fakecall(label* from, label* to, void* func)
{
#if defined(HAVE_fakecall_constpool)
      label* l;
      constpool* c;

      /* Set the label for getting here */
      slot_slot_const(NULL, NULL, (jword)to, HAVE_set_label, Tnull);

      /* We must put our 'from' in a constant.  We use the 'from' as
       * the constant value so it won't be aliases with others.
       */
      c = KaffeJIT3_newConstant(CPlabel, from);
      from->type |= Lconstantpool|Labsolute|Llong;
      from->at = (uintp)c;

      from = KaffeJIT3_newLabel();
      from->type = Lconstant;
      from->at = 0;
      from->to = (uintp)c;
      from->from = 0;

      /* Build a label to hold the fake call */
      l = KaffeJIT3_newLabel();
      c = KaffeJIT3_newConstant(CPref, func);
      l->type = Lconstant;
      l->at = 0;
      l->to = (uintp)c;
      l->from = 0;

      /* Make the fake call - passing the call label and the label we
       * got here from.
       */
      slot_const_const(NULL, (jword)from, (jword)l, HAVE_fakecall_constpool, Tnull);
#elif defined(HAVE_fakecall)
      label* l;

      /* Set the label for getting here */
      slot_slot_const(NULL, NULL, (jword)to, HAVE_set_label, Tnull);

      /* Build a label to hold the fake call */
      l = KaffeJIT3_newLabel();
      l->type = Lexternal;
      l->at = 0;
      l->to = (uintp)func;
      l->from = 0;

      /* Make the fake call - passing the call label and the label we
       * got here from.
       */
      slot_const_const(NULL, (jword)from, (jword)l, HAVE_fakecall, Tnull);
#endif
}

void
softcall_nosuchclass(Utf8Const* name)
{
      begin_func_sync();
      pusharg_utf8_const(name, 0);
      call_soft(soft_nosuchclass);
      popargs_noreturn();
      end_func_sync();
}

void
softcall_nosuchmethod(struct Hjava_lang_Class* cls, Utf8Const* name, Utf8Const* sig)
{
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_class_const(cls, 0);
      pusharg_utf8_const(name, 1);
      pusharg_utf8_const(sig, 2);
#else
      pusharg_utf8_const(sig, 2);
      pusharg_utf8_const(name, 1);
      pusharg_class_const(cls, 0);
#endif
      call_soft(soft_nosuchmethod);
      popargs_noreturn();
      end_func_sync();
}

void
softcall_nosuchfield(Utf8Const* cls, Utf8Const* name)
{
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_utf8_const(cls, 0);
      pusharg_utf8_const(name, 1);
#else
      pusharg_utf8_const(name, 1);
      pusharg_utf8_const(cls, 0);
#endif
      call_soft(soft_nosuchfield);
      popargs_noreturn();
      end_func_sync();
}

void
softcall_linkage(Utf8Const* cls, Utf8Const* name)
{
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_utf8_const(cls, 0);
      pusharg_utf8_const(name, 1);
#else
      pusharg_utf8_const(name, 1);
      pusharg_utf8_const(cls, 0);
#endif
      call_soft(soft_linkage);
      popargs_noreturn();
      end_func_sync();
}

void
softcall_illegalaccess(Utf8Const* cls, Utf8Const* name)
{
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_utf8_const(cls, 0);
      pusharg_utf8_const(name, 1);
#else
      pusharg_utf8_const(name, 1);
      pusharg_utf8_const(cls, 0);
#endif
      call_soft(soft_illegalaccess);
      popargs_noreturn();
      end_func_sync();
}

void
softcall_incompatibleclasschange(Utf8Const* cls, Utf8Const* name)
{
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_utf8_const(cls, 0);
      pusharg_utf8_const(name, 1);
#else
      pusharg_utf8_const(name, 1);
      pusharg_utf8_const(cls, 0);
#endif
      call_soft(soft_incompatibleclasschange);
      popargs_noreturn();
      end_func_sync();
}

void
softcall_abstractmethod(Utf8Const* cls, Utf8Const* name)
{
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_utf8_const(cls, 0);
      pusharg_utf8_const(name, 1);
#else
      pusharg_utf8_const(name, 1);
      pusharg_utf8_const(cls, 0);
#endif
      call_soft(soft_abstractmethod);
      popargs_noreturn();
      end_func_sync();
}

void
softcall_new(SlotInfo* dst, Hjava_lang_Class* classobj)
{
      begin_func_sync();
      pusharg_class_const(classobj, 0);
      call_soft(soft_new);
      popargs();
      end_func_sync();
      return_ref(dst);
}

void
softcall_newarray(SlotInfo* dst, SlotInfo* size, int type)
{
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_int_const(type, 0);
      pusharg_int(size, 1);
#else
      pusharg_int(size, 1);
      pusharg_int_const(type, 0);
#endif
      call_soft(soft_newarray);
      popargs();
      pop(1);
      end_func_sync();
      push(1);
      return_ref(dst);
}

void
softcall_anewarray(SlotInfo* dst, SlotInfo* size, Hjava_lang_Class* type)
{
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_class_const(type, 0);
      pusharg_int(size, 1);
#else
      pusharg_int(size, 1);
      pusharg_class_const(type, 0);
#endif
      call_soft(soft_anewarray);
      popargs();
      pop(1);
      end_func_sync();
      push(1);
      return_ref(dst);
}

void
softcall_multianewarray(SlotInfo* dst, int size, SlotInfo* stktop, Hjava_lang_Class* classobj)
{
      int i;

      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_class_const(classobj, 0);
      pusharg_int_const(size, 1);
      for (i = size - 1; i >= 0; i--) {
            pusharg_int(&stktop[i], 1+size-i);
      }
#else
      for (i = 0; i < size; i++) {
            pusharg_int(&stktop[i], 1+size-i);
      }
      pusharg_int_const(size, 1);
      pusharg_class_const(classobj, 0);
#endif
      call_soft(jit_soft_multianewarray);
      popargs();
      pop(size);
      end_func_sync();
      push(1);
      return_ref(dst);
}

void
softcall_athrow(SlotInfo* obj)
{
      begin_func_sync();
      pusharg_ref(obj, 0);
      call_soft(soft_athrow);
      popargs_noreturn();
      end_func_sync();
}

void
softcall_checkcast(SlotInfo* objw, SlotInfo* objr, Hjava_lang_Class* class)
{
      /* Must keep 'obj' */
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_class_const(class, 0);
      pusharg_ref(objr, 1);
#else
      pusharg_ref(objr, 1);
      pusharg_class_const(class, 0);
#endif
      call_soft(soft_checkcast);
      popargs();
      end_func_sync();
      return_ref(objw);
}

void
softcall_instanceof(SlotInfo* dst, SlotInfo* obj, Hjava_lang_Class* class)
{
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_class_const(class, 0);
      pusharg_ref(obj, 1);
#else
      pusharg_ref(obj, 1);
      pusharg_class_const(class, 0);
#endif
      call_soft(soft_instanceof);
      popargs();
      pop(1);
      end_func_sync();
      push(1);
      return_int(dst);
}

void
softcall_initialise_class(Hjava_lang_Class* c)
{
      if (c != 0 && c->state != CSTATE_COMPLETE) {
            begin_func_sync();
            pusharg_class_const(c, 0);
            call_soft(soft_initialise_class);
            popargs();
            end_func_sync();
      }
}

void
softcall_debug1(void* a0, void* a1, void* a2)
{
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_ref_const(a0, 0);
      pusharg_ref_const(a1, 1);
      pusharg_ref_const(a2, 2);
#else
      pusharg_ref_const(a2, 2);
      pusharg_ref_const(a1, 1);
      pusharg_ref_const(a0, 0);
#endif
      call_soft(soft_debug1);
      popargs();
      end_func_sync();
}

void
softcall_debug2(void* a0, void* a1, void* a2)
{
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_ref_const(a0, 0);
      pusharg_ref_const(a1, 1);
      pusharg_ref_const(a2, 2);
#else
      pusharg_ref_const(a2, 2);
      pusharg_ref_const(a1, 1);
      pusharg_ref_const(a0, 0);
#endif
      call_soft(soft_debug2);
      popargs();
      end_func_sync();
}

void
softcall_trace(Method* meth)
{
#if defined(HAVE_get_arg_ptr)
        SlotInfo* tmp;

        slot_alloctmp(tmp);
        get_arg_ptr(tmp);
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
        pusharg_ref_const(meth, 0);
        pusharg_ref(tmp, 1);
#else
        pusharg_ref(tmp, 1);
        pusharg_ref_const(meth, 0);
#endif
        call_soft(soft_trace);
        popargs();
      end_func_sync();
        slot_freetmp(tmp);
#else
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_ref_const(meth, 0);
        pusharg_ref_const(0, 1);
#else
        pusharg_ref_const(0, 1);
      pusharg_ref_const(meth, 0);
#endif
      call_soft(soft_trace);
      popargs();
      end_func_sync();
#endif
}

void
softcall_enter_method(SlotInfo *obj, Method* meth)
{
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_ref(obj, 0);
        pusharg_ref_const(meth, 1);
#else
        pusharg_ref_const(meth, 1);
      pusharg_ref(obj, 0);
#endif
      call_soft(soft_enter_method);
      popargs();
      end_func_sync();
}

void
softcall_exit_method(Method* meth)
{
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_ref_const(meth, 0);
#else
      pusharg_ref_const(meth, 0);
#endif
      call_soft(soft_exit_method);
      popargs();
      end_func_sync();
}

#if defined(KGC_INCREMENTAL)
#if defined(KGC_INCREMENTAL)
void
softcall_writeref(SlotInfo* from, SlotInfo* to)
{
      end_sub_block();

      cbranch_int_const_eq(to, 0, reference_label(1, 1));
      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_ref(from, 0);
      pusharg_ref(to, 1);
#else
      pusharg_ref(to, 1);
      pusharg_ref(from, 0);
#endif
      call_soft(gcWriteRef);
      popargs();
      end_func_sync();

      start_sub_block();
        set_label(1, 1);
}

void
softcall_writeref_static(void* from, SlotInfo* to)
{
      end_sub_block();
      cbranch_int_const_eq(to, 0, reference_label(1, 1));

      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_ref_const(from, 0);
      pusharg_ref(to, 1);
#else
      pusharg_ref(to, 1);
      pusharg_ref_const(from, 0);
#endif
      call_soft(gcWriteRef);
      popargs();
      end_func_sync();

      start_sub_block();
        set_label(1, 1);
}

#else
/* Smarter write barriers to save calls.
 * Benchmarking suggests this may not be that useful.
 */
void
softcall_writeref(SlotInfo* from, SlotInfo* to)
{
      SlotInfo* tmp1;

      end_sub_block();
      cbranch_int_const_eq(to, 0, reference_label(1, 2));
      slot_alloctmp(tmp1);
      load_offset_int(tmp1, from, object_gc_color);
      cbranch_int_const_ne(tmp1, COLOR_BLACK, reference_label(1, 1));
        slot_freetmp(tmp1);

      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_ref(from, 0);
      pusharg_ref(to, 1);
#else
      pusharg_ref(to, 1);
      pusharg_ref(from, 0);
#endif
      call_soft(gcWriteRef);
      popargs();
      end_func_sync();

      start_sub_block();
        set_label(1, 1);
      set_label(1, 2);
}

void
softcall_writeref_static(void* from, SlotInfo* to)
{
      SlotInfo* tmp1,*tmp2;

      slot_alloctmp(tmp1);

      end_sub_block();
      cbranch_int_const_eq(to, 0, reference_label(1, 2));
      load_addr_int(tmp1, (void*)((uintp)from + object_gc_color));
      cbranch_int_const_ne(tmp1, COLOR_BLACK, reference_label(1, 1));
        slot_freetmp(tmp1);

      begin_func_sync();
#if defined(PUSHARG_FORWARDS)
      pusharg_ref_const(from, 0);
      pusharg_ref(to, 1);
#else
      pusharg_ref(to, 1);
      pusharg_ref_const(from, 0);
#endif
      call_soft(gcWriteRef);
      popargs();
      end_func_sync();

      start_sub_block();
        set_label(1, 1);
      set_label(1, 2);
}
#endif
#endif

#if defined(HAVE_get_arg_ptr)
void
get_arg_ptr(SlotInfo* dst)
{
        slot_slot_slot(dst, NULL, NULL, HAVE_get_arg_ptr, Tcomplex);
}
#endif

Generated by  Doxygen 1.6.0   Back to index