home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / AACD / Programming / sofa / archive / SmallEiffel.lha / SmallEiffel / lib_se / switch.e < prev    next >
Text File  |  1999-06-05  |  14KB  |  454 lines

  1. --          This file is part of SmallEiffel The GNU Eiffel Compiler.
  2. --          Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
  3. --            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr
  4. --                       http://SmallEiffel.loria.fr
  5. -- SmallEiffel is  free  software;  you can  redistribute it and/or modify it
  6. -- under the terms of the GNU General Public License as published by the Free
  7. -- Software  Foundation;  either  version  2, or (at your option)  any  later
  8. -- version. SmallEiffel is distributed in the hope that it will be useful,but
  9. -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. -- or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU General Public License
  11. -- for  more  details.  You  should  have  received a copy of the GNU General
  12. -- Public  License  along  with  SmallEiffel;  see the file COPYING.  If not,
  13. -- write to the  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  14. -- Boston, MA 02111-1307, USA.
  15. --
  16. expanded class SWITCH
  17.    --
  18.    -- Set of tools (no attributes) to handle one switching site.
  19.    --
  20.  
  21. inherit GLOBALS;
  22.  
  23. feature {NONE}
  24.  
  25.    running: ARRAY[RUN_CLASS] is
  26.          -- The global one.
  27.       once
  28.          !!Result.with_capacity(256,1);
  29.       end;
  30.  
  31. feature
  32.  
  33.    c_define(up_rf: RUN_FEATURE) is
  34.          -- Define the switching C function for `up_rf'.
  35.       require
  36.          cpp.on_c
  37.       local
  38.          boost: BOOLEAN;
  39.          arguments:  FORMAL_ARG_LIST;
  40.          result_type, arg_type: TYPE;
  41.          i: INTEGER;
  42.       do
  43.          boost := run_control.boost;
  44.          arguments := up_rf.arguments;
  45.          result_type := up_rf.result_type;
  46.          c_code.clear;
  47.          if result_type = Void then
  48.             c_code.append(fz_void);
  49.          else
  50.             result_type := result_type.run_type;
  51.             result_type.c_type_for_result_in(c_code);
  52.          end;
  53.          c_code.extend(' ');
  54.          c_code.extend('X');
  55.          up_rf.current_type.id.append_in(c_code);
  56.          up_rf.name.mapping_c_in(c_code);
  57.          if boost then
  58.             c_code.append("(void *C");
  59.          else
  60.             c_code.append("(se_dump_stack*caller,int l,int c,int f, void *C");
  61.          end;
  62.          if arguments /= Void then
  63.             from
  64.                i := 1;
  65.             until
  66.                i > arguments.count
  67.             loop
  68.                c_code.extend(',');
  69.                arg_type := arguments.type(i).run_type;
  70.                arg_type.c_type_for_argument_in(c_code);
  71.                c_code.append(" a");
  72.                i.append_in(c_code);
  73.                i := i + 1;
  74.             end;
  75.          end;
  76.          c_code.extend(')');
  77.          cpp.put_c_heading(c_code);
  78.          cpp.swap_on_c;
  79.          if result_type /= Void then
  80.             c_code.clear;
  81.             result_type.c_type_for_result_in(c_code);
  82.             c_code.extend(' ');
  83.             c_code.extend('R');
  84.             if not boost then
  85.                c_code.extend('=');
  86.                result_type.c_initialize_in(c_code);
  87.             end;
  88.             c_code.append(fz_00);
  89.             cpp.put_string(c_code);
  90.          end;
  91.          if not boost then
  92.             cpp.put_string("se_dump_stack ds=*caller;%N");
  93.          end;
  94.          cpp.put_string("{int id=");
  95.          running.copy(up_rf.current_type.run_class.running);
  96.          sort_running(running);
  97.          if boost then
  98.             cpp.put_string("((T0*)C)->id;%N");
  99.          else
  100.             cpp.put_string("vc(C,l,c,f)->id;%N");
  101.          end;
  102.          if run_control.all_check then
  103.             c_switch(up_rf);
  104.          else
  105.             c_dicho(up_rf,1,running.upper);
  106.          end;
  107.          cpp.put_string(fz_12);
  108.          if not boost then
  109.             cpp.put_string("se_dst=caller;%N");
  110.          end;
  111.          if result_type /= Void then
  112.             cpp.put_string(fz_15);
  113.          else
  114.             cpp.put_string(fz_12);
  115.          end;
  116.          cpp.finished_switch(running.upper);
  117.       ensure
  118.          cpp.on_c
  119.       end;
  120.  
  121. feature {C_PRETTY_PRINTER}
  122.  
  123.    put_arguments(up_rf: RUN_FEATURE; fal: FORMAL_ARG_LIST) is
  124.          -- Produce C code for arguments of `fal' used
  125.          -- inside the switching C function.
  126.       require
  127.          cpp.on_c;
  128.          fal.count = up_rf.arguments.count
  129.       local
  130.          i, up: INTEGER;
  131.       do
  132.          from
  133.             i := 1;
  134.             up := fal.count;
  135.          until
  136.             i > up
  137.          loop
  138.             if i > 1 then
  139.                cpp.put_character(',');
  140.             end;
  141.             put_ith_argument(up_rf,fal,i);
  142.             i := i + 1;
  143.          end;
  144.       ensure
  145.          cpp.on_c
  146.       end;
  147.  
  148.    put_ith_argument(up_rf: RUN_FEATURE; fal: FORMAL_ARG_LIST; index: INTEGER) is
  149.          -- Produce C code for argument `index' of `fal' used
  150.          -- inside the switching C function.
  151.       require
  152.          cpp.on_c;
  153.          fal.count = up_rf.arguments.count;
  154.          1 <= index;
  155.          index <= fal.count
  156.       local
  157.          eal: like fal;
  158.          at, ft: TYPE;
  159.       do
  160.          eal := up_rf.arguments;
  161.          at := eal.type(index).run_type;
  162.          ft := fal.type(index).run_type;
  163.          if at.is_reference and then ft.is_basic_eiffel_expanded then
  164.             cpp.put_character('(');
  165.             ft.cast_to_ref;
  166.             cpp.put_character('a');
  167.             cpp.put_integer(index);
  168.             cpp.put_string(")->_item");
  169.          else
  170.             cpp.put_character('a');
  171.             cpp.put_integer(index);
  172.          end;
  173.       ensure
  174.          cpp.on_c
  175.       end;
  176.  
  177. feature {NONE}
  178.  
  179.    c_dicho(up_rf: RUN_FEATURE; bi, bs: INTEGER) is
  180.          -- Produce dichotomic inspection code for Current id.
  181.       require
  182.          bi <= bs
  183.       local
  184.          m: INTEGER;
  185.          dyn_rc: RUN_CLASS;
  186.          dyn_rf: RUN_FEATURE;
  187.       do
  188.          if bi = bs then
  189.             dyn_rc := running.item(bi);
  190.             dyn_rf := dyn_rc.dynamic(up_rf);
  191.             tail_opening(up_rf.result_type,dyn_rf.result_type);
  192.             cpp.push_switch(dyn_rf,up_rf);
  193.             dyn_rf.mapping_c;
  194.             cpp.pop;
  195.             tail_closing(up_rf.result_type,dyn_rf.result_type);
  196.          else
  197.             m := (bi + bs) // 2;
  198.             dyn_rc := running.item(m);
  199.             cpp.put_string("if(id<=");
  200.             cpp.put_integer(dyn_rc.id);
  201.             cpp.put_string("){%N");
  202.             c_dicho(up_rf,bi,m);
  203.             cpp.put_string("}%Nelse{%N");
  204.             c_dicho(up_rf,m + 1,bs);
  205.             cpp.put_character('}');
  206.          end;
  207.       end;
  208.  
  209.    c_switch(up_rf: RUN_FEATURE) is
  210.          -- Produce C switch inspection code for Current id.
  211.       local
  212.          i: INTEGER;
  213.          dyn_rc: RUN_CLASS;
  214.          dyn_rf: RUN_FEATURE;
  215.       do
  216.          cpp.put_string("switch(id){%N");
  217.          from
  218.             i := 1;
  219.          until
  220.             i > running.upper
  221.          loop
  222.             dyn_rc := running.item(i);
  223.             dyn_rf := dyn_rc.dynamic(up_rf);
  224.             cpp.put_string("case ");
  225.             cpp.put_integer(dyn_rc.id);
  226.             cpp.put_character(':');
  227.             tail_opening(up_rf.result_type,dyn_rf.result_type);
  228.             cpp.push_switch(dyn_rf,up_rf);
  229.             dyn_rf.mapping_c;
  230.             cpp.pop;
  231.             tail_closing(up_rf.result_type,dyn_rf.result_type);
  232.             cpp.put_string("%Nbreak;%N");
  233.             i := i + 1;
  234.          end;
  235.          if run_control.no_check then
  236.             cpp.put_string("default: error2(C,l,c,f);%N");
  237.          end;
  238.          cpp.put_string(fz_12);
  239.       end;
  240.  
  241. feature {C_PRETTY_PRINTER,SWITCH}
  242.  
  243.    name(up_rf: RUN_FEATURE): STRING is
  244.       do
  245.          c_code.clear;
  246.          c_code.extend('X');
  247.          up_rf.current_type.id.append_in(c_code);
  248.          c_code.append(up_rf.name.to_key);
  249.          Result := c_code;
  250.       end;
  251.  
  252. feature
  253.  
  254.    jvm_descriptor(up_rf: RUN_FEATURE): STRING is
  255.       local
  256.          arguments:  FORMAL_ARG_LIST;
  257.          rt: TYPE;
  258.       do
  259.          arguments := up_rf.arguments;
  260.          tmp_jvmd.clear;
  261.          tmp_jvmd.extend('(');
  262.          tmp_jvmd.append(jvm_root_descriptor);
  263.          if arguments /= Void then
  264.             arguments.jvm_descriptor_in(tmp_jvmd);
  265.          end;
  266.          rt := up_rf.result_type;
  267.          if rt = Void then
  268.             tmp_jvmd.append(fz_19);
  269.          else
  270.             rt := rt.run_type;
  271.             tmp_jvmd.extend(')');
  272.             if rt.is_reference then
  273.                tmp_jvmd.append(jvm_root_descriptor);
  274.             else
  275.                rt.jvm_descriptor_in(tmp_jvmd);
  276.             end;
  277.          end;
  278.          Result := tmp_jvmd;
  279.       end;
  280.  
  281. feature {NONE}
  282.  
  283.    tmp_jvmd: STRING is
  284.       once
  285.          !!Result.make(32);
  286.       end;
  287.  
  288. feature
  289.  
  290.    idx_methodref(up_rf: RUN_FEATURE): INTEGER is
  291.       require
  292.          up_rf /= Void
  293.       do
  294.          Result := constant_pool.idx_methodref3(jvm_root_class,
  295.                                                 name(up_rf),
  296.                                                 jvm_descriptor(up_rf));
  297.       end;
  298.  
  299. feature {JVM}
  300.  
  301.    jvm_mapping(cpc: CALL_PROC_CALL) is
  302.       require
  303.          cpc /= Void
  304.       local
  305.          idx, stack_level: INTEGER;
  306.          up_rf: RUN_FEATURE;
  307.          target: EXPRESSION;
  308.          eal: EFFECTIVE_ARG_LIST;
  309.          fal: FORMAL_ARG_LIST;
  310.          switch: SWITCH;
  311.       do
  312.          target := cpc.target;
  313.          up_rf := cpc.run_feature;
  314.          eal := cpc.arguments;
  315.          target.compile_to_jvm;
  316.          stack_level := 1;
  317.          if eal /= Void then
  318.             fal := up_rf.arguments;
  319.             stack_level := stack_level + eal.compile_to_jvm(fal);
  320.          end;
  321.          if up_rf.result_type /= Void then
  322.             stack_level := stack_level - up_rf.result_type.jvm_stack_space;
  323.          end;
  324.          idx := switch.idx_methodref(up_rf);
  325.          code_attribute.opcode_invokestatic(idx,-stack_level);
  326.       end;
  327.  
  328. feature {SWITCH_COLLECTION}
  329.  
  330.    jvm_define(up_rf: RUN_FEATURE) is
  331.       local
  332.          rt: TYPE;
  333.       do
  334.          -- Define the Java switching static method for `up_rf'.
  335.          method_info.start(9,name(up_rf),jvm_descriptor(up_rf));
  336.          running.copy(up_rf.current_type.run_class.running);
  337.          rt := up_rf.result_type;
  338.          if rt /= Void then
  339.             rt := rt.run_type;
  340.          end;
  341.          jvm_switch(up_rf,rt);
  342.          method_info.finish;
  343.       end;
  344.  
  345. feature {NONE}
  346.  
  347.    c_code: STRING is
  348.       once
  349.          !!Result.make(256);
  350.       end;
  351.  
  352.    tail_opening(x_type, r_type: TYPE) is
  353.       do
  354.          if x_type /= Void then
  355.             c_code.copy("R=((");
  356.             x_type.c_type_for_result_in(c_code);
  357.             c_code.append(")(");
  358.             cpp.put_string(c_code);
  359.             if r_type.is_expanded and then x_type.is_reference then
  360.                r_type.to_reference;
  361.                cpp.put_character('(');
  362.             end;
  363.          end;
  364.       end;
  365.  
  366.    tail_closing(x_type, r_type: TYPE) is
  367.       do
  368.          if x_type /= Void then
  369.             if r_type.is_expanded and then x_type.is_reference then
  370.                cpp.put_character(')');
  371.             end;
  372.             cpp.put_string(fz_16);
  373.          end;
  374.       end;
  375.  
  376. feature {NONE}
  377.  
  378.    jvm_switch(up_rf: RUN_FEATURE; rt: TYPE) is
  379.          -- Produce Java sequential switch code.
  380.       require
  381.          rt /= Void implies rt.run_type = rt
  382.       local
  383.          space, point, i: INTEGER;
  384.          dyn_rc: RUN_CLASS;
  385.          dyn_rf: RUN_FEATURE;
  386.          boost: BOOLEAN;
  387.          ca: like code_attribute;
  388.          static_na, dynamic_na: TYPE_NATIVE_ARRAY;
  389.       do
  390.          ca := code_attribute;
  391.          from
  392.             boost := run_control.boost;
  393.             i := running.upper;
  394.          until
  395.             i = 0
  396.          loop
  397.             dyn_rc := running.item(i);
  398.             dyn_rf := dyn_rc.dynamic(up_rf);
  399.             if i = 1 and then boost then
  400.             else
  401.                ca.opcode_aload_0;
  402.                dyn_rf.run_class.opcode_instanceof;
  403.                point := ca.opcode_ifeq;
  404.             end;
  405.             jvm.push_switch(dyn_rf,up_rf);
  406.             dyn_rf.mapping_jvm;
  407.             jvm.pop;
  408.             if rt = Void then
  409.                ca.opcode_return;
  410.             elseif rt.is_native_array then
  411.                static_na ?= rt.run_type;
  412.                dynamic_na ?= dyn_rf.result_type.run_type;
  413.                if static_na.run_time_mark = dynamic_na.run_time_mark then
  414.                   static_na.jvm_return_code;
  415.                elseif static_na.of_references and then dynamic_na.of_references then
  416.                   static_na.jvm_return_code;
  417.                else
  418.                   if run_control.no_check then
  419.                      ca.runtime_error(up_rf.start_position,up_rf.current_type,
  420.                      "System-level Validity error detected inside virtual %
  421.                      %switching code.%N%
  422.                      %Bad NATIVE_ARRAY type return type.");
  423.                   end;
  424.                   ca.opcode_pop;
  425.                   space := rt.jvm_push_default;
  426.                   rt.jvm_return_code;
  427.                end;
  428.             else
  429.                space := dyn_rf.result_type.jvm_convert_to(rt);
  430.                rt.jvm_return_code;
  431.             end;
  432.             if i = 1 and then boost then
  433.             else
  434.                ca.resolve_u2_branch(point);
  435.             end;
  436.             i := i - 1;
  437.          end;
  438.          if not boost then
  439.             ca.opcode_aload_0;
  440.             ca.runtime_error_bad_target(up_rf.start_position,up_rf.current_type,
  441.                "System-level Validity error detected inside virtual %
  442.                %switching code.%N%
  443.                %Bad target type for dynamic dispatch.");
  444.             if rt = Void then
  445.                ca.opcode_return;
  446.             else
  447.                space := rt.jvm_push_default;
  448.                rt.jvm_return_code;
  449.             end;
  450.          end;
  451.       end;
  452.  
  453. end
  454.