

/* Pocket Smalltalk
   Copyright (c) 1998,1999 by Andrew Brault
   http://www.pocketsmalltalk.com
   See LICENSE.TXT for license information */

/* Core of the virtual machine */


#include "main.h"




#ifdef METHOD_CACHE

/* Must be 1 less than a power of 2 */
#define METHOD_CACHE_SIZE  63

static Object search_class_cache[METHOD_CACHE_SIZE+1];
static uint16 selector_cache[METHOD_CACHE_SIZE+1];
static uint8 * instruction_ptr_cache[METHOD_CACHE_SIZE+1];

#endif



#ifdef PROFILING
unsigned long instructions_executed = 0L;
unsigned long garbage_collections = 0L;

#ifdef METHOD_CACHE
unsigned long cache_hits = 0L;
unsigned long cache_misses = 0L;
#endif

#endif


/* VM registers
   Some are external, some are static */

Value * data_stack;
uint16 data_stack_ptr;
Value receiver;
StackFrame * call_stack;
uint16 call_stack_ptr;
boolean should_quit;

static uint16 local_var_base;
static uint8 * instruction_ptr;
static Object closure_chain = nil;
static uint16 data_stack_limit;



/* Convenience macros */
#define NEXT_INSTRUCTION  *instruction_ptr++

#ifdef SAFETY
static void safe_push(Object object)
{
  if(data_stack_ptr < system_properties.data_stack_size-10)
    data_stack[data_stack_ptr++] = object;
  else panic("data stack overflow");
}

static Object safe_pop(void)
{
  if(data_stack_ptr > 0)
    return data_stack[--data_stack_ptr];
  panic("data stack underflow");
  return nil;
}

#define PUSH(object)  safe_push(object)
#define POP  safe_pop()
#else
#define PUSH(object)  data_stack[data_stack_ptr++] = (object)
#define POP  data_stack[--data_stack_ptr]
#endif /* SAFETY */


#define POP_INTO(var)  var = POP
#define STACKTOP  data_stack[data_stack_ptr - 1]

#define SAVE_CALL_FRAME  save_call_frame()


static void create_initial_context(void);
static void interpret(void);

static boolean lookup_method(Object search_class, uint16 selector,
			     uint16 argument_count);
static void invoke_method(uint16 arg_count);
static void release_closure_chain(void);
static void local_return(Object value);
static void nonlocal_return(Object value, uint16 distance);

static void send_message(uint16 selector, uint16 argument_count);
static uint16 get_outer_context(uint16 distance);
static void push_outer_inst_var(uint8 index, uint8 distance);
static void store_outer_inst_var(uint8 index, uint8 distance);
static void push_outer_local(uint8 index, uint8 distance);
static void store_outer_local(uint8 index, uint8 distance);
static void push_outer_receiver(uint8 distance);
static void make_full_block(Object owner_class);
static void call_primitive(uint16 index);
static void illegal_instruction(void);

static void i_systrap(boolean ignore_return);

uint32 int_trap_short(uint16 * p);
uint32 int_trap_long(uint16 * p);
void * ptr_trap_short(uint16 * p);
void * ptr_trap_long(uint16 * p);
int dummy_function(void);



void initialize_vm(void)
{
#ifdef METHOD_CACHE
  MEMSET(search_class_cache,
         sizeof(search_class_cache[0]) * METHOD_CACHE_SIZE, 0);
  MEMSET(selector_cache,
         sizeof(selector_cache[0]) * METHOD_CACHE_SIZE, 0);
#endif

#ifndef PROCESSES
  call_stack = (StackFrame *)
	allocate_chunk(sizeof(StackFrame) * 
		       system_properties.call_stack_size);
  data_stack = (Value *)
	allocate_chunk(system_properties.data_stack_size * sizeof(Value));
  data_stack_limit = system_properties.data_stack_size - 50;
#endif

#ifdef PROCESSES
  MEMSET(process_queues, sizeof(process_queues), 0);
  MEMSET(process_status, sizeof(process_status), 0);
#endif /* PROCESSES */    
}


void run_vm(void)
{
  create_initial_context();

  /* cheezy PalmOS exception handling */
  ErrTry {
    interpret();
  }
  ErrCatch(err) { } ErrEndCatch
}


static void create_initial_context(void)
{
  call_stack_ptr = 1;  /* must not start at 0 ! */
  lookup_method(OBJECT_CLASS(Smalltalk), Selector_basicStart, 0);
  instruction_ptr += 2;  /* skip over # of locals & args */
  receiver = Smalltalk;
  local_var_base = 0;
  data_stack_ptr = 0;
}


static void interpret(void)
{
  uint8 instruction;
  uint16 value;
  int16 integer;
  int32 integer32;
  Object object, object2;


nextInstruction:
#ifdef STRESS
    collect_garbage();
#endif
    instruction = NEXT_INSTRUCTION;
#ifdef PROFILING
    instructions_executed++;
#endif
    switch(instruction) {
      /* 0x - Push instance variable x */
    case 0x00:
      PUSH(OBJECT_ACCESS(receiver, 0));
      break;
    case 0x01:
      PUSH(OBJECT_ACCESS(receiver, 1));
      break;
    case 0x02:
      PUSH(OBJECT_ACCESS(receiver, 2));
      break;
    case 0x03:
      PUSH(OBJECT_ACCESS(receiver, 3));
      break;
    case 0x04:
      PUSH(OBJECT_ACCESS(receiver, 4));
      break;
    case 0x05:
      PUSH(OBJECT_ACCESS(receiver, 5));
      break;
    case 0x06:
      PUSH(OBJECT_ACCESS(receiver, 6));
      break;
    case 0x07:
      PUSH(OBJECT_ACCESS(receiver, 7));
      break;
    case 0x08:
      PUSH(OBJECT_ACCESS(receiver, 8));
      break;
    case 0x09:
      PUSH(OBJECT_ACCESS(receiver, 9));
      break;
    case 0x0A:
      PUSH(OBJECT_ACCESS(receiver, 10));
      break;
    case 0x0B:
      PUSH(OBJECT_ACCESS(receiver, 11));
      break;
    case 0x0C:
      PUSH(OBJECT_ACCESS(receiver, 12));
      break;
    case 0x0D:
      PUSH(OBJECT_ACCESS(receiver, 13));
      break;
    case 0x0E:
      PUSH(OBJECT_ACCESS(receiver, 14));
      break;
    case 0x0F:
      PUSH(OBJECT_ACCESS(receiver, 15));
      break;
      /* 1x - Store instance variable x */
    case 0x10:
      OBJECT_SET(receiver, 0, POP);
      break;
    case 0x11:
      OBJECT_SET(receiver, 1, POP);
      break;
    case 0x12:
      OBJECT_SET(receiver, 2, POP);
      break;
    case 0x13:
      OBJECT_SET(receiver, 3, POP);
      break;
    case 0x14:
      OBJECT_SET(receiver, 4, POP);
      break;
    case 0x15:
      OBJECT_SET(receiver, 5, POP);
      break;
    case 0x16:
      OBJECT_SET(receiver, 6, POP);
      break;
    case 0x17:
      OBJECT_SET(receiver, 7, POP);
      break;
    case 0x18:
      OBJECT_SET(receiver, 8, POP);
      break;
    case 0x19:
      OBJECT_SET(receiver, 9, POP);
      break;
    case 0x1A:
      OBJECT_SET(receiver, 10, POP);
      break;
    case 0x1B:
      OBJECT_SET(receiver, 11, POP);
      break;
    case 0x1C:
      OBJECT_SET(receiver, 12, POP);
      break;
    case 0x1D:
      OBJECT_SET(receiver, 13, POP);
      break;
    case 0x1E:
      OBJECT_SET(receiver, 14, POP);
      break;
    case 0x1F:
      OBJECT_SET(receiver, 15, POP);
      break;
      /* 2x - Push local x */
    case 0x20:
      PUSH(data_stack[local_var_base + 0]);
      break;
    case 0x21:
      PUSH(data_stack[local_var_base + 1]);
      break;
    case 0x22:
      PUSH(data_stack[local_var_base + 2]);
      break;
    case 0x23:
      PUSH(data_stack[local_var_base + 3]);
      break;
    case 0x24:
      PUSH(data_stack[local_var_base + 4]);
      break;
    case 0x25:
      PUSH(data_stack[local_var_base + 5]);
      break;
    case 0x26:
      PUSH(data_stack[local_var_base + 6]);
      break;
    case 0x27:
      PUSH(data_stack[local_var_base + 7]);
      break;
    case 0x28:
      PUSH(data_stack[local_var_base + 8]);
      break;
    case 0x29:
      PUSH(data_stack[local_var_base + 9]);
      break;
    case 0x2A:
      PUSH(data_stack[local_var_base + 10]);
      break;
    case 0x2B:
      PUSH(data_stack[local_var_base + 11]);
      break;
    case 0x2C:
      PUSH(data_stack[local_var_base + 12]);
      break;
    case 0x2D:
      PUSH(data_stack[local_var_base + 13]);
      break;
    case 0x2E:
      PUSH(data_stack[local_var_base + 14]);
      break;
    case 0x2F:
      PUSH(data_stack[local_var_base + 15]);
      break;
      /* 3x - Store local x */
    case 0x30:
      data_stack[local_var_base + 0] = POP;
      break;
    case 0x31:
      data_stack[local_var_base + 1] = POP;
      break;
    case 0x32:
      data_stack[local_var_base + 2] = POP;
      break;
    case 0x33:
      data_stack[local_var_base + 3] = POP;
      break;
    case 0x34:
      data_stack[local_var_base + 4] = POP;
      break;
    case 0x35:
      data_stack[local_var_base + 5] = POP;
      break;
    case 0x36:
      data_stack[local_var_base + 6] = POP;
      break;
    case 0x37:
      data_stack[local_var_base + 7] = POP;
      break;
    case 0x38:
      data_stack[local_var_base + 8] = POP;
      break;
    case 0x39:
      data_stack[local_var_base + 9] = POP;
      break;
    case 0x3A:
      data_stack[local_var_base + 10] = POP;
      break;
    case 0x3B:
      data_stack[local_var_base + 11] = POP;
      break;
    case 0x3C:
      data_stack[local_var_base + 12] = POP;
      break;
    case 0x3D:
      data_stack[local_var_base + 13] = POP;
      break;
    case 0x3E:
      data_stack[local_var_base + 14] = POP;
      break;
    case 0x3F:
      data_stack[local_var_base + 15] = POP;
      break;
    case 0x40:
    case 0x41:
    case 0x42:
    case 0x43:
      /* 4[0..3] xx - Unconditional jump forward */
      value = instruction & 3;
      value = (value << 8) | NEXT_INSTRUCTION;
      instruction_ptr += value;
      break;
    case 0x44:
    case 0x45:
    case 0x46:
    case 0x47:
      /* 4[4..7] xx - Unconditional jump backward */
      value = instruction & 3;
      value = (value << 8) | NEXT_INSTRUCTION;
      instruction_ptr -= value;
      break;
    case 0x48:
    case 0x49:
    case 0x4A:
    case 0x4B:
    case 0x4C:
    case 0x4D:
    case 0x4E:
    case 0x4F:
      illegal_instruction();
      break;
    case 0x50:
    case 0x51:
    case 0x52:
    case 0x53:
#ifdef JAVA_INSTRUCTIONS    
      /* 5[0..3] xx - Jump forward if true */
      POP_INTO(object);
      if(object == true_obj) {
        value = instruction & 3;
        value = (value << 8) | NEXT_INSTRUCTION;
        instruction_ptr += value;
      }
      else if(object == false_obj)
        instruction_ptr++;
      else send_message(Selector_mustBeBoolean, 0);
#else
      illegal_instruction();
#endif            
      break;
    case 0x54:
    case 0x55:
    case 0x56:
    case 0x57:
#ifdef JAVA_INSTRUCTIONS
      /* 5[4..7] xx - Jump backward if true */
      POP_INTO(object);
      if(object == true_obj) {
        value = instruction & 3;
        value = (value << 8) | NEXT_INSTRUCTION;
        instruction_ptr -= value;
      }
      else if(object == false_obj)
        instruction_ptr++;
      else send_message(Selector_mustBeBoolean, 0);
#else
      illegal_instruction();
#endif      
      break;
    case 0x58:
    case 0x59:
    case 0x5A:
    case 0x5B:
      /* 5[8..B] xx - Jump forward if false */
      POP_INTO(object);
      if(object == false_obj) {
        value = instruction & 3;
        value = (value << 8) | NEXT_INSTRUCTION;
        instruction_ptr += value;
      }
      else if(object == true_obj)
        instruction_ptr++;
      else send_message(Selector_mustBeBoolean, 0);
      break;
    case 0x5C:
    case 0x5D:
    case 0x5E:
    case 0x5F:
#ifdef JAVA_INSTRUCTIONS    
      /* 5[C..F] xx - Jump backward if false */
      POP_INTO(object);
      if(object == false_obj) {
        value = instruction & 3;
        value = (value << 8) | NEXT_INSTRUCTION;
        instruction_ptr -= value;
      }
      else if(object == true_obj)
        instruction_ptr++;
      else send_message(Selector_mustBeBoolean, 0);
#else
      illegal_instruction();
#endif            
      break;
    case 0x60:
#ifdef JAVA_INSTRUCTIONS
      /* 60 xx - Inline instVarAt: */
      instruction = NEXT_INSTRUCTION;
      POP_INTO(object);
      object = inst_var_at(object, instruction);
      if(object == Failure_value)
        object = nil;
      PUSH(object);
      break;
#endif
    case 0x61:
#ifdef JAVA_INSTRUCTIONS
      /* 61 xx - Inline instVarAt:put: */
      instruction = NEXT_INSTRUCTION;
      POP_INTO(object);
      inst_var_at_put(POP, instruction, object);
      break;
#endif
    case 0x62: 
      i_systrap(FALSE);
      break;
    case 0x63: /* 63 - Push global xxxx*/
      integer = NEXT_INSTRUCTION;
      integer <<= 8;
      integer |= NEXT_INSTRUCTION;
      PUSH(basic_at(globals_array, integer));
      break;
    case 0x64: /* 64 - Store global xxxx*/
      integer = NEXT_INSTRUCTION;
      integer <<= 8;
      integer |= NEXT_INSTRUCTION;
      basic_at_put(globals_array, integer, POP);
      break;
    case 0x65:
#ifdef JAVA_INSTRUCTIONS
      /* 65 xx yyyy - Send yyyy, xx args, receiver on stack top */
      instruction = NEXT_INSTRUCTION;  /* arg count */
      value = NEXT_INSTRUCTION;  /* get selector */
      value <<= 8;
      value |= NEXT_INSTRUCTION;
      POP_INTO(object);
      data_stack_ptr -= instruction;
      SAVE_CALL_FRAME;
      receiver = object;
      if(lookup_method(CLASS_OF(receiver), value, instruction))
        invoke_method(instruction);
      else invoke_method(1);
      break;
#endif      
    case 0x66: 
#ifdef JAVA_INSTRUCTIONS
      /* 66 xx yyyy - Directed send yyyy, xx args, receiver beneath args */
      instruction = NEXT_INSTRUCTION;  /* arg count */
      value = NEXT_INSTRUCTION;  /* selector */
      value <<= 8;
      value |= NEXT_INSTRUCTION;
      POP_INTO(object);
      data_stack_ptr -= instruction + 1;
      SAVE_CALL_FRAME;
      receiver = data_stack[data_stack_ptr++];
      if(lookup_method(object, value, instruction))
        invoke_method(instruction);
      else invoke_method(1);
      break;      
#endif /* JAVA_INSTRUCTIONS */    
    case 0x67:
      i_systrap(TRUE);
      break;
    case 0x68:
    case 0x69:
    case 0x6A:
    case 0x6B:
    case 0x6C:
    case 0x6D:
    case 0x6E:
    case 0x6F:
      illegal_instruction();
      break;
    case 0x70:
    case 0x71:
    case 0x72:
    case 0x73:
    case 0x74:
    case 0x75:
    case 0x76:
    case 0x77:
    case 0x78:
    case 0x79:
    case 0x7A:
    case 0x7B:
    case 0x7C:
    case 0x7D:
    case 0x7E:
    case 0x7F:
      /* 7x yyyy - Send self yyyy, x args */
      value = NEXT_INSTRUCTION;  /* get selector */
      value <<= 8;
      value |= NEXT_INSTRUCTION;
      instruction &= 0x0F;  /* argument count */
      data_stack_ptr -= instruction;
      SAVE_CALL_FRAME;
      if(lookup_method(CLASS_OF(receiver), value, instruction))
        invoke_method(instruction);
      else invoke_method(1);
      break;       
    case 0x80:
    case 0x81:
    case 0x82:
    case 0x83:
    case 0x84:
    case 0x85:
    case 0x86:
    case 0x87:
    case 0x88:
    case 0x89:
    case 0x8A:
    case 0x8B:    
    case 0x8C:
    case 0x8D:
    case 0x8E:
    case 0x8F:
      /* 8x yyyy - Send yyyy, x args */
      value = NEXT_INSTRUCTION;  /* get selector */
      value <<= 8;
      value |= NEXT_INSTRUCTION;
      instruction &= 0x0F;  /* argument count */
      data_stack_ptr -= instruction + 1;
      SAVE_CALL_FRAME;
      receiver = data_stack[data_stack_ptr++];
      if(lookup_method(CLASS_OF(receiver), value, instruction))
        invoke_method(instruction);
      else invoke_method(1);
      break;
    case 0x90:
    case 0x91:
    case 0x92:
    case 0x93:
    case 0x94:
    case 0x95:
    case 0x96:
    case 0x97:
    case 0x98:
    case 0x99:
    case 0x9A:
    case 0x9B:
    case 0x9C:
    case 0x9D:
    case 0x9E:
    case 0x9F:
      /* 9x yyyy - Send super yyyy, x args */
      value = NEXT_INSTRUCTION;  /* get selector */
      value <<= 8;
      value |= NEXT_INSTRUCTION;
      instruction &= 0x0F;  /* argument count */
      POP_INTO(object);  /* search class */
      data_stack_ptr -= instruction;
      SAVE_CALL_FRAME;
      if(lookup_method(object, value, instruction))
        invoke_method(instruction);
      else invoke_method(1);
      break;
    case 0xA0:
    case 0xA1:
    case 0xA2:
    case 0xA3:
    case 0xA4:
    case 0xA5:
    case 0xA6:
    case 0xA7:
    case 0xA8:
    case 0xA9:
    case 0xAA:
    case 0xAB:
    case 0xAC:
    case 0xAD:
    case 0xAE:
    case 0xAF:
      /* Ax yy - Send self yy, x args */
      value = NEXT_INSTRUCTION;  /* get selector */
      instruction &= 0x0F;  /* argument count */
      data_stack_ptr -= instruction;
      SAVE_CALL_FRAME;
      if(lookup_method(CLASS_OF(receiver), value, instruction))
        invoke_method(instruction);
      else invoke_method(1);
      break;
    case 0xB0: /* B0 - Push object xx */
      object = NEXT_INSTRUCTION;
      PUSH(object << 1);
      break;
    case 0xB1: /* B1 - Push object xxxx */
      object = NEXT_INSTRUCTION;
      object <<= 8;
      object |= NEXT_INSTRUCTION;
      PUSH(object << 1);
      break;
    case 0xB2: /* B2 - Push next outer inst var xx */
      push_outer_inst_var(NEXT_INSTRUCTION, 1);
      break;
    case 0xB3: /* B3 - Store next outer inst var xx */
      store_outer_inst_var(NEXT_INSTRUCTION, 1);
      break;
    case 0xB4: /* B4 - Push next outer local xx */
      push_outer_local(NEXT_INSTRUCTION, 1);
      break;
    case 0xB5: /* B5 - Store next outer local xx */
      store_outer_local(NEXT_INSTRUCTION, 1);
      break;
    case 0xB6: /* B6 - Push (yyth) outer local xx */
      value = NEXT_INSTRUCTION;
      push_outer_local(value, NEXT_INSTRUCTION);
      break;
    case 0xB7: /* B7 - Store (yyth) outer local xx */
      value = NEXT_INSTRUCTION;
      store_outer_local(value, NEXT_INSTRUCTION);
      break;
    case 0xB8: /* B8 - Nonlocal return to next context */
      nonlocal_return(POP, 1);
      break;
    case 0xB9: /* B9 - Make full block */
      make_full_block(POP);
      break;
    case 0xBA: /* BA - Make hybrid block */
      illegal_instruction();
      break;
    case 0xBB: /* BB - Push yyth outer inst var xx */
      value = NEXT_INSTRUCTION;
      push_outer_inst_var(value, NEXT_INSTRUCTION);
      break;
    case 0xBC: /* BC - Store yyth outer inst var xx */
      value = NEXT_INSTRUCTION;
      store_outer_inst_var(value, NEXT_INSTRUCTION);
      break;
    case 0xBD: /* BD - Nonlocal return, distance xx */
      nonlocal_return(POP, NEXT_INSTRUCTION);
      break;
    case 0xBE: /* BE - Push next outer receiver */
      push_outer_receiver(1);
      break;
    case 0xBF: /* BF - Push xxth outer receiver */
      push_outer_receiver(NEXT_INSTRUCTION);
      break;
    case 0xC0:
    case 0xC1:
    case 0xC2:
    case 0xC3:
      /* C[0..3] - Inline integer comparison */
      object = data_stack[data_stack_ptr - 1];
      object2 = data_stack[data_stack_ptr - 2];
      if(is_integer(object) && is_integer(object2)) {
        data_stack_ptr--;
        STACKTOP = integer_compare(object2, object, 
                                   "[]<>"[instruction & 3]);
      }
      else send_message(Selector_lesseq + (instruction & 3), 1);
      break;
    case 0xC4: /* == */
      value = data_stack[data_stack_ptr - 2] ==
  	      data_stack[data_stack_ptr - 1];
      data_stack_ptr--;
      STACKTOP = AS_BOOLEAN(value);
      break;
    case 0xC5: /* ~~ */
      value = data_stack[data_stack_ptr - 2] !=
  	      data_stack[data_stack_ptr - 1];
      data_stack_ptr--;
      STACKTOP = AS_BOOLEAN(value);
      break;
    case 0xC6: /* not */
      if(STACKTOP == true_obj)
        STACKTOP = false_obj;
      else STACKTOP = true_obj;
      break;
    case 0xC7: /* + */
      object = data_stack[data_stack_ptr - 1];
      object2 = data_stack[data_stack_ptr - 2];
      if(is_integer(object) && is_integer(object2)) {
        data_stack_ptr--;
        STACKTOP = integer_op(object2, object, '+');
      }
      else send_message(Selector_plus, 1);
      break;
    case 0xC8: /* - */
      object = data_stack[data_stack_ptr - 1];
      object2 = data_stack[data_stack_ptr - 2];
      if(is_integer(object) && is_integer(object2)) {
        data_stack_ptr--;
        STACKTOP = integer_op(object2, object, '-');
      }
      else send_message(Selector_minus, 1);
      break;
    case 0xC9: /* basicAt: */
      if(IS_SMALLINT(STACKTOP)) {
        object = basic_at(data_stack[data_stack_ptr - 2],
                          FROM_SMALLINT(STACKTOP)-1);
        if(object != Failure_value) {
  	  data_stack_ptr--;
 	  STACKTOP = object;
	  break;
	}
      }
      send_message(Selector_basicAt, 1);
      break;
    case 0xCA:  /* basicAt:put: */
      if(IS_SMALLINT(data_stack[data_stack_ptr - 2])) {
        object = data_stack[data_stack_ptr - 1];
        if(basic_at_put(data_stack[data_stack_ptr - 3],
		      FROM_SMALLINT(data_stack[data_stack_ptr - 2])-1,
		      object)) {
  	  data_stack_ptr -= 2;
	  STACKTOP = object;
	  break;
        }
      }
      send_message(Selector_basicAtPut, 2);
      break;   
    case 0xCB: /* isNil */
      if(STACKTOP)
        STACKTOP = false_obj;
      else STACKTOP = true_obj;
      break;
    case 0xCC: /* notNil */
      if(STACKTOP)
        STACKTOP = true_obj;
      else STACKTOP = false_obj;
      break;
    case 0xCD:
    case 0xCE:
    case 0xCF:
      illegal_instruction();
      break;  
    case 0xD0:
    case 0xD1:
    case 0xD2:
    case 0xD3:
    case 0xD4:
    case 0xD5:
    case 0xD6:
    case 0xD7:
    case 0xD8:
    case 0xD9:
    case 0xDA:
    case 0xDB:
    case 0xDC:
    case 0xDD:
    case 0xDE:
    case 0xDF:
      /* Dx yy - Send yy, x args */
      value = NEXT_INSTRUCTION;  /* get selector */
      instruction &= 0x0F;  /* argument count */
      data_stack_ptr -= instruction + 1;
      SAVE_CALL_FRAME;
      receiver = data_stack[data_stack_ptr++];
      if(lookup_method(CLASS_OF(receiver), value, instruction))
        invoke_method(instruction);
      else invoke_method(1);
      break;
    case 0xE0: /* E0 - Pop */
      POP;
      break;
    case 0xE1: /* E1 - Dup */
      data_stack[data_stack_ptr] = STACKTOP;
      data_stack_ptr++;
      break;
    case 0xE2: /* E2 - Duplicate stack level 2 (OVER) */
      data_stack[data_stack_ptr] = data_stack[data_stack_ptr - 2];
      data_stack_ptr++;
      break;
    case 0xE3: /* E3 - Return stack top */
      local_return(POP);
      break;
    case 0xE4: /* E4 - Return true */
      local_return(true_obj);
      break;
    case 0xE5: /* E5 - Return false */
      local_return(false_obj);
      break;
    case 0xE6: /* E6 - Return nil */
      local_return(nil);
      break;
    case 0xE7: /* E7 - Return self */
      local_return(receiver);
      break;
    case 0xE8: /* E8 - Push false */
      PUSH(false_obj);
      break;
    case 0xE9: /* E9 - Push true */
      PUSH(true_obj);
      break;
    case 0xEA: /* EA - Push nil */
      PUSH(nil); 
      break;
    case 0xEB: /* EB - Push self */
      PUSH(receiver);
      break;
    case 0xEC: /* EC - Push integer -xx */
      integer = NEXT_INSTRUCTION;
      PUSH(TO_SMALLINT(-integer));
      break;
    case 0xED:  /* ED - Push integer xx */
      integer = NEXT_INSTRUCTION;
      PUSH(TO_SMALLINT(integer));
      break;
    case 0xEE:  /* EE - Push integer -xxxx */
      integer32 = NEXT_INSTRUCTION;
      integer32 <<= 8;
      integer32 |= NEXT_INSTRUCTION;
      PUSH(as_smalltalk_integer(-integer32));
      break;
    case 0xEF:  /* EF - Push integer xxxx */
      integer32 = NEXT_INSTRUCTION;
      integer32 <<= 8;
      integer32 |= NEXT_INSTRUCTION;
      PUSH(as_smalltalk_integer(integer32));
      break;  
    case 0xF0: /* F0 - Push inst var xx */
      PUSH(OBJECT_ACCESS(receiver, NEXT_INSTRUCTION));
      break;
    case 0xF1: /* F1 - Store inst var xx */
      OBJECT_SET(receiver, NEXT_INSTRUCTION, POP);
      break;
    case 0xF2: /* F2 - Push local xx */
      PUSH(data_stack[local_var_base + NEXT_INSTRUCTION]);
      break;
    case 0xF3: /* F3 - Store local xx */
      data_stack[local_var_base + NEXT_INSTRUCTION] = POP;
      break;
    case 0xF4: /* F4 - Push global xx */
      PUSH(basic_at(globals_array, NEXT_INSTRUCTION));
      break;
    case 0xF5: /* F5 - Store global xx */
      basic_at_put(globals_array, NEXT_INSTRUCTION, POP);
      break;
    case 0xF6: /* F6 - Push character xx */
      PUSH(TO_CHARACTER(NEXT_INSTRUCTION));
      break;
    case 0xF7: /* F7 - Add 1 */
      if(is_integer(STACKTOP))
        STACKTOP = integer_op(STACKTOP, TO_SMALLINT(1), '+');
      else {
        /* Send it as a normal message */
        PUSH(TO_SMALLINT(1));
        send_message(Selector_plus, 1);
      }
      break;
    case 0xF8: /* F8 - Subtract 1 */
      if(is_integer(STACKTOP))
        STACKTOP = integer_op(STACKTOP, TO_SMALLINT(1), '-');
      else {
        /* Send it as a normal message */
        PUSH(TO_SMALLINT(1));
        send_message(Selector_minus, 1);
      }
      break;
    case 0xF9: /* F9 - thisContext */
      PUSH(TO_SMALLINT(call_stack_ptr));
      break;
    case 0xFA:
    case 0xFB:
    case 0xFC:
    case 0xFD:
      illegal_instruction();
      break;
    case 0xFE: /* FE - Primitive xx */
      call_primitive(NEXT_INSTRUCTION);
      break;
    case 0xFF:
      illegal_instruction();
      break;
    default:
      illegal_instruction();
      break;
    }
  goto nextInstruction;
}


/* Answer whether the given class directly implements the
   given selector.  Does a linear search, so can be slow. */
boolean class_implements(Object search_class, uint16 selector)
{
  uint16 * class_ptr;
  uint16 method_count;

  class_ptr = (uint16 *)(LOOKUP_CLASS(search_class));
  method_count = *class_ptr++;
  while(method_count-- > 0) {
    if(*class_ptr++ == selector)
      return TRUE;
    class_ptr++;
  }
  return FALSE;
}


/* Sets instruction_ptr to the correct place in the new method.
   This function normally never fails -- if it can't
   find the given selector it sends doesNotUnderstand: instead.
   If anything goes wrong in this function, it is likely because
   of a corrupted image/memory and the VM will probably crash. */
/* Answers whether the method was found without having to
   resort to #doesNotUnderstand:  */
static boolean lookup_method(Object search_class, uint16 selector,
			     uint16 argument_count)
{
  Object probe_class, message, array;
  uint8 * class_base;
  uint16 * class_ptr;
  int16 method_count, middle, top, bottom, scratch;
  uint16 n;

#ifdef METHOD_CACHE
  uint16 hash_index;

  hash_index = ((search_class >> 1) ^ selector) & METHOD_CACHE_SIZE;
  if((search_class_cache[hash_index] == search_class) &&
     (selector_cache[hash_index] == selector)) {
#ifdef PROFILING
    cache_hits++;
#endif
    instruction_ptr = instruction_ptr_cache[hash_index];
    return TRUE;
  }
#ifdef PROFILING
  else cache_misses++;
#endif
#endif /* METHOD_CACHE */

  probe_class = search_class;
  while(probe_class) {
    class_base = LOOKUP_CLASS(probe_class);
    class_ptr = (uint16 *)class_base;

    /* Binary search---selectors are in ascending order. */
    method_count = *class_ptr++;
    top = method_count - 1;
    bottom = 0;
    while(top >= bottom) {
      middle = (top + bottom) >> 1;
      scratch = class_ptr[middle << 1];
      if(scratch == selector) {
        /* refer to the documentation of the structure of class
           segments to understand the following */
	instruction_ptr = class_base + 2 +
            (method_count << 2) + class_ptr[(middle << 1) + 1];
#ifdef METHOD_CACHE
	hash_index = ((search_class >> 1) ^ selector) & METHOD_CACHE_SIZE;
	search_class_cache[hash_index] = search_class;
	selector_cache[hash_index] = selector;
	instruction_ptr_cache[hash_index] = instruction_ptr;
#endif
	return TRUE;
      }
      else if(scratch < selector)
        bottom = middle + 1;
      else top = middle - 1;
    }

    /* Not found here; check the superclass */
    probe_class = OBJECT_ACCESS(probe_class, Behavior_superclass);
  }

  /* Message not understood---create a Message object and
     send #doesNotUnderstand:.  A little tricky. */
  data_stack_ptr += argument_count;  /* positioned after last arg */
  message = instantiate_normal(Message);
  data_stack[data_stack_ptr++] = message;  /* protect from GC */
  array = instantiate_indexed(Array, argument_count);
  OBJECT_SET(message, Message_selector, TO_SMALLINT(selector));
  OBJECT_SET(message, Message_arguments, array);
  data_stack_ptr -= argument_count+1;  /* positioned at 1st arg (if any) */
  for(n = 0; n < argument_count; n++)
    OBJECT_SET(array, n, data_stack[data_stack_ptr + n]);
  data_stack[data_stack_ptr] = message;  /* overwrites 1st arg */

  lookup_method(search_class, Selector_doesNotUnderstand, 1);
  return FALSE;
}


/* Attempt to infer the selector used to invoke the method
   specified by the given method class and instruction pointer.
   Answers 0 if it cannot be determined. */
uint16 infer_selector(Object m_class, uint8 * ip)
{
  uint8 * class_base, * ip_start;
  uint16 * class_ptr;
  uint16 method_count, n;

  class_base = LOOKUP_CLASS(m_class);
  class_ptr = (uint16 *)class_base;
  method_count = *class_ptr++;
  class_ptr += method_count * 2;  /* point to after method table */
  n = method_count;
  while(n-- > 0) {
    class_ptr -= 2;
    /* Find starting address of this method */
    ip_start = class_base + 2 + (method_count * 4) + (class_ptr[1]);
    if(ip > ip_start)
      return class_ptr[0];
  }
  return 0;
}



static void invoke_method(uint16 arg_count)
{
  uint16 temps;

  /* Check for data stack overflow.  Be conservative and allow
     a headroom of about 50 slots.  Generally this is OK as long
     as the programmer is not actively trying to break the system.
     In any event, the call stack should be exhausted before the
     data stack. */
  if(data_stack_ptr >= data_stack_limit)
    panic("data stack overflow");  /* blarg */

  temps = NEXT_INSTRUCTION - arg_count;
  instruction_ptr++;
  local_var_base = data_stack_ptr;
  data_stack_ptr += arg_count;
  while(temps-- > 0)
    data_stack[data_stack_ptr++] = nil;
}


/* this and restore_call_frame are good candidates for inlining */
void save_call_frame(void)
{
  StackFrame * frame;

  if(call_stack_ptr >= (system_properties.call_stack_size-3))
    panic("call stack overflow!");

  frame = call_stack + call_stack_ptr++;
  frame->receiver = receiver;
  frame->local_var_base = local_var_base;
  frame->data_stack_ptr = data_stack_ptr;
  frame->instruction_ptr = instruction_ptr;
  frame->closure_chain = closure_chain;
  closure_chain = nil;
}


void restore_call_frame(void)
{
  StackFrame * frame;

  release_closure_chain();

  if(call_stack_ptr <= 1)
    panic("call stack underflow!");

  frame = call_stack + --call_stack_ptr;
  receiver = frame->receiver;
  local_var_base = frame->local_var_base;
  data_stack_ptr = frame->data_stack_ptr;
  instruction_ptr = frame->instruction_ptr;
  closure_chain = frame->closure_chain;
}


/* This tells each (non-GC'd) block created by the current
   context that its parent context is finished (so it can
   signal an error if a nonlocal return is attempted later). */
static void release_closure_chain(void)
{
  Object object, next;

  next = nil;  /* satisfy compiler */
  for(object = closure_chain; object; object = next) {
    next = OBJECT_ACCESS(object, Block_nextLink);
    if(next) next--;  /* convert smallint -> objref ("weak" link) */
    OBJECT_SET(object, Block_nextOuter, nil);
  }
  closure_chain = nil;  /* not strictly necessary */
}


/* Return from a method or a block */
static void local_return(Object value)
{
  restore_call_frame();
  PUSH(value);
}


/* Hard (^) return from inside a full block */
static void nonlocal_return(Object value, uint16 distance)
{
  uint16 context_index;

  context_index = get_outer_context(distance);
  if(context_index == 0)
    return;  /* hosed */
  while(call_stack_ptr > context_index)
    restore_call_frame();
  
  /* Now it's the same as local_return() */
  restore_call_frame();
  PUSH(value);
}


/* Send a message to the receiver on the stack */
static void send_message(uint16 selector, uint16 argument_count)
{
  data_stack_ptr -= argument_count + 1;
  save_call_frame();
  receiver = data_stack[data_stack_ptr++];
  if(lookup_method(CLASS_OF(receiver), selector, argument_count))
    invoke_method(argument_count);
  else invoke_method(1);
}


/* Answer the index of the context (stack frame) at the
   given distance from the current one. */
static uint16 get_outer_context(uint16 distance)
{
  Object closure;
  uint16 context_index;

  /* Until we get past 'distance' contexts, all the
     receivers must be FullBlockClosures. */
  closure = receiver;
  while(distance-- > 0) {
    context_index = OBJECT_ACCESS(closure, Block_nextOuter) >> 1;
    if(context_index == 0) {
      /* don't bother fixing the stack up nicely - we're 
         already hosed */
      PUSH(receiver);
      send_message(Selector_contextAlreadyReturned, 0);
      return 0;
    }
    closure = call_stack[context_index].receiver;
  }

  return context_index;
}


static void push_outer_inst_var(uint8 index, uint8 distance)
{
  uint16 context;

  context = get_outer_context(distance);
  if(context)
    PUSH(OBJECT_ACCESS(call_stack[context].receiver, index));
}


static void store_outer_inst_var(uint8 index, uint8 distance)
{
  uint16 context;
  Object object;

  context = get_outer_context(distance);
  if(context) {
    POP_INTO(object);
    OBJECT_SET(call_stack[context].receiver, index, object);
  }
}


static void push_outer_local(uint8 index, uint8 distance)
{
  uint16 context;

  context = get_outer_context(distance);
  if(context) {
    PUSH(data_stack[call_stack[context].local_var_base + index]);
  }
}


static void store_outer_local(uint8 index, uint8 distance)
{
  uint16 context;
  Object object;

  context = get_outer_context(distance);
  if(context) {
    POP_INTO(object);
    data_stack[call_stack[context].local_var_base + index] = object;
  }
}


static void push_outer_receiver(uint8 distance)
{
  uint16 context;

  context = get_outer_context(distance);
  if(context) {
    PUSH(call_stack[context].receiver);
  }
}


static void make_full_block(Object owner_class)
{
  Object closure;
  uint8 * class_base;
  uint16 arg_count, * class_ptr;
  int32 offset;

  class_base = LOOKUP_CLASS(owner_class);
  class_ptr = (uint16 *)class_base;
  class_ptr += 1 + ((*class_ptr) << 1);

  arg_count = NEXT_INSTRUCTION;

  /* Get offset from instruction pointer to class pointer */
  offset = instruction_ptr - ((uint8 *)class_ptr);

  /* Skip past jump (2 bytes) instruction */
  offset += 2;

  closure = instantiate_normal(FullBlockClosure);

  OBJECT_SET(closure, Block_ownerClass, owner_class);
  OBJECT_SET(closure, Block_offset, TO_SMALLINT(offset));
  OBJECT_SET(closure, Block_argumentCount, TO_SMALLINT(arg_count));
  OBJECT_SET(closure, Block_nextOuter, TO_SMALLINT(call_stack_ptr));
  /* Note: nextLink holds a SmallInteger alias to the next closure */
  OBJECT_SET(closure, Block_nextLink, closure_chain | 1);
  closure_chain = closure;

  PUSH(closure);
}


static void call_primitive(uint16 index)
{
  Object result;
  Primitive_Function f;

  if(index >= PRIMITIVE_COUNT)
    panic("undefined primitive");

  fail_code = 0;
  f = primitive_table[index].function;
  if(!f) { panic("unbound primitive"); }
  switch(primitive_table[index].argument_count) {
  case 0:
    result = (*f)();
    break;
  case 1:
    result = (*f)(data_stack[data_stack_ptr - 1]);
    break;
  case 2:
    result = (*f)(data_stack[data_stack_ptr - 2],
		  data_stack[data_stack_ptr - 1]);
    break;
  case 3:
    result = (*f)(data_stack[data_stack_ptr - 3],
		  data_stack[data_stack_ptr - 2],
		  data_stack[data_stack_ptr - 1]);
    break;
  case 4:
    result = (*f)(data_stack[data_stack_ptr - 4],
		  data_stack[data_stack_ptr - 3],
		  data_stack[data_stack_ptr - 2],
		  data_stack[data_stack_ptr - 1]);
    break;
  case 5:
    result = (*f)(data_stack[data_stack_ptr - 5],
                  data_stack[data_stack_ptr - 4],
		  data_stack[data_stack_ptr - 3],
		  data_stack[data_stack_ptr - 2],
		  data_stack[data_stack_ptr - 1]);
    break;
  case 6:
    result = (*f)(data_stack[data_stack_ptr - 6],
                  data_stack[data_stack_ptr - 5],
                  data_stack[data_stack_ptr - 4],
		  data_stack[data_stack_ptr - 3],
		  data_stack[data_stack_ptr - 2],
		  data_stack[data_stack_ptr - 1]);
    break;
  default:
    panic("too many arguments to primitive");
    break;
  }

  if(result == Failure_value) {
    /* Primitive failed */
    return;  /* execute fallback code */
  }
  else {
    /* Primitive succeeded - return the value */
    local_return(result);
  }
}


static void illegal_instruction(void)
{
  panic("illegal bytecode executed");
}


/* There *must* be an Array on the stack top.
   Remove the Array from the stack and push each element of the
   array back onto the stack.  May blow the stack if there are
   more than a reasonable number of entries in the array, so the
   caller should check this. */
void destructure_array(void)
{
  Object array, element;
  int16 size, n;

  POP_INTO(array);
  size = OBJECT_SIZE(array);
  for(n = 0; n < size; n++) {
    element = OBJECT_ACCESS(array, n);
    PUSH(element);
  }
}


/* Answer TRUE if the selector was valid, FALSE if not. */
void perform(uint16 arg_count)
{
  Object selector;
  uint16 locals, args;
  boolean understood;

  /* Stack has this layout (topmost item shown last) :
       selector
       arg1
       arg2
       ...
       argn
  */

  save_call_frame();
  selector = data_stack[local_var_base];
  if(!IS_SMALLINT(selector)) {
    restore_call_frame();  /* primitive failure */
    return;
  }
  selector >>= 1;
  data_stack_ptr = local_var_base + 1;  /* point at arg1 */
  understood = lookup_method(CLASS_OF(receiver), selector, arg_count);
  locals = NEXT_INSTRUCTION;
  args = NEXT_INSTRUCTION;
  if(args != arg_count && understood) {
    /* Wrong number of arguments -- do a primitive fail */
    restore_call_frame();
  }
  else {
    /* Correct number of arguments */
    /* Nip the most recent stack frame (the one for
       the #perform primitive) */
    call_stack_ptr--;
    local_var_base++;  /* skip selector */
    locals -= args;  /* locals = number of temps */
    data_stack_ptr = local_var_base + args;
    while(locals-- > 0)
      data_stack[data_stack_ptr++] = nil;  /* clear temps */
  }
}


/* Invoke a BlockClosure.  Answer whether the number
   of arguments was correct (if incorrect, the block
   closure is not invoked). */
boolean block_value(uint16 arg_count)
{
  uint16 locals;
  uint8 * class_base;
  uint16 * class_ptr;
  Object owner_class;

  if(FROM_SMALLINT(OBJECT_ACCESS(receiver, Block_argumentCount))
	!= arg_count) {
    /* Wrong number of arguments */
    return FALSE;
  }

  /* Find instruction pointer */
  owner_class = OBJECT_ACCESS(receiver, Block_ownerClass);
  class_base = LOOKUP_CLASS(owner_class);
  class_ptr = (uint16 *)class_base;  /* hope it's word aligned ... */

  /* Skip over method table */
  class_ptr += 1 + ((*class_ptr) << 1);

  /* Now class_ptr points at the first byte of the method table */
  instruction_ptr = (uint8 *)class_ptr;

  /* Add the offset contained in the block to get the
     address of the block's instructions */
  instruction_ptr += FROM_SMALLINT(OBJECT_ACCESS(receiver, Block_offset));
  locals = NEXT_INSTRUCTION - arg_count;  /* # of temps */
  data_stack_ptr = local_var_base + arg_count;
  while(locals-- > 0)
    data_stack[data_stack_ptr++] = nil;

  return TRUE;
}


typedef int32 (* IntFunction)(uint16 *);
typedef void * (* PtrFunction)(uint16 *);

/* Machine language offsets where systrap is stored.
   These are WORD offsets, not BYTE offsets.
   If ANY of the systrap functions are changes, these
   numbers must be changed to match */
#ifdef __GNUC__
#define SHORT_TRAP_OFFSET  20
#define LONG_TRAP_OFFSET  56
#endif __GNUC__
  // 1.6 Fix Start
#ifdef __MWERKS__
#define SHORT_TRAP_OFFSET  21
#define LONG_TRAP_OFFSET  57
#endif __MWERKS__
  // 1.6 Fix End


/* Sizes of systrap proxy routines in bytes. */
#ifdef __GNUC__
#define SHORT_TRAP_SIZE  46
#define LONG_TRAP_SIZE  118
#endif __GNUC__

  // 1.6 Fix Start
#ifdef __MWERKS__
#define SHORT_TRAP_SIZE  54
#define LONG_TRAP_SIZE  126
#endif __MWERKS__
  // 1.6 Fix End

static uint8 int_trap_short_buf[SHORT_TRAP_SIZE];
static uint8 int_trap_long_buf[LONG_TRAP_SIZE];
static uint8 ptr_trap_short_buf[SHORT_TRAP_SIZE];
static uint8 ptr_trap_long_buf[LONG_TRAP_SIZE];


static void i_systrap(boolean ignore_return)
{
  uint16 trap;
  uint8 arg_count, spec;
  void * address;
  Object object;
  uint16 pp, dptr;
  uint32 value;
  static uint16 p[26];
  IntFunction int_function;
  PtrFunction ptr_function;
  uint16 * fixup_ptr;

  trap = NEXT_INSTRUCTION;
  trap <<= 8;
  trap |= NEXT_INSTRUCTION;
  arg_count = NEXT_INSTRUCTION;
  
  pp = 0;
  /* Read in arguments ... */
  data_stack_ptr -= arg_count;  /* point at 1st arg */
  dptr = data_stack_ptr;
  while(arg_count-- != 0) {
    spec = NEXT_INSTRUCTION;
    object = data_stack[data_stack_ptr++];
    if(spec == 1) {
      /* 16 bit argument */
      if(!is_integer(object))
	goto bad_arg;
      p[pp++] = as_c_integer(object);
    }
    else if(spec == 2) {
      /* 32 bit int argument */
      if(!is_integer(object))
	goto bad_arg;
      value = as_c_integer(object);
      p[pp++] = value >> 16;  /* could use typecast */
      p[pp++] = (uint16)value;  /* strip high bits */
    }
    else if(spec == 3) {
      /* 32 bit CPointer argument */
      if(CLASS_OF(object) != CPointer) {
        if(IS_SMALLINT(object) || OBJECT_HAS_POINTERS(object))
	  goto bad_arg;
        else value = (int32)OBJECT_BYTES(object);
      }
      else value = as_c_integer(object);
      p[pp++] = value >> 16;
      p[pp++] = (uint16)value;
    }
    else panic("bad systrap spec");      
  }
  data_stack_ptr = dptr;
  spec = NEXT_INSTRUCTION;  /* return type spec */
  if(spec <= 2) {
    if(pp > 8) {
      fixup_ptr = (uint16 *)int_trap_long_buf;
      fixup_ptr[LONG_TRAP_OFFSET] = trap;
    }
    else {
      fixup_ptr = (uint16 *)int_trap_short_buf;
      fixup_ptr[SHORT_TRAP_OFFSET] = trap;
    }
    int_function = (IntFunction)fixup_ptr;
    value = (*int_function)(p);
    if(spec == 0 || ignore_return)
      PUSH(nil);
    else {
      PUSH(as_smalltalk_integer(value));
    }
  }
  else {
    if(pp > 8) {
      fixup_ptr = (uint16 *)ptr_trap_long_buf;
      fixup_ptr[LONG_TRAP_OFFSET] = trap;
    }
    else {
      fixup_ptr = (uint16 *)ptr_trap_short_buf;
      fixup_ptr[SHORT_TRAP_OFFSET] = trap;
    }
    ptr_function = (PtrFunction)fixup_ptr;
    address = (*ptr_function)(p);
    if(ignore_return)
      PUSH(nil);
    else
      PUSH(encode_pointer(address));
  }
  return;
bad_arg:;
  PUSH(receiver);
  PUSH(as_smalltalk_integer(trap));
  send_message(Selector_badTrapArgument, 1);
}


uint32 int_systrap() SYS_TRAP(0xA000);
void * ptr_systrap() SYS_TRAP(0xA000);


void init_trap_dispatcher(void)
{
  MEMCOPY(int_trap_short_buf, int_trap_short, SHORT_TRAP_SIZE);
  MEMCOPY(int_trap_long_buf, int_trap_long, LONG_TRAP_SIZE);
  MEMCOPY(ptr_trap_short_buf, ptr_trap_short, SHORT_TRAP_SIZE);
  MEMCOPY(ptr_trap_long_buf, ptr_trap_long, LONG_TRAP_SIZE);
}


/* If the following trap function helpers are modified in ANY
   way, great care must be taken to make sure that the buffer
   size allocated to copy these functions, and the offset to
   the trap instruction are correct.  Look up from here a
   little */
   

uint32 int_trap_short(uint16 * p)
{
  return int_systrap(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
}


uint32 int_trap_long(uint16 * p)
{
  return int_systrap
	(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
	 p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15],
	 p[16], p[17], p[18], p[19], p[20], p[21], p[22], p[23],
	 p[24], p[25]);
}


void * ptr_trap_short(uint16 * p)
{
  return ptr_systrap(p[0], p[1], p[2], p[3], 
		     p[4], p[5], p[6], p[7]);
}


void * ptr_trap_long(uint16 * p)
{
  return ptr_systrap
	(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
	 p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15],
	 p[16], p[17], p[18], p[19], p[20], p[21], p[22], p[23],
	 p[24], p[25]);
}

