--          This file is part of SmartEiffel The GNU Eiffel Compiler.
--       Copyright (C) 1994-2002 LORIA - INRIA - U.H.P. Nancy 1 - FRANCE
--          Dominique COLNET and Suzanne COLLIN - SmartEiffel@loria.fr
--                       http://SmartEiffel.loria.fr
-- SmartEiffel is  free  software;  you can  redistribute it and/or modify it
-- under the terms of the GNU General Public License as published by the Free
-- Software  Foundation;  either  version  2, or (at your option)  any  later
-- version. SmartEiffel is distributed in the hope that it will be useful,but
-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-- or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU General Public License
-- for  more  details.  You  should  have  received a copy of the GNU General
-- Public  License  along  with  SmartEiffel;  see the file COPYING.  If not,
-- write to the  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-- Boston, MA 02111-1307, USA.
--
class CODE_ATTRIBUTE
   --
   -- Unique Global Object in charge of a Code_attribute as
   -- describe in the JVM specification.
   -- Obviously, the same object is recycled for all code part.
   --
inherit GLOBALS

feature {NONE}

   code: FIXED_ARRAY[INTEGER] is
      once
         !!Result.with_capacity(1024)
      end

   max_stack: INTEGER
         -- To compute the maximum size of the operand stack.

   max_locals: INTEGER

feature

   stack_level: INTEGER
         -- Used to compute `max_stack'

feature {METHOD_INFO}

   clear is
      do
         code.clear
         exception_table.clear
         line_number_table.clear
         max_stack := 0
         stack_level := 0
         max_locals := jvm.max_locals
      end

   store_in(storage: STRING) is
      local
         i: INTEGER
      do
         append_u2(storage,constant_pool.idx_constant_utf8)
         check
            program_counter > 0
         end
         append_u4(storage,12 + program_counter + exception_table.length + line_number_table.length )
         append_u2(storage,max_stack)
         append_u2(storage,max_locals)
         append_u4(storage,program_counter)
         from
            i := 0
         until
            i > code.upper
         loop
            append_u1(storage,code.item(i))
            i := i + 1
         end
         exception_table.store_in(storage)
         -- attribute_count :
         line_number_table.store_in( storage )
      end

feature

   program_counter: INTEGER is
      do
         Result := code.count
      end

   extra_local(local_type: E_TYPE): INTEGER is
      require
         local_type.is_run_type
      do
         Result := max_locals
         max_locals := max_locals + local_type.jvm_stack_space
      end

   extra_local_size1: INTEGER is
      do
         Result := max_locals
         max_locals := max_locals + 1
      end

feature -- opcode feature list :

   opcode_nop is
      do
         opcode(0,0)
      end

   opcode_aconst_null is
      do
         opcode(1,1)
      end

   opcode_iconst_m1 is
      do
         opcode(2,1)
      end

   opcode_iconst_0 is
      do
         opcode(3,1)
      end

   opcode_iconst_1 is
      do
         opcode(4,1)
      end

   opcode_iconst_i(n: INTEGER) is
      require
         -1 <= n
         n <= 5
      do
         opcode(3 + n,1)
      end

   opcode_lconst_0 is
      do
         opcode(9,2)
      end

   opcode_lconst_1 is
      do
         opcode(10,2)
      end

   opcode_lconst_i(n: INTEGER) is
      require
         0 <= n
         n <= 1
      do
         opcode(9 + n,2)
      end

   opcode_fconst_0 is
      do
         opcode(11,1)
      end

   opcode_dconst_0 is
      do
         opcode(14,2)
      end

   opcode_bipush(byte: INTEGER) is
         -- Sign-extended value.
      require
         byte.in_range(0,255)
      do
         opcode(16,1)
         add_u1(byte)
      end

   opcode_sipush(u2: INTEGER) is
      require
         -32768 <= u2
         u2 <= 32767
         (u2 < -128 or 127 < u2)
      do
         opcode(17,1)
         add_u2(u2)
      end

   opcode_ldc(idx: INTEGER) is
         -- For both ldc and ldc_w.
      require
         constant_pool.valid_index(idx)
      do
         if idx < 255 then
            opcode(18,1)
            add_u1(idx)
         else
            opcode(19,1)
            add_u2(idx)
         end
      end

   opcode_fload(index: INTEGER) is
      require
         0 <= index
         index <= 255
      do
         if index <= 3 then
            opcode(34 + index,1)
         else
            opcode(23,1)
            add_u1(index)
         end
      end

   opcode_dload_0 is
      do
         opcode(38,2)
      end

   opcode_dload(index: INTEGER) is
      require
         0 <= index
         index <= 255
      do
         if index <= 3 then
            opcode(38 + index,2)
         else
            opcode(24,2)
            add_u1(index)
         end
      end

   opcode_aload(index: INTEGER) is
      require
         0 <= index
         index <= 255
      do
         if index <= 3 then
            opcode(42 + index,1)
         else
            opcode(25,1)
            add_u1(index)
         end
      end

   opcode_iload_0 is
      do
         opcode(26,1)
      end

   opcode_iload_1 is
      do
         opcode(27,1)
      end

   opcode_iload_2 is
      do
         opcode(28,1)
      end

   opcode_iload_3 is
      do
         opcode(29,1)
      end

   opcode_iload(index: INTEGER) is
      require
         0 <= index
         index <= 255
      do
         if index <= 3 then
            opcode(26 + index,1)
         else
            opcode(21,1)
            add_u1(index)
         end
      end

   opcode_lload_0 is
      do
         opcode(30,2)
      end

   opcode_lload_1 is
      do
         opcode(31,2)
      end

   opcode_lload_2 is
      do
         opcode(32,2)
      end

   opcode_lload_3 is
      do
         opcode(33,2)
      end

   opcode_lload(index: INTEGER) is
      require
         0 <= index
         index <= 255
      do
         if index <= 3 then
            opcode(30 + index,2)
         else
            opcode(22,2)
            add_u1(index)
         end
      end

   opcode_aload_0 is
      do
         opcode(42,1)
      end

   opcode_aload_1 is
      do
         opcode(43,1)
      end

   opcode_aload_2 is
      do
         opcode(44,1)
      end

   opcode_aload_3 is
      do
         opcode(45,1)
      end

   opcode_iaload is
      do
         opcode(46,-1)
      end

   opcode_laload is
      do
         opcode(47,0)
      end

   opcode_faload is
      do
         opcode(48,-1)
      end

   opcode_daload is
      do
         opcode(49,0)
      end

   opcode_aaload is
      do
         opcode(50,-1)
      end

   opcode_baload is
      do
         opcode(51,-1)
      end

   opcode_caload is
      do
         opcode(52,-1)
      end

   opcode_saload is
      do
         opcode(53,-1)
      end

   opcode_istore_3 is
      do
         opcode(62,-1)
      end

   opcode_istore(offset: INTEGER) is
      require
         0 <= offset
         offset <= 255
      do
         if offset <= 3 then
            opcode(59 + offset,-1)
         else
            opcode(54,-1)
            add_u1(offset)
         end
      end

   opcode_lstore(offset: INTEGER) is
      require
         0 <= offset
         offset <= 255
      do
         if offset <= 3 then
            opcode(63 + offset,-1)
         else
            opcode(55,-1)
            add_u1(offset)
         end
      end

   opcode_fstore(offset: INTEGER) is
      require
         0 <= offset
         offset <= 255
      do
         if offset <= 3 then
            opcode(67 + offset,-1)
         else
            opcode(56,-1)
            add_u1(offset)
         end
      end

   opcode_dstore(offset: INTEGER) is
      require
         0 <= offset
         offset <= 255
      do
         if offset <= 3 then
            opcode(71 + offset,-1)
         else
            opcode(57,-1)
            add_u1(offset)
         end
      end

   opcode_astore_0 is
      do
         opcode(75,-1)
      end

   opcode_astore_1 is
      do
         opcode(76,-1)
      end

   opcode_astore_2 is
      do
         opcode(77,-1)
      end

   opcode_astore_3 is
      do
         opcode(78,-1)
      end

   opcode_astore(offset: INTEGER) is
      require
         0 <= offset
         offset <= 255
      do
         if offset <= 3 then
            opcode(75 + offset,-1)
         else
            opcode(58,-1)
            add_u1(offset)
         end
      end

   opcode_iastore is
      do
         opcode(79,-3)
      end

   opcode_lastore is
      do
         opcode(80,-4)
      end

   opcode_fastore is
      do
         opcode(81,-3)
      end

   opcode_dastore is
      do
         opcode(82,-4)
      end

   opcode_aastore is
      do
         opcode(83,-3)
      end

   opcode_bastore is
      do
         opcode(84,-3)
      end

   opcode_castore is
      do
         opcode(85,-3)
      end

   opcode_sastore is
      do
         opcode(86,-3)
      end

   opcode_pop is
      do
         opcode(87,-1)
      end

   opcode_pop2 is
      do
         opcode(88,-2)
      end

   opcode_dup is
      do
         opcode(89,1)
      end

   opcode_dup_x1 is
      do
         opcode(90,1)
      end

   opcode_dup_x2 is
      do
         opcode(91,1)
      end

   opcode_dup2 is
      do
         opcode(92,2)
      end

   opcode_dup2_x1 is
      do
         opcode(93,2)
      end

   opcode_swap is
      do
         opcode(95,0)
      end

   opcode_iadd is
      do
         opcode(96,-1)
      end

   opcode_ladd is
      do
         opcode(97,-2)
      end

   opcode_fadd is
      do
         opcode(98,-1)
      end

   opcode_dadd is
      do
         opcode(99,-2)
      end

   opcode_isub is
      do
         opcode(100,-1)
      end

   opcode_lsub is
      do
         opcode(101,-2)
      end

   opcode_fsub is
      do
         opcode(102,-1)
      end

   opcode_dsub is
      do
         opcode(103,-2)
      end

   opcode_imul is
      do
         opcode(104,-1)
      end

   opcode_lmul is
      do
         opcode(105,-2)
      end

   opcode_fmul is
      do
         opcode(106,-1)
      end

   opcode_dmul is
      do
         opcode(107,-2)
      end

   opcode_idiv is
      do
         opcode(108,-1)
      end

   opcode_ldiv is
      do
         opcode(109,-2)
      end

   opcode_fdiv is
      do
         opcode(110,-1)
      end

   opcode_ddiv is
      do
         opcode(111,-2)
      end

   opcode_irem is
      do
         opcode(112,-1)
      end

   opcode_lrem is
      do
         opcode(113,-2)
      end

   opcode_ineg is
      do
         opcode(116,0)
      end

   opcode_lneg is
      do
         opcode(117,0)
      end

   opcode_fneg is
      do
         opcode(118,0)
      end

   opcode_dneg is
      do
         opcode(119,0)
      end

   opcode_ishl is
      do
         opcode(120,-1)
      end

   opcode_lshl is
      do
         opcode(121,-2)
      end

   opcode_ishr is
      do
         opcode(122,-1)
      end

   opcode_lshr is
      do
         opcode(123,-2)
      end
 
   opcode_iushr is
      do
         opcode(124,-1)
      end

   opcode_lushr is
      do
         opcode(125,-2)
      end

   opcode_iand is
      do
         opcode(126,-1)
      end

   opcode_land is
      do
         opcode(127,-2)
      end

   opcode_ior is
      do
         opcode(128,-1)
      end

   opcode_lor is
      do
         opcode(129,-2)
      end

   opcode_ixor is
      do
         opcode(130,-1)
      end

   opcode_lxor is
      do
         opcode(131,-2)
      end

   opcode_iinc(loc_idx, u1_increment: INTEGER) is
      do
         opcode(132,0)
         add_u1(loc_idx)
         add_u1(u1_increment)
      end

   opcode_i2l is
      do
         opcode(133,1)
      end

   opcode_i2f is
      do
         opcode(134,0)
      end

   opcode_i2d is
      do
         opcode(135,1)
      end

   opcode_l2i is
      do
         opcode(136,-1)
      end

   opcode_l2f is
      do
         opcode(137,-1)
      end

   opcode_l2d is
      do
         opcode(138,0)
      end

   opcode_f2i is
      do
         opcode(139,0)
      end

   opcode_f2l is
      do
         opcode(140,1)
      end

   opcode_f2d is
      do
         opcode(141,1)
      end

   opcode_d2i is
      do
         opcode(142,-1)
      end

   opcode_d2l is
      do
         opcode(143,0)
      end

   opcode_d2f is
      do
         opcode(144,-1)
      end

   opcode_i2b is
      do
         opcode(145,0)
      end

   opcode_i2c is
      do
         opcode(146,0)
      end

   opcode_i2s is
      do
         opcode(147,0)
      end

   opcode_lcmp is
      do
         opcode(148,-3)
      end

   opcode_fcmpg is
      do
         opcode(150,-1)
      end

   opcode_fcmpl is
      do
         opcode(149,-1)
      end

   opcode_dcmpl is
      do
         opcode(151,-3)
      end

   opcode_dcmpg is
      do
         opcode(152,-3)
      end

   opcode_ifeq: INTEGER is
      do
         opcode(153,-1)
         Result := skip_2_bytes
      end

   opcode_ifne: INTEGER is
      do
         opcode(154,-1)
         Result := skip_2_bytes
      end

   opcode_iflt: INTEGER is
      do
         opcode(155,-1)
         Result := skip_2_bytes
      end

   opcode_ifge: INTEGER is
      do
         opcode(156,-1)
         Result := skip_2_bytes
      end

   opcode_ifgt: INTEGER is
      do
         opcode(157,-1)
         Result := skip_2_bytes
      end

   opcode_ifle: INTEGER is
      do
         opcode(158,-1)
         Result := skip_2_bytes
      end

   opcode_if_icmpeq: INTEGER is
      do
         opcode(159,-2)
         Result := skip_2_bytes
      end

   opcode_if_icmpne: INTEGER is
      do
         opcode(160,-2)
         Result := skip_2_bytes
      end

   opcode_if_icmplt: INTEGER is
      do
         opcode(161,-2)
         Result := skip_2_bytes
      end

   opcode_if_icmpge: INTEGER is
      do
         opcode(162,-2)
         Result := skip_2_bytes
      end

   opcode_if_icmpgt: INTEGER is
      do
         opcode(163,-2)
         Result := skip_2_bytes
      end

   opcode_if_icmple: INTEGER is
      do
         opcode(164,-2)
         Result := skip_2_bytes
      end

   opcode_if_acmpeq: INTEGER is
      do
         opcode(165,-2)
         Result := skip_2_bytes
      end

   opcode_if_acmpne: INTEGER is
      do
         opcode(166,-2)
         Result := skip_2_bytes
      end

   opcode_goto: INTEGER is
      do
         opcode(167,0)
         Result := skip_2_bytes
      end

   opcode_goto_backward(back_point: INTEGER) is
         -- Produce a goto opcode to go back at `back_point'.
      require
         back_point < program_counter
      local
         r, q, offset: INTEGER
      do
         offset := program_counter - back_point
         opcode(167,0)
         r := offset \\ 256
         q := offset // 256
         if r = 0 then
            add_u1(256 - q)
            add_u1(0)
         else
            add_u1(255 - q)
            add_u1(256 - r)
         end
      end

   opcode_ireturn is
      do
         add_u1(172)
      end

   opcode_lreturn is
      do
         add_u1(173)
      end

   opcode_freturn is
      do
         add_u1(174)
      end

   opcode_dreturn is
      do
         add_u1(175)
      end

   opcode_areturn is
      do
         add_u1(176)
      end

   opcode_return is
      do
         add_u1(177)
      end

   opcode_getstatic(fieldref_idx, stack_inc: INTEGER) is
      require
         constant_pool.valid_index(fieldref_idx)
      do
         opcode(178,stack_inc)
         add_u2(fieldref_idx)
      end

   opcode_putstatic(fieldref_idx, stack_inc: INTEGER) is
      require
         constant_pool.valid_index(fieldref_idx)
      do
         opcode(179,stack_inc)
         add_u2(fieldref_idx)
      end

   opcode_getfield(fieldref_idx, stack_inc: INTEGER) is
      require
         constant_pool.valid_index(fieldref_idx)
      do
         opcode(180,stack_inc)
         add_u2(fieldref_idx)
      end

   opcode_putfield(fieldref_idx, stack_inc: INTEGER) is
      require
         constant_pool.valid_index(fieldref_idx)
      do
         opcode(181,stack_inc)
         add_u2(fieldref_idx)
      end

   opcode_invokevirtual(methodref_idx, stack_inc: INTEGER) is
      require
         constant_pool.is_methodref(methodref_idx)
      do
         opcode(182,stack_inc)
         add_u2(methodref_idx)
      end

   opcode_invokespecial(methodref_idx, stack_inc: INTEGER) is
      require
         constant_pool.is_methodref(methodref_idx)
      do
         opcode(183,stack_inc)
         add_u2(methodref_idx)
      end

   opcode_invokestatic(methodref_idx, stack_inc: INTEGER) is
      require
         constant_pool.is_methodref(methodref_idx)
      do
         opcode(184,stack_inc)
         add_u2(methodref_idx)
      end

   opcode_invokeinterface(methodref_idx, stack_inc, stack_words: INTEGER) is
      require
         constant_pool.is_interface_methodref(methodref_idx)
      do
         opcode(185,stack_inc)
         add_u2(methodref_idx)
         add_u1(stack_words)
         opcode_nop
      end

   opcode_new(class_idx: INTEGER) is
      require
         constant_pool.is_class(class_idx)
      do
         opcode(187,1)
         add_u2(class_idx)
      end

   opcode_newarray(u1: INTEGER) is
      require
         4 <= u1
         u1 <= 11
      do
         opcode(188,0)
         add_u1(u1)
      end

   opcode_anewarray(idx: INTEGER) is
      require
         constant_pool.valid_index(idx)
      do
         opcode(189,0)
         add_u2(idx)
      end

   opcode_arraylength is
      do
         opcode(190,0)
      end

   opcode_athrow is
      do
         opcode(191,0)
      end

feature 

   opcode_checkcast(class_idx: INTEGER) is
      require
         constant_pool.is_class(class_idx)
      do
         opcode(192,0)
         add_u2(class_idx)
      end

feature {RUN_CLASS,NATIVE}

   opcode_instanceof(class_idx: INTEGER) is
      require
         constant_pool.is_class(class_idx)
      do
         opcode(193,0)
         add_u2(class_idx)
      end

feature {NATIVE}

   opcode_monitorenter is
      do
         opcode(194,0)
      end

   opcode_monitorexit is
      do
         opcode(195,0)
      end

feature

   opcode_multianewarray(idx: INTEGER; dims: INTEGER) is
      require
         constant_pool.valid_index(idx)
         dims > 0 and dims < 256
      do
         opcode(197,0)
         add_u2(idx)
         add_u1(dims)
      end

feature

   opcode_ifnull: INTEGER is
      do
         opcode(198,-1)
         Result := skip_2_bytes
      end

   opcode_ifnonnull: INTEGER is
      do
         opcode(199,-1)
         Result := skip_2_bytes
      end

feature -- High level opcode calls :

   opcode_push_integer(i: INTEGER) is
      do
         if i < -32768 then
            push_strange_integer(i)
         elseif i < -128 then
            opcode_sipush(i)
         elseif i < -1 then
            opcode_bipush(256 + i)
         elseif i <= 5 then
            opcode_iconst_i(i)
         elseif i <= 127 then
            opcode_bipush(i)
         elseif i <= 32767 then
            opcode_sipush(i)
         else
            push_strange_integer(i)
         end
      end

   opcode_push_long(i: INTEGER) is
      do
         if i < 0 then
            push_strange_long(i)
         elseif i <= 1 then
            opcode_lconst_i(i)
         else
            push_strange_long(i)
         end
      end

   opcode_push_as_integer_64(str: STRING) is
      require
         str.count >= 1
      do
         if str.item(1) = '0' and str.count = 1 then
            opcode(9,2)
         elseif str.item(1) = '1' and str.count = 1 then
            opcode(10,2)
         else
            opcode_string2long(str)
         end
      end

   opcode_push_as_float(str: STRING) is
      require
         str.count >= 1
      do
         inspect
            str.item(1)
         when '0' then
            if str.count = 1 then
               opcode(11,1)
            else
               inspect
                  str.item(2)
               when '.' then
                  if str.count = 2 then
                     opcode(11,1)
                  elseif str.count = 3 and then str.item(3) = '0' then
                     opcode(11,1)
                  else
                     opcode_string2float(str)
                  end
               else
                  opcode_string2float(str)
               end
            end
         when '1' then
            if str.count = 1 then
               opcode(12,1)
            else
               inspect
                  str.item(2)
               when '.' then
                  if str.count = 2 then
                     opcode(12,1)
                  elseif str.count = 3 and then str.item(3) = '0' then
                     opcode(12,1)
                  else
                     opcode_string2float(str)
                  end
               else
                  opcode_string2float(str)
               end
            end
         when '2' then
            if str.count = 1 then
               opcode(13,1)
            else
               inspect
                  str.item(2)
               when '.' then
                  if str.count = 2 then
                     opcode(13,1)
                  elseif str.count = 3 and then str.item(3) = '0' then
                     opcode(13,1)
                  else
                     opcode_string2float(str)
                  end
               else
                  opcode_string2float(str)
               end
            end
         else
            opcode_string2float(str)
         end
      end

   opcode_push_as_double(str: STRING) is
      require
         str.count >= 1
      do
         inspect
            str.item(1)
         when '0' then
            if str.count = 1 then
               opcode(14,2)
            else
               inspect
                  str.item(2)
               when '.' then
                  if str.count = 2 then
                     opcode(14,2)
                  elseif str.count = 3 and then str.item(3) = '0' then
                     opcode(14,2)
                  else
                     opcode_string2double(str)
                  end
               else
                  opcode_string2double(str)
               end
            end
         when '1' then
            if str.count = 1 then
               opcode(15,2)
            else
               inspect
                  str.item(2)
               when '.' then
                  if str.count = 2 then
                     opcode(15,2)
                  elseif str.count = 3 and then str.item(3) = '0' then
                     opcode(15,2)
                  else
                     opcode_string2double(str)
                  end
               else
                  opcode_string2double(str)
               end
            end
         else
            opcode_string2double(str)
         end
      end

   opcode_push_manifest_string(ms: STRING) is
         -- Produces code to push the corresponding Eiffel STRING.
      local
         ms_idx: INTEGER
      do
         ms_idx := constant_pool.idx_string2(ms)
         opcode_ldc(ms_idx)
         opcode_java_string2eiffel_string
      end

   opcode_java_string2bytes_array is
         -- Used the pushed Java String to create the bytes array.
      local
         idx: INTEGER
      do
         idx := constant_pool.idx_methodref3(fz_java_lang_string,fz_33,fz_34)
         opcode_invokevirtual(idx,0)
      end

   opcode_java_string2eiffel_string is
         -- Used the pushed Java String to create a new Eiffel STRING.
      do
         opcode_java_string2bytes_array
         opcode_bytes_array2eiffel_string
      end

   opcode_bytes_array2eiffel_string is
         -- Used the pushed Bytes array to create a new Eiffel STRING.
      local
         cp: like constant_pool
         loc: INTEGER
         rc_string: RUN_CLASS
      do
         cp := constant_pool
         rc_string := type_string.run_class
         loc := extra_local_size1
         opcode_astore(loc)
         -- The new STRING :
         rc_string.jvm_basic_new
         -- Set count :
         opcode_dup
         opcode_aload(loc)
         opcode_arraylength
         opcode_putfield(cp.idx_eiffel_string_count_fieldref,-2)
         -- Set capacity :
         opcode_dup
         opcode_aload(loc)
         opcode_arraylength
         opcode_putfield(cp.idx_eiffel_string_capacity_fieldref,-2)
         -- Set storage :
         opcode_dup
         opcode_aload(loc)
         opcode_putfield(cp.idx_eiffel_string_storage_fieldref,-2)
      end

feature {TYPE_BIT}

   opcode_bitset_clone is
      local
         cp: like constant_pool
         idx: INTEGER
      do
         cp := constant_pool
         idx := cp.idx_methodref3(fz_java_util_bitset,fz_a6,fz_a7)
         opcode_invokevirtual(idx,0)
         idx := cp.idx_class2(fz_java_util_bitset)
         opcode_checkcast(idx)
      end

feature -- Easy access to some Java basics:

   opcode_println(string_idx: INTEGER) is
      require
         constant_pool.valid_index(string_idx)
      local
         idx: INTEGER
      do
         opcode_ldc(string_idx)
         idx := constant_pool.idx_methodref3(fz_25,fz_51,fz_57)
         opcode_invokevirtual(idx,-2)
      end

feature {NONE}

   opcode(opcode_value, max_stack_increment: INTEGER) is
      require
         stack_level >= 0
         opcode_value <= 255
      local
         cs: INTEGER
      do
         add_u1(opcode_value)
         cs := stack_level + max_stack_increment
         if cs >= 0 then
            stack_level := cs
         else
            -- ????
         end
         if stack_level > max_stack then
            max_stack := stack_level
         end
      ensure
         stack_level >= 0
      end

   add_u1(u1: INTEGER) is
      do
         code.add_last(u1)
      ensure
         program_counter = 1 + old program_counter
      end

   add_u2(u2: INTEGER) is
      local
         hi: INTEGER
         lo: INTEGER
         u: INTEGER
      do
         u := u2.abs
         hi := u // 256
         lo := u \\ 256
         if u2 < 0 then
            hi := hi.bit_not
            hi := hi.bit_and( 255 )
            lo := lo.bit_not
            lo := lo.bit_and( 255 )
            lo := lo + 1
            if lo = 256 then
               lo := 0
               hi := hi + 1
            end
         end
         add_u1( hi )
         add_u1( lo )
      ensure
         program_counter = 2 + old program_counter
      end

   skip_2_bytes: INTEGER is
         -- Return the `programm_counter' before the skip.
      do
         Result := program_counter
         code.add_last(0)
         code.add_last(0)
      end

feature

   resolve_u2_branch(start_point: INTEGER) is
      require
         start_point < program_counter
         start_point > 0
      local
         offset: INTEGER
      do
         offset := program_counter - start_point + 1
         code.put(offset // 256,start_point)
         code.put(offset \\ 256,start_point + 1)
      end

feature

   next_branch_array_index: INTEGER
   
   get_branch_array_index: INTEGER is
      require
         next_branch_array_index >= 0
      local
         fai: FIXED_ARRAY[INTEGER]
      do
         branch_array.item(next_branch_array_index).clear
         Result := next_branch_array_index
         next_branch_array_index := next_branch_array_index + 1
         if not branch_array.valid_index( next_branch_array_index ) then
            create fai.with_capacity(16)
            branch_array.force( fai, next_branch_array_index )
         end
      end
      
   release_branch_array_index is
      do
         next_branch_array_index := next_branch_array_index - 1
      ensure
         next_branch_array_index >= 0
      end
      
   add_branch( point: INTEGER; index: INTEGER ) is
      require
         branch_array.valid_index(index)
      do
         branch_array.item(index).add_last(point)
      ensure
         branch_array.item(index).has(point)
      end
      
   branch_array: FIXED_ARRAY[FIXED_ARRAY[INTEGER]] is
      local
         fai: FIXED_ARRAY[INTEGER]
      once
         !!Result.with_capacity(4)
         create fai.with_capacity(16)
         branch_array.force( fai, 0 )
         create fai.with_capacity(16)
         branch_array.force( fai, 1 )
         create fai.with_capacity(16)
         branch_array.force( fai, 2 )
         create fai.with_capacity(16)
         branch_array.force( fai, 3 )
      end

   resolve_branches( index: INTEGER ) is
      do
         resolve_with(branch_array.item(index))
      end

   resolve_with(points: FIXED_ARRAY[INTEGER]) is
      local
         i: INTEGER
      do
         from
            i := points.upper
         until
            i < 0
         loop
            resolve_u2_branch(points.item(i))
            i := i - 1
         end
      end

feature {NONE}

   check_flag_idx,  skip_check: INTEGER

feature {ASSERTION_LIST}

   check_opening is
      local
         cp: like constant_pool
      do
         cp := constant_pool
         opcode_iconst_1
         check_flag_idx := cp.idx_fieldref3(jvm_root_class,fz_58,fz_41)
         opcode_getstatic(check_flag_idx,1)
         skip_check := opcode_ifne
         opcode_putstatic(check_flag_idx,-1)
      end

   check_closing is
      do
         opcode_iconst_0
         opcode_putstatic(check_flag_idx,-1)
         resolve_u2_branch(skip_check)
      end

feature {NONE}

   opcode_string2long(str: STRING) is
      local
         idx: INTEGER
      do
         idx := constant_pool.idx_string(str)
         opcode_ldc(idx)
         idx := constant_pool.idx_methodref3(fz_java_lang_long,fz_c1,fz_de)
         opcode_invokestatic(idx,1)
      end

   opcode_string2double(str: STRING) is
      local
         idx: INTEGER
      do
         idx := constant_pool.idx_string(str)
         opcode_ldc(idx)
         idx := constant_pool.idx_methodref3(fz_java_lang_double,fz_c0,fz_61)
         opcode_invokestatic(idx,1)
      end

   opcode_string2float(str: STRING) is
      do
         opcode_string2double(str)
         opcode_d2f
      end

feature {NONE}

   push_strange_integer(i: INTEGER) is
      local
         idx: INTEGER
         cp: like constant_pool
      do
         cp := constant_pool
         tmp_string.clear
         i.append_in(tmp_string)
         idx := cp.idx_string(tmp_string)
         opcode_ldc(idx)
         idx := cp.idx_methodref3(fz_java_lang_integer,fz_82,fz_83)
         opcode_invokestatic(idx,0)
      end

   push_strange_long(i: INTEGER) is
      local
         idx: INTEGER
         cp: like constant_pool
      do
         cp := constant_pool
         tmp_string.clear
         i.append_in(tmp_string)
         idx := cp.idx_string(tmp_string)
         opcode_ldc(idx)
         idx := cp.idx_methodref3(fz_java_lang_long,fz_c1,fz_de)
         opcode_invokestatic(idx,0)
       end

   tmp_string: STRING is
      once
         !!Result.make(32)
      end

feature {NONE}

   exception_table: EXCEPTION_TABLE is
      once
         !!Result.make
      end

feature

   add_exception(f, t, h, idx: INTEGER) is
      do
         exception_table.add(f,t,h,idx)
      end

feature -- Calls to SmartEiffelRuntime.java :


   runtime_die_with_code is
         -- Assume the status code is already pushed.
      local
         cp: like constant_pool
         idx: INTEGER
      do
         cp := constant_pool
         idx := cp.idx_methodref3(fz_se_runtime,as_die_with_code,fz_27)
         opcode_invokestatic(idx,-1)
      end

   runtime_internal_exception_number is
      local
         cp: like constant_pool
         idx: INTEGER
      do
         cp := constant_pool
         idx := cp.idx_fieldref3(fz_se_runtime,"internal_exception_number",fz_i)
         opcode_getstatic(idx,1)
      end

   runtime_error(p: POSITION; t: E_TYPE; message: STRING) is
      local
         cp: like constant_pool
         idx: INTEGER
      do
         cp := constant_pool
         push_position(p)
         if t = Void then
            opcode_aconst_null
         else
            opcode_ldc(cp.idx_string(t.run_time_mark))
         end
         opcode_ldc(cp.idx_string(message))
         idx := cp.idx_methodref3(fz_se_runtime,"runtime_error",
         "(IILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V")
         opcode_invokestatic(idx,-5)
      end

   runtime_error_bad_target(p: POSITION; t: E_TYPE; message: STRING) is
         -- Assume the bad target is pushed.
         -- The expected type, if any is `t'.
      local
         cp: like constant_pool
         idx: INTEGER
      do
         cp := constant_pool
         push_position(p)
         opcode_ldc(cp.idx_string(t.run_time_mark))
         if message = Void then
            opcode_aconst_null
         else
            opcode_ldc(cp.idx_string(message))
         end
         idx := cp.idx_methodref3(fz_se_runtime,"runtime_error_bad_target",
         "(Ljava/lang/Object;IILjava/lang/String;Ljava/lang/String;%
         %Ljava/lang/String;)V")
         opcode_invokestatic(idx,-6)
      end

feature {E_LOOP}

   runtime_check_loop_variant(expression: EXPRESSION) is
         -- Assume the loop counter and the previous variant value
         -- is already pushed.
         -- Returns the next variant value.
      require
         expression /= Void
      local
         cp: like constant_pool
         idx: INTEGER
      do
         cp := constant_pool
         expression.compile_to_jvm
         push_position(expression.start_position)
         idx := cp.idx_methodref3(fz_se_runtime,"runtime_check_loop_variant",
         "(IIIIILjava/lang/String;)I")
         opcode_invokestatic(idx,-5)
      end

feature {E_INSPECT}

   runtime_error_inspect(expression: EXPRESSION) is
         -- Assume the not selected inspect value of `expression' is
         -- already pushed.
      local
         cp: like constant_pool
         rt: E_TYPE
         idx: INTEGER
      do
         cp := constant_pool
         rt := expression.result_type
         if rt.is_character then
            -- Convert byte 2 int ??
         end
         push_position(expression.start_position)
         idx := cp.idx_methodref3(fz_se_runtime,"runtime_error_inspect",
         "(IIILjava/lang/String;)I")
         opcode_invokestatic(idx,-3)
      end

feature {COMPOUND}

   se_trace(ct: E_TYPE; p: POSITION) is
         -- Assume the Current target of type `ct' is pushed.
      require
         p.sedb_trace
      local
         cp: like constant_pool
         idx: INTEGER
      do
         if p.is_unknown then
            opcode_pop
         else
            cp := constant_pool
            ct.jvm_push_local(0)
            push_position(p)
            tmp_string.clear
            tmp_string.extend('(')
            if ct.is_basic_eiffel_expanded then
               ct.jvm_descriptor_in(tmp_string)
            else
               tmp_string.append("Ljava/lang/Object;")
            end
            tmp_string.append("IILjava/lang/String;)V")
            idx := cp.idx_methodref3(fz_se_runtime,"se_trace",tmp_string)
            opcode_invokestatic(idx,- ct.jvm_stack_space - 3)
         end
      end

feature {NONE}

   push_position(p: POSITION) is
      do
         opcode_push_integer(p.line)
         opcode_push_integer(p.column)
         if p.is_unknown then
            opcode_aconst_null
         else
            opcode_ldc(constant_pool.idx_string(p.path))
         end
      end

invariant

   stack_level >= 0

   stack_level <= max_stack

end -- CODE_ATTRIBUTE