/* Copyright 1994 - 1996 LongView Technologies L.L.C. $Revision: 1.25 $ */
/* Copyright (c) 2006, Sun Microsystems, Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 
following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
	  disclaimer in the documentation and/or other materials provided with the distribution.
    * Neither the name of Sun Microsystems nor the names of its contributors may be used to endorse or promote products derived 
	  from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE


*/

// Bytecodes comprises the definition of all bytecodes
// and provides utility functions working on bytecodes.
//
//
// Naming conventions for send bytecodes;
// basically they are coming in three forms:
//
// a) <send type>_send_<argument specification>
// b) <send_type>_send_<argument specification>_pop
// c) <name of predicted smi selector>
//
// <send_type> is one of:
//
// interpreted	monomorphic send to interpreted method
// compiled	monomorphic send to compiled method
// primitive	monomorphic send to primitive method
// access	monomorphic send to access method
// polymorphic	polymorphic send to interpreted or compiled method
// megamorphic	megamorphic send to interpreted or compiled method
//
// <argument specification is one of:
//
// 0		receiver & 0 arguments on stack, normal send
// 1		receiver & 1 argument  on stack, normal send
// 2		receiver & 2 arguments on stack, normal send
// n		receiver & n arguments on stack, normal send
// self		no receiver, arguments on stack, normal send
// super	no receiver, arguments on stack, super  send


class Bytecodes: AllStatic {
 public:
  // Returns the bytecode set version number.
  // Must match the version number generated by the Digitalk system.
  static int version()	{ return 2; }

  enum Format {		// Format of instruction: * means align to oop
    B,			// {byte}
    BB,			// {byte, byte}
    BBB,		// {byte, byte, byte}
    BBBB,		// {byte, byte, byte, byte}
    BBO,		// {byte, byte, *, oop}
    BBL,		// {byte, byte, *, long}
    BO,			// {byte, *, oop}
    BOO,		// {byte, *, oop, oop}
    BLO,		// {byte, *, long, oop}
    BOL,		// {byte, *, oop, long}
    BLL,		// {byte, *, long, long}
    BL,			// {byte, *, long}
    BLB,		// {byte, *, byte}
    BBOO,		// {byte, byte, *, oop, oop}
    BBLO,		// {byte, byte, *, long, oop}
    BOOLB,		// {byte, *, oop, oop, long, byte}
    BBS,		// {byte, byte = number of bytes to follow, {byte}*}
    UNDEF,		// for undefined codes

    number_of_formats
  };

  enum CodeType {	// Instruction classification
    local_access,	// loads & stores of temps and args
    instVar_access,	// loads & stores of instVars
    context_access,	// loads & stores of context temps
    classVar_access,	// loads & stores to class variables
    global_access,	// loads & stores to global variables
    new_closure,	// closure creation
    new_context,	// context creation
    control_struc,	// control structures (incl. local return)
    message_send,	// all sends
    nonlocal_return,	// non-local returns
    primitive_call,	// primitive calls
    dll_call,		// dll calls
    float_operation,	// float operations
    miscellaneous,	// for all other instructions

    number_of_code_types
  };

  enum ArgumentSpec {	// Argument specification for sends
    recv_0_args,	// recv & 0 arguments on stack
    recv_1_args,	// recv & 1 arguments on stack
    recv_2_args,	// recv & 2 arguments on stack
    recv_n_args,	// recv & n arguments on stack
    args_only,		// only arguments on stack
    no_args,		// for non-send instructions

    number_of_argument_specs
  };

  enum SendType {	// Send classification
    interpreted_send,	// interpreted monomorphic send
    compiled_send,	// compiled monomorphic send
    polymorphic_send,	// interpreted polymorphic send
    megamorphic_send,	// interpreted megamorphic send
    predicted_send,	// send to interpreted predicted method (method containing a predicted primitive call with own bytecode)
    accessor_send,	// send to interpreted accessor method (method containing a predicted instVar access)
    primitive_send,	// send to interpreted primitive method (method containing a predicted primitive call)
    no_send,		// for non-send instructions

    number_of_send_types
  };

  enum LoopType {	// Loop classification
    loop_start,		// instruction starting a loop
    loop_end, 		// instruction ending a loop
    no_loop,		// for non-loop instructions

    number_of_loop_types
  };

  enum Code {
    // row 0
    push_temp_0				= 0x00,
    push_temp_1				= 0x01,
    push_temp_2				= 0x02,
    push_temp_3				= 0x03,
    push_temp_4				= 0x04,
    push_temp_5				= 0x05,
    unimplemented_06			= 0x06,
    push_temp_n				= 0x07,
    push_arg_1				= 0x08, // n-1
    push_arg_2				= 0x09, // n-2
    push_arg_3				= 0x0a, // n-3
    push_arg_n				= 0x0b, // n-1-b
    allocate_temp_1			= 0x0c,
    allocate_temp_2			= 0x0d,
    allocate_temp_3			= 0x0e,
    allocate_temp_n			= 0x0f, // 0 means 256

    // row 1
    store_temp_0_pop			= 0x10,
    store_temp_1_pop			= 0x11,
    store_temp_2_pop			= 0x12,
    store_temp_3_pop			= 0x13,
    store_temp_4_pop			= 0x14,
    store_temp_5_pop			= 0x15,
    store_temp_n			= 0x16, // 255-b
    store_temp_n_pop			= 0x17, // 255-b
    push_neg_n				= 0x18, // -b
    push_succ_n				= 0x19, // b+1
    push_literal			= 0x1a,
    push_tos				= 0x1b,
    push_self				= 0x1c,
    push_nil				= 0x1d,
    push_true				= 0x1e,
    push_false				= 0x1f,

    // row 2
    unimplemented_20			= 0x20,
    unimplemented_21			= 0x21,
    unimplemented_22			= 0x22,
    unimplemented_23			= 0x23,
    unimplemented_24			= 0x24,
    unimplemented_25			= 0x25,
    unimplemented_26			= 0x26,
    unimplemented_27			= 0x27,
    return_instVar_name			= 0x28,
    push_classVar			= 0x29,
    store_classVar_pop			= 0x2a,
    store_classVar			= 0x2b,
    return_instVar			= 0x2c,
    push_instVar			= 0x2d,
    store_instVar_pop			= 0x2e,
    store_instVar			= 0x2f,

    // row 3
    float_allocate			= 0x30,
    float_floatify_pop			= 0x31,
    float_move				= 0x32,
    float_set				= 0x33,
    float_nullary_op			= 0x34,
    float_unary_op			= 0x35,
    float_binary_op			= 0x36,
    float_unary_op_to_oop		= 0x37,
    float_binary_op_to_oop		= 0x38,
    unimplemented_39			= 0x39,
    unimplemented_3a			= 0x3a,
    unimplemented_3b			= 0x3b,
    unimplemented_3c			= 0x3c,
    push_instVar_name			= 0x3d,
    store_instVar_pop_name		= 0x3e,
    store_instVar_name			= 0x3f,

    // row 4
    push_temp_0_context_0		= 0x40,
    push_temp_1_context_0		= 0x41,
    push_temp_2_context_0		= 0x42,
    push_temp_n_context_0		= 0x43,
    store_temp_0_context_0_pop		= 0x44,
    store_temp_1_context_0_pop		= 0x45,
    store_temp_2_context_0_pop		= 0x46,
    store_temp_n_context_0_pop		= 0x47,
    push_new_closure_context_0		= 0x48,
    push_new_closure_context_1		= 0x49,
    push_new_closure_context_2		= 0x4a,
    push_new_closure_context_n		= 0x4b,
    install_new_context_method_0	= 0x4c,
    install_new_context_method_1	= 0x4d,
    install_new_context_method_2	= 0x4e,
    install_new_context_method_n	= 0x4f,

    // row 5
    push_temp_0_context_1		= 0x50,
    push_temp_1_context_1		= 0x51,
    push_temp_2_context_1		= 0x52,
    push_temp_n_context_1		= 0x53,
    store_temp_0_context_1_pop		= 0x54,
    store_temp_1_context_1_pop		= 0x55,
    store_temp_2_context_1_pop		= 0x56,
    store_temp_n_context_1_pop		= 0x57,
    push_new_closure_tos_0		= 0x58,
    push_new_closure_tos_1		= 0x59,
    push_new_closure_tos_2		= 0x5a,
    push_new_closure_tos_n		= 0x5b,
    only_pop				= 0x5c,
    install_new_context_block_1		= 0x5d,
    install_new_context_block_2		= 0x5e,
    install_new_context_block_n		= 0x5f,

    // row 6
    push_temp_0_context_n		= 0x60,
    push_temp_1_context_n		= 0x61,
    push_temp_2_context_n		= 0x62,
    push_temp_n_context_n		= 0x63,
    store_temp_0_context_n_pop		= 0x64,
    store_temp_1_context_n_pop		= 0x65,
    store_temp_2_context_n_pop		= 0x66,
    store_temp_n_context_n_pop		= 0x67,
    set_self_via_context		= 0x68,
    copy_1_into_context			= 0x69,
    copy_2_into_context			= 0x6a,
    copy_n_into_context			= 0x6b,
    copy_self_into_context		= 0x6c,
    copy_self_1_into_context		= 0x6d,
    copy_self_2_into_context		= 0x6e,
    copy_self_n_into_context		= 0x6f,

    // row 7
    ifTrue_byte				= 0x70,
    ifFalse_byte			= 0x71,
    and_byte				= 0x72,
    or_byte				= 0x73,
    whileTrue_byte			= 0x74,
    whileFalse_byte			= 0x75,
    jump_else_byte			= 0x76,
    jump_loop_byte			= 0x77,
    ifTrue_word				= 0x78,
    ifFalse_word			= 0x79,
    and_word				= 0x7a,
    or_word				= 0x7b,
    whileTrue_word			= 0x7c,
    whileFalse_word			= 0x7d,
    jump_else_word			= 0x7e,
    jump_loop_word			= 0x7f,

    // row 8
    interpreted_send_0			= 0x80,
    interpreted_send_1			= 0x81,
    interpreted_send_2			= 0x82,
    interpreted_send_n			= 0x83,
    interpreted_send_0_pop		= 0x84,
    interpreted_send_1_pop		= 0x85,
    interpreted_send_2_pop		= 0x86,
    interpreted_send_n_pop		= 0x87,
    interpreted_send_self		= 0x88,
    interpreted_send_self_pop		= 0x89,
    interpreted_send_super		= 0x8a,
    interpreted_send_super_pop		= 0x8b,
    return_tos_pop_0			= 0x8c,
    return_tos_pop_1			= 0x8d,
    return_tos_pop_2			= 0x8e,
    return_tos_pop_n			= 0x8f,

    // row 9
    polymorphic_send_0			= 0x90,
    polymorphic_send_1			= 0x91,
    polymorphic_send_2			= 0x92,
    polymorphic_send_n			= 0x93,
    polymorphic_send_0_pop		= 0x94,
    polymorphic_send_1_pop		= 0x95,
    polymorphic_send_2_pop		= 0x96,
    polymorphic_send_n_pop		= 0x97,
    polymorphic_send_self		= 0x98,
    polymorphic_send_self_pop		= 0x99,
    polymorphic_send_super		= 0x9a,
    polymorphic_send_super_pop		= 0x9b,
    return_self_pop_0			= 0x9c,
    return_self_pop_1			= 0x9d,
    return_self_pop_2			= 0x9e,
    return_self_pop_n			= 0x9f,

    // row a
    compiled_send_0			= 0xa0,
    compiled_send_1			= 0xa1,
    compiled_send_2			= 0xa2,
    compiled_send_n			= 0xa3,
    compiled_send_0_pop			= 0xa4,
    compiled_send_1_pop			= 0xa5,
    compiled_send_2_pop			= 0xa6,
    compiled_send_n_pop			= 0xa7,
    compiled_send_self			= 0xa8,
    compiled_send_self_pop		= 0xa9,
    compiled_send_super			= 0xaa,
    compiled_send_super_pop		= 0xab,
    return_tos_zap_pop_n		= 0xac,
    return_self_zap_pop_n		= 0xad,
    non_local_return_tos_pop_n		= 0xae,
    non_local_return_self_pop_n		= 0xaf,

    // row b
    prim_call				= 0xb0,
    predict_prim_call			= 0xb1,
    prim_call_failure			= 0xb2,
    predict_prim_call_failure		= 0xb3,
    dll_call_sync			= 0xb4,
    prim_call_self			= 0xb5,
    prim_call_self_failure		= 0xb6,
    unimplemented_b7			= 0xb7,
    access_send_self			= 0xb8,
    primitive_send_0			= 0xb9,
    primitive_send_super		= 0xba,
    primitive_send_super_pop		= 0xbb,
    unimplemented_bc			= 0xbc,
    primitive_send_1			= 0xbd,
    primitive_send_2			= 0xbe,
    primitive_send_n			= 0xbf,

    // row c
    prim_call_lookup			= 0xc0,
    predict_prim_call_lookup		= 0xc1,
    prim_call_failure_lookup		= 0xc2,
    predict_prim_call_failure_lookup	= 0xc3,
    dll_call_async			= 0xc4,
    prim_call_self_lookup		= 0xc5,
    prim_call_self_failure_lookup	= 0xc6,
    unimplemented_c7			= 0xc7,
    access_send_0			= 0xc8,
    primitive_send_0_pop		= 0xc9,
    primitive_send_self			= 0xca,
    primitive_send_self_pop		= 0xcb,
    unimplemented_cc			= 0xcc,
    primitive_send_1_pop		= 0xcd,
    primitive_send_2_pop		= 0xce,
    primitive_send_n_pop		= 0xcf,

    // row d
    megamorphic_send_0			= 0xd0,
    megamorphic_send_1			= 0xd1,
    megamorphic_send_2			= 0xd2,
    megamorphic_send_n			= 0xd3,
    megamorphic_send_0_pop		= 0xd4,
    megamorphic_send_1_pop		= 0xd5,
    megamorphic_send_2_pop		= 0xd6,
    megamorphic_send_n_pop		= 0xd7,
    megamorphic_send_self		= 0xd8,
    megamorphic_send_self_pop		= 0xd9,
    megamorphic_send_super		= 0xda,
    megamorphic_send_super_pop		= 0xdb,
    unimplemented_dc			= 0xdc,
    special_primitive_send_1_hint	= 0xdd,
    unimplemented_de			= 0xde,
    unimplemented_df			= 0xdf,

    // row e
    smi_add				= 0xe0,
    smi_sub				= 0xe1,
    smi_mult				= 0xe2,
    smi_div				= 0xe3,
    smi_mod				= 0xe4,
    smi_create_point			= 0xe5,
    smi_equal				= 0xe6,
    smi_not_equal			= 0xe7,
    smi_less				= 0xe8,
    smi_less_equal			= 0xe9,
    smi_greater				= 0xea,
    smi_greater_equal			= 0xeb,
    objArray_at				= 0xec,
    objArray_at_put			= 0xed,
    double_equal			= 0xee,
    double_tilde			= 0xef,

    // row f
    push_global				= 0xf0,
    store_global_pop			= 0xf1,
    store_global			= 0xf2,
    push_classVar_name			= 0xf3,
    store_classVar_pop_name		= 0xf4,
    store_classVar_name			= 0xf5,
    smi_and				= 0xf6,
    smi_or				= 0xf7,
    smi_xor				= 0xf8,
    smi_shift				= 0xf9,
    unimplemented_fa			= 0xfa,
    unimplemented_fb			= 0xfb,
    unimplemented_fc			= 0xfc,
    unimplemented_fd			= 0xfd,
    unimplemented_fe			= 0xfe,
    halt				= 0xff,

    number_of_codes			= 0x100
  };

 private:
  static char*		_entry_point[number_of_codes];
  static char*		_name[number_of_codes];
  static Format		_format[number_of_codes];
  static CodeType	_code_type[number_of_codes];
  static ArgumentSpec	_argument_spec[number_of_codes];
  static SendType	_send_type[number_of_codes];
  static bool		_single_step[number_of_codes];
  static bool		_pop_tos[number_of_codes];
  
  static void	def(Code code);
  static void	def(Code code, char* name, Format format, CodeType code_type, bool single_step, bool pop_tos = false);
  static void	def(Code code, char* name, Format format, ArgumentSpec argument_spec, SendType send_type, bool pop_tos = false);
  static void	def(Code code, char* name, Format format, CodeType code_type, bool single_step, ArgumentSpec argument_spec, SendType send_type, bool pop_tos);

 public:
  // Define entry points
  static void	set_entry_point(Code code, char* entry_point);


  // Testers
  static bool	is_defined(Code code)			{ return 0 <= code && code < number_of_codes && _format[code] != UNDEF; }
  static bool	is_self_send(Code code);
  static bool	is_super_send(Code code);
  static bool	has_access_send_code(Code code);
  static bool	has_predicted_send_code(Code code);
  static bool	is_send_code(Code code)			{ return send_type(code) != no_send; }


  // Bytecode specification
  static char*		entry_point	(Code code)	{ return _entry_point[code]; }
  static char*		name		(Code code)	{ return _name[code]; }
  static Format		format		(Code code)	{ return _format[code]; }
  static CodeType	code_type	(Code code)	{ return _code_type[code]; }
  static ArgumentSpec	argument_spec	(Code code)	{ return _argument_spec[code]; }
  static SendType	send_type	(Code code)	{ return _send_type[code]; }
  static bool		single_step	(Code code)	{ return _single_step[code]; }
  static bool		pop_tos		(Code code)	{ return _pop_tos[code]; }
  static LoopType	loop_type	(Code code);


  // Helpers for printing
  static char*	format_as_string	(Format format);
  static char*	code_type_as_string	(CodeType code_type);
  static char*	argument_spec_as_string	(ArgumentSpec argument_spec);
  static char*	send_type_as_string	(SendType send_type);
  static char*	loop_type_as_string	(LoopType loop_type);


  // Send bytecode transitions
  //
  // The following functions return the corresponding interpreted, compiled,
  // polymorphic or megamorphic send bytecode for a given send bytecode. They
  // are used to implement the bytecode transitions during interpreter inline
  // cache misses.

  static Code original_send_code_for	(Code code);	// predicted sends keep original code (smi_add -> smi_add)
  static Code interpreted_send_code_for	(Code code);	// predicted sends loose their original value (smi_add -> int'_send_1)
  static Code compiled_send_code_for	(Code code);
  static Code access_send_code_for	(Code code);
  static Code primitive_send_code_for	(Code code);
  static Code polymorphic_send_code_for	(Code code);
  static Code megamorphic_send_code_for	(Code code);


  // Primitive lookup bytecode transitions
  //
  // The following function returns the corresponding primitive call
  // bytecode for a given primitive call lookup bytecode. It is used
  // to implement the bytecode transition during a primitive lookup.

  static Code original_primitive_call_code_for	(Code code);
  static Code primitive_call_code_for		(Code code);


  // Initialization/debugging
  static void init();
  static void print();
};
