<commit_before>/*********************************************************************
 *
 * Copyright (C) 2008,  <NAME>
 *
 * Filename:      javamethod.cc
 * Author:        <NAME> <<EMAIL>>
 * Description:   Java method implementation
 *
 * $Id:$
 *
 ********************************************************************/
#include <stdio.h>
#include <string.h>
#include <javamethod.hh>
#include <controller.hh>
#include <config.hh>
#include <emit.hh>

JavaMethod::JavaMethod(Function **fns,
		       int first, int last) : CodeBlock()
{
  panic_if(first > last,
           "First and last %d:%d in method constructor are invalid\n",
           first, last);

  if (fns)
    {
      this->functions = &(fns[first]);
      this->n_functions = last - first + 1;
    }
  else
    {
      this->functions = NULL;
      this->n_functions = 0;
    }

  this->javaName = NULL;
  this->n_registersToPass = 0;
  this->registerIndirectJumps = false;

  this->address = 0;
  this->size = 0;
  for (int i = 0; i < this->n_functions; i++)
    {
      /* The address is the lowest of the functions' */
      if ( this->functions[i]->getAddress() > this->address)
	this->address = this->functions[i]->getAddress();
      this->size += this->functions[i]->getSize();
    }

  memset(this->registerUsage, 0, sizeof(this->registerUsage));
  this->n_exceptionHandlers = 0;
  this->exceptionHandlers = NULL;

  this->n_returnLocations = 0;
  this->returnLocations = NULL;

  /* Fixup the bytecode size */
  this->bc_size = 0;
  for (int i = 0; i < this->n_functions; i++)
    this->bc_size += this->functions[i]->getBytecodeSize();
}

JavaMethod::~JavaMethod()
{
}

char *JavaMethod::getJavaMethodName()
{
  if ( this->javaName )
    return this->javaName;
  int n = this->n_registersToPass;

  /* THIS is soo much nicer in Python! */
  int len = strlen(this->functions[0]->getName()) + n + 8;
  this->javaName = (char*)xcalloc( len, sizeof(char));

  int o = snprintf(this->javaName, len, "%s(", this->getName());
  for (; n > 0; n--, o++)
    this->javaName[o] = 'I';
  this->javaName[o++] = ')';

  if ( config->threadSafe )
    {
      if ( this->clobbersReg(R_V0) && this->clobbersReg(R_V1) )
        this->javaName[o++] = 'J'; /* long */
      else if ( this->clobbersReg(R_V0) || this->clobbersReg(R_V1) )
        this->javaName[o++] = 'I';
      else
        this->javaName[o++] = 'V';
    }
  else
    {
      if ( this->clobbersReg(R_V0) )
        this->javaName[o++] = 'I';
      else
        this->javaName[o++] = 'V';
    }

  return this->javaName;
}

bool JavaMethod::pass1()
{
  bool out = true;
  void *it;

  for (int i = 0; i < this->n_functions; i++)
    {
      Function *fn = this->functions[i];

      if ( !fn->pass1() )
	out = false;
      if ( fn->hasRegisterIndirectJumps() )
        this->registerIndirectJumps = true;
    }

  for (int i = 0; i < this->n_functions; i++)
    {
      Function *fn = this->functions[i];

      fn->fillDestinations(this->registerUsage);
      fn->fillSources(this->registerUsage);
    }

  for (MIPS_register_t reg = this->getFirstRegisterToPass(&it); reg != R_ZERO; reg = this->getNextRegisterToPass(&it))
    this->n_registersToPass++;

  return out;
}


int JavaMethod::addReturnLocation(uint32_t address)
{
  int out = this->n_returnLocations;

  this->n_returnLocations++;
  this->returnLocations = (uint32_t*)xrealloc(this->returnLocations,
                                              this->n_returnLocations * sizeof(uint32_t*));

  this->returnLocations[out] = address;

  return out;
}

Function *JavaMethod::getFunctionByAddress(uint32_t addr)
{
  for (int i = 0; i < this->n_functions; i++)
    {
      Function *fn = this->functions[i];

      if ( addr >= fn->getAddress() && addr < fn->getAddress() + fn->getSize() )
        return fn;
    }

  return NULL;
}

void JavaMethod::emitStoreSubroutine(mips_opcode_t op)
{
}

void JavaMethod::emitLoadSubroutine(mips_opcode_t op)
{
  uint32_t and_value = 3; /* Assume byte*/
  uint32_t mask_value = 0xff;

  if (op == OP_LHU || op == OP_LH)
    {
      and_value = 2;
      mask_value = 0xffff;
    }

  /*
   * These are called with the following stack:
   *
   *          value to store (for sb/sh)
   *          address to load/store
   *   top -> return address
   */
  emit->bc_label("__CIBYL_memoryRead%s%s",
                 (op == OP_LBU || op == OP_LB) ? "Byte" : "Short",
                 (op == OP_LBU || op == OP_LHU) ? "Unsigned" : "");
  emit->bc_astore( R_MADR );

  /* The address to load is now on the top */
  emit->bc_dup();
  emit->bc_pushregister(R_MEM);
  emit->bc_swap();
  emit->bc_pushconst(2);
  emit->bc_iushr();      /* push addr >>> 2 */
  emit->bc_iaload();     /* and load the word */

  /* b = 3 - (address & 3) */
  emit->bc_swap();
  emit->bc_pushconst(and_value);
  emit->bc_iand();       /* push address & 3 */
  emit->bc_pushconst(and_value);
  emit->bc_swap();
  emit->bc_isub();       /* push 3 - (address & 3) */

  /* b = b * 8 */
  emit->bc_pushconst(3);
  emit->bc_ishl();

  /* Value now on the top, shift it down and mask it out */
  emit->bc_iushr();
  if (op == OP_LHU)
    emit->bc_i2c();
  else if (op == OP_LB)
    emit->bc_i2b(); /* Sign extension */
  else if (op == OP_LH)
    emit->bc_i2s(); /* Ditto */
  else
    {
      /* LBU */
      emit->bc_pushconst(mask_value);
      emit->bc_iand(); /* out = val >>> (b*8) */
    }

  /* Back again, now with the result on the top of the stack */
  emit->bc_ret( R_MADR );
}

void JavaMethod::emitSubroutineForOp(mips_opcode_t op)
{
  panic_if(op != OP_LB && op != OP_LBU && op != OP_LH &&
           op != OP_LHU && op != OP_SB && op != OP_SH,
           "Illegal opcode %s passed to emitLoadStoreSubroutines\n",
           mips_op_strings[op]);

  if (op == OP_LBU || op == OP_LHU || op == OP_LB || op == OP_LH)
    this->emitLoadSubroutine(op);
  else /* op == OP_SB || op == OP_SH */
    this->emitStoreSubroutine(op);
}

void JavaMethod::emitSubroutines()
{
  uint8_t is_emitted[N_INSNS];

  memset(is_emitted, 0, sizeof(is_emitted));

  /* If any of LB/LBU, LH/LHU, SB,SH, emit subroutines to handle
   * these */
  for (int i = 0; i < this->n_functions; i++)
    {
      mips_opcode_t ops_to_check[] = {OP_LB, OP_LBU, OP_LH, OP_LHU, OP_SB, OP_SH};

      for (unsigned int j = 0; j < sizeof(ops_to_check) / sizeof(mips_opcode_t); j++)
        {
          mips_opcode_t op = ops_to_check[j];

          if ( !is_emitted[op] && this->functions[i]->opcodeIsUsed(op) )
            {
              this->emitSubroutineForOp(op);
              is_emitted[op] = 1;
            }
        }
    }
}

bool JavaMethod::pass2()
{
  bool out = true;

  regalloc->setAllocation(this->registerUsage);

  emit->generic("\n.method public static %s\n"
                ".limit stack 20\n"
                ".limit locals %d\n",
                this->getJavaMethodName(),
                regalloc->getNumberOfLocals());

  /* Emit register mapping */
  for (int i = 0; i < N_REGS; i++)
    {
      if (this->registerUsage[i])
        emit->generic("; local %2d is register %s\n",
                      regalloc->regToLocal((MIPS_register_t)i),
                      mips_reg_strings[i]);
    }

  /* Zero all used registers */
  for (int i = 0; i < N_REGS; i++)
    {
      panic_if(i == R_FNA && this->registerUsage[i] > 0 && !this->hasMultipleFunctions(),
               "%s is a single-function method but uses R_FNA %d times\n",
               this->getName(), this->registerUsage[i]);

      /* These are passed as arguments, skip them */
      if (i == R_FNA || i == R_SP || i == R_A0 || i == R_A1 || i == R_A2 || i == R_A3)
        continue;

      /* If this register is used, initialize it */
      if (this->registerUsage[i] > 0)
        {
          /* Multi-function classes assign to RA */
          if (this->hasMultipleFunctions() && i == R_RA)
            emit->bc_pushconst(-1);
          else
            emit->bc_pushconst(0);
          emit->bc_popregister((MIPS_register_t)i);
        }
    }

  /* If we are configured for it, generate jsr targets for lb/lh
   * etc */
  if (config->optimizePartialMemoryOps)
    {
      emit->bc_goto("__CIBYL_javamethod_begin");
      this->emitSubroutines();
    }

  emit->bc_label("__CIBYL_javamethod_begin");

  if (this->hasMultipleFunctions())
    {
      uint32_t *table = (uint32_t*)xcalloc(this->n_functions,
                                           sizeof(uint32_t));

      /* Setup a table of functions to jump to */
      for (int i = 0; i < this->n_functions; i++)
        table[i] = this->functions[i]->getAddress();

      emit->bc_pushregister(R_FNA);
      emit->bc_tableswitch(0, this->n_functions,
                           table, "__CIBYL_function_return");

      free(table);
    }

  for (int i = 0; i < this->n_functions; i++)
    {
      Function *fn = this->functions[i];

      /* And compile the function */
      if ( !fn->pass2() )
	out = false;
    }

  if (this->registerIndirectJumps)
    {
      emit->bc_goto("__CIBYL_function_return");
      emit->bc_label("__CIBYL_local_jumptab");

      /* Emit the actual jumptab */
      emit->bc_lookupswitch(this->n_jumptabLabels, this->jumptabLabels,
                            "__CIBYL_function_return");
    }

  for (int i = 0; i < this->n_exceptionHandlers; i++)
    {
      ExceptionHandler *eh = this->exceptionHandlers[i];
      JavaClass *dstClass;
      JavaMethod *dstMethod;

      dstMethod = controller->getCallTableMethod();
      panic_if(!dstMethod,
               "No call table method???\n");
      dstClass = controller->getClassByMethodName(dstMethod->getName());
      panic_if(!dstClass,
               "No class for the call table method???\n");

      emit->bc_label("%s", eh->name);
      /* Register the object passed here */
      emit->bc_invokestatic("CRunTime/registerObject(Ljava/lang/Object;)I");
      emit->bc_pushregister(R_ECB);
      emit->bc_swap();
      /* This is just a jalr(ecb, sp, ear (exception obj)) */
      emit->bc_pushregister(R_SP);
      emit->bc_swap();
      emit->bc_pushregister(R_EAR);
      emit->bc_pushconst(0);
      emit->bc_pushconst(0);
      emit->bc_invokestatic("%s/%s", dstClass->getName(),
                            dstMethod->getJavaMethodName());
      emit->bc_pop();
      emit->bc_goto( eh->end );
    }

  emit->bc_label("__CIBYL_function_return");
  if (this->hasMultipleFunctions())
    {
      emit->bc_pushregister(R_RA);
      emit->bc_tableswitch(0, this->n_returnLocations, this->returnLocations,
                           "__CIBYL_function_return_non_local");
      emit->bc_label("__CIBYL_function_return_non_local");
    }

  if (config->threadSafe)
    {
      if (this->clobbersReg(R_V1) && this->clobbersReg(R_V0))
        {
          /* Return a 64-bit value */
          emit->bc_pushregister(R_V1);
          emit->bc_i2l();
          emit->bc_pushconst(32);
          emit->bc_lshl();
          emit->bc_pushregister(R_V0);
          emit->bc_i2l();
          emit->bc_lor(); /* push (v1 << 32) | v0 */
          emit->bc_lreturn();
        }
      else if (this->clobbersReg(R_V1)) /* Only v1 */
        {
          emit->bc_pushregister(R_V1);
          emit->bc_ireturn();
        }
      else if (this->clobbersReg(R_V0)) /* Only v0 */
        {
          emit->bc_pushregister(R_V0);
          emit->bc_ireturn();
        }
      else
        emit->bc_return();
    }
  else
    {
      /* Not thread safe */
      if (this->clobbersReg(R_V1))
        {
          emit->bc_pushregister(R_V1);
          emit->bc_putstatic("CRunTime/saved_v1 I");
        }
      if (this->clobbersReg(R_V0))
        {
          emit->bc_pushregister(R_V0);
          emit->bc_ireturn();
        }
      else
        emit->bc_return();
    }

  emit->generic(".end method ; %s\n", this->getJavaMethodName());

  return out;
}

/* R_ZERO terminates it */
static MIPS_register_t possibleArgumentRegs[] = { R_SP, R_A0, R_A1, R_A2, R_A3, R_ZERO };

MIPS_register_t JavaMethod::getFirstRegisterToPass(void *_it)
{
  int *it = (int*)_it;
  MIPS_register_t ret;

  *it = 0;

  while (possibleArgumentRegs[*it] != R_ZERO &&
	 this->clobbersReg( possibleArgumentRegs[*it] ) == 0)
      (*it)++;
  ret = possibleArgumentRegs[*it];
  (*it)++;

  return ret;
}

MIPS_register_t JavaMethod::getNextRegisterToPass(void *_it)
{
  int *it = (int*)_it;
  MIPS_register_t ret;

  while (possibleArgumentRegs[*it] != R_ZERO &&
	 this->clobbersReg( possibleArgumentRegs[*it] ) == 0)
      (*it)++;
  ret = possibleArgumentRegs[*it];
  (*it)++;
  return ret;
}

bool JavaMethod::clobbersReg(MIPS_register_t reg)
{
  return this->registerUsage[reg] > 0;
}

char *JavaMethod::addExceptionHandler(uint32_t start, uint32_t end)
{
  int n = this->n_exceptionHandlers;
  ExceptionHandler *eh;

  this->exceptionHandlers = (ExceptionHandler**)xrealloc(this->exceptionHandlers,
                                                         (n + 1) * sizeof(ExceptionHandler*) );
  this->n_exceptionHandlers = n + 1;

  eh = new ExceptionHandler(start, end);
  this->exceptionHandlers[n] = eh;

  return eh->name;
}
<commit_msg>Ouch. Missed the last addr<commit_after>/*********************************************************************
 *
 * Copyright (C) 2008,  <NAME>
 *
 * Filename:      javamethod.cc
 * Author:        <NAME> <<EMAIL>>
 * Description:   Java method implementation
 *
 * $Id:$
 *
 ********************************************************************/
#include <stdio.h>
#include <string.h>
#include <javamethod.hh>
#include <controller.hh>
#include <config.hh>
#include <emit.hh>

JavaMethod::JavaMethod(Function **fns,
		       int first, int last) : CodeBlock()
{
  panic_if(first > last,
           "First and last %d:%d in method constructor are invalid\n",
           first, last);

  if (fns)
    {
      this->functions = &(fns[first]);
      this->n_functions = last - first + 1;
    }
  else
    {
      this->functions = NULL;
      this->n_functions = 0;
    }

  this->javaName = NULL;
  this->n_registersToPass = 0;
  this->registerIndirectJumps = false;

  this->address = 0;
  this->size = 0;
  for (int i = 0; i < this->n_functions; i++)
    {
      /* The address is the lowest of the functions' */
      if ( this->functions[i]->getAddress() > this->address)
	this->address = this->functions[i]->getAddress();
      this->size += this->functions[i]->getSize();
    }

  memset(this->registerUsage, 0, sizeof(this->registerUsage));
  this->n_exceptionHandlers = 0;
  this->exceptionHandlers = NULL;

  this->n_returnLocations = 0;
  this->returnLocations = NULL;

  /* Fixup the bytecode size */
  this->bc_size = 0;
  for (int i = 0; i < this->n_functions; i++)
    this->bc_size += this->functions[i]->getBytecodeSize();
}

JavaMethod::~JavaMethod()
{
}

char *JavaMethod::getJavaMethodName()
{
  if ( this->javaName )
    return this->javaName;
  int n = this->n_registersToPass;

  /* THIS is soo much nicer in Python! */
  int len = strlen(this->functions[0]->getName()) + n + 8;
  this->javaName = (char*)xcalloc( len, sizeof(char));

  int o = snprintf(this->javaName, len, "%s(", this->getName());
  for (; n > 0; n--, o++)
    this->javaName[o] = 'I';
  this->javaName[o++] = ')';

  if ( config->threadSafe )
    {
      if ( this->clobbersReg(R_V0) && this->clobbersReg(R_V1) )
        this->javaName[o++] = 'J'; /* long */
      else if ( this->clobbersReg(R_V0) || this->clobbersReg(R_V1) )
        this->javaName[o++] = 'I';
      else
        this->javaName[o++] = 'V';
    }
  else
    {
      if ( this->clobbersReg(R_V0) )
        this->javaName[o++] = 'I';
      else
        this->javaName[o++] = 'V';
    }

  return this->javaName;
}

bool JavaMethod::pass1()
{
  bool out = true;
  void *it;

  for (int i = 0; i < this->n_functions; i++)
    {
      Function *fn = this->functions[i];

      if ( !fn->pass1() )
	out = false;
      if ( fn->hasRegisterIndirectJumps() )
        this->registerIndirectJumps = true;
    }

  for (int i = 0; i < this->n_functions; i++)
    {
      Function *fn = this->functions[i];

      fn->fillDestinations(this->registerUsage);
      fn->fillSources(this->registerUsage);
    }

  for (MIPS_register_t reg = this->getFirstRegisterToPass(&it); reg != R_ZERO; reg = this->getNextRegisterToPass(&it))
    this->n_registersToPass++;

  return out;
}


int JavaMethod::addReturnLocation(uint32_t address)
{
  int out = this->n_returnLocations;

  this->n_returnLocations++;
  this->returnLocations = (uint32_t*)xrealloc(this->returnLocations,
                                              this->n_returnLocations * sizeof(uint32_t*));

  this->returnLocations[out] = address;

  return out;
}

Function *JavaMethod::getFunctionByAddress(uint32_t addr)
{
  for (int i = 0; i < this->n_functions; i++)
    {
      Function *fn = this->functions[i];

      if ( addr >= fn->getAddress() && addr <= fn->getAddress() + fn->getSize() )
        return fn;
    }

  return NULL;
}

void JavaMethod::emitStoreSubroutine(mips_opcode_t op)
{
}

void JavaMethod::emitLoadSubroutine(mips_opcode_t op)
{
  uint32_t and_value = 3; /* Assume byte*/
  uint32_t mask_value = 0xff;

  if (op == OP_LHU || op == OP_LH)
    {
      and_value = 2;
      mask_value = 0xffff;
    }

  /*
   * These are called with the following stack:
   *
   *          value to store (for sb/sh)
   *          address to load/store
   *   top -> return address
   */
  emit->bc_label("__CIBYL_memoryRead%s%s",
                 (op == OP_LBU || op == OP_LB) ? "Byte" : "Short",
                 (op == OP_LBU || op == OP_LHU) ? "Unsigned" : "");
  emit->bc_astore( R_MADR );

  /* The address to load is now on the top */
  emit->bc_dup();
  emit->bc_pushregister(R_MEM);
  emit->bc_swap();
  emit->bc_pushconst(2);
  emit->bc_iushr();      /* push addr >>> 2 */
  emit->bc_iaload();     /* and load the word */

  /* b = 3 - (address & 3) */
  emit->bc_swap();
  emit->bc_pushconst(and_value);
  emit->bc_iand();       /* push address & 3 */
  emit->bc_pushconst(and_value);
  emit->bc_swap();
  emit->bc_isub();       /* push 3 - (address & 3) */

  /* b = b * 8 */
  emit->bc_pushconst(3);
  emit->bc_ishl();

  /* Value now on the top, shift it down and mask it out */
  emit->bc_iushr();
  if (op == OP_LHU)
    emit->bc_i2c();
  else if (op == OP_LB)
    emit->bc_i2b(); /* Sign extension */
  else if (op == OP_LH)
    emit->bc_i2s(); /* Ditto */
  else
    {
      /* LBU */
      emit->bc_pushconst(mask_value);
      emit->bc_iand(); /* out = val >>> (b*8) */
    }

  /* Back again, now with the result on the top of the stack */
  emit->bc_ret( R_MADR );
}

void JavaMethod::emitSubroutineForOp(mips_opcode_t op)
{
  panic_if(op != OP_LB && op != OP_LBU && op != OP_LH &&
           op != OP_LHU && op != OP_SB && op != OP_SH,
           "Illegal opcode %s passed to emitLoadStoreSubroutines\n",
           mips_op_strings[op]);

  if (op == OP_LBU || op == OP_LHU || op == OP_LB || op == OP_LH)
    this->emitLoadSubroutine(op);
  else /* op == OP_SB || op == OP_SH */
    this->emitStoreSubroutine(op);
}

void JavaMethod::emitSubroutines()
{
  uint8_t is_emitted[N_INSNS];

  memset(is_emitted, 0, sizeof(is_emitted));

  /* If any of LB/LBU, LH/LHU, SB,SH, emit subroutines to handle
   * these */
  for (int i = 0; i < this->n_functions; i++)
    {
      mips_opcode_t ops_to_check[] = {OP_LB, OP_LBU, OP_LH, OP_LHU, OP_SB, OP_SH};

      for (unsigned int j = 0; j < sizeof(ops_to_check) / sizeof(mips_opcode_t); j++)
        {
          mips_opcode_t op = ops_to_check[j];

          if ( !is_emitted[op] && this->functions[i]->opcodeIsUsed(op) )
            {
              this->emitSubroutineForOp(op);
              is_emitted[op] = 1;
            }
        }
    }
}

bool JavaMethod::pass2()
{
  bool out = true;

  regalloc->setAllocation(this->registerUsage);

  emit->generic("\n.method public static %s\n"
                ".limit stack 20\n"
                ".limit locals %d\n",
                this->getJavaMethodName(),
                regalloc->getNumberOfLocals());

  /* Emit register mapping */
  for (int i = 0; i < N_REGS; i++)
    {
      if (this->registerUsage[i])
        emit->generic("; local %2d is register %s\n",
                      regalloc->regToLocal((MIPS_register_t)i),
                      mips_reg_strings[i]);
    }

  /* Zero all used registers */
  for (int i = 0; i < N_REGS; i++)
    {
      panic_if(i == R_FNA && this->registerUsage[i] > 0 && !this->hasMultipleFunctions(),
               "%s is a single-function method but uses R_FNA %d times\n",
               this->getName(), this->registerUsage[i]);

      /* These are passed as arguments, skip them */
      if (i == R_FNA || i == R_SP || i == R_A0 || i == R_A1 || i == R_A2 || i == R_A3)
        continue;

      /* If this register is used, initialize it */
      if (this->registerUsage[i] > 0)
        {
          /* Multi-function classes assign to RA */
          if (this->hasMultipleFunctions() && i == R_RA)
            emit->bc_pushconst(-1);
          else
            emit->bc_pushconst(0);
          emit->bc_popregister((MIPS_register_t)i);
        }
    }

  /* If we are configured for it, generate jsr targets for lb/lh
   * etc */
  if (config->optimizePartialMemoryOps)
    {
      emit->bc_goto("__CIBYL_javamethod_begin");
      this->emitSubroutines();
    }

  emit->bc_label("__CIBYL_javamethod_begin");

  if (this->hasMultipleFunctions())
    {
      uint32_t *table = (uint32_t*)xcalloc(this->n_functions,
                                           sizeof(uint32_t));

      /* Setup a table of functions to jump to */
      for (int i = 0; i < this->n_functions; i++)
        table[i] = this->functions[i]->getAddress();

      emit->bc_pushregister(R_FNA);
      emit->bc_tableswitch(0, this->n_functions,
                           table, "__CIBYL_function_return");

      free(table);
    }

  for (int i = 0; i < this->n_functions; i++)
    {
      Function *fn = this->functions[i];

      /* And compile the function */
      if ( !fn->pass2() )
	out = false;
    }

  if (this->registerIndirectJumps)
    {
      emit->bc_goto("__CIBYL_function_return");
      emit->bc_label("__CIBYL_local_jumptab");

      /* Emit the actual jumptab */
      emit->bc_lookupswitch(this->n_jumptabLabels, this->jumptabLabels,
                            "__CIBYL_function_return");
    }

  for (int i = 0; i < this->n_exceptionHandlers; i++)
    {
      ExceptionHandler *eh = this->exceptionHandlers[i];
      JavaClass *dstClass;
      JavaMethod *dstMethod;

      dstMethod = controller->getCallTableMethod();
      panic_if(!dstMethod,
               "No call table method???\n");
      dstClass = controller->getClassByMethodName(dstMethod->getName());
      panic_if(!dstClass,
               "No class for the call table method???\n");

      emit->bc_label("%s", eh->name);
      /* Register the object passed here */
      emit->bc_invokestatic("CRunTime/registerObject(Ljava/lang/Object;)I");
      emit->bc_pushregister(R_ECB);
      emit->bc_swap();
      /* This is just a jalr(ecb, sp, ear (exception obj)) */
      emit->bc_pushregister(R_SP);
      emit->bc_swap();
      emit->bc_pushregister(R_EAR);
      emit->bc_pushconst(0);
      emit->bc_pushconst(0);
      emit->bc_invokestatic("%s/%s", dstClass->getName(),
                            dstMethod->getJavaMethodName());
      emit->bc_pop();
      emit->bc_goto( eh->end );
    }

  emit->bc_label("__CIBYL_function_return");
  if (this->hasMultipleFunctions())
    {
      emit->bc_pushregister(R_RA);
      emit->bc_tableswitch(0, this->n_returnLocations, this->returnLocations,
                           "__CIBYL_function_return_non_local");
      emit->bc_label("__CIBYL_function_return_non_local");
    }

  if (config->threadSafe)
    {
      if (this->clobbersReg(R_V1) && this->clobbersReg(R_V0))
        {
          /* Return a 64-bit value */
          emit->bc_pushregister(R_V1);
          emit->bc_i2l();
          emit->bc_pushconst(32);
          emit->bc_lshl();
          emit->bc_pushregister(R_V0);
          emit->bc_i2l();
          emit->bc_lor(); /* push (v1 << 32) | v0 */
          emit->bc_lreturn();
        }
      else if (this->clobbersReg(R_V1)) /* Only v1 */
        {
          emit->bc_pushregister(R_V1);
          emit->bc_ireturn();
        }
      else if (this->clobbersReg(R_V0)) /* Only v0 */
        {
          emit->bc_pushregister(R_V0);
          emit->bc_ireturn();
        }
      else
        emit->bc_return();
    }
  else
    {
      /* Not thread safe */
      if (this->clobbersReg(R_V1))
        {
          emit->bc_pushregister(R_V1);
          emit->bc_putstatic("CRunTime/saved_v1 I");
        }
      if (this->clobbersReg(R_V0))
        {
          emit->bc_pushregister(R_V0);
          emit->bc_ireturn();
        }
      else
        emit->bc_return();
    }

  emit->generic(".end method ; %s\n", this->getJavaMethodName());

  return out;
}

/* R_ZERO terminates it */
static MIPS_register_t possibleArgumentRegs[] = { R_SP, R_A0, R_A1, R_A2, R_A3, R_ZERO };

MIPS_register_t JavaMethod::getFirstRegisterToPass(void *_it)
{
  int *it = (int*)_it;
  MIPS_register_t ret;

  *it = 0;

  while (possibleArgumentRegs[*it] != R_ZERO &&
	 this->clobbersReg( possibleArgumentRegs[*it] ) == 0)
      (*it)++;
  ret = possibleArgumentRegs[*it];
  (*it)++;

  return ret;
}

MIPS_register_t JavaMethod::getNextRegisterToPass(void *_it)
{
  int *it = (int*)_it;
  MIPS_register_t ret;

  while (possibleArgumentRegs[*it] != R_ZERO &&
	 this->clobbersReg( possibleArgumentRegs[*it] ) == 0)
      (*it)++;
  ret = possibleArgumentRegs[*it];
  (*it)++;
  return ret;
}

bool JavaMethod::clobbersReg(MIPS_register_t reg)
{
  return this->registerUsage[reg] > 0;
}

char *JavaMethod::addExceptionHandler(uint32_t start, uint32_t end)
{
  int n = this->n_exceptionHandlers;
  ExceptionHandler *eh;

  this->exceptionHandlers = (ExceptionHandler**)xrealloc(this->exceptionHandlers,
                                                         (n + 1) * sizeof(ExceptionHandler*) );
  this->n_exceptionHandlers = n + 1;

  eh = new ExceptionHandler(start, end);
  this->exceptionHandlers[n] = eh;

  return eh->name;
}

{'fraction_non_alphanumeric': 0.16726440289965663, 'fraction_numerical': 0.00984357115604731, 'mean_word_length': 2.457915567282322, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 467, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4878456', 'n_tokens_mistral': 9400, 'n_tokens_neox': 9061, 'n_words': 1822}