note description: "Generation of IL code using a bridge pattern." legal: "See notice at end of class." status: "See notice at end of class." date: "$Date$" revision: "$Revision$" deferred class CIL_CODE_GENERATOR inherit IL_CODE_GENERATOR rename generate_last_exception as generate_get_last_exception end IL_CONST IL_PREDEFINED_CUSTOM_ATTRIBUTES export {NONE} all end IL_PREDEFINED_STRINGS export {NONE} all end SHARED_IL_CONSTANTS SHARED_IL_DEBUG_INFO_RECORDER SHARED_WORKBENCH export {NONE} all end COMPILER_EXPORTER export {NONE} all end SHARED_INST_CONTEXT export {NONE} all end ASSERT_TYPE export {NONE} all end SHARED_NAMES_HEAP export {NONE} all end SHARED_BYTE_CONTEXT rename context as byte_context export {NONE} all end SHARED_IL_CASING export {NONE} all end SHARED_GENERATION export {NONE} all end SHARED_ERROR_HANDLER export {NONE} all end SHARED_TYPES export {NONE} all end REFACTORING_HELPER export {NONE} all end SHARED_BN_STATELESS_VISITOR export {NONE} all end INTERNAL_COMPILER_STRING_EXPORTER export {NONE} all end SHARED_ENCODING_CONVERTER export {NONE} all end CLI_EMITTER_SERVICE export {NONE} all end feature {NONE} -- Initialization make -- Initialize generator. local f: FEATURE_I do f := System.any_class.compiled_class.feature_table. item_id ({PREDEFINED_NAMES}.Standard_twin_name_id) if f = Void then -- "standard_twin" is not found in ANY standard_twin_body_index := -1 else standard_twin_body_index := f.body_index end internal_finalize_rout_id := System.system_object_class.compiled_class.feature_table. item_id ({PREDEFINED_NAMES}.finalize_name_id).rout_id_set.first end feature -- Status report is_debug_info_enabled: BOOLEAN -- Are we generating debug information? is_implementation_generated: BOOLEAN -- Is implementation of a class type being generated rather than interface? require not_current_class_type_is_single: not current_class_type.is_generated_as_single_type do Result := current_class_type.implementation_id = current_type_id ensure definition: Result = (current_class_type.implementation_id = current_type_id) end feature {IL_MODULE} -- Access is_single_inheritance_implementation: BOOLEAN -- Is current generation of type SINGLE_IL_CODE_GENERATOR? deferred end method_body: MD_METHOD_BODY -- Body for currently generated routine. local_start_offset, local_end_offset: INTEGER -- Data for debugging information for current feature. feature {CIL_CODE_GENERATOR, IL_MODULE} -- Access is_single_module: BOOLEAN -- Is current module generated as just a single module? -- Case of precompiled libraries or finalized systems. main_module: IL_MODULE -- Module containing assembly manifest. feature {NONE} -- Access current_module: IL_MODULE -- Module being used for code generation. is_single_class: BOOLEAN -- Can current class only be single inherited? internal_finalize_rout_id: INTEGER -- Routine ID of `finalize' from ANY standard_twin_body_index: INTEGER -- Body index of `standard_twin' from ANY output_file_name: READABLE_STRING_32 -- File where assembly is stored. md_dispenser: MD_DISPENSER -- Access to MetaData generator. md_emit: MD_EMIT -- Metadata emitter. do Result := current_module.md_emit ensure md_emit_not_void: Result /= Void end method_writer: MD_METHOD_WRITER -- To store method bodys. do Result := current_module.method_writer ensure method_writer_not_void: Result /= Void end type_count: INTEGER -- Number of generated types in Current system. do Result := (create {SHARED_COUNTER}).static_type_id_counter.count + 10 ensure type_count_positive: type_count >= 0 end done_sig: MD_FIELD_SIGNATURE -- Precomputed signature of `done_token' so that we do not have -- to compute it too often exception_sig: MD_FIELD_SIGNATURE -- Precomputed signature of `exception_token' so that we do not have -- to compute it too often do -- It is the same as `sync_sig' Result := sync_sig end sync_sig: MD_FIELD_SIGNATURE -- Precomputed signature of `sync_token' so that we do not have -- to compute it too often default_sig: MD_METHOD_SIGNATURE -- Precomputed signature of a feature with no arguments and no return type. -- Used to define default constructors and other features with same signature. method_sig: MD_METHOD_SIGNATURE -- Permanent signature for features. field_sig: MD_FIELD_SIGNATURE -- Permanent signature for attributes. local_sig: MD_LOCAL_SIGNATURE -- Permanent signature for locals. type_sig: MD_TYPE_SIGNATURE -- Permanent signature for types. property_sig: MD_PROPERTY_SIGNATURE -- Permanent signature for properties. boolean_native_signature: MD_NATIVE_TYPE_SIGNATURE -- Marshaller signature for converting IL boolean to Eiffel C boolean once create Result.make Result.set_native_type ({MD_SIGNATURE_CONSTANTS}.native_type_i1) end local_types: ARRAYED_LIST [PAIR [TYPE_A, STRING]] -- To store types of local variables. uni_string: CLI_STRING -- Buffer for all Unicode string conversion. is_console_application: BOOLEAN -- Is current a console application? is_dll: BOOLEAN -- Is current generated as a DLL? is_32bits: BOOLEAN -- Is current generated as a 32bit application? is_verifiable: BOOLEAN -- Does code generation has to be verifiable? is_cls_compliant: BOOLEAN -- Does code generation generate CLS compliant code? assembly_name: STRING -- Name of current assembly. c_module_name: STRING -- Name of C generated module containing all C externals. location_path: PATH -- Path where assemblies are being generated. current_feature_token: INTEGER -- Token of feature being generated in `generate_feature_code'. once_generation: BOOLEAN -- Are we currently generating a once feature? object_relative_once_generation: BOOLEAN -- Are we currently generating a once per object feature? feature {NONE} -- Debug info dbg_writer: DBG_WRITER -- PDB writer. do Result := current_module.dbg_writer end dbg_offsets, dbg_start_lines, dbg_start_columns, dbg_end_lines, dbg_end_columns: ARRAY [INTEGER] -- Data holding debug information for current feature. dbg_offsets_count: INTEGER -- Number of meaningful elements in above arrays. feature -- Access runtime_type_id: INTEGER -- Identifier for class EiffelSoftware.Runtime.RT_TYPE. class_type_id: INTEGER -- Identifier for class EiffelSoftware.Runtime.RT_CLASS_TYPE. basic_type_id: INTEGER -- Identifier for class EiffelSoftware.Runtime.RT_BASIC_TYPE. generic_type_id: INTEGER -- Identifier for class EiffelSoftware.Runtime.RT_GENERIC_TYPE. tuple_type_id: INTEGER -- Identifier for class EiffelSoftware.Runtime.RT_TUPLE_TYPE formal_type_id: INTEGER -- Identifier for class EiffelSoftware.Runtime.RT_FORMAL_TYPE. none_type_id: INTEGER -- Identifier for class EiffelSoftware.Runtime.RT_NONE_TYPE. eiffel_type_info_type_id: INTEGER -- Identifier for class EiffelSoftware.Runtime.EIFFEL_TYPE_INFO. generic_conformance_type_id: INTEGER -- Identifier for class EiffelSoftware.Runtime.GENERIC_CONFORMANCE. assertion_level_enum_type_id: INTEGER -- Identifier for class EiffelSoftware.Runtime.Enums.ASSERTION_LEVEL_ENUM. public_key: MD_PUBLIC_KEY -- Public key if used of current assembly. feature -- Settings set_runtime_type_id (an_id: like runtime_type_id) -- Set `an_id' to `runtime_type_id'. require valid_id: an_id > 0 do runtime_type_id := an_id ensure runtime_type_id_set: runtime_type_id = an_id end set_class_type_id (an_id: like class_type_id) -- Set `an_id' to `class_type_id'. require valid_id: an_id > 0 do class_type_id := an_id ensure class_type_id_set: class_type_id = an_id end set_generic_type_id (an_id: like generic_type_id) -- Set `an_id' to `generic_type_id'. require valid_id: an_id > 0 do generic_type_id := an_id ensure generic_type_id_set: generic_type_id = an_id end set_tuple_type_id (an_id: like tuple_type_id) -- Set `an_id' to `tuple_type_id'. require valid_id: an_id > 0 do tuple_type_id := an_id ensure tuple_type_id_set: tuple_type_id = an_id end set_formal_type_id (an_id: like formal_type_id) -- Set `an_id' to `formal_type_id'. require valid_id: an_id > 0 do formal_type_id := an_id ensure formal_type_id_set: formal_type_id = an_id end set_none_type_id (an_id: like none_type_id) -- Set `an_id' to `none_type_id'. require valid_id: an_id > 0 do none_type_id := an_id ensure none_type_id_set: none_type_id = an_id end set_eiffel_type_info_type_id (an_id: like eiffel_type_info_type_id) -- Set `an_id' to `eiffel_type_info_type_id'. require valid_id: an_id > 0 do eiffel_type_info_type_id := an_id ensure eiffel_type_info_type_id_set: eiffel_type_info_type_id = an_id end set_basic_type_id (an_id: like basic_type_id) -- Set `an_id' to `basic_type_id'. require valid_id: an_id > 0 do basic_type_id := an_id ensure basic_type_id_set: basic_type_id = an_id end set_generic_conformance_type_id (an_id: like generic_conformance_type_id) -- Set `an_id' to `generic_conformance_type_id'. require valid_id: an_id > 0 do generic_conformance_type_id := an_id ensure generic_conformance_type_id_set: generic_conformance_type_id = an_id end set_assertion_level_enum_type_id (an_id: like assertion_level_enum_type_id) -- Set `an_id' to `assertion_level_enum_type_id'. require valid_id: an_id > 0 do assertion_level_enum_type_id := an_id ensure assertion_level_enum_type_id_set: assertion_level_enum_type_id = an_id end set_once_generation (v: BOOLEAN) -- Set `once_generation' to `v'. do once_generation := v ensure once_generation_set: once_generation = v end set_object_relative_once_generation (v: BOOLEAN) -- Set `object_relative_once_generation' to `v'. do object_relative_once_generation := v ensure object_relative_once_generation_set: object_relative_once_generation = v end set_current_module_for_class (class_c: CLASS_C) -- Update `current_module' so that it refers to module in which -- data class for `class_c' is generated. require class_c_not_void: class_c /= Void do current_module := il_module_for_class (class_c) -- Refine so that only classes being generated in current compilation -- unit needs the module to be generated as well. if not current_module.is_generated then current_module.prepare (md_dispenser, type_count) end ensure current_module_set: current_module /= Void associated_current_module: current_module = il_module_for_class (class_c) end set_current_module_with (a_class_type: CLASS_TYPE) -- Update `current_module' so that it refers to module in which -- `a_class_type' is generated. require a_class_type_not_void: a_class_type /= Void local l_old_module: like current_module do l_old_module := current_module current_module := il_module (a_class_type) -- Refine so that only classes being generated in current compilation -- unit needs the module to be generated as well. debug ("il_emitter") if attached current_module as m then if l_old_module = Void or else l_old_module /= m then print (generator + ".set_current_module_with (...) -> switched to ") print (m.module_name_with_extension) print ("%N") end end end if a_class_type.is_generated and then not current_module.is_generated then current_module.prepare (md_dispenser, type_count) end ensure current_module_set: current_module /= Void associated_current_module: current_module = il_module (a_class_type) end feature -- Cleanup clean_debug_information (a_class_type: CLASS_TYPE) -- Clean recorded debug information. do Il_debug_info_recorder.clean_class_type_info_for (a_class_type) end cleanup -- Clean up all data structures that were used for this code generation. local retried: BOOLEAN do if not retried then --| End recording session, (then Save IL Information used for eStudio .NET debugger) Il_debug_info_recorder.end_recording_session --| Clean up data if internal_il_modules /= Void then across internal_il_modules as m loop if attached m.item as module then module.cleanup end end -- Now all underlying COM objects should have been unreferenced, so we -- can safely collect them. We really have to collect them now because -- some cannot wait. For example if you still have an instance of -- DBG_DOCUMENT_WRITER of an Eiffel source file, it will refuse to create -- a new instance if you haven't freed the first one. ;(create {MEMORY}).full_collect end end rescue retried := True retry end feature -- Generation Structure start_assembly_generation ( a_assembly_name: STRING; a_file_name: READABLE_STRING_GENERAL; a_public_key: like public_key; location: PATH; assembly_info: ASSEMBLY_INFO; debug_mode: BOOLEAN) -- Create Assembly with `name'. require a_assembly_name_not_void: a_assembly_name /= Void a_assembly_name_not_empty: not a_assembly_name.is_empty a_file_name_not_void: a_file_name /= Void a_file_name_not_empty: not a_file_name.is_empty location_not_void: location /= Void location_not_empty: not location.is_empty local p: PATH ext: READABLE_STRING_GENERAL l_assembly_name_with_extension: STRING s32: STRING_32 do -- For netcore, use multi-assemblies instead of multi-modules. is_using_multi_assemblies := system.is_il_netcore --| Initialize recording of IL Information used for eStudio .NET debugger Il_debug_info_recorder.start_recording_session (debug_mode) --| beginning of assembly generation location_path := location assembly_name := a_assembly_name -- Set CLR host to proper version if not yet done. setup_cil_code_generation (System.clr_runtime_version) -- Create Unicode string buffer. create uni_string.make_empty (1024) -- Name of `dll' containing all C externals. create c_module_name.make_from_string ("lib" + a_assembly_name + ".dll") md_dispenser := md_factory.dispenser -- Create signature for `done' and `sync' in once computation. create done_sig.make done_sig.set_type ({MD_SIGNATURE_CONSTANTS}.Element_type_boolean, 0) create sync_sig.make sync_sig.set_type ({MD_SIGNATURE_CONSTANTS}.Element_type_object, 0) -- Create default signature. create default_sig.make default_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Has_current) default_sig.set_parameter_count (0) default_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.Element_type_void, 0) -- Create permanent signature for feature. create method_sig.make create field_sig.make create local_sig.make create type_sig.make create property_sig.make create local_types.make (5) last_non_recorded_feature_token := 0 create override_counter public_key := a_public_key is_debug_info_enabled := debug_mode -- FIXME jfiat [2003/10/10 - 16:41] try without debug_mode, for no pdb info p := location.extended (a_file_name) output_file_name := p.name ext := p.extension if ext = Void then ext := system.msil_generation_type end if a_assembly_name.to_string_32.ends_with (ext) then l_assembly_name_with_extension := a_assembly_name else s32 := (create {PATH}.make_from_string (a_assembly_name)).appended_with_extension (ext).name if s32.is_valid_as_string_8 then l_assembly_name_with_extension := s32.to_string_8 else check expected_non_unicode_name: False end l_assembly_name_with_extension := {UTF_CONVERTER}.utf_32_string_to_utf_8_string_8 (s32) end end create main_module.make ( l_assembly_name_with_extension, -- Extension is required output_file_name, c_module_name, a_public_key, Current, assembly_info, 1, is_debug_info_enabled, True, is_using_multi_assemblies -- Main assembly ) current_module := main_module if is_console_application then main_module.set_console_application else main_module.set_window_application end if is_dll then main_module.set_dll end if is_32bits then main_module.set_32bits end main_module.prepare (md_dispenser, type_count) is_single_module := System.in_final_mode or else Compilation_modes.is_precompiling if is_single_module then internal_il_modules.put (main_module, 1) end ensure assembly_name_set: assembly_name = a_assembly_name end start_module_generation (a_module_id: INTEGER) -- Start generation of `a_module_id'. do current_module := internal_il_modules.item (a_module_id) end define_entry_point (creation_type: CLASS_TYPE; a_class_type: CLASS_TYPE; a_feature_id: INTEGER; a_has_arguments: BOOLEAN) -- Define entry point for IL component from `a_feature_id' in -- class `a_type_id'. require creation_type_not_void: creation_type /= Void a_class_type_not_void: a_class_type /= Void positive_feature_id: a_feature_id > 0 local l_cur_mod: like current_module do l_cur_mod := current_module current_module := main_module current_class_type := a_class_type main_module.define_entry_point (creation_type, a_class_type, a_feature_id, a_has_arguments) current_module := l_cur_mod end generate_runtime_helper -- Generate a class for run-time needs. local l_cur_mod: like current_module helper_emit: MD_EMIT oms_field_cil_token: INTEGER oms_field_eiffel_token, oms_32_field_eiffel_token, omis_8_field_eiffel_token, omis_32_field_eiffel_token: INTEGER oms_array_type_cil_token: INTEGER oms_array_type_eiffel_token: INTEGER array_type_token: INTEGER array_copy_method_token: INTEGER check_body_index_range_label: IL_LABEL allocate_for_body_index_label: IL_LABEL do if workbench.precompilation_directories = Void or else workbench.precompilation_directories.is_empty then -- Generate code to handle once manifest strings. l_cur_mod := current_module current_module := main_module helper_emit := main_module.md_emit -- Define fields and methods to deal with once manifest strings. current_module.define_once_string_tokens oms_field_cil_token := current_module.once_string_field_token (string_type_cil) oms_field_eiffel_token := current_module.once_string_field_token (string_type_string) oms_32_field_eiffel_token := current_module.once_string_field_token (string_type_string_32) omis_8_field_eiffel_token := current_module.once_string_field_token (string_type_immutable_string_8) omis_32_field_eiffel_token := current_module.once_string_field_token (string_type_immutable_string_32) -- Generate allocation routine. -- Check if fields were initialized. start_new_body (current_module.once_string_allocation_routine_token) local_sig.reset local_sig.set_local_count (1) local_sig.add_local_type ({MD_SIGNATURE_CONSTANTS}.element_type_i4, 0) method_body.set_local_token (helper_emit.define_signature (local_sig)) check_body_index_range_label := create_label allocate_for_body_index_label := create_label array_type_token := helper_emit.define_type_ref (create {CLI_STRING}.make ("System.Array"), current_module.mscorlib_token) method_sig.reset method_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.default_sig) method_sig.set_parameter_count (3) method_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.element_type_void, 0) method_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_class, array_type_token) method_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_class, array_type_token) method_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_i4, 0) array_copy_method_token := helper_emit.define_member_ref (create {CLI_STRING}.make ("Copy"), array_type_token, method_sig) method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, oms_field_cil_token) method_body.put_opcode ({MD_OPCODES}.dup) branch_on_true (check_body_index_range_label) -- Create array(s) indexed by body index. -- Remove null from stack top. method_body.put_opcode ({MD_OPCODES}.pop) -- Create "STRING[][]" and assign it to "oms_eiffel". method_body.put_opcode ({MD_OPCODES}.ldarg_0) put_integer_32_constant (1) method_body.put_opcode ({MD_OPCODES}.add) type_sig.reset type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_szarray, 0) type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_class, current_module.actual_class_type_token (string_type_id)) oms_array_type_eiffel_token := helper_emit.define_type_spec (type_sig) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, oms_array_type_eiffel_token) method_body.put_opcode_mdtoken ({MD_OPCODES}.stsfld, oms_field_eiffel_token) -- Create "STRING_32[][]" and assign it to "oms32_eiffel". method_body.put_opcode ({MD_OPCODES}.ldarg_0) put_integer_32_constant (1) method_body.put_opcode ({MD_OPCODES}.add) type_sig.reset type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_szarray, 0) type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_class, current_module.actual_class_type_token (string_32_type_id)) oms_array_type_eiffel_token := helper_emit.define_type_spec (type_sig) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, oms_array_type_eiffel_token) method_body.put_opcode_mdtoken ({MD_OPCODES}.stsfld, oms_32_field_eiffel_token) -- Create "IMMUTABLE_STRING_8[][]" and assign it to "omis8_eiffel". method_body.put_opcode ({MD_OPCODES}.ldarg_0) put_integer_32_constant (1) method_body.put_opcode ({MD_OPCODES}.add) type_sig.reset type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_szarray, 0) type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_class, current_module.actual_class_type_token (immutable_string_8_type_id)) oms_array_type_eiffel_token := helper_emit.define_type_spec (type_sig) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, oms_array_type_eiffel_token) method_body.put_opcode_mdtoken ({MD_OPCODES}.stsfld, omis_8_field_eiffel_token) -- Create "IMMUTABLE_STRING_32[][]" and assign it to "omis32_eiffel". method_body.put_opcode ({MD_OPCODES}.ldarg_0) put_integer_32_constant (1) method_body.put_opcode ({MD_OPCODES}.add) type_sig.reset type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_szarray, 0) type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_class, current_module.actual_class_type_token (immutable_string_32_type_id)) oms_array_type_eiffel_token := helper_emit.define_type_spec (type_sig) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, oms_array_type_eiffel_token) method_body.put_opcode_mdtoken ({MD_OPCODES}.stsfld, omis_32_field_eiffel_token) -- Create "string[][]" and assign it to "oms_cil". -- Leave "string[][]" at stack top. method_body.put_opcode ({MD_OPCODES}.ldarg_0) put_integer_32_constant (1) method_body.put_opcode ({MD_OPCODES}.add) type_sig.reset type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_szarray, 0) type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_string, 0) oms_array_type_cil_token := helper_emit.define_type_spec (type_sig) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, oms_array_type_cil_token) method_body.put_opcode ({MD_OPCODES}.dup) method_body.put_opcode_mdtoken ({MD_OPCODES}.stsfld, oms_field_cil_token) branch_to (allocate_for_body_index_label) mark_label (check_body_index_range_label) -- Check whether body index fits current body index range. method_body.put_opcode ({MD_OPCODES}.dup) method_body.put_opcode ({MD_OPCODES}.ldlen) method_body.put_opcode ({MD_OPCODES}.dup) method_body.put_opcode ({MD_OPCODES}.stloc_0) method_body.put_opcode ({MD_OPCODES}.ldarg_0) method_body.put_opcode_label ({MD_OPCODES}.bgt, allocate_for_body_index_label.id) -- Body index is too large. Reallocate array(s). -- All previously stored data have to be preserved. -- Reallocate "string[][]". method_body.put_opcode ({MD_OPCODES}.ldarg_0) put_integer_32_constant (1) method_body.put_opcode ({MD_OPCODES}.add) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, oms_array_type_cil_token) method_body.put_opcode ({MD_OPCODES}.dup) method_body.put_opcode_mdtoken ({MD_OPCODES}.stsfld, oms_field_cil_token) method_body.put_opcode ({MD_OPCODES}.ldloc_0) method_body.put_static_call (array_copy_method_token, 3, False) -- Reallocate "STRING[][]". method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, oms_field_eiffel_token) method_body.put_opcode ({MD_OPCODES}.ldarg_0) put_integer_32_constant (1) method_body.put_opcode ({MD_OPCODES}.add) type_sig.reset type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_szarray, 0) type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_class, current_module.actual_class_type_token (string_type_id)) oms_array_type_eiffel_token := helper_emit.define_type_spec (type_sig) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, oms_array_type_eiffel_token) method_body.put_opcode ({MD_OPCODES}.dup) method_body.put_opcode_mdtoken ({MD_OPCODES}.stsfld, oms_field_eiffel_token) method_body.put_opcode ({MD_OPCODES}.ldloc_0) method_body.put_static_call (array_copy_method_token, 3, False) -- Reallocate "STRING_32[][]". method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, oms_32_field_eiffel_token) method_body.put_opcode ({MD_OPCODES}.ldarg_0) put_integer_32_constant (1) method_body.put_opcode ({MD_OPCODES}.add) type_sig.reset type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_szarray, 0) type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_class, current_module.actual_class_type_token (string_32_type_id)) oms_array_type_eiffel_token := helper_emit.define_type_spec (type_sig) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, oms_array_type_eiffel_token) method_body.put_opcode ({MD_OPCODES}.dup) method_body.put_opcode_mdtoken ({MD_OPCODES}.stsfld, oms_32_field_eiffel_token) method_body.put_opcode ({MD_OPCODES}.ldloc_0) method_body.put_static_call (array_copy_method_token, 3, False) -- Reallocate "IMMUTABLE_STRING_8[][]". method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, omis_8_field_eiffel_token) method_body.put_opcode ({MD_OPCODES}.ldarg_0) put_integer_32_constant (1) method_body.put_opcode ({MD_OPCODES}.add) type_sig.reset type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_szarray, 0) type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_class, current_module.actual_class_type_token (immutable_string_8_type_id)) oms_array_type_eiffel_token := helper_emit.define_type_spec (type_sig) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, oms_array_type_eiffel_token) method_body.put_opcode ({MD_OPCODES}.dup) method_body.put_opcode_mdtoken ({MD_OPCODES}.stsfld, omis_8_field_eiffel_token) method_body.put_opcode ({MD_OPCODES}.ldloc_0) method_body.put_static_call (array_copy_method_token, 3, False) -- Reallocate "IMMUTABLE_STRING_32[][]". method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, omis_32_field_eiffel_token) method_body.put_opcode ({MD_OPCODES}.ldarg_0) put_integer_32_constant (1) method_body.put_opcode ({MD_OPCODES}.add) type_sig.reset type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_szarray, 0) type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_class, current_module.actual_class_type_token (immutable_string_32_type_id)) oms_array_type_eiffel_token := helper_emit.define_type_spec (type_sig) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, oms_array_type_eiffel_token) method_body.put_opcode ({MD_OPCODES}.dup) method_body.put_opcode_mdtoken ({MD_OPCODES}.stsfld, omis_32_field_eiffel_token) method_body.put_opcode ({MD_OPCODES}.ldloc_0) method_body.put_static_call (array_copy_method_token, 3, False) -- Leave "string[][]" on stack top. method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, oms_field_cil_token) mark_label (allocate_for_body_index_label) -- Create array(s) indexed by manifest string number. -- oms_cil method_body.put_opcode ({MD_OPCODES}.ldarg_0) method_body.put_opcode ({MD_OPCODES}.ldarg_1) type_sig.reset type_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_string, 0) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, helper_emit.define_type_spec (type_sig)) method_body.put_opcode ({MD_OPCODES}.stelem_ref) -- oms_eiffel method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, oms_field_eiffel_token) method_body.put_opcode ({MD_OPCODES}.ldarg_0) method_body.put_opcode ({MD_OPCODES}.ldarg_1) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, current_module.actual_class_type_token (string_type_id)) method_body.put_opcode ({MD_OPCODES}.stelem_ref) -- oms32_eiffel method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, oms_32_field_eiffel_token) method_body.put_opcode ({MD_OPCODES}.ldarg_0) method_body.put_opcode ({MD_OPCODES}.ldarg_1) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, current_module.actual_class_type_token (string_32_type_id)) method_body.put_opcode ({MD_OPCODES}.stelem_ref) -- omis8_eiffel method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, omis_8_field_eiffel_token) method_body.put_opcode ({MD_OPCODES}.ldarg_0) method_body.put_opcode ({MD_OPCODES}.ldarg_1) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, current_module.actual_class_type_token (immutable_string_8_type_id)) method_body.put_opcode ({MD_OPCODES}.stelem_ref) -- omis32_eiffel method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, omis_32_field_eiffel_token) method_body.put_opcode ({MD_OPCODES}.ldarg_0) method_body.put_opcode ({MD_OPCODES}.ldarg_1) method_body.put_opcode_mdtoken ({MD_OPCODES}.newarr, current_module.actual_class_type_token (immutable_string_32_type_id)) method_body.put_opcode ({MD_OPCODES}.stelem_ref) -- Done. generate_return (False) method_writer.write_current_body current_module := l_cur_mod end end end_assembly_generation (a_signing: MD_STRONG_NAME) -- Finish creation of current assembly. require a_signing_exists: a_signing /= Void and then a_signing.exists local l_types: like class_types l_type: CLASS_TYPE l_class: CLASS_C i, nb: INTEGER l_uni_string: CLI_STRING l_module: IL_MODULE l_file_token: INTEGER l_assembly_ref_token: INTEGER do current_module := main_module if not is_single_module then from l_types := System.class_types i := l_types.lower nb := l_types.upper create l_uni_string.make_empty (0) until i > nb loop l_type := l_types.item (i) if l_type /= Void then if not l_type.is_external then define_assertion_level (l_type) end l_class := l_type.associated_class if l_type.is_generated and then not l_class.is_typed_pointer then l_module := il_module (l_type) if is_using_multi_assemblies then l_assembly_ref_token := main_module.module_reference_token (l_module) l_uni_string.set_string (l_type.full_il_type_name) md_emit.define_exported_type (l_uni_string, l_assembly_ref_token, l_type.last_type_token, {MD_TYPE_ATTRIBUTES}.Public).do_nothing if l_type.implementation_id /= l_type.static_type_id then l_uni_string.set_string (l_type.full_il_implementation_type_name) md_emit.define_exported_type (l_uni_string, l_assembly_ref_token, l_type.last_implementation_type_token, {MD_TYPE_ATTRIBUTES}.Public).do_nothing end if not l_class.is_deferred and (attached l_class.creators as cs implies not cs.is_empty) then l_uni_string.set_string (l_type.full_il_create_type_name) md_emit.define_exported_type (l_uni_string, l_assembly_ref_token, l_type.last_create_type_token, {MD_TYPE_ATTRIBUTES}.Public).do_nothing end else file_token.search (l_module) if file_token.found then l_file_token := file_token.found_item else l_file_token := define_file (main_module, l_module.module_file_name, l_module.module_name_with_extension, {MD_FILE_FLAGS}.Has_meta_data, a_signing) file_token.put (l_file_token, l_module) end l_uni_string.set_string (l_type.full_il_type_name) md_emit.define_exported_type (l_uni_string, l_file_token, l_type.last_type_token, {MD_TYPE_ATTRIBUTES}.Public).do_nothing if l_type.implementation_id /= l_type.static_type_id then l_uni_string.set_string (l_type.full_il_implementation_type_name) md_emit.define_exported_type (l_uni_string, l_file_token, l_type.last_implementation_type_token, {MD_TYPE_ATTRIBUTES}.Public).do_nothing end if not l_class.is_deferred and (attached l_class.creators as cs implies not cs.is_empty) then l_uni_string.set_string (l_type.full_il_create_type_name) md_emit.define_exported_type (l_uni_string, l_file_token, l_type.last_create_type_token, {MD_TYPE_ATTRIBUTES}.Public).do_nothing end end end end i := i + 1 end elseif system.keep_assertions then from l_types := System.class_types i := l_types.lower nb := l_types.upper until i > nb loop l_type := l_types.item (i) if attached l_type and then not l_type.is_external then define_assertion_level (l_type) end i := i + 1 end end define_assembly_attributes main_module.save_to_disk (a_signing) --| End recording session, (then Save IL Information used for eStudio .NET debugger) -- The real end of recording is done in `cleanup' end generate_resources (a_resources: LIST [CONF_EXTERNAL_RESOURCE]) -- Generate all resources in assembly. require a_resources_not_void: a_resources /= Void do (create {IL_RESOURCE_GENERATOR}.make (main_module, a_resources)).generate end define_file (a_module: IL_MODULE; a_file: READABLE_STRING_GENERAL; a_name: READABLE_STRING_GENERAL; file_flags: INTEGER; a_signing: detachable MD_STRONG_NAME): INTEGER -- Add `a_file' of name `a_name' in list of files referenced by `a_module'. require a_module_not_void: a_module /= Void a_file_not_void: a_file /= Void a_name_not_void: a_name /= Void a_file_valid: a_file.has_substring (a_name) and a_name.same_string ( a_file.substring (a_file.count - a_name.count + 1, a_file.count)) file_flags_valid: (file_flags = {MD_FILE_FLAGS}.Has_meta_data) or (file_flags = {MD_FILE_FLAGS}.Has_no_meta_data) a_signing_exists: a_signing /= Void and then a_signing.exists local l_uni_string: CLI_STRING l_hash_res: MANAGED_POINTER do create l_uni_string.make (a_file) l_hash_res := a_signing.hash_of_file (l_uni_string) l_uni_string.set_string (a_name) Result := a_module.md_emit.define_file (l_uni_string, l_hash_res, file_flags) ensure valid_result: Result & {MD_TOKEN_TYPES}.Md_mask = {MD_TOKEN_TYPES}.Md_file end define_assertion_level (class_type: CLASS_TYPE) -- Define assertion level for `class_type'. require class_type_not_void: class_type /= Void local l_assert_ca: MD_CUSTOM_ATTRIBUTE l_type_name: STRING_32 do check main_module_not_void: main_module /= Void end create l_assert_ca.make if class_type.implementation_id = class_type.static_type_id then create l_type_name.make_from_string_general (escape_type_name (class_type.full_il_type_name)) else create l_type_name.make_from_string_general (escape_type_name (class_type.full_il_implementation_type_name)) end if class_type.is_precompiled then l_type_name.append_string_general (", ") l_type_name.append (class_type.assembly_info.full_name) end l_assert_ca.put_string (l_type_name) l_assert_ca.put_integer_32 (class_type.associated_class.assertion_level.level) l_assert_ca.put_integer_16 (0) define_custom_attribute (main_module.associated_assembly_token, main_module.ise_assertion_level_attr_ctor_token, l_assert_ca) end define_interface_type (class_type: CLASS_TYPE; parent_token: INTEGER) -- Define creation type for `class_type' in module generated for `class_type'. -- Needed for creating proper type in a formal generic creation. require class_type_not_void: class_type /= Void local l_assert_ca: MD_CUSTOM_ATTRIBUTE l_type_name: STRING_32 do create l_assert_ca.make create l_type_name.make_from_string_general (escape_type_name (class_type.full_il_type_name)) if class_type.is_precompiled then l_type_name.append_string_general (", ") l_type_name.append (class_type.assembly_info.full_name) end l_assert_ca.put_string (l_type_name) l_assert_ca.put_integer_16 (0) define_custom_attribute (parent_token, current_module.ise_interface_type_attr_ctor_token, l_assert_ca) end end_module_generation (has_root_type: BOOLEAN; a_signing: detachable MD_STRONG_NAME) -- Finish creation of current module. require a_signing_exists: a_signing /= Void and then a_signing.exists local a_class: CLASS_C root_feat: FEATURE_I l_decl_type: CL_TYPE_A entry_point_token: INTEGER do if not is_single_module and then (current_module /= Void and then current_module.is_generated) then -- Mark now entry point for debug information if is_debug_info_enabled and then has_root_type and then not system.root_creation_name.is_empty then a_class := system.root_type.base_class root_feat := a_class.feature_table.item (system.root_creation_name) l_decl_type := system.root_class_type (system.root_type).type.implemented_type (root_feat.origin_class_id) entry_point_token := current_module.implementation_feature_token ( l_decl_type.associated_class_type (system.root_class_type (system.root_type).type).implementation_id, root_feat.origin_feature_id) -- Debugger API does not allow to use MethodRef token for user entry point if entry_point_token & {MD_TOKEN_TYPES}.md_mask = {MD_TOKEN_TYPES}.md_method_def then current_module.dbg_writer.set_user_entry_point (entry_point_token) else fixme ("Regenerate root procedure to get MethodDef token or generate a fictious procedure with relevant debug information that will call root procedure.") end end -- Save module. current_module.save_to_disk (a_signing) end end feature -- Generation type set_console_application -- Current generated application is a CONSOLE application. do is_console_application := True is_dll := False end set_window_application -- Current generated application is a WINDOW application. do is_console_application := False is_dll := False end set_dll -- Current generated application is a DLL. do is_dll := True is_console_application := True end set_32bits -- Current generated application is a 32bit application do is_32bits := True end feature -- Generation Info set_version (build, major, minor, revision: INTEGER) -- Assign current generated assembly with given version details. do check not_yet_implemented: False end end set_verifiability (verifiable: BOOLEAN) -- Mark current generation to generate verifiable code. do is_verifiable := verifiable ensure then is_verifiable_set: is_verifiable = verifiable end set_cls_compliant (cls_compliant: BOOLEAN) -- Mark current generation to generate cls_compliant code. do is_cls_compliant := cls_compliant ensure then is_cls_compliant_set: is_cls_compliant = cls_compliant end feature -- Class info initialize_class_mappings (class_count: INTEGER) -- Initialize structures that holds some system data during code generation. do create internal_il_modules.make_filled (Void, 0, class_count) create file_token.make (10) create external_class_mapping.make (class_count) -- Predefined .NET basic types. external_class_mapping.put (create {BOOLEAN_A}, "System.Boolean") external_class_mapping.put (create {CHARACTER_A}.make (False), "System.Char") external_class_mapping.put (create {NATURAL_A}.make (8), "System.Byte") external_class_mapping.put (create {NATURAL_A}.make (16), "System.UInt16") external_class_mapping.put (create {NATURAL_A}.make (32), "System.UInt32") external_class_mapping.put (create {NATURAL_A}.make (64), "System.UInt64") external_class_mapping.put (create {INTEGER_A}.make (8), "System.SByte") external_class_mapping.put (create {INTEGER_A}.make (16), "System.Int16") external_class_mapping.put (create {INTEGER_A}.make (32), "System.Int32") external_class_mapping.put (create {INTEGER_A}.make (64), "System.Int64") external_class_mapping.put (create {REAL_A}.make (32), "System.Single") external_class_mapping.put (create {REAL_A}.make (64), "System.Double") external_class_mapping.put (create {POINTER_A}, "System.IntPtr") -- Debug data structure. internal_class_types := Void end generate_class_mappings (class_type: CLASS_TYPE; for_interface: BOOLEAN) -- Define all types, both external and eiffel one. require class_type_not_void: class_type /= Void class_type_generated: class_type.is_generated do if for_interface then current_module.generate_interface_class_mapping (class_type) elseif not class_type.is_generated_as_single_type then current_module.generate_implementation_class_mapping (class_type) end end generate_class_interfaces (class_type: CLASS_TYPE; class_c: CLASS_C) -- Initialize `class_interface' from `class_type' with info from `class_c'. require class_type_not_void: class_type /= Void class_c_not_void: class_c /= Void local pars: ARRAYED_LIST [CLASS_INTERFACE] class_interface: CLASS_INTERFACE parents: FIXED_LIST [CL_TYPE_A] do if attached {NATIVE_ARRAY_CLASS_TYPE} class_type as l_native_array then external_class_mapping.put (class_type.type, l_native_array.il_type_name) elseif class_type.is_external and then not (class_c.is_basic and then class_c.is_typed_pointer) then -- We do not process TYPED_POINTER as it is not a real class type in .NET so -- TYPED_POINTER doesn't really have a `full_il_type_name'. external_class_mapping.put (class_type.type, class_type.full_il_type_name) end parents := class_c.parents create class_interface.make_from_context (class_c.class_interface, class_type) create pars.make (parents.count) across parents as p loop pars.force (p.item.associated_class_type (class_type.type).class_interface) end class_interface.set_parents (pars) class_type.set_class_interface (class_interface) end generate_class_attributes (class_type: CLASS_TYPE) -- Define custom attributes of `class_type'. require class_type_not_void: class_type /= Void local l_ca_factory: CUSTOM_ATTRIBUTE_FACTORY l_class: CLASS_C l_attributes: BYTE_LIST [BYTE_NODE] do current_class_type := class_type l_class := class_type.associated_class create l_ca_factory -- First we generate attributes common to both generated class and interface. l_attributes := l_class.custom_attributes if l_attributes /= Void then l_ca_factory.generate_custom_attributes ( actual_class_type_token (class_type.implementation_id), l_attributes) -- Generate custome attribute on interface if it is generated. if class_type.static_type_id /= class_type.implementation_id then l_ca_factory.generate_custom_attributes ( actual_class_type_token (class_type.static_type_id), l_attributes) end end -- Then we generate only class or interface specific attribute if we indeed -- generate a class and an interface associated to an Eiffel class. if class_type.static_type_id /= class_type.implementation_id then l_attributes := l_class.class_custom_attributes if l_attributes /= Void then l_ca_factory.generate_custom_attributes ( actual_class_type_token (class_type.implementation_id), l_attributes) end l_attributes := l_class.interface_custom_attributes if l_attributes /= Void then l_ca_factory.generate_custom_attributes ( actual_class_type_token (class_type.static_type_id), l_attributes) end end define_interface_type (class_type, actual_class_type_token (class_type.implementation_id)) end define_assembly_attributes -- Define custom attributes for current assembly. local l_ca_factory: CUSTOM_ATTRIBUTE_FACTORY l_class: CLASS_C l_attributes: BYTE_LIST [BYTE_NODE] l_cur_mod: like current_module do if System.root_type /= Void and then System.root_type.base_class.original_class.is_compiled then l_cur_mod := current_module current_module := main_module current_class_type := System.root_class_type (system.root_type) l_class := current_class_type.associated_class create l_ca_factory -- First we generate attributes common to both generated class and interface. l_attributes := l_class.assembly_custom_attributes if l_attributes /= Void then l_ca_factory.generate_custom_attributes (main_module.associated_assembly_token, l_attributes) end current_module := l_cur_mod end if is_cls_compliant then define_custom_attribute (main_module.associated_assembly_token, main_module.cls_compliant_ctor_token, cls_compliant_ca) end define_custom_attribute (main_module.associated_assembly_token, main_module.ise_eiffel_consumable_attr_ctor_token, eiffel_non_consumable_ca) end define_constructors (class_type: CLASS_TYPE; is_reference: BOOLEAN) -- Define constructors for implementation of `class_type' require class_type_not_void: class_type /= Void do current_module.define_constructors (class_type, is_reference) end define_runtime_features (class_type: CLASS_TYPE) -- Define all features needed by ISE .NET runtime. It generates -- `____class_name', `$$____type', `____type', -- `____copy', `____is_equal' and `____standard_twin'. require class_type_not_void: class_type /= Void not_external_class_type: not class_type.is_external local l_meth_token: INTEGER l_sig: like method_sig l_field_sig: like field_sig l_type_field_token: INTEGER l_class_token: INTEGER l_ca: MD_CUSTOM_ATTRIBUTE l_class_name: STRING_32 l_meth_attr: INTEGER i, nb: INTEGER l_type: TYPE_A l_class_type: CLASS_TYPE l_ext_class: EXTERNAL_CLASS_C l_feature: FEATURE_I do l_class_token := actual_class_type_token (class_type.implementation_id) create l_class_name.make_from_string_general (class_type.associated_class.name_in_upper) create l_ca.make l_ca.put_string (l_class_name) if attached {GEN_TYPE_A} class_type.type as l_gen_type then from l_ca.put_integer_32 (l_gen_type.generics.count) i := l_gen_type.generics.lower nb := l_gen_type.generics.upper until i > nb loop l_ext_class := Void l_type := l_gen_type.generics.i_th (i) if l_type.is_formal then -- It is a formal, simply put ANY here l_class_type := any_type.associated_class_type (Void) elseif attached {CL_TYPE_A} l_type as l_cl_type then -- It is an expanded generic derivation l_class_type := l_cl_type.associated_class_type (class_type.type) if l_cl_type.is_external then l_ext_class := {EXTERNAL_CLASS_C} / l_cl_type.base_class end end if l_class_type.is_basic and then l_class_type.type.generics = Void then -- Use built-in type. l_class_name := l_class_type.associated_class.external_class_name.twin else l_class_name := escape_type_name (l_class_type.full_il_type_name) end if l_ext_class = Void then -- Case of an Eiffel class if l_class_type.is_precompiled and then not l_class_type.associated_class.is_external then check has_assembly_info: l_class_type.assembly_info /= Void end l_class_name.append_string_general (", ") l_class_name.append (l_class_type.assembly_info.full_name) end else -- External class, add assembly full name only when it is -- not `mscorlib'. if not l_ext_class.assembly.assembly_name.same_string_general ("mscorlib") then l_class_name.append_string_general (", ") l_class_name.append (l_ext_class.assembly.full_name) end end l_ca.put_string (l_class_name) i := i + 1 end l_ca.put_integer_16 (0) define_custom_attribute (l_class_token, current_module.ise_eiffel_name_attr_generic_ctor_token, l_ca) else l_ca.put_integer_16 (0) define_custom_attribute (l_class_token, current_module.ise_eiffel_name_attr_ctor_token, l_ca) end if attached class_type.associated_class.storable_version as l_version and then not l_version.is_empty then create l_ca.make l_ca.put_string (l_version) define_custom_attribute (l_class_token, current_module.ise_eiffel_version_attr_ctor_token, l_ca) end if not class_type.type.has_no_mark then create l_ca.make l_ca.put_integer_32 (class_type.type.declaration_mark) l_ca.put_integer_16 (0) define_custom_attribute (l_class_token, current_module.ise_eiffel_class_type_mark_attr_ctor_token, l_ca) end if is_single_inheritance_implementation or else is_single_class then l_meth_attr := {MD_METHOD_ATTRIBUTES}.Public | {MD_METHOD_ATTRIBUTES}.Hide_by_signature | {MD_METHOD_ATTRIBUTES}.Virtual else l_meth_attr := {MD_METHOD_ATTRIBUTES}.Public | {MD_METHOD_ATTRIBUTES}.Hide_by_signature | {MD_METHOD_ATTRIBUTES}.Virtual | {MD_METHOD_ATTRIBUTES}.Final end -- Define `____class_name'. l_sig := method_sig l_sig.reset l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Has_current) l_sig.set_parameter_count (0) l_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.Element_type_string, 0) uni_string.set_string ("____class_name") l_meth_token := md_emit.define_method (uni_string, l_class_token, l_meth_attr, l_sig, {MD_METHOD_ATTRIBUTES}.Managed) if is_cls_compliant then define_custom_attribute (l_meth_token, current_module.cls_compliant_ctor_token, not_cls_compliant_ca) end start_new_body (l_meth_token) put_system_string (l_class_name) generate_return (True) store_locals (l_meth_token, class_type) method_writer.write_current_body if (is_single_inheritance_implementation and (class_type.static_type_id = any_type_id)) or (not is_single_inheritance_implementation and (not is_single_class or else (current_class.has_external_main_parent or class_type.is_expanded))) then l_meth_attr := l_meth_attr | {MD_METHOD_ATTRIBUTES}.Final -- Define `$$____type'. l_field_sig := field_sig l_field_sig.reset l_field_sig.set_type ({MD_SIGNATURE_CONSTANTS}.Element_type_class, current_module.ise_generic_type_token) uni_string.set_string ("$$____type") l_type_field_token := md_emit.define_field (uni_string, l_class_token, {MD_FIELD_ATTRIBUTES}.Family, l_field_sig) if is_cls_compliant then define_custom_attribute (l_type_field_token, current_module.cls_compliant_ctor_token, not_cls_compliant_ca) end -- Define `____type'. l_sig.reset l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Has_current) l_sig.set_parameter_count (0) l_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.Element_type_class, current_module.ise_generic_type_token) uni_string.set_string ("____type") l_meth_token := md_emit.define_method (uni_string, l_class_token, l_meth_attr, l_sig, {MD_METHOD_ATTRIBUTES}.Managed) if is_cls_compliant then define_custom_attribute (l_meth_token, current_module.cls_compliant_ctor_token, not_cls_compliant_ca) end start_new_body (l_meth_token) generate_current method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldfld, l_type_field_token) generate_return (True) method_writer.write_current_body -- Define `____standard_twin' l_sig.reset l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Has_current) l_sig.set_parameter_count (0) l_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.Element_type_object, 0) uni_string.set_string ("____standard_twin") l_meth_token := md_emit.define_method (uni_string, l_class_token, l_meth_attr, l_sig, {MD_METHOD_ATTRIBUTES}.Managed) start_new_body (l_meth_token) -- If `current_class_type' is expanded, cloning is done by compiler. if not class_type.is_expanded then generate_current method_body.put_call ({MD_OPCODES}.Call, current_module.memberwise_clone_token, 0, True) generate_check_cast (Void, class_type.type) generate_return (True) else generate_current generate_load_from_address_as_object (class_type.type) generate_metamorphose (class_type.type) generate_return (True) end store_locals (l_meth_token, class_type) method_writer.write_current_body -- Define `____copy' l_sig.reset l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Has_current) l_sig.set_parameter_count (1) l_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.Element_type_void, 0) l_sig.set_type ({MD_SIGNATURE_CONSTANTS}.Element_type_object, 0) uni_string.set_string ("____copy") l_meth_token := md_emit.define_method (uni_string, l_class_token, l_meth_attr, l_sig, {MD_METHOD_ATTRIBUTES}.Managed) start_new_body (l_meth_token) generate_current generate_argument (1) if class_type.is_expanded then l_feature := class_type.associated_class.feature_of_rout_id (copy_rout_id) l_type := argument_actual_type_in (l_feature.arguments.first, current_class_type) if l_type.is_basic then -- Unbox a value object. generate_load_address (l_type) generate_load_from_address_as_basic (l_type) elseif l_type.is_expanded then -- Unbox a value object. generate_unmetamorphose (l_type) end internal_generate_feature_access (class_type.implementation_id, l_feature.feature_id, 1, False, False) else internal_generate_feature_access (any_type_id, copy_feat_id, 1, False, True) end generate_return (False) store_locals (l_meth_token, class_type) method_writer.write_current_body -- Define `____is_equal' l_sig.reset l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Has_current) l_sig.set_parameter_count (1) l_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.Element_type_boolean, 0) l_sig.set_type ({MD_SIGNATURE_CONSTANTS}.Element_type_object, 0) uni_string.set_string ("____is_equal") l_meth_token := md_emit.define_method (uni_string, l_class_token, l_meth_attr, l_sig, {MD_METHOD_ATTRIBUTES}.Managed) start_new_body (l_meth_token) generate_current generate_argument (1) if class_type.is_expanded then l_feature := class_type.associated_class.feature_of_rout_id (is_equal_rout_id) l_type := argument_actual_type_in (l_feature.arguments.first, current_class_type) if l_type.is_basic then -- Unbox a value object. generate_load_address (l_type) generate_load_from_address_as_basic (l_type) elseif l_type.is_expanded then -- Unbox a value object. generate_unmetamorphose (l_type) end internal_generate_feature_access (class_type.implementation_id, l_feature.feature_id, 1, True, False) else internal_generate_feature_access (any_type_id, is_equal_feat_id, 1, True, True) end generate_return (True) store_locals (l_meth_token, class_type) method_writer.write_current_body end end define_system_object_features (class_type: CLASS_TYPE) -- Define all features of SYSTEM_OBJECT on Eiffel types so that -- they have a meaning. It includes: -- to_string, finalize, equals, get_hash_code require class_type_not_void: class_type /= Void not_external_class_type: not class_type.is_external local l_select_tbl: SELECT_TABLE l_feat: FEATURE_I l_class_id: INTEGER do -- To generate those routines, we first check if they are -- redefined in the current class. If they are, we keep the -- definition given by the user, otherwise we put the Eiffel one. -- We only do the later if the .NET one was not frozen to begin with. -- Gets current feature table. l_select_tbl := class_type.associated_class.feature_table.select_table l_class_id := class_type.associated_class.class_id -- Process `equals' if l_select_tbl.has_key (equals_rout_id) then l_feat := l_select_tbl.found_item if l_feat.written_in /= l_class_id and not l_feat.is_frozen then define_equals_routine (class_type) end else define_equals_routine (class_type) end -- Process `finalize' if l_select_tbl.has_key (finalize_rout_id) then l_feat := l_select_tbl.found_item if l_feat.written_in /= l_class_id and not l_feat.is_frozen then define_finalize_routine (class_type) end else define_finalize_routine (class_type) end -- Process `get_hash_code' if l_select_tbl.has_key (get_hash_code_rout_id) then l_feat := l_select_tbl.found_item if l_feat.written_in /= l_class_id and not l_feat.is_frozen then define_get_hash_code_routine (class_type) end else define_get_hash_code_routine (class_type) end -- Process `to_string' if l_select_tbl.has_key (to_string_rout_id) then l_feat := l_select_tbl.found_item if l_feat.written_in /= l_class_id and not l_feat.is_frozen then define_to_string_routine (class_type) end else define_to_string_routine (class_type) end end feature {NONE} -- SYSTEM_OBJECT features define_equals_routine (class_type: CLASS_TYPE) -- Define Eiffel implementation of `equals' from SYSTEM_OBJECT. require class_type_not_void: class_type /= Void not_external_class_type: not class_type.is_external has_any_class: system.any_class /= Void has_compiled_any_class: system.any_class.compiled_class /= Void has_feature_table_in_any_class: system.any_class.compiled_class.has_feature_table has_feature_table: class_type.associated_class.has_feature_table local l_meth_token: INTEGER l_sig: like method_sig l_class_token: INTEGER l_meth_attr: INTEGER l_label, l_end_label: IL_LABEL feature_i: FEATURE_I class_c: CLASS_C type_i: TYPE_A arg_type: TYPE_A do class_c := system.any_class.compiled_class feature_i := class_c.feature_table.item_id ({PREDEFINED_NAMES}.is_equal_name_id) if feature_i /= Void then -- Provide implementation matching definition of feature "is_equal" from class ANY debug ("fixme") fixme ("Check that the signature of the feature is as expected.") end if class_type.is_expanded then -- Call feature directly from implementation class class_c := class_type.associated_class feature_i := class_c.feature_table.feature_of_rout_id (feature_i.rout_id_set.first) check feature_i_not_void: feature_i /= Void end type_i := class_type.type else type_i := class_c.actual_type end l_class_token := actual_class_type_token (class_type.implementation_id) l_meth_attr := {MD_METHOD_ATTRIBUTES}.public | {MD_METHOD_ATTRIBUTES}.hide_by_signature | {MD_METHOD_ATTRIBUTES}.virtual l_sig := method_sig l_sig.reset l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.has_current) l_sig.set_parameter_count (1) l_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.element_type_boolean, 0) l_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_object, 0) uni_string.set_string ("Equals") l_meth_token := md_emit.define_method (uni_string, l_class_token, l_meth_attr, l_sig, {MD_METHOD_ATTRIBUTES}.managed) start_new_body (l_meth_token) generate_current generate_argument (1) generate_is_instance_of (class_type.type) duplicate_top l_label := create_label l_end_label := create_label branch_on_false (l_label) arg_type := argument_actual_type_in (feature_i.arguments.first, class_type) if arg_type.is_basic then generate_external_unmetamorphose (arg_type) elseif arg_type.is_expanded then generate_unmetamorphose (arg_type) end generate_feature_access (type_i, feature_i.feature_id, 1, True, True) branch_to (l_end_label) mark_label (l_label) -- We need to pop both Current and argument pop pop put_boolean_constant (False) mark_label (l_end_label) generate_return (True) method_writer.write_current_body end end define_finalize_routine (class_type: CLASS_TYPE) -- Define Eiffel implementation of `finalize' from SYSTEM_OBJECT. require class_type_not_void: class_type /= Void not_external_class_type: not class_type.is_external has_feature_table: class_type.associated_class.has_feature_table local l_meth_token: INTEGER l_sig: like method_sig l_class_token: INTEGER l_meth_attr: INTEGER l_feat: FEATURE_I do if System.disposable_descendants.has (class_type.associated_class) then l_class_token := actual_class_type_token (class_type.implementation_id) l_meth_attr := {MD_METHOD_ATTRIBUTES}.public | {MD_METHOD_ATTRIBUTES}.hide_by_signature | {MD_METHOD_ATTRIBUTES}.virtual l_sig := method_sig l_sig.reset l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.has_current) l_sig.set_parameter_count (0) l_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.element_type_void, 0) uni_string.set_string ("Finalize") l_meth_token := md_emit.define_method (uni_string, l_class_token, l_meth_attr, l_sig, {MD_METHOD_ATTRIBUTES}.managed) l_feat := system.disposable_class.compiled_class.feature_table. item_id ({PREDEFINED_NAMES}.dispose_name_id) if class_type.is_expanded then -- Call feature directly from implementation class l_feat := class_type.associated_class.feature_table.feature_of_rout_id (l_feat.rout_id_set.first) check l_feat_not_void: l_feat /= Void end end start_new_body (l_meth_token) cil_node_generator.generate_il_node (Current, l_feat.access (void_type, False, False)) generate_return (False) method_writer.write_current_body end end define_get_hash_code_routine (class_type: CLASS_TYPE) -- Define Eiffel implementation of `get_hash_code' from SYSTEM_OBJECT. require class_type_not_void: class_type /= Void not_external_class_type: not class_type.is_external has_feature_table: class_type.associated_class.has_feature_table local l_hashable_class_id: INTEGER l_meth_token: INTEGER l_sig: like method_sig l_class_token: INTEGER l_meth_attr: INTEGER class_c: CLASS_C feature_i: FEATURE_I type_i: TYPE_A do l_hashable_class_id := hashable_class_id if l_hashable_class_id > 0 and then class_type.associated_class.feature_table.select_table.has (hash_code_rout_id) then class_c := hashable_type.base_class feature_i := class_c.feature_table.item_id ({PREDEFINED_NAMES}.hash_code_name_id) debug ("fixme") fixme ("Check that the signature of the feature is as expected.") end if class_type.is_expanded then -- Call feature directly from implementation class class_c := class_type.associated_class feature_i := class_c.feature_table.feature_of_rout_id (feature_i.rout_id_set.first) check feature_i_not_void: feature_i /= Void end type_i := class_type.type else type_i := class_c.actual_type end l_class_token := actual_class_type_token (class_type.implementation_id) l_meth_attr := {MD_METHOD_ATTRIBUTES}.public | {MD_METHOD_ATTRIBUTES}.hide_by_signature | {MD_METHOD_ATTRIBUTES}.virtual l_sig := method_sig l_sig.reset l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.has_current) l_sig.set_parameter_count (0) l_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.element_type_i4, 0) uni_string.set_string ("GetHashCode") l_meth_token := md_emit.define_method (uni_string, l_class_token, l_meth_attr, l_sig, {MD_METHOD_ATTRIBUTES}.managed) start_new_body (l_meth_token) generate_current generate_feature_access (type_i, feature_i.feature_id, 0, True, True) generate_return (True) method_writer.write_current_body end end define_to_string_routine (class_type: CLASS_TYPE) -- Define Eiffel implementation of `to_string' from SYSTEM_OBJECT. require class_type_not_void: class_type /= Void not_external_class_type: not class_type.is_external has_any_class: system.any_class /= Void has_compiled_any_class: system.any_class.compiled_class /= Void has_feature_table_in_any_class: system.any_class.compiled_class.has_feature_table has_feature_table: class_type.associated_class.has_feature_table local l_meth_token: INTEGER l_sig: like method_sig l_class_token: INTEGER l_meth_attr: INTEGER class_c: CLASS_C feature_i: FEATURE_I type_i: TYPE_A do class_c := system.any_class.compiled_class feature_i := class_c.feature_table.item_id ({PREDEFINED_NAMES}.out_name_id) if feature_i /= Void then -- Provide implementation matching definition of feature "out" from class ANY debug ("fixme") fixme ("Check that the signature of the feature is as expected.") end if class_type.is_expanded then -- Call feature directly from implementation class class_c := class_type.associated_class feature_i := class_c.feature_table.feature_of_rout_id (feature_i.rout_id_set.first) check feature_i_not_void: feature_i /= Void end type_i := class_type.type else type_i := class_c.actual_type end l_class_token := actual_class_type_token (class_type.implementation_id) l_meth_attr := {MD_METHOD_ATTRIBUTES}.public | {MD_METHOD_ATTRIBUTES}.hide_by_signature | {MD_METHOD_ATTRIBUTES}.virtual l_sig := method_sig l_sig.reset l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.has_current) l_sig.set_parameter_count (0) l_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.element_type_string, 0) uni_string.set_string ("ToString") l_meth_token := md_emit.define_method (uni_string, l_class_token, l_meth_attr, l_sig, {MD_METHOD_ATTRIBUTES}.managed) start_new_body (l_meth_token) generate_current generate_feature_access (type_i, feature_i.feature_id, 0, True, True) internal_generate_feature_access (to_cil_feat.static_type_id, to_cil_feat.feature_id, 0, True, True) generate_return (True) method_writer.write_current_body end end feature {NONE} -- Class info generate_class_features (class_c: CLASS_C; class_type: CLASS_TYPE) -- Generate IL code for class invariant of `class_c' and other internal -- features required by run-time, CIL, etc. require class_c_not_void: class_c /= Void class_type_not_void: class_type /= Void do -- Define all features used by ISE runtime define_runtime_features (class_type) -- Define definition of SYSTEM_OBJECT features for .NET types define_system_object_features (class_type) -- Generate invariant routine generate_invariant_feature (class_c.invariant_feature) end clean_implementation_class_data -- Clean current class implementation data. require current_type_id_set: current_type_id > 0 do current_module.clean_implementation_class_data (current_type_id) end feature -- Features info generate_il_features_description (class_c: CLASS_C; class_type: CLASS_TYPE) -- Generate features description of `class_type'. require class_c_not_void: class_c /= Void class_type_not_void: class_type /= Void not_external_class_type: not class_type.is_external local type_feature_processor: PROCEDURE [TYPE_FEATURE_I] do set_current_class_type (class_type) set_current_type_id (class_type.static_type_id) inst_context.set_group (class_c.group) is_single_class := class_type.is_generated_as_single_type current_class_token := actual_class_type_token (current_type_id) debug ("debugger_il_info_trace") print ("### SINGLE CLEANING " + class_type.associated_class.name_in_upper + "---%N") end clean_debug_information (class_type) if is_single_class then -- Define implementation features on Eiffel classes generate_features (class_c, class_type, False) else -- Define interface features on Eiffel classes generate_features (class_c, class_type, True) type_feature_processor := agent generate_type_feature_description end -- Define implementation features on Eiffel classes generate_il_features (class_c, class_type, Void, agent generate_local_feature_description, agent generate_inherited_feature_description, type_feature_processor, agent generate_feature (?, False, True, False)) end generate_local_feature_description (local_feature: FEATURE_I; inherited_feature: FEATURE_I; class_type: CLASS_TYPE; is_replicated: BOOLEAN) -- Define local feature `local_feature' with a possible precursor feature `inherited_feature' from `class_type'. require local_feature_not_void: local_feature /= Void class_type_not_void: class_type /= Void do generate_inherited_feature_description (local_feature, inherited_feature, class_type) end generate_inherited_feature_description (local_feature: FEATURE_I; inherited_feature: FEATURE_I; class_type: CLASS_TYPE) -- Define local feature `local_feature' with a possible precursor feature `inherited_feature' from `class_type'. require local_feature_not_void: local_feature /= Void class_type_not_void: class_type /= Void local duplicated_feature: FEATURE_I do if inherited_feature /= Void then if is_method_impl_needed (local_feature, inherited_feature, class_type) or else is_local_signature_changed (inherited_feature, local_feature) then generate_feature (local_feature, False, False, False) else -- Generate local definition signature using the parent -- signature. We do not do it on the parent itself because -- its `feature_id' is not appropriate in `current_class_type'. duplicated_feature := local_feature.duplicate if duplicated_feature.is_routine and then attached {PROCEDURE_I} duplicated_feature as proc then proc.set_arguments (inherited_feature.arguments) end duplicated_feature.set_type (inherited_feature.type, inherited_feature.assigner_name_id) duplicated_feature.set_rout_id_set (inherited_feature.rout_id_set) implementation_generate_feature (duplicated_feature, False, False, False, False, False, class_type) end elseif not is_single_class then generate_feature (local_feature, False, False, False) end if current_class_type.is_expanded and then local_feature.is_attribute then generate_feature (local_feature, False, True, False) end end generate_type_feature_description (type_feature: TYPE_FEATURE_I) -- Define type feature `type_feature'. require type_feature_not_void: type_feature /= Void do generate_feature (type_feature, False, False, False) end generate_features (class_c: CLASS_C; class_type: CLASS_TYPE; is_interface: BOOLEAN) -- Generate features written in `class_c' for interface -- (`is_interface' is `True') or implementation (`is_interface' is `False'). require class_c_not_void: class_c /= Void class_type_not_void: class_type /= Void local select_tbl: SELECT_TABLE features: SEARCH_TABLE [INTEGER] sorted_array: SORTABLE_ARRAY [FEATURE_I] i: INTEGER do -- Features have to be generated in alphabetical order -- as this order is expected by COM Interop that defines -- the virtual table this way. from select_tbl := class_c.feature_table.select_table features := class_type.class_interface.features i := features.count features.start if features.after then create sorted_array.make_empty else create sorted_array.make_filled (select_tbl.item (features.item_for_iteration), 1, i) end invariant consistent_index: (i = 0) = features.after until i = 0 loop sorted_array.put (select_tbl.item (features.item_for_iteration), i) features.forth i := i - 1 end sorted_array.sort sorted_array.do_all (agent generate_feature (?, is_interface, False, False)) -- Generate type features for formal generic parameters. if class_c.generic_features /= Void then generate_type_features (class_c.generic_features, class_c.class_id, is_interface) end -- Generate type features for feature used as anchor. if class_c.anchored_features /= Void then generate_type_features (class_c.anchored_features, class_c.class_id, is_interface) end end define_feature_reference (a_type_id, a_feature_id: INTEGER; in_interface, is_static, is_override: BOOLEAN) -- Define reference to feature `a_feature_id' defined in `a_type_id'. require type_id_valid: a_type_id > 0 feature_id_valid: a_feature_id > 0 local l_feat: FEATURE_I l_class_type: CLASS_TYPE do l_class_type := class_types.item (a_type_id) l_feat := l_class_type.associated_class.feature_of_feature_id (a_feature_id) check same_feature_id: l_feat.feature_id = a_feature_id end define_feature_i_reference (a_type_id, l_feat, in_interface, is_static, is_override) end define_feature_i_reference (a_type_id: INTEGER; a_feature_i: FEATURE_I; in_interface, is_static, is_override: BOOLEAN) -- Define reference to feature `a_feature_i' defined in `a_type_id'. require type_id_valid: a_type_id > 0 feature_id_valid: a_feature_i /= Void local l_feature_id: INTEGER l_class_type: CLASS_TYPE l_meth_sig: like method_sig l_field_sig: like field_sig l_name: STRING l_type_i: TYPE_A l_meth_token, l_setter_token: INTEGER l_parameter_count: INTEGER l_is_attribute: BOOLEAN l_return_type: TYPE_A l_is_c_external: BOOLEAN l_class_token: like current_class_token l_naming_convention: BOOLEAN l_is_single_class: BOOLEAN l_is_static: BOOLEAN l_is_attribute_generated_as_field: BOOLEAN l_declaration_class: CLASS_C do l_class_type := class_types.item (a_type_id) l_feature_id := a_feature_i.feature_id l_class_token := actual_class_type_token (a_type_id) l_is_single_class := l_class_type.is_generated_as_single_type l_is_attribute := a_feature_i.is_attribute l_is_c_external := a_feature_i.is_c_external if attached {IL_EXTENSION_I} a_feature_i.extension as e then l_is_static := not e.need_current (e.type) l_name := e.alias_name elseif l_class_type.is_expanded and then l_is_attribute then l_is_static := True elseif not l_is_single_class then l_is_static := is_static end l_parameter_count := a_feature_i.argument_count l_return_type := result_type_in (a_feature_i, l_class_type) l_is_attribute_generated_as_field := l_is_attribute and (l_is_single_class or (not in_interface and l_is_static)) if not a_feature_i.is_type_feature then -- Only for not automatically generated feature do we use the -- naming convention chosen by user. l_naming_convention := l_class_type.is_dotnet_name end -- When we are handling with an external feature, we have to extract its -- real name, not the Eiffel one. if not attached l_name then if a_feature_i.is_type_feature then l_name := a_feature_i.feature_name else if l_is_static then if l_is_c_external then l_name := encoder.feature_name (l_class_type.type_id, a_feature_i.body_index) else if l_is_attribute then l_name := "$$" + il_casing.camel_casing ( l_naming_convention, a_feature_i.feature_name) else l_name := "$$" + il_casing.pascal_casing ( l_naming_convention, a_feature_i.feature_name, {IL_CASING_CONVERSION}.lower_case) end end else l_name := il_casing.pascal_casing ( l_naming_convention, a_feature_i.feature_name, {IL_CASING_CONVERSION}.lower_case) if a_feature_i.has_property_getter then prepare_property_getter (a_feature_i, l_class_type, l_name, l_return_type, l_class_type) current_module.insert_property_getter (md_emit.define_member_ref (uni_string, l_class_token, method_sig), a_type_id, l_feature_id) end if a_feature_i.has_property_setter then l_type_i := l_return_type if l_type_i.is_void then l_type_i := argument_actual_type_in (a_feature_i.arguments.first, l_class_type) end prepare_property_setter (a_feature_i, l_class_type, l_name, l_type_i, l_class_type) current_module.insert_property_setter (md_emit.define_member_ref (uni_string, l_class_token, method_sig), a_type_id, l_feature_id) end if a_feature_i.has_property and then l_is_single_class and then not is_override and then l_is_attribute_generated_as_field then -- Use a field name different from the property name. l_name := "$$" + il_casing.camel_casing (l_naming_convention, a_feature_i.feature_name) end check l_name_attached: l_name /= Void end end end end uni_string.set_string (l_name) if l_is_attribute_generated_as_field then -- Evaluate signature of the field. l_field_sig := field_sig l_field_sig.reset set_signature_type (l_field_sig, l_return_type, l_class_type) if a_feature_i.origin_class_id = 0 then l_declaration_class := system.class_of_id (a_feature_i.access_in) else l_declaration_class := system.class_of_id (a_feature_i.origin_class_id) end if l_declaration_class.is_true_external or else (l_declaration_class.is_single and then l_declaration_class /= l_class_type.associated_class) then -- No field is generated because it is inherited or if this was a .NET class -- it has already been generated. check is_single_class: is_single_class end l_meth_token := attribute_token (l_class_type.type.implemented_type (l_declaration_class.class_id).associated_class_type (l_class_type.type).static_type_id, l_declaration_class.feature_of_rout_id (a_feature_i.rout_id_set.first).feature_id) else l_meth_token := md_emit.define_member_ref (uni_string, l_class_token, l_field_sig) end insert_attribute (l_meth_token, a_type_id, l_feature_id) if l_is_single_class then insert_signature ([l_class_type, a_feature_i.rout_id_set.first], a_type_id, l_feature_id) end else -- Normal method. -- Evaluate its signature. l_meth_sig := method_sig l_meth_sig.reset l_meth_sig.set_method_type (if l_is_static and not in_interface then {MD_SIGNATURE_CONSTANTS}.Default_sig else {MD_SIGNATURE_CONSTANTS}.Has_current end) l_meth_sig.set_parameter_count (l_parameter_count + (l_is_static and not l_is_c_external).to_integer) if a_feature_i.is_type_feature then l_meth_sig.set_return_type ( {MD_SIGNATURE_CONSTANTS}.Element_type_class, current_module.ise_type_token) elseif l_return_type.is_void then l_meth_sig.set_return_type ( {MD_SIGNATURE_CONSTANTS}.Element_type_void, 0) else set_method_return_type (l_meth_sig, l_return_type, l_class_type) end if l_is_static and not l_is_c_external then set_signature_type (l_meth_sig, l_class_type.type, l_class_type) end if a_feature_i.has_arguments then across a_feature_i.arguments as a loop set_signature_type (l_meth_sig, argument_actual_type_in (a.item, l_class_type), l_class_type) end end l_meth_token := md_emit.define_member_ref (uni_string, l_class_token, l_meth_sig) if not l_is_static and l_is_attribute and not is_override then -- Let's define attribute setter. l_meth_sig.reset l_meth_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Has_current) l_meth_sig.set_parameter_count (1) l_meth_sig.set_return_type ( {MD_SIGNATURE_CONSTANTS}.Element_type_void, 0) set_signature_type (l_meth_sig, l_return_type, l_class_type) uni_string.set_string (setter_prefix + l_name) l_setter_token := md_emit.define_member_ref (uni_string, l_class_token, l_meth_sig) insert_setter (l_setter_token, a_type_id, l_feature_id) end if not is_override then if l_is_single_class then insert_implementation_feature (l_meth_token, a_type_id, l_feature_id) insert_implementation_signature ([l_class_type, a_feature_i.rout_id_set.first], a_type_id, l_feature_id) insert_feature (l_meth_token, a_type_id, l_feature_id) insert_signature ([l_class_type, a_feature_i.rout_id_set.first], a_type_id, l_feature_id) else if l_is_static then insert_implementation_feature (l_meth_token, a_type_id, l_feature_id) insert_implementation_signature ([l_class_type, a_feature_i.rout_id_set.first], a_type_id, l_feature_id) else insert_feature (l_meth_token, a_type_id, l_feature_id) insert_signature ([l_class_type, a_feature_i.rout_id_set.first], a_type_id, l_feature_id) end end else last_non_recorded_feature_token := l_meth_token end end end generate_feature (feat: FEATURE_I; in_interface, is_static, is_c_external: BOOLEAN) -- Generate interface `feat' description. require feat_not_void: feat /= Void do implementation_generate_feature (feat, in_interface, is_static, is_c_external, False, False, current_class_type) end implementation_generate_feature ( feat: FEATURE_I; in_interface, is_static, is_external, is_override, is_empty: BOOLEAN; signature_declaration_type: CLASS_TYPE) -- Generate interface `feat' description using for `signature_declaration_type' for signature evaluation. require feat_not_void: feat /= Void signature_declaration_type_not_void: signature_declaration_type /= Void found_feature_in_declaration_type: (not feat.is_inline_agent and not feat.is_hidden) implies signature_declaration_type.associated_class.feature_of_rout_id (feat.rout_id_set.first) /= Void local is_override_or_c_external: BOOLEAN l_feature_name: STRING l_meth_sig: like method_sig l_field_sig: like field_sig l_name: STRING l_type_feature: TYPE_FEATURE_I l_type_i: TYPE_A l_type_a: TYPE_A l_meth_token, l_setter_token: INTEGER l_param_token: INTEGER l_meth_attr: INTEGER l_field_attr: INTEGER l_parameter_count: INTEGER l_is_attribute: BOOLEAN l_return_type: TYPE_A l_has_arguments: BOOLEAN l_feat_arg: like {FEATURE_I}.arguments i, j: INTEGER l_is_c_external: BOOLEAN l_ca_factory: CUSTOM_ATTRIBUTE_FACTORY l_naming_convention: BOOLEAN l_name_ca: MD_CUSTOM_ATTRIBUTE l_is_attribute_generated_as_field: BOOLEAN -- l_is_field_hidden: BOOLEAN l_declaration_class: CLASS_C l_getter: INTEGER l_setter: INTEGER l_property_name: STRING l_property_token: INTEGER l_has_property: BOOLEAN do is_override_or_c_external := is_external or is_override l_feature_name := feat.feature_name if is_override then l_feature_name := Override_prefix + l_feature_name + override_counter.next.out end last_property_getter_token := {MD_TOKEN_TYPES}.md_method_def last_property_setter_token := {MD_TOKEN_TYPES}.md_method_def l_is_attribute := feat.is_attribute l_is_c_external := feat.is_c_external l_parameter_count := feat.argument_count l_return_type := result_type_in (feat, signature_declaration_type) l_is_attribute_generated_as_field := l_is_attribute and then ((is_single_class and not current_class_type.is_expanded and not is_override_or_c_external) or (not in_interface and is_static)) if l_is_attribute_generated_as_field then l_field_sig := field_sig l_field_sig.reset set_signature_type (l_field_sig, l_return_type, signature_declaration_type) else l_meth_sig := method_sig l_meth_sig.reset l_meth_sig.set_method_type (if is_static and not in_interface then {MD_SIGNATURE_CONSTANTS}.Default_sig else {MD_SIGNATURE_CONSTANTS}.Has_current end) l_meth_sig.set_parameter_count (l_parameter_count + (is_static and not l_is_c_external).to_integer) if feat.is_type_feature then l_meth_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.Element_type_class, current_module.ise_type_token) elseif l_return_type.is_void then l_meth_sig.set_return_type ( {MD_SIGNATURE_CONSTANTS}.Element_type_void, 0) else set_method_return_type (l_meth_sig, l_return_type, signature_declaration_type) end if is_static and not l_is_c_external then set_signature_type (l_meth_sig, current_class_type.type, current_class_type) end if feat.has_arguments then l_has_arguments := True across feat.arguments as a loop set_signature_type (l_meth_sig, argument_actual_type_in (a.item, signature_declaration_type), signature_declaration_type) end end end if not feat.is_type_feature then -- Only for not automatically generated feature do we use the -- naming convention chosen by user. l_naming_convention := System.dotnet_naming_convention end if is_static then if l_is_c_external then l_name := encoder.feature_name (current_class_type.type_id, feat.body_index) else if l_is_attribute then l_name := "$$" + il_casing.camel_casing ( l_naming_convention, l_feature_name) -- Ensure the field is not accessible outside Eiffel system. -- l_is_field_hidden := True else l_name := "$$" + il_casing.pascal_casing ( l_naming_convention, l_feature_name, {IL_CASING_CONVERSION}.lower_case) end end else l_name := il_casing.pascal_casing ( l_naming_convention, l_feature_name, {IL_CASING_CONVERSION}.lower_case) if feat.has_property_getter or else feat.has_property_setter then -- Define property. l_meth_sig := method_sig l_meth_attr := {MD_METHOD_ATTRIBUTES}.Public ⦶ {MD_METHOD_ATTRIBUTES}.Hide_by_signature ⦶ {MD_METHOD_ATTRIBUTES}.Virtual ⦶ ({MD_METHOD_ATTRIBUTES}.Abstract ⊗ (- in_interface.to_integer.to_integer_16)) if feat.has_property and then (is_single_class or else in_interface) and then not is_override_or_c_external then l_has_property := True l_meth_attr := l_meth_attr | {MD_METHOD_ATTRIBUTES}.special_name end if feat.has_property_setter then if is_property_setter_generated (feat, signature_declaration_type) then l_property_name := feat.property_name if is_override then l_property_name := Override_prefix + l_property_name + override_counter.value.out end l_type_i := l_return_type if l_type_i.is_void then l_type_i := argument_actual_type_in (feat.arguments.first, signature_declaration_type) end -- Define setter method. prepare_property_setter (feat, current_class_type, l_property_name, l_type_i, signature_declaration_type) l_setter := md_emit.define_method (uni_string, current_class_token, l_meth_attr | {MD_METHOD_ATTRIBUTES}.New_slot, l_meth_sig, {MD_METHOD_ATTRIBUTES}.Managed) if is_override_or_c_external then last_property_setter_token := l_setter else current_module.insert_property_setter (l_setter, current_type_id, feat.feature_id) end elseif not is_override then -- Eiffel method is used as a setter. postponed_property_setters.extend (create {PAIR [INTEGER, INTEGER]}.make (feat.feature_id, current_type_id)) end end if is_property_getter_generated (feat, signature_declaration_type) then l_property_name := feat.property_name if is_override then l_property_name := Override_prefix + l_property_name + override_counter.value.out end -- Define getter method. prepare_property_getter (feat, current_class_type, l_property_name, l_return_type, signature_declaration_type) l_getter := md_emit.define_method (uni_string, current_class_token, l_meth_attr | {MD_METHOD_ATTRIBUTES}.New_slot, l_meth_sig, {MD_METHOD_ATTRIBUTES}.Managed) if is_override_or_c_external then last_property_getter_token := l_getter else current_module.insert_property_getter (l_getter, current_type_id, feat.feature_id) end end if l_has_property then -- Define property on a single class or interface only. properties.extend (feat.feature_id) if l_is_attribute_generated_as_field then -- Use a field name different from the property name. l_name := "$$" + il_casing.camel_casing ( l_naming_convention, l_feature_name) -- Ensure the field is not accessible outside Eiffel system. -- l_is_field_hidden := True end end end end uni_string.set_string (l_name) if l_is_attribute_generated_as_field then l_declaration_class := system.class_of_id (if feat.origin_class_id = 0 then feat.access_in else feat.origin_class_id end) if l_declaration_class.is_true_external or else (l_declaration_class.is_single and then l_declaration_class /= current_class) then -- No field is generated because it is inherited or if this was a .NET class -- it has already been generated. check is_single_class: is_single_class end l_meth_token := attribute_token (current_class_type.type.implemented_type (l_declaration_class.class_id).associated_class_type (current_class_type.type).static_type_id, l_declaration_class.feature_of_rout_id (feat.rout_id_set.first).feature_id) else -- The field could be made non-public. But some third-party -- auto-generated code relies on the fact that it is public. -- if l_is_field_hidden and then not Compilation_modes.is_precompiling then -- l_field_attr := {MD_FIELD_ATTRIBUTES}.family_or_assembly -- else l_field_attr := {MD_FIELD_ATTRIBUTES}.public -- end l_meth_token := md_emit.define_field (uni_string, current_class_token, l_field_attr, l_field_sig) -- Define associated name corresponding to the Eiffel name create l_name_ca.make l_name_ca.put_string (l_feature_name) l_name_ca.put_integer_16 (0) define_custom_attribute (l_meth_token, current_module.ise_eiffel_name_attr_ctor_token, l_name_ca) if feat.is_transient then define_custom_attribute (l_meth_token, current_module.dotnet_non_serialized_attr_ctor_token, empty_ca) end -- Define name of routine used to find out the attribute static type -- if it is generic or a formal. l_type_a := result_type_in (feat, signature_declaration_type).actual_type if l_type_a.is_formal or l_type_a.has_generics then -- Lookup associated TYPE_FEATURE_I to get its name l_type_feature := current_class_type.associated_class.anchored_features.item (feat.rout_id_set.first) check l_type_feature_not_void: l_type_feature /= Void end create l_name_ca.make l_name_ca.put_string (l_type_feature.feature_name) l_name_ca.put_integer_16 (0) define_custom_attribute (l_meth_token, current_module.ise_type_feature_attr_ctor_token, l_name_ca) elseif l_type_a.has_associated_class and then l_type_a.base_class.lace_class = system.any_class then -- Type is ANY, so because we actually generate a field of type SYSTEM_OBJECT -- we generate a special custom attribute that says it is actually ANY, and not -- a field of type SYSTEM_OBJECT define_interface_type (l_type_a.base_class.types.first, l_meth_token) end end insert_attribute (l_meth_token, current_type_id, feat.feature_id) if is_single_class then insert_signature ([signature_declaration_type, feat.rout_id_set.first], current_type_id, feat.feature_id) end else l_meth_attr := {MD_METHOD_ATTRIBUTES}.Public | {MD_METHOD_ATTRIBUTES}.Hide_by_signature if in_interface then l_meth_attr := l_meth_attr | {MD_METHOD_ATTRIBUTES}.Virtual | {MD_METHOD_ATTRIBUTES}.Abstract | {MD_METHOD_ATTRIBUTES}.New_slot else if is_static then l_meth_attr := l_meth_attr | {MD_METHOD_ATTRIBUTES}.Static else l_meth_attr := l_meth_attr ⦶ {MD_METHOD_ATTRIBUTES}.Virtual ⦶ ({MD_METHOD_ATTRIBUTES}.New_slot ⊗ (- feat.is_origin.to_integer.to_integer_16)) ⦶ ({MD_METHOD_ATTRIBUTES}.Abstract ⊗ (- (feat.is_deferred and not is_empty and not is_override_or_c_external).to_integer.to_integer_16)) end end if is_static and l_is_c_external then -- Let's define Pinvoke here. -- The COM interface updates the method definition attributes behind the scenes, -- so it is not necessary to update the method attribute with p_invoke_implementation. -- However, with IL_EMITTER, we need to explicitly update the method attribute -- with p_invoke_implementation. if system.is_il_netcore then l_meth_attr := l_meth_attr | {MD_METHOD_ATTRIBUTES}.pinvoke_implementation end l_meth_token := md_emit.define_method (uni_string, current_class_token, l_meth_attr, l_meth_sig, {MD_METHOD_ATTRIBUTES}.Managed | {MD_METHOD_ATTRIBUTES}.Preserve_sig) md_emit.define_pinvoke_map (l_meth_token, {MD_PINVOKE_CONSTANTS}.Charset_ansi | {MD_PINVOKE_CONSTANTS}.Stdcall, uni_string, current_module.c_module_token) else -- Normal method l_meth_token := md_emit.define_method (uni_string, current_class_token, l_meth_attr, l_meth_sig, {MD_METHOD_ATTRIBUTES}.Managed) end if is_cls_compliant and (is_static or feat.is_type_feature) then define_custom_attribute (l_meth_token, current_module.cls_compliant_ctor_token, not_cls_compliant_ca) end if feat.is_type_feature then define_custom_attribute (l_meth_token, current_module.com_visible_ctor_token, not_com_visible_ca) end if not is_static and l_is_attribute and not is_override_or_c_external then -- Let's define attribute setter. l_meth_attr := {MD_METHOD_ATTRIBUTES}.Public ⦶ {MD_METHOD_ATTRIBUTES}.Hide_by_signature ⦶ {MD_METHOD_ATTRIBUTES}.Virtual ⦶ ({MD_METHOD_ATTRIBUTES}.Abstract ⊗ (- in_interface.to_integer.to_integer_16)) l_meth_sig.reset l_meth_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Has_current) l_meth_sig.set_parameter_count (1) l_meth_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.Element_type_void, 0) set_signature_type (l_meth_sig, l_return_type, signature_declaration_type) uni_string.set_string (setter_prefix + l_name) l_setter_token := md_emit.define_method (uni_string, current_class_token, l_meth_attr, l_meth_sig, {MD_METHOD_ATTRIBUTES}.Managed) insert_setter (l_setter_token, current_type_id, feat.feature_id) create l_ca_factory l_ca_factory.set_feature_custom_attributes (feat, l_setter_token) if is_cls_compliant then define_custom_attribute (l_setter_token, current_module.cls_compliant_ctor_token, not_cls_compliant_ca) end end -- Let's generate argument names now. if is_static and not l_is_c_external then -- Offset for static features as we generate one more argument. j := 1 -- Current needs to be generated only for static wrapper of Eiffel -- feature so that metadata consumer can pick the name (e.g. debugger) -- but it is not needed when it is defined as an instance method. uni_string.set_string ("Current") md_emit.define_parameter (l_meth_token, uni_string, j, {MD_PARAM_ATTRIBUTES}.In).do_nothing end if is_static and then l_is_c_external and then attached l_return_type and then l_return_type.is_boolean then uni_string.set_string ("Result") l_param_token := md_emit.define_parameter (l_meth_token, uni_string, 0, 0) md_emit.set_field_marshal (l_param_token, boolean_native_signature) end if l_has_arguments then from l_feat_arg := feat.arguments i := 1 until i > l_parameter_count loop uni_string.set_string (l_feat_arg.item_name_32 (i)) md_emit.define_parameter (l_meth_token, uni_string, i + j, {MD_PARAM_ATTRIBUTES}.In).do_nothing i := i + 1 end end if not is_override_or_c_external then if is_single_class then insert_implementation_feature (l_meth_token, current_type_id, feat.feature_id) insert_implementation_signature ([signature_declaration_type, feat.rout_id_set.first], current_type_id, feat.feature_id) insert_feature (l_meth_token, current_type_id, feat.feature_id) insert_signature ([signature_declaration_type, feat.rout_id_set.first], current_type_id, feat.feature_id) else if is_static then insert_implementation_feature (l_meth_token, current_type_id, feat.feature_id) insert_implementation_signature ([signature_declaration_type, feat.rout_id_set.first], current_type_id, feat.feature_id) else insert_feature (l_meth_token, current_type_id, feat.feature_id) insert_signature ([signature_declaration_type, feat.rout_id_set.first], current_type_id, feat.feature_id) end end else last_non_recorded_feature_token := l_meth_token end end if not is_override_or_c_external and (not is_static or else l_is_attribute) then create l_ca_factory l_ca_factory.set_feature_custom_attributes (feat, l_meth_token) if l_property_token /= 0 then l_ca_factory.set_feature_custom_attributes (feat, l_property_token) end end if is_debug_info_enabled and l_is_attribute then Il_debug_info_recorder.set_record_context (is_single_class, l_is_attribute, is_static, in_interface) Il_debug_info_recorder.record_il_feature_info (current_module, current_class_type, feat, current_class_token, l_meth_token) end end argument_actual_type_in (a_type: TYPE_A; class_type: CLASS_TYPE): TYPE_A -- Compute real type of `a_type' in `class_type'. require a_type_not_void: a_type /= Void class_type_not_void: class_type /= Void do if a_type.is_none then Result := System.any_class.compiled_class.types.first.type else Result := byte_context.real_type_in (a_type, class_type.type) end ensure valid_result: Result /= Void end result_type_in (feature_i: FEATURE_I; class_type: CLASS_TYPE): TYPE_A -- Actual type of a result of feature `feature_i' in `class_type' require feature_i_not_viod: feature_i /= Void class_type_not_void: class_type /= Void do Result := if feature_i.is_once_creation (class_type.associated_class) then class_type.type else argument_actual_type_in (feature_i.type, class_type) end ensure result_not_void: Result /= Void void_if_procedure: not feature_i.has_return_value implies Result.is_void end set_method_return_type (a_sig: MD_METHOD_SIGNATURE; a_type: TYPE_A; a_context_type: CLASS_TYPE) -- Set `a_type' to return type of `a_sig'. require valid_sig: a_sig /= Void valid_type: a_type /= Void a_context_type_not_void: a_context_type /= Void do current_module.set_method_return_type (a_sig, a_type, a_context_type) end set_signature_type (a_sig: MD_SIGNATURE; a_type: TYPE_A; a_context_type: CLASS_TYPE) -- Set `a_type' to return type of `a_sig'. require valid_sig: a_sig /= Void valid_type: a_type /= Void a_context_type_not_void: a_context_type /= Void do current_module.set_signature_type (a_sig, a_type, a_context_type) end generate_type_features (feats: HASH_TABLE [TYPE_FEATURE_I, INTEGER]; class_id: INTEGER; is_interface: BOOLEAN) -- Generate all TYPE_FEATURE_I that must be generated in -- interface corresponding to class ID `class_id'. require feats_not_void: feats /= Void local l_type_feature: TYPE_FEATURE_I do across feats as f loop l_type_feature := f.item if is_interface implies l_type_feature.origin_class_id = class_id then generate_feature (l_type_feature, is_interface, False, False) end end end prepare_property_getter (f: FEATURE_I; s: CLASS_TYPE; property_name: STRING; return_type: TYPE_A; t: CLASS_TYPE) -- Fill `uni_string' and `method_sig' with a property getter data -- in class type `t'. require f_attached: f /= Void s_attached: s /= Void property_name_attached: property_name /= Void property_name_not_empty: not property_name.is_empty return_type_attached: return_type /= Void t_attached: t /= Void local l_meth_sig: like method_sig n: STRING do l_meth_sig := method_sig l_meth_sig.reset l_meth_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.has_current) l_meth_sig.set_parameter_count (0) set_signature_type (l_meth_sig, return_type, t) n := property_getter_prefix + property_name if s.associated_class.feature_named (n) /= Void then -- Property getter name conflicts with the feature name. n := property_getter_prefix + t.associated_class.name + "." + f.feature_name end uni_string.set_string (n) end prepare_property_setter (f: FEATURE_I; s: CLASS_TYPE; property_name: STRING; return_type: TYPE_A; t: CLASS_TYPE) -- Fill `uni_string' and `method_sig' with a property setter data -- in class type `t'. require f_attached: f /= Void property_name_attached: property_name /= Void property_name_not_empty: not property_name.is_empty return_type_attached: return_type /= Void t_attached: t /= Void local l_meth_sig: like method_sig n: STRING do l_meth_sig := method_sig l_meth_sig.reset l_meth_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.has_current) l_meth_sig.set_parameter_count (1) l_meth_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.element_type_void, 0) set_signature_type (l_meth_sig, return_type, t) n := property_setter_prefix + property_name if s.associated_class.feature_named (n) /= Void then -- Property setter name conflicts with the feature name. n := property_setter_prefix + t.associated_class.name + "." + f.feature_name end uni_string.set_string (n) end is_property_getter_generated (f: FEATURE_I; t: CLASS_TYPE): BOOLEAN -- Is property getter method explicitly generated for `f' in `t'? require f_attached: f /= Void t_attached: t /= Void local n: STRING do if f.has_property_getter then n := il_casing.pascal_casing (t.is_dotnet_name, f.feature_name, {IL_CASING_CONVERSION}.lower_case) if n.is_equal (property_getter_prefix + f.property_name) then Result := f.written_class.is_single and then f.written_in /= t.type.class_id else Result := True end end end is_property_setter_generated (f: FEATURE_I; t: CLASS_TYPE): BOOLEAN -- Is property setter method explicitly generated for `f' in `t'? require f_attached: f /= Void t_attached: t /= Void local s: FEATURE_I sn: STRING do if f.has_property_setter then s := f.property_setter_in (t) if s /= Void then sn := il_casing.pascal_casing (t.is_dotnet_name, s.feature_name, {IL_CASING_CONVERSION}.lower_case) if sn.is_equal (property_setter_prefix + f.property_name) then Result := s.written_class.is_single and then s.written_in /= t.type.class_id else Result := True end end end end feature -- IL Generation generate_creation_procedures (class_c: CLASS_C; class_type: CLASS_TYPE) -- Generate IL code for creation procedures in `class_c'. require class_c_not_void: class_c /= Void class_type_not_void: class_type /= Void not_external_class_type: not class_type.is_external local create_name: STRING l_attributes: INTEGER l_creators: like {CLASS_C}.creators l_feat_tbl: FEATURE_TABLE l_type_token: INTEGER l_is_generic: BOOLEAN do l_creators := class_c.creators -- Let's define factory class if needed, i.e.: -- 1 - class is not deferred -- 2 - class has exported creation procedure -- 3 - class has automatic `default_create' procedure if not class_c.is_deferred and (attached l_creators implies not l_creators.is_empty) then l_is_generic := class_c.is_generic or else class_c.is_tuple create_name := class_type.full_il_create_type_name l_attributes := {MD_TYPE_ATTRIBUTES}.Public | {MD_TYPE_ATTRIBUTES}.Auto_layout | {MD_TYPE_ATTRIBUTES}.Ansi_class | {MD_TYPE_ATTRIBUTES}.Is_class uni_string.set_string (create_name) l_type_token := md_emit.define_type (uni_string, l_attributes, current_module.object_type_token, Void) if not is_single_module then class_type.set_last_create_type_token (l_type_token) end current_class_token := l_type_token current_class_type := class_type if attached l_creators then l_feat_tbl := class_c.feature_table across l_creators as c loop generate_creation_procedure (class_c, class_type, l_feat_tbl.item_id (c.key), l_is_generic) end elseif attached class_c.default_create_feature as f then -- It is not guaranteed that a class defines `default_create', e.g. -- a class that does not inherit from ANY. generate_creation_procedure (class_c, class_type, f, l_is_generic) end end end generate_creation_procedure (class_c: CLASS_C; class_type: CLASS_TYPE; feat: FEATURE_I; is_generic: BOOLEAN) -- Generate IL code for creation procedures in `class_c'. require class_c_not_void: class_c /= Void class_type_not_void: class_type /= Void not_external_class_type: not class_type.is_external feat_not_void: feat /= Void feat_not_attribute: not feat.is_attribute feat_not_function: not feat.is_function feat_not_deferred: not feat.is_deferred feat_not_constant: not feat.is_constant feat_not_type_feature: not feat.is_type_feature local l_meth_sig: like method_sig l_name: STRING l_is_il_external: BOOLEAN l_meth_token, l_meth_attr: INTEGER i, nb: INTEGER is_once_creation: BOOLEAN do nb := feat.argument_count l_meth_sig := method_sig l_meth_sig.reset l_meth_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Default_sig) l_meth_sig.set_parameter_count (nb + is_generic.to_integer) set_method_return_type (l_meth_sig, current_class_type.type, current_class_type) if feat.is_external and then attached {EXTERNAL_I} feat as l_external_i then l_is_il_external := l_external_i.extension.is_il end if nb > 0 then -- Only add arguments when calling parent ctor with arguments. across feat.arguments as a loop set_signature_type (l_meth_sig, argument_actual_type_in (a.item, class_type), class_type) end end if is_generic then l_meth_sig.set_type ({MD_SIGNATURE_CONSTANTS}.Element_type_class, current_module.ise_generic_type_token) end l_name := il_casing.pascal_casing (System.dotnet_naming_convention, feat.feature_name, {IL_CASING_CONVERSION}.lower_case) uni_string.set_string (l_name) l_meth_attr := {MD_METHOD_ATTRIBUTES}.Public | {MD_METHOD_ATTRIBUTES}.Hide_by_signature | {MD_METHOD_ATTRIBUTES}.Static -- Normal method l_meth_token := md_emit.define_method (uni_string, current_class_token, l_meth_attr, l_meth_sig, {MD_METHOD_ATTRIBUTES}.Managed) start_new_body (l_meth_token) if l_is_il_external then -- Generate constructor arguments from i := 0 until i = nb loop generate_argument (i) i := i + 1 end if is_generic then generate_argument (nb) create_object_with_args (current_class_type.implementation_id, feat.feature_id, nb + 1) else create_object_with_args (current_class_type.implementation_id, feat.feature_id, nb) end else if is_generic then generate_argument (nb) create_generic_object (current_class_type.implementation_id) else create_object (current_class_type.implementation_id) end if current_class_type.is_expanded then -- Box expanded object. generate_metamorphose (current_class_type.type) -- Take address of expanded object. generate_load_address (current_class_type.type) end if class_c.is_once then -- Result is computed by the called creation method. is_once_creation := True else -- Result is the newly created object. duplicate_top end if nb > 0 then from until i >= nb loop generate_argument (i) i := i + 1 end end if current_class_type.is_expanded then method_body.put_call ({MD_OPCODES}.Call, feature_token (current_class_type.implementation_id, current_class_type.associated_class.feature_of_rout_id (feat.rout_id_set.first).feature_id), nb, is_once_creation) else method_body.put_call ({MD_OPCODES}.callvirt, feature_token (current_class_type.type.implemented_type (feat.origin_class_id).static_type_id (Void), feat.origin_feature_id), nb, is_once_creation) end fixme ("Generate class invariant check (if enabled).") if current_class_type.type.is_basic then -- Load basic object value. generate_load_from_address_as_basic (current_class_type.type) elseif current_class_type.is_expanded then -- Load expanded object value. generate_load_from_address (current_class_type.type) end end generate_return (True) store_locals (l_meth_token, class_type) method_writer.write_current_body byte_context.clear_feature_data end generate_il_implementation (class_c: CLASS_C; class_type: CLASS_TYPE) -- Generate IL code for feature in `class_c'. require class_c_not_void: class_c /= Void class_type_not_void: class_type /= Void not_external_class_type: not class_type.is_external deferred end generate_il_features (class_c: CLASS_C; class_type: CLASS_TYPE; implemented_feature_processor: PROCEDURE [FEATURE_I, CLASS_TYPE, FEATURE_I]; local_feature_processor: PROCEDURE [FEATURE_I, FEATURE_I, CLASS_TYPE, BOOLEAN]; inherited_feature_processor: PROCEDURE [FEATURE_I, FEATURE_I, CLASS_TYPE]; type_feature_processor: PROCEDURE [TYPE_FEATURE_I] inline_agent_processor: PROCEDURE [FEATURE_I]) -- Generate IL code for feature in `class_c'. require class_c_not_void: class_c /= Void class_type_not_void: class_type /= Void local_feature_processor_not_void: local_feature_processor /= Void inherited_feature_processor_not_void: inherited_feature_processor /= Void inline_agent_processor_attached: inline_agent_processor /= Void not_external_class_type: not class_type.is_external deferred end generate_empty_body (a_feat: FEATURE_I) -- Generate a valid empty body for `a_feat' in `current_type_id'. require feature_not_void: a_feat /= Void local l_type: TYPE_A do start_new_body (feature_token (current_type_id, a_feat.feature_id)) l_type := result_type_in (a_feat, current_class_type) if not l_type.is_void then put_default_value (l_type) end generate_return (not l_type.is_void) method_writer.write_current_body end generate_feature_il (feat: FEATURE_I; a_type_id, code_feature_id: INTEGER) -- Specifies for which feature `feat' of `feat.feature_id' written in class of -- `a_type_id' IL code will be generated. If `a_type_id' is different from current -- type id, it means that `a_feature_id' is simply a delegation to a call on -- `code_feature_id' defined in `a_type_id': call to static version of feature if -- not `imp_inherited'. require feature_not_void: feat /= Void positive_type_id: a_type_id > 0 positive_code_feature_id: code_feature_id > 0 local l_token: INTEGER l_meth_token: INTEGER l_cur_sig, l_impl_sig: like signature l_cur_feat, l_impl_feat: FEATURE_I l_cur_type, l_impl_type: CLASS_TYPE i, nb: INTEGER l_is_external: BOOLEAN l_sequence_point: like sequence_point l_class_type: CLASS_TYPE l_type_i, l_impl_type_i: TYPE_A l_same_signature: BOOLEAN l_dbg_document: DBG_DOCUMENT_WRITER has_return_value: BOOLEAN do l_meth_token := feature_token (current_type_id, feat.feature_id) if feat.is_attribute then l_token := attribute_token (a_type_id, code_feature_id) start_new_body (l_meth_token) generate_current method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldfld, l_token) generate_return (True) method_writer.write_current_body l_meth_token := setter_token (current_type_id, feat.feature_id) start_new_body (l_meth_token) generate_current generate_argument (1) -- To verify if it should be `current_class_type' or the one from `a_type_id'. generate_check_cast (Void, result_type_in (feat, current_class_type)) method_body.put_opcode_mdtoken ({MD_OPCODES}.Stfld, l_token) generate_return (False) method_writer.write_current_body else l_token := implementation_feature_token (a_type_id, code_feature_id) -- Retrieve the information about the routine. l_cur_sig := signature (current_type_id, feat.feature_id) l_impl_sig := implementation_signature (a_type_id, code_feature_id) l_same_signature := (l_cur_sig.class_type = l_impl_sig.class_type) and (l_cur_sig.routine_id = l_impl_sig.routine_id) if not l_same_signature then l_cur_type := l_cur_sig.class_type l_impl_type := l_impl_sig.class_type l_cur_feat := l_cur_type.associated_class.feature_of_rout_id (l_cur_sig.routine_id) l_impl_feat := l_impl_type.associated_class.feature_of_rout_id (l_impl_sig.routine_id) l_same_signature := same_signature (l_cur_feat, l_impl_feat, l_cur_type, l_impl_type) end l_is_external := feat.is_external or feat.is_il_external l_class_type := class_types.item (a_type_id) if -- False here because of a few things: -- 1 - It is not clear that generated executable are faster by -- having the code inlined. It depends on the JIT quality which -- we don't know much about it. -- 2 - For EiffelStudio debugger, it is not easy to perform mapping -- between breakpoints and generated code. -- 3 - For code using $Current, it does not work as in this fake -- duplication `$Current' is of type address of Impl.CLASS -- instead of being address of CLASS. Makes the generated code -- unverifiable. -- -- However we keep this code as it might be useful in the future -- if we introduce a new project settings option to turn this on -- or off. False and then (not l_is_external and then not l_class_type.is_precompiled and then il_module (current_class_type) = il_module (l_class_type) and then l_same_signature) then if is_debug_info_enabled then l_dbg_document := dbg_documents (l_sequence_point.written_class_id) dbg_writer.open_method (l_meth_token) dbg_writer.open_local_signature (l_dbg_document, method_body.local_token) across current_module.method_sequence_points.item (l_token) as p loop l_sequence_point := p.item dbg_offsets_count := l_sequence_point.offset_count dbg_offsets := l_sequence_point.offsets dbg_start_lines := l_sequence_point.start_lines dbg_start_columns := l_sequence_point.start_columns dbg_end_lines := l_sequence_point.end_lines dbg_end_columns := l_sequence_point.end_columns dbg_writer.define_sequence_points ( l_dbg_document, dbg_offsets_count, dbg_offsets, dbg_start_lines, dbg_start_columns, dbg_end_lines, dbg_end_columns ) end generate_local_debug_info (l_token, l_class_type) dbg_writer.close_local_signature (l_dbg_document) dbg_writer.close_method end method_writer.write_duplicate_body (l_token, l_meth_token) else if is_debug_info_enabled then -- Enable debugger to go through stub definition. define_custom_attribute (l_meth_token, current_module.debugger_step_through_ctor_token, empty_ca) define_custom_attribute (l_meth_token, current_module.debugger_hidden_ctor_token, empty_ca) end start_new_body (l_meth_token) if not feat.is_c_external then generate_current end from i := 1 nb := feat.argument_count until i > nb loop generate_argument (i) if is_verifiable and not l_same_signature then l_type_i := argument_actual_type_in (l_cur_feat.arguments.i_th (i), l_cur_type).adapted_in (l_cur_type) l_impl_type_i := argument_actual_type_in (l_impl_feat.arguments.i_th (i), l_impl_type).adapted_in (l_impl_type) -- Ideally a conformance check would possibly remove some unnecessary casts. if not l_impl_type_i.is_expanded and not l_type_i.is_safe_equivalent (l_impl_type_i) then method_body.put_opcode_mdtoken ({MD_OPCODES}.Castclass, mapped_class_type_token (l_impl_type_i.static_type_id (l_impl_type.type))) end end i := i + 1 end has_return_value := feat.has_return_value or else feat.is_once_creation (l_class_type.associated_class) if not feat.is_c_external then method_body.put_call ({MD_OPCODES}.call, l_token, nb, has_return_value) else method_body.put_static_call (l_token, nb, has_return_value) end if has_return_value and then is_verifiable and then not l_same_signature then l_type_i := result_type_in (l_cur_feat, l_cur_type).adapted_in (l_cur_type) l_impl_type_i := result_type_in (l_impl_feat, l_impl_type).adapted_in (l_impl_type) -- Ideally a conformance check would possibly remove some unnecessary casts. if not l_type_i.is_expanded and not l_type_i.is_safe_equivalent (l_impl_type_i) then method_body.put_opcode_mdtoken ({MD_OPCODES}.Castclass, mapped_class_type_token (l_type_i.static_type_id (l_cur_type.type))) end end generate_return (has_return_value) method_writer.write_current_body end end end generate_external_il (feat: FEATURE_I) -- Generate call to external feature `feat'. Its token is `last_non_recorded_feature_token'. require feature_not_void: feat /= Void feature_is_c_external: feat.is_c_external local l_token: INTEGER l_meth_token: INTEGER i, nb: INTEGER do l_token := last_non_recorded_feature_token l_meth_token := feature_token (current_type_id, feat.feature_id) if is_debug_info_enabled then -- Enable debugger to go through stub definition. define_custom_attribute (l_meth_token, current_module.debugger_step_through_ctor_token, empty_ca) define_custom_attribute (l_meth_token, current_module.debugger_hidden_ctor_token, empty_ca) end start_new_body (l_meth_token) from i := 1 nb := feat.argument_count until i > nb loop generate_argument (i) i := i + 1 end method_body.put_static_call (l_token, nb, feat.has_return_value) generate_return (feat.has_return_value) method_writer.write_current_body end generate_feature_code (feat: FEATURE_I; is_implementation: BOOLEAN) -- Generate IL code for feature `feat' using its implementation -- token if `is_implementation' is true. require feat_not_void: feat /= Void local l_meth_token: INTEGER l_sequence_point_list: LINKED_LIST [like sequence_point] l_dbg_document: DBG_DOCUMENT_WRITER do if not feat.is_attribute and then not feat.is_c_external and not feat.is_deferred then if is_implementation then l_meth_token := implementation_feature_token (current_type_id, feat.feature_id) else l_meth_token := feature_token (current_type_id, feat.feature_id) end current_feature_token := l_meth_token start_new_body (l_meth_token) if is_debug_info_enabled then dbg_writer.open_method (l_meth_token) local_start_offset := method_body.count create dbg_offsets.make_filled (0, 0, 5) create dbg_start_lines.make_filled (0, 0, 5) create dbg_start_columns.make_filled (0, 0, 5) create dbg_end_lines.make_filled (0, 0, 5) create dbg_end_columns.make_filled (0, 0, 5) dbg_offsets_count := 0 end current_class_type.generate_il_feature (feat) local_end_offset := method_body.count store_locals (l_meth_token, current_class_type) method_writer.write_current_body if is_debug_info_enabled then l_dbg_document := dbg_documents (current_class.class_id) -- Note: the local_token will be updated where needed by `open_local_signature` dbg_writer.open_local_signature (l_dbg_document, method_body.local_token) generate_local_debug_info (l_meth_token, current_class_type) dbg_writer.define_sequence_points ( l_dbg_document, dbg_offsets_count, dbg_offsets, dbg_start_lines, dbg_start_columns, dbg_end_lines, dbg_end_columns) dbg_writer.close_local_signature (l_dbg_document) dbg_writer.close_method l_sequence_point_list := current_module.method_sequence_points.item (l_meth_token) if l_sequence_point_list = Void then create l_sequence_point_list.make current_module.method_sequence_points.put (l_sequence_point_list, l_meth_token) end l_sequence_point_list.extend ([dbg_offsets_count, dbg_offsets, dbg_start_lines, dbg_start_columns, dbg_end_lines, dbg_end_columns, feat.written_in]) --| feature is not attribute |-- -- we assume the feature concerned by `generate_feature_code' -- here are static and not in_interface Il_debug_info_recorder.set_record_context (is_single_class, False, True, False) Il_debug_info_recorder.record_il_feature_info (current_module, current_class_type, feat, current_class_token, l_meth_token) end end end generate_property (f: FEATURE_I; i: FEATURE_I; parent_type: CLASS_TYPE; is_impl_required: BOOLEAN) -- Generate property methods associated with feature `f' (if any) -- given that the inherited feature is `i' (if any) from parent -- class type `parent_type'. require f_attached: f /= Void parent_type_attached: i /= Void implies parent_type /= Void do if is_property_setter_generated (f, current_class_type) then start_new_body (current_module.property_setter_token (current_type_id, f.feature_id)) -- Look for assigner command. generate_property_setter_body (f) method_writer.write_current_body if is_impl_required and then i /= Void and then is_property_setter_generated (i, parent_type) then md_emit.define_method_impl (current_class_token, current_module.property_setter_token (current_type_id, f.feature_id), current_module.property_setter_token (parent_type.static_type_id, i.feature_id)) end end if is_property_getter_generated (f, current_class_type) then start_new_body (current_module.property_getter_token (current_type_id, f.feature_id)) generate_property_getter_body (f) method_writer.write_current_body if is_impl_required and then i /= Void and then is_property_getter_generated (i, parent_type) then md_emit.define_method_impl (current_class_token, current_module.property_getter_token (current_type_id, f.feature_id), current_module.property_getter_token (parent_type.static_type_id, i.feature_id)) end end end generate_property_setter_body (f: FEATURE_I) -- Generate property setter body for feature `f'. require f_not_void: f /= Void local target_type: CL_TYPE_A target_feature: FEATURE_I do -- Look for a property setter. target_feature := f.ancestor_property_setter_in (current_class) if target_feature /= Void then target_type := current_class_type.type if not target_type.is_expanded then target_type := target_type.implemented_type (target_feature.access_in) end target_feature := target_type.base_class.feature_of_rout_id (target_feature.rout_id_set.first) generate_current generate_argument (1) generate_feature_access (target_type, target_feature.feature_id, 1, False, True) end generate_return (False) end generate_property_getter_body (f: FEATURE_I) -- Generate property getter body for feature `f'. require f_not_void: f /= Void local target_type: CL_TYPE_A target_feature: FEATURE_I do target_type := current_class_type.type if not target_type.is_expanded then if f.origin_class_id = 0 then target_type := target_type.implemented_type (f.access_in) else target_type := target_type.implemented_type (f.origin_class_id) end end target_feature := target_type.base_class.feature_table.feature_of_rout_id_set (f.rout_id_set) generate_current if f.is_attribute then generate_attribute (True, target_type, target_feature.feature_id) else generate_feature_access (target_type, target_feature.feature_id, 0, True, True) end generate_check_cast (byte_context.real_type_in (target_feature.type, target_type.associated_class_type (current_class_type.type).type), byte_context.real_type (f.type)) generate_return (True) end generate_feature_standard_twin (feat: FEATURE_I) -- Generate IL code for feature `standard_twin' from ANY. require feat_not_void: feat /= Void local type_i: TYPE_A do start_new_body (feature_token (current_type_id, feat.feature_id)) generate_current -- If `current_class_type' is expanded, cloning is done by compiler. type_i := current_class_type.type if type_i.is_expanded then -- Stack contains a pointer to value type object. -- Load a value of the object. if type_i.is_basic then generate_load_from_address_as_basic (type_i) else generate_load_from_address (type_i) end else method_body.put_call ({MD_OPCODES}.Call, current_module.memberwise_clone_token, 0, True) generate_check_cast (Void, type_i) end generate_return (True) method_writer.write_current_body end generate_call_to_standard_copy -- Generate a call to run-time feature `standard_copy' -- assuming that Current and argument are on the evaluation stack. do internal_generate_external_call (current_module.ise_runtime_token, 0, runtime_class_name, "standard_copy", Static_type, <<system_object_class_name, system_object_class_name>>, Void, False, Void) end generate_object_equality_test -- Generate comparison of two objects. do internal_generate_external_call (current_module.ise_runtime_token, 0, runtime_class_name, "is_equal", Static_type, <<system_object_class_name, system_object_class_name>>, "System.Boolean", False, Void) end generate_same_type_test -- Generate comparison of two objects. -- (The feature is invoked with a current object on the stack, -- i.e. takes 3 arguments: Current, some, other.) do internal_generate_external_call (current_module.ise_runtime_token, 0, runtime_class_name, "same_type", Static_type, <<system_object_class_name, system_object_class_name>>, "System.Boolean", False, Void) end start_new_body (method_token: INTEGER) -- Start a new body definition for method `method_token'. require valid_method_token: method_token /= 0 do method_body := method_writer.new_method_body (method_token) result_position := -1 check local_count = 0 local_types.is_empty end ensure method_body_set: method_body /= Void end last_non_recorded_feature_token: INTEGER -- Token of last defined feature that we did not record or last override. last_property_setter_token: INTEGER -- Token of last defined property setter method resulted from override. last_property_getter_token: INTEGER -- Token of last defined property getter method resulted from override. override_counter: COUNTER -- Number of generated override methods. is_method_impl_needed (feat, inh_feat: FEATURE_I; class_type: CLASS_TYPE): BOOLEAN -- Is a MethodImpl needed between `inh_feat' and `feat'? require feat_not_void: feat /= Void inh_feat_not_void: inh_feat /= Void class_type_not_void: class_type /= Void local l_naming_convention: BOOLEAN do l_naming_convention := System.dotnet_naming_convention if l_naming_convention = class_type.is_dotnet_name then Result := feat.feature_name_id /= inh_feat.feature_name_id if not Result and then attached {IL_EXTENSION_I} inh_feat.extension as l_ext then Result := not il_casing.pascal_casing (System.dotnet_naming_convention, feat.feature_name, {IL_CASING_CONVERSION}.lower_case).is_equal (l_ext.alias_name) end else if attached {IL_EXTENSION_I} inh_feat.extension as l_ext then Result := not il_casing.pascal_casing (l_naming_convention, feat.feature_name, {IL_CASING_CONVERSION}.lower_case).is_equal (l_ext.alias_name) else Result := not il_casing.pascal_casing (l_naming_convention, feat.feature_name, {IL_CASING_CONVERSION}.lower_case).is_equal ( il_casing.pascal_casing (class_type.is_dotnet_name, inh_feat.feature_name, {IL_CASING_CONVERSION}.lower_case)) end end if Result and then class_type.is_external then -- Ensure the feature is declared in `class_type' -- to avoid generating a MethodImpl twice. Result := inh_feat.written_in = class_type.associated_class.class_id end if not Result then -- When we handle an attribute defined in an inherited Eiffel class in a class now -- generated as `is_single_class' we have to generate a MethodImpl, because -- in the interface it is defined as a function, thus the generated MethodImpl will actually implement -- the function to retrieve the attribute field. Result := is_single_class and then not feat.written_class.is_single and then feat.is_attribute and then feat.written_in /= current_class.class_id and then not feat.written_class.is_external end end generate_method_impl (cur_feat: FEATURE_I; parent_type: CLASS_TYPE; inh_feat: FEATURE_I) -- Generate a MethodImpl from `parent_type' and `inh_feat' -- to `current_class_type' and `cur_feat'. require cur_feat_not_void: cur_feat /= Void parent_type_not_void: parent_type /= Void inh_feat_not_void: inh_feat /= Void local l_cur_sig, l_inh_sig: like signature l_cur_type, l_inh_type: CLASS_TYPE l_cur_feat, l_inh_feat: FEATURE_I l_same_signature: BOOLEAN l_setter_token: INTEGER i, nb: INTEGER l_meth_attr: INTEGER l_meth_sig: MD_METHOD_SIGNATURE l_parent_type_id: INTEGER l_return_type: TYPE_A l_token: like last_non_recorded_feature_token l_args: FEAT_ARG l_type_i: like argument_actual_type_in l_parent_arg_type_i: like argument_actual_type_in do l_parent_type_id := parent_type.static_type_id -- Very tricky part here. We are going to retrieve the FEATURE_I instance that -- was actually used to define the signature of the current implementation and store -- it in `l_cur_feat'. We do the same for the parent one in `l_inh_feat'. -- These are the FEATURE_I objects we need to use to compare signature. l_cur_sig := signature (current_type_id, cur_feat.feature_id) l_cur_type := l_cur_sig.class_type l_cur_feat := l_cur_type.associated_class.feature_of_rout_id (l_cur_sig.routine_id) l_inh_sig := signature (l_parent_type_id, inh_feat.feature_id) l_inh_type := l_inh_sig.class_type l_inh_feat := l_inh_type.associated_class.feature_of_rout_id (l_inh_sig.routine_id) -- Notion of same signature depends on wether or not we handle an attribute which is -- directly implemented as a field rather than a function when it occurs in class -- generated as `is_single_class'. l_same_signature := (not is_single_class or else not cur_feat.is_attribute) and then same_signature (l_inh_feat, l_cur_feat, l_inh_type, l_cur_type) if l_same_signature then md_emit.define_method_impl (current_class_token, feature_token (current_type_id, cur_feat.feature_id), feature_token (l_parent_type_id, inh_feat.feature_id)) if cur_feat.is_attribute and then inh_feat.is_attribute then md_emit.define_method_impl (current_class_token, setter_token (current_type_id, cur_feat.feature_id), setter_token (l_parent_type_id, inh_feat.feature_id)) end if is_property_getter_generated (inh_feat, parent_type) then md_emit.define_method_impl (current_class_token, current_module.property_getter_token (current_type_id, cur_feat.feature_id), current_module.property_getter_token (l_parent_type_id, inh_feat.feature_id)) end if is_property_setter_generated (inh_feat, parent_type) then md_emit.define_method_impl (current_class_token, current_module.property_setter_token (current_type_id, cur_feat.feature_id), current_module.property_setter_token (l_parent_type_id, inh_feat.feature_id)) end elseif not is_single_class or else not inh_feat.is_attribute or else not parent_type.associated_class.is_single then -- We have to generate body of `inh_feat' in context of -- `parent_type' in order to correctly evaluate its -- signature in current context. implementation_generate_feature (inh_feat, False, False, False, True, False, parent_type) l_return_type := result_type_in (inh_feat, parent_type) byte_context.clear_feature_data l_token := last_non_recorded_feature_token start_new_body (l_token) generate_current nb := l_cur_feat.argument_count if nb > 0 then from i := 1 l_args := l_cur_feat.arguments l_args.start until i > nb loop generate_argument (i) l_type_i := argument_actual_type_in (l_args.item, l_cur_type).adapted_in (l_cur_type) l_parent_arg_type_i := argument_actual_type_in (l_inh_feat.arguments [i], l_inh_type).adapted_in (l_inh_type) -- Ideally a conformance check would possibly remove some unnecessary casts. if not l_type_i.is_safe_equivalent (l_parent_arg_type_i) then if l_type_i.is_basic then -- Do nothing if a TYPED_POINTER derivation is being reattached to another TYPED_POINTER derivation. if not l_parent_arg_type_i.is_basic then generate_load_address (l_type_i) generate_load_from_address_as_basic (l_type_i) end elseif l_type_i.is_expanded then generate_unmetamorphose (l_type_i) elseif is_verifiable then method_body.put_opcode_mdtoken ({MD_OPCODES}.Castclass, mapped_class_type_token (l_type_i.static_type_id (l_cur_type.type))) end end l_args.forth i := i + 1 end end if cur_feat.is_attribute and is_single_class then -- Attribute was already generated as a field, we simply generate a routine to -- perform the MethodImpl. method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldfld, attribute_token (current_type_id, cur_feat.feature_id)) elseif current_class_type.is_expanded then -- Call feature directly. method_body.put_call ({MD_OPCODES}.Call, feature_token (current_type_id, cur_feat.feature_id), nb, cur_feat.has_return_value) else -- Call feature polymorphically. method_body.put_call ({MD_OPCODES}.Callvirt, feature_token (current_type_id, cur_feat.feature_id), nb, cur_feat.has_return_value) end if cur_feat.has_return_value then l_type_i := result_type_in (l_cur_feat, l_cur_type).adapted_in (l_cur_type) l_parent_arg_type_i := result_type_in (l_inh_feat, l_inh_type).adapted_in (l_inh_type) -- Ideally a conformance check would possibly remove some unnecessary casts. if not l_type_i.is_safe_equivalent (l_parent_arg_type_i) then if l_type_i.is_basic then if attached {BASIC_A} l_type_i as b then generate_eiffel_metamorphose (b) else check from_condition: False then end end elseif l_type_i.is_expanded then generate_metamorphose (l_type_i) elseif is_verifiable and not l_parent_arg_type_i.is_expanded then method_body.put_opcode_mdtoken ({MD_OPCODES}.Castclass, mapped_class_type_token (l_parent_arg_type_i.static_type_id (l_inh_type.type))) end end end generate_return (cur_feat.has_return_value) store_locals (l_token, current_class_type) method_writer.write_current_body md_emit.define_method_impl (current_class_token, l_token, feature_token (l_parent_type_id, inh_feat.feature_id)) if cur_feat.is_attribute and then inh_feat.is_attribute then l_meth_attr := {MD_METHOD_ATTRIBUTES}.Virtual | {MD_METHOD_ATTRIBUTES}.Hide_by_signature | {MD_METHOD_ATTRIBUTES}.Private l_meth_sig := method_sig l_meth_sig.reset l_meth_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Has_current) l_meth_sig.set_parameter_count (1) l_meth_sig.set_return_type ( {MD_SIGNATURE_CONSTANTS}.Element_type_void, 0) set_signature_type (l_meth_sig, l_return_type, parent_type) uni_string.set_string (Override_prefix + setter_prefix + inh_feat.feature_name + override_counter.next.out) l_setter_token := md_emit.define_method (uni_string, current_class_token, l_meth_attr, l_meth_sig, {MD_METHOD_ATTRIBUTES}.Managed) start_new_body (l_setter_token) generate_current generate_argument (1) l_type_i := result_type_in (l_cur_feat, l_cur_type).adapted_in (l_cur_type) if l_return_type.is_reference and then l_type_i.is_expanded then -- Unbox argument. generate_external_unmetamorphose (l_type_i) elseif is_verifiable then l_parent_arg_type_i := result_type_in (l_inh_feat, l_inh_type).adapted_in (l_inh_type) -- Ideally a conformance check would possibly remove some unnecessary casts. if not l_type_i.is_expanded and not l_type_i.is_safe_equivalent (l_parent_arg_type_i) then method_body.put_opcode_mdtoken ({MD_OPCODES}.Castclass, mapped_class_type_token (l_type_i.static_type_id (l_cur_type.type))) end end -- Hard coded `1' for number of arguments since there is one, -- we cannot use `nb' as it is `0' for attributes. if is_single_class then -- Attribute was already generated as a field, we simply generate a routine to -- perform the MethodImpl on the setter. method_body.put_opcode_mdtoken ({MD_OPCODES}.Stfld, attribute_token (current_type_id, cur_feat.feature_id)) else method_body.put_call ({MD_OPCODES}.Callvirt, setter_token (current_type_id, cur_feat.feature_id), 1, False) end generate_return (False) method_writer.write_current_body md_emit.define_method_impl (current_class_token, l_setter_token, setter_token (l_parent_type_id, inh_feat.feature_id)) end if last_property_setter_token /= {MD_TOKEN_TYPES}.md_method_def then -- Generate property setter implementation. start_new_body (last_property_setter_token) generate_property_setter_body (cur_feat) method_writer.write_current_body if is_property_setter_generated (inh_feat, parent_type) then md_emit.define_method_impl (current_class_token, last_property_setter_token, current_module.property_setter_token (l_parent_type_id, inh_feat.feature_id)) end end if last_property_getter_token /= {MD_TOKEN_TYPES}.md_method_def then -- Generate property getter implementation. start_new_body (last_property_getter_token) generate_property_getter_body (cur_feat) method_writer.write_current_body if is_property_getter_generated (inh_feat, parent_type) then md_emit.define_method_impl (current_class_token, last_property_getter_token, current_module.property_getter_token (l_parent_type_id, inh_feat.feature_id)) end end end end generate_runtime_builtin_call (a_feature: FEATURE_I) -- Generate the call to the corresponding builtin routine in ISE_RUNTIME for the implementation of `a_feature' local l_token: INTEGER l_method_sig: like method_sig nb: INTEGER m: INTEGER do if attached {BUILT_IN_EXTENSION_I} a_feature.extension as l_ext then l_method_sig := method_sig l_method_sig.reset l_method_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Default_sig) nb := a_feature.argument_count m := nb if l_ext.is_static then l_method_sig.set_parameter_count (nb) else generate_current m := nb + 1 l_method_sig.set_parameter_count (m) end if a_feature.has_return_value then set_method_return_type (l_method_sig, a_feature.type, current_class_type) else l_method_sig.set_return_type ( {MD_SIGNATURE_CONSTANTS}.element_type_void, 0) end if m /= nb then -- Call is not static, but the builtin declaration is, so we need to provide -- Current's type to the routine l_method_sig.set_type ({MD_SIGNATURE_CONSTANTS}.element_type_object, 0) end if nb > 0 then from a_feature.arguments.start until a_feature.arguments.after loop set_signature_type (l_method_sig, a_feature.arguments.item, current_class_type) generate_argument (a_feature.arguments.index) a_feature.arguments.forth end end uni_string.set_string ("builtin_" + a_feature.written_class.name + "_" + a_feature.feature_name) l_token := md_emit.define_member_ref (uni_string, current_module.ise_runtime_type_token, l_method_sig) method_body.put_static_call (l_token, m, a_feature.has_return_value) generate_return (a_feature.has_return_value) end end generate_external_call (base_name: STRING; name: STRING; ext_kind: INTEGER; parameters_type: ARRAY [INTEGER]; return_type: INTEGER; is_virtual: BOOLEAN) -- Generate call to `name' with signature `parameters_type' + `return_type'. local l_type_token: INTEGER do l_type_token := current_module.external_token_mapping (base_name) internal_generate_external_call (0, l_type_token, Void, name, ext_kind, Names_heap.convert_to_string_array (parameters_type), Names_heap.item (return_type), is_virtual, Void) end generate_external_generic_call (base_name: STRING; name: STRING; ext_kind: INTEGER; parameters_type: ARRAY [INTEGER]; generic_method_parameters_info: CONSUMED_GENERIC_PARAMETERS_INFO; return_type: INTEGER; is_virtual: BOOLEAN) -- Generate generic method call to `name' with signature `parameters_type' + `return_type'. local l_type_token: INTEGER do l_type_token := current_module.external_token_mapping (base_name) internal_generate_external_call (0, l_type_token, Void, name, ext_kind, Names_heap.convert_to_string_array (parameters_type), Names_heap.item (return_type), is_virtual, generic_method_parameters_info) end generate_external_creation_call (a_actual_type: CL_TYPE_A; name: STRING; ext_kind: INTEGER; parameters_type: ARRAY [INTEGER]; return_type: INTEGER) -- Generate call to `name' with signature `parameters_type' + `return_type'. local l_type_id: INTEGER l_type_token: INTEGER l_argument_types: ARRAY [STRING] do l_type_id := a_actual_type.implementation_id (current_class_type.type) l_type_token := actual_class_type_token (l_type_id) l_argument_types := Names_heap.convert_to_string_array (parameters_type) if not a_actual_type.is_external and then a_actual_type.generics /= Void and then ext_kind = creator_type then -- Supply generic type information. generate_generic_type_info (a_actual_type) l_argument_types.force (generic_type_class_name, l_argument_types.upper + 1) end internal_generate_external_call (0, l_type_token, Void, name, ext_kind, l_argument_types, Names_heap.item (return_type), False, Void) end external_token (base_name: STRING; member_name: STRING; ext_kind: INTEGER; parameters_type: ARRAY [INTEGER]; return_type: INTEGER) : INTEGER -- Get token for feature specified by `base_name' and `member_name' local l_meth_sig: like method_sig l_field_sig: like field_sig l_class_token: INTEGER i, nb: INTEGER l_parameters_string: ARRAY [STRING] l_return_type: STRING l_context_class_type: CLASS_TYPE do l_context_class_type := current_class_type l_class_token := current_module.external_token_mapping (base_name) l_parameters_string := Names_heap.convert_to_string_array (parameters_type) l_return_type := Names_heap.item (return_type) inspect ext_kind when Field_type, Static_field_type then l_field_sig := field_sig l_field_sig.reset set_type_in_signature (l_field_sig, l_return_type, l_context_class_type) uni_string.set_string (member_name) Result := md_emit.define_member_ref (uni_string, l_class_token, l_field_sig) when Set_field_type, Set_static_field_type then check l_parameters_string_not_void: l_parameters_string /= Void l_parameters_string_count_is_one: l_parameters_string.count = 1 end l_field_sig := field_sig l_field_sig.reset -- Type of field is actually the first argument of our setter routine. set_type_in_signature (l_field_sig, l_parameters_string.item (1), l_context_class_type) uni_string.set_string (member_name) Result := md_emit.define_member_ref (uni_string, l_class_token, l_field_sig) else l_meth_sig := method_sig l_meth_sig.reset if ext_kind = Static_type or ext_kind = Operator_type then l_meth_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Default_sig) else l_meth_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Has_current) end if l_parameters_string /= Void then nb := l_parameters_string.count end l_meth_sig.set_parameter_count (nb) -- Set return type if any in `l_meth_sig'. if l_return_type /= Void then set_type_in_signature (l_meth_sig, l_return_type, l_context_class_type) else l_meth_sig.set_return_type ( {MD_SIGNATURE_CONSTANTS}.Element_type_void, 0) end -- Set arguments in `l_meth_sig'. from i := 1 until i > nb loop set_type_in_signature (l_meth_sig, l_parameters_string.item (i), l_context_class_type) i := i + 1 end if member_name = Void then uni_string.set_string (".ctor") else uni_string.set_string (member_name) end Result := md_emit.define_member_ref (uni_string, l_class_token, l_meth_sig) end end internal_generate_external_call (an_assembly_token, a_type_token: INTEGER; base_name: STRING; member_name: STRING; ext_kind: INTEGER; parameters_string: ARRAY [STRING]; return_type: STRING; is_virtual: BOOLEAN; generic_method_parameters_info: detachable CONSUMED_GENERIC_PARAMETERS_INFO;) -- Generate call to `member_name' with signature `parameters_type' + `return_type'. require valid_external_type: valid_type (ext_kind) local l_member_ref_token: INTEGER l_token: INTEGER l_meth_sig: like method_sig l_field_sig: like field_sig l_class_token: INTEGER i, nb: INTEGER l_context_class_type: CLASS_TYPE is_generic_method: BOOLEAN do is_generic_method := generic_method_parameters_info /= Void and then generic_method_parameters_info.has_generic l_context_class_type := current_class_type if base_name /= Void then uni_string.set_string (base_name) l_class_token := md_emit.define_type_ref (uni_string, an_assembly_token) else l_class_token := a_type_token end inspect ext_kind when Field_type, Static_field_type then l_field_sig := field_sig l_field_sig.reset set_type_in_signature (l_field_sig, return_type, l_context_class_type) uni_string.set_string (member_name) l_member_ref_token := md_emit.define_member_ref (uni_string, l_class_token, l_field_sig) if ext_kind = field_type then method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldfld, l_member_ref_token) else method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldsfld, l_member_ref_token) end when Set_field_type, Set_static_field_type then l_field_sig := field_sig l_field_sig.reset check parameters_string_not_void: parameters_string /= Void parameters_string_count_is_one: parameters_string.count = 1 end -- Type of field is actually the first argument of our setter routine. set_type_in_signature (l_field_sig, parameters_string.item (1), l_context_class_type) uni_string.set_string (member_name) l_member_ref_token := md_emit.define_member_ref (uni_string, l_class_token, l_field_sig) if ext_kind = set_field_type then method_body.put_opcode_mdtoken ({MD_OPCODES}.Stfld, l_member_ref_token) else method_body.put_opcode_mdtoken ({MD_OPCODES}.Stsfld, l_member_ref_token) end else l_meth_sig := method_sig l_meth_sig.reset if ext_kind = Static_type or ext_kind = Operator_type then l_meth_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Default_sig) else -- TODO: first check with this case, then try for static, ... if is_generic_method then l_meth_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Has_current | {MD_SIGNATURE_CONSTANTS}.generic_sig) l_meth_sig.set_generic_parameter_count (if attached generic_method_parameters_info then generic_method_parameters_info.generic_parameters.count else 0 end) else l_meth_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Has_current) end end if parameters_string /= Void then nb := parameters_string.count end l_meth_sig.set_parameter_count (nb) -- Set return type if any in `l_meth_sig'. if return_type /= Void then if generic_method_parameters_info /= Void and then attached generic_method_parameters_info.generic_return_type_info as rt_gen_info then set_generic_parameter_type_in_signature (l_meth_sig, rt_gen_info.formal_position, l_context_class_type) else set_type_in_signature (l_meth_sig, return_type, l_context_class_type) end else l_meth_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.Element_type_void, 0) end -- Set arguments in `l_meth_sig'. -- if is_generic_method then -- -- FIXME: not all parameters are generic/formal ! -- from -- i := 1 -- until -- i > nb -- loop -- set_generic_parameter_type_in_signature (l_meth_sig, i, l_context_class_type) -- i := i + 1 -- end -- else from i := 1 until i > nb loop if is_generic_method and then generic_method_parameters_info /= Void and then attached generic_method_parameters_info.generic_argument_info (i) as l_arg_info then set_generic_parameter_type_in_signature (l_meth_sig, l_arg_info.formal_position, l_context_class_type) else set_type_in_signature (l_meth_sig, parameters_string.item (i), l_context_class_type) end i := i + 1 end -- end if member_name = Void then uni_string.set_string (".ctor") else uni_string.set_string (member_name) end l_member_ref_token := md_emit.define_member_ref (uni_string, l_class_token, l_meth_sig) if is_generic_method and then generic_method_parameters_info /= Void then -- Use a MethodSpec token instead of MemberRef token. create l_meth_sig.make l_meth_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.GENRICINST_sig) if attached generic_method_parameters_info.generic_parameters as l_gen_params then l_meth_sig.set_parameter_count (l_gen_params.count) from i := 1 until i > l_gen_params.count loop set_type_in_signature (l_meth_sig, system_object_class_name, l_context_class_type) --FIXME: no hard coded System.Object !!! i := i + 1 end elseif parameters_string /= Void and then not parameters_string.is_empty then nb := parameters_string.count l_meth_sig.set_parameter_count (generic_method_parameters_info.generic_arguments_count) from i := 1 until i > nb loop if generic_method_parameters_info.is_generic_argument (i) then set_type_in_signature (l_meth_sig, parameters_string.item (i), l_context_class_type) end i := i + 1 end else l_meth_sig.set_parameter_count (0) end l_token := md_emit.define_method_spec (l_member_ref_token, l_meth_sig) else l_token := l_member_ref_token end inspect ext_kind when Creator_call_type then method_body.put_call ({MD_OPCODES}.Call, l_token, nb, return_type /= Void) when Static_type, Operator_type then method_body.put_static_call (l_token, nb, return_type /= Void) when Normal_type, Deferred_type then if is_virtual then method_body.put_call ( {MD_OPCODES}.Callvirt, l_token, nb, return_type /= Void) else method_body.put_call ( {MD_OPCODES}.Call, l_token, nb, return_type /= Void) end when Creator_type then method_body.put_newobj (l_token, nb) end end end feature {NONE} -- Implementation is_local_signature_changed (inherited_feature, local_feature: FEATURE_I): BOOLEAN -- Is signature of a local feature `local_feature' changed -- from the one of the associated interface? require inherited_feature_not_void: inherited_feature /= Void local_feature_not_void: local_feature /= Void same_arguments_count: inherited_feature.argument_count = local_feature.argument_count local l_inh_arguments, l_arguments: FEAT_ARG l_is_expanded: BOOLEAN do -- Optimization as many times `inherited_feature' and `local_feature' are the same. if inherited_feature /= local_feature then l_is_expanded := current_class_type.is_expanded Result := (inherited_feature.type.is_reference and local_feature.type.is_expanded) or (l_is_expanded and local_feature.type.has_like_current) l_arguments := local_feature.arguments if not Result and attached l_arguments then across l_arguments as a from l_inh_arguments := inherited_feature.arguments l_inh_arguments.start until Result loop if (l_inh_arguments.item.is_reference and a.item.is_expanded) or (l_is_expanded and a.item.has_like_current) then Result := True end l_inh_arguments.forth end end end end set_type_in_signature (a_sig: MD_SIGNATURE; a_type_name: STRING; a_context_type: CLASS_TYPE) -- Set `a_type_name' into `a_sig'. It properly analyzes `a_type_name' -- to detect if it is an array type or a byref. require a_sig_not_void: a_sig /= Void a_type_name_not_void: a_type_name /= Void local l_is_by_ref, l_is_array: BOOLEAN l_real_type: STRING l_type: TYPE_A do l_real_type := a_type_name if l_real_type.item (l_real_type.count) = '&' then l_is_by_ref := True l_real_type := l_real_type.substring (1, l_real_type.count - 1) else l_is_by_ref := False end if l_real_type.item (l_real_type.count) = ']' then l_is_array := True l_real_type := l_real_type.substring (1, l_real_type.count - 2) else l_is_array := False end l_type := external_class_mapping.item (l_real_type) if l_is_by_ref then a_sig.set_type ( {MD_SIGNATURE_CONSTANTS}.Element_type_byref, 0) end if l_is_array then a_sig.set_type ( {MD_SIGNATURE_CONSTANTS}.Element_type_szarray, 0) end if l_type /= Void then set_signature_type (a_sig, l_type, a_context_type) else -- A runtime type. if l_real_type.is_equal (Assertion_level_enum_class_name) then a_sig.set_type ( {MD_SIGNATURE_CONSTANTS}.Element_type_valuetype, current_module.external_token_mapping (l_real_type)) else a_sig.set_type ( {MD_SIGNATURE_CONSTANTS}.Element_type_class, current_module.external_token_mapping (l_real_type)) end end end set_generic_parameter_type_in_signature (a_sig: MD_SIGNATURE; a_generic_param_index: INTEGER; a_context_type: CLASS_TYPE) -- Set formal type for 0-based index `a_generic_param_index' into `a_sig'. require a_sig_not_void: a_sig /= Void a_generic_param_index_valid: a_generic_param_index >= 0 do a_sig.set_generic_parameter_type ({MD_SIGNATURE_CONSTANTS}.element_type_mvar, a_generic_param_index) end feature -- Local variable info generation set_local_count (a_count: INTEGER) -- Set `local_count' to `a_count'. do local_count := a_count end put_result_info (type_i: TYPE_A) -- Specifies `type_i' of type of result. do if not once_generation then result_position := 0 local_types.extend (create {PAIR [TYPE_A, STRING]}.make (type_i, "Result")) end end put_local_info (type_i: TYPE_A; name_id: INTEGER) -- Specifies `type_i' of type of local. do local_types.extend (create {PAIR [TYPE_A, STRING]}.make (type_i, Names_heap.item (name_id))) end put_nameless_local_info (type_i: TYPE_A; name_id: INTEGER) -- Specifies `type_i' of type of local. do local_types.extend (create {PAIR [TYPE_A, STRING]}.make (type_i, "_" + name_id.out)) end put_dummy_local_info (type_i: TYPE_A; name_id: INTEGER) -- Specifies `type_i' of type of local. do local_types.extend (create {PAIR [TYPE_A, STRING]}.make (type_i, "_dummy_" + name_id.out)) end feature -- Local saving reset_local_types -- Reset `local_types'. do create local_types.make (5) end store_locals (a_meth_token: INTEGER; a_context_type: CLASS_TYPE) -- Store `local_types' into `method_body' for routine `a_meth_token'. require method_token_valid: a_meth_token & {MD_TOKEN_TYPES}.Md_mask = {MD_TOKEN_TYPES}.Md_method_def a_context_type_not_void: a_context_type /= Void do current_module.store_locals (local_types, a_meth_token, a_context_type) local_count := 0 end generate_local_debug_info (a_method_token: INTEGER; a_context_type: CLASS_TYPE) -- Generate local information about routine `method_token'. require debug_info_requested: is_debug_info_enabled method_token_valid: a_method_token & {MD_TOKEN_TYPES}.Md_mask = {MD_TOKEN_TYPES}.Md_method_def a_context_type_not_void: a_context_type /= Void do current_module.generate_local_debug_info (a_method_token, a_context_type) end feature -- Object creation create_object (a_type_id: INTEGER) -- Create non-generic object of `a_type_id'. do method_body.put_newobj (constructor_token (a_type_id), 0) end create_generic_object (a_type_id: INTEGER) -- Create generic object of `a_type_id'. require type_generic: class_types.item (a_type_id).is_generic do method_body.put_newobj (constructor_token (a_type_id), 1) end create_object_with_args (a_type_id: INTEGER; a_feature_id: INTEGER; a_arg_count: INTEGER) -- Create object of `a_type_id'. require valid_type_id: a_type_id > 0 a_arg_count_not_negative: a_arg_count >= 0 do method_body.put_newobj (inherited_constructor_token (a_type_id, a_feature_id), a_arg_count) end create_like_object -- Create object of same type as object on top of stack. do internal_generate_external_call (current_module.ise_runtime_token, 0, generic_conformance_class_name, "create_like_object", Static_type, <<type_info_class_name>>, type_info_class_name, False, Void) end load_type -- Load on stack type of object on top of stack. do internal_generate_external_call (current_module.ise_runtime_token, 0, generic_conformance_class_name, "load_type_of_object", Static_type, <<system_object_class_name>>, type_class_name, False, Void) end create_type -- Given info on stack, it will create a new instance of a generic formal -- parameter. do internal_generate_external_call (current_module.ise_runtime_token, 0, generic_conformance_class_name, "create_type", Static_type, <<type_class_name, type_info_class_name>>, type_info_class_name, False, Void) end create_expanded_object (t: CL_TYPE_A) -- Create an object of expanded type `t'. local creation_procedure: FEATURE_I do -- Initialize inner expanded attributes and set type information. generate_creation (t) -- Load address of a value type object. generate_load_address (t) -- Call creation procedure (if any). creation_procedure := t.base_class.creation_feature if creation_procedure /= Void then duplicate_top generate_feature_access (t, creation_procedure.feature_id, 0, False, False) end generate_load_from_address (t) end generate_creation (a_type: TYPE_A) -- Generate IL code for a hardcoded creation type `a_type'. -- Expanded object will be boxed after creation. local local_index: INTEGER do if a_type.is_expanded and a_type.is_true_external then -- Load a default value of a local variable. byte_context.add_local (a_type) local_index := byte_context.local_list.count put_dummy_local_info (a_type, local_index) generate_local (local_index) elseif attached {GEN_TYPE_A} a_type as gen_type_i then -- Create object using default constructor. generate_generic_type_info (gen_type_i) create_generic_object (a_type.implementation_id (current_class_type.type)) else -- Create object using default constructor. create_object (a_type.implementation_id (current_class_type.type)) end if a_type.is_expanded then -- Box expanded object. generate_metamorphose (a_type) end end feature {NONE} -- Object creation generate_generic_type_info (t: CL_TYPE_A) -- Generate code that evaluates and puts -- generic type information on the stack require t_attached: t /= Void local generic_type_token: INTEGER do t.generate_gen_type_il (Current, True) generate_current_as_reference method_body.put_call ({MD_OPCODES}.callvirt, current_module.ise_get_type_token, 0, True) generic_type_token := actual_class_type_token (generic_type_id) internal_generate_external_call (current_module.ise_runtime_token, generic_type_token, Void, "evaluated_type", normal_type, <<generic_type_class_name>>, type_class_name, True, Void) if is_verifiable then method_body.put_opcode_mdtoken ({MD_OPCODES}.castclass, generic_type_token) end end feature {IL_MODULE} -- Initialization of expanded attributes initialize_expanded_attributes (class_type: CLASS_TYPE) -- Initialize expanded attributes of `class_type' -- assuming that a reference or a pointer to the object -- of type `class_type' is on the stack. require class_type_not_void: class_type /= Void local skeleton: SKELETON do from skeleton := class_type.skeleton skeleton.go_expanded until skeleton.off or else skeleton.item.level /= skeleton.expanded_level loop if attached {EXPANDED_DESC} skeleton.item as desc and then attached {CL_TYPE_A} desc.cl_type_i as attribute_type and then attribute_type.is_true_expanded and then not attribute_type.is_external then duplicate_top create_expanded_object (attribute_type) method_body.put_opcode_mdtoken ({MD_OPCODES}.stfld, attribute_token (class_type.implementation_id, skeleton.item.feature_id)) end skeleton.forth end end is_initialization_required (class_type: CLASS_TYPE): BOOLEAN -- Is initialization of class attributes is required for `class_type'? require class_type_not_void: class_type /= Void local attribute_type: TYPE_A skeleton: SKELETON do from skeleton := class_type.skeleton skeleton.go_expanded until Result or else skeleton.off or else skeleton.item.level /= skeleton.expanded_level loop if attached {EXPANDED_DESC} skeleton.item as desc then attribute_type := desc.cl_type_i Result := attribute_type.is_true_expanded and then not attribute_type.is_external end skeleton.forth end end feature -- IL stack managment duplicate_top -- Duplicate top element of IL stack. do method_body.put_opcode ({MD_OPCODES}.Dup) end pop -- Remove top element of IL stack. do method_body.put_opcode ({MD_OPCODES}.Pop) end feature -- Variables access generate_current -- Generate access to `Current'. do method_body.put_opcode ({MD_OPCODES}.Ldarg_0) end generate_current_as_reference -- Generate access to `Current' in its reference form. -- (I.e. box value type object if required.) local type_i: TYPE_A do type_i := current_class_type.type generate_current if type_i.is_expanded then -- Box expanded object. generate_load_from_address_as_object (type_i) generate_metamorphose (type_i) elseif type_i.base_class = any_type.base_class then -- Special case where we need to cast to EIFFEL_TYPE_INFO -- since all routines of ANY are taking System.Object and not ANY as argument. -- This fixes a verification error when generating the code for {ANY}.generating_type. method_body.put_opcode_mdtoken ({MD_OPCODES}.castclass, current_module.ise_eiffel_type_info_type_token) end end generate_current_as_basic -- Load `Current' as a basic value. do generate_current generate_load_from_address_as_basic (current_class_type.type) end generate_result -- Generate access to `Result'. do if once_generation then generate_once_result else generate_local (result_position) end end generate_attribute (need_target: BOOLEAN; type_i: TYPE_A; a_feature_id: INTEGER) -- Generate access to attribute of `a_feature_id' in `type_i'. do if attached {CL_TYPE_A} type_i as cl_type and then attached cl_type.associated_class_type (current_class_type.type) as l_class_type and then (l_class_type.is_generated_as_single_type or l_class_type.is_expanded) then if need_target then method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldfld, attribute_token (cl_type.implementation_id (current_class_type.type), a_feature_id)) else method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldsfld, attribute_token (cl_type.implementation_id (current_class_type.type), a_feature_id)) end else -- Attribute are accessed through their feature encapsulation. internal_generate_feature_access (type_i.static_type_id (current_class_type.type), a_feature_id, 0, True, True) end end generate_feature_access (type_i: TYPE_A; a_feature_id: INTEGER; nb: INTEGER; is_function, is_virtual: BOOLEAN) -- Generate access to feature of `a_feature_id' in `type_i'. local l_type_id: INTEGER l_virtual: BOOLEAN do if type_i.is_expanded then l_type_id := type_i.implementation_id (current_class_type.type) l_virtual := False else l_type_id := type_i.static_type_id (current_class_type.type) l_virtual := True end internal_generate_feature_access (l_type_id, a_feature_id, nb, is_function, l_virtual) end generate_precompiled_feature_access (type_i: TYPE_A; a_feature: FEATURE_I) -- Generate a call to a precompiled library. require type_i_not_void: type_i /= Void a_feature_not_void: a_feature /= Void do end internal_generate_feature_access (a_type_id, a_feature_id: INTEGER; nb: INTEGER; is_function, is_virtual: BOOLEAN) -- Generate access to feature of `a_feature_id' in `a_type_id'. require positive_type_id: a_type_id > 0 positive_feature_id: a_feature_id > 0 local l_opcode: INTEGER_16 do if is_virtual then l_opcode := {MD_OPCODES}.Callvirt else l_opcode := {MD_OPCODES}.Call end method_body.put_call (l_opcode, feature_token (a_type_id, a_feature_id), nb, is_function) end generate_precursor_feature_access (type_i: TYPE_A; a_feature_id: INTEGER; nb: INTEGER; is_function: BOOLEAN) -- Generate access to feature of `a_feature_id' in `type_i' with `nb' arguments. do method_body.put_call ({MD_OPCODES}.Call, implementation_feature_token (type_i.implementation_id (current_class_type.type), a_feature_id), nb, is_function) end generate_type_feature_call_on_type (f: TYPE_FEATURE_I; t: CL_TYPE_A) -- <Precursor> local target_type: CL_TYPE_A target_feature_id: INTEGER target_routine_id: INTEGER anchored_features: HASH_TABLE [TYPE_FEATURE_I, INTEGER] do if t.is_expanded then -- Call feature directly. target_type := t target_routine_id := f.rout_id_set.first anchored_features := target_type.base_class.anchored_features anchored_features.search (target_routine_id) if anchored_features.found then target_feature_id := anchored_features.found_item.feature_id else target_feature_id := target_type.base_class.generic_features.item (target_routine_id).feature_id end else -- Call feature using parent type. target_type := t.implemented_type (f.origin_class_id) target_feature_id := f.origin_feature_id end generate_feature_access (target_type, target_feature_id, 0, True, True) end generate_type_feature_call (f: TYPE_FEATURE_I) -- Generate a call to a type feature `f' on current. do generate_current generate_type_feature_call_on_type (f, current_class_type.type) end generate_type_feature_call_for_formal (a_position: INTEGER) -- Generate a call to a type feature for formal at position `a_position'. do generate_type_feature_call (current_class_type.associated_class.formal_at_position (a_position)) end put_type_token (a_type_id: INTEGER) -- Put token associated to `a_type_id' on stack. do method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldtoken, actual_class_type_token (a_type_id)) end put_type_instance (a_type: TYPE_A) -- <Precursor> do put_type_token (a_type.external_id (current_class_type.type)) internal_generate_external_call (current_module.mscorlib_token, 0, system_type_class_name, "GetTypeFromHandle", static_type, << type_handle_class_name >>, system_type_class_name, False, Void) end put_method_token (type_i: TYPE_A; a_feature_id: INTEGER) -- Generate access to feature of `a_feature_id' in `type_i'. do method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldtoken, feature_token (type_i.static_type_id (current_class_type.type), a_feature_id)) end put_impl_method_token (type_i: TYPE_A; a_feature_id: INTEGER) -- Generate access to feature of `a_feature_id' in `type_i'. do method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldtoken, implementation_feature_token (type_i.implementation_id (current_class_type.type), a_feature_id)) end generate_argument (n: INTEGER) -- Generate access to `n'-th variable arguments of current feature. do inspect n when 0 then method_body.put_opcode ({MD_OPCODES}.Ldarg_0) when 1 then method_body.put_opcode ({MD_OPCODES}.Ldarg_1) when 2 then method_body.put_opcode ({MD_OPCODES}.Ldarg_2) when 3 then method_body.put_opcode ({MD_OPCODES}.Ldarg_3) else if n <= 255 then method_body.put_opcode_integer_8 ({MD_OPCODES}.Ldarg_s, n.to_integer_8) else method_body.put_opcode_integer_16 ({MD_OPCODES}.Ldarg, n.to_integer_16) end end end generate_local (n: INTEGER) -- Generate access to `n'-th local variable of current feature. local l_pos: INTEGER do l_pos := n + result_position inspect l_pos when 0 then method_body.put_opcode ({MD_OPCODES}.Ldloc_0) when 1 then method_body.put_opcode ({MD_OPCODES}.Ldloc_1) when 2 then method_body.put_opcode ({MD_OPCODES}.Ldloc_2) when 3 then method_body.put_opcode ({MD_OPCODES}.Ldloc_3) else if l_pos <= 255 then method_body.put_opcode_integer_8 ({MD_OPCODES}.Ldloc_s, l_pos.to_integer_8) else method_body.put_opcode_integer_16 ({MD_OPCODES}.Ldloc, l_pos.to_integer_16) end end end generate_metamorphose (type_i: TYPE_A) -- Generate `metamorphose', ie boxing a basic type of `type_i' into its -- corresponding reference type. do -- It has to be the `implementation_id' because for us `box' -- can only be applied to expanded types and only `implementation_id' -- refers to the value type implementation for Eiffel generated types, -- and for .NET classes `static_type_id' and `implementation_id' are -- the same. method_body.put_opcode_mdtoken ({MD_OPCODES}.Box, actual_class_type_token (type_i.implementation_id (current_class_type.type))) end generate_external_metamorphose (type_i: TYPE_A) -- Generate `metamorphose', ie boxing an expanded type `type_i' -- using an associated external type (if any). do -- See comment in `generate_metamorphose'. method_body.put_opcode_mdtoken ({MD_OPCODES}.Box, actual_class_type_token (type_i.external_id (current_class_type.type))) end generate_eiffel_metamorphose (a_type: BASIC_A) -- Generate a metamorphose of `a_type' into a _REF type. local l_local_number: INTEGER l_feat: FEATURE_I do -- FIXME: We only half support metamorphose of basic types -- through the `set_item' routine. -- Assign value to a temporary local variable. byte_context.add_local (a_type) l_local_number := byte_context.local_list.count put_dummy_local_info (a_type, l_local_number) generate_local_assignment (l_local_number) -- Create a new (boxed) instance. generate_creation (a_type) -- Call `set_item' from the _REF class. duplicate_top generate_load_address (a_type) generate_local (l_local_number) l_feat := a_type.base_class.feature_table.item_id ({PREDEFINED_NAMES}.set_item_name_id) generate_feature_access (a_type, l_feat.feature_id, l_feat.argument_count, l_feat.has_return_value, False) end generate_unmetamorphose (type_i: TYPE_A) -- Generate `unmetamorphose', ie unboxing a reference to a basic type of `type_i'. -- Load content of address resulting from unbox operation. do generate_load_address (type_i) generate_load_from_address (type_i) end generate_external_unmetamorphose (type_i: TYPE_A) -- Generate `unmetamorphose', ie unboxing an external reference to a basic type of `type_i'. -- Load content of address resulting from unbox operation. do generate_load_address_as_external (type_i) generate_load_from_address (type_i) end feature -- Addresses generate_local_address (n: INTEGER) -- Generate address of `n'-th local variable. local l_pos: INTEGER do l_pos := n + result_position if l_pos <= 255 then method_body.put_opcode_integer_8 ({MD_OPCODES}.Ldloca_s, l_pos.to_integer_8) else method_body.put_opcode_integer_16 ({MD_OPCODES}.Ldloca, l_pos.to_integer_16) end end generate_argument_address (n: INTEGER) -- Generate address of `n'-th argument variable. do if n <= 255 then method_body.put_opcode_integer_8 ({MD_OPCODES}.Ldarga_s, n.to_integer_8) else method_body.put_opcode_integer_16 ({MD_OPCODES}.Ldarga, n.to_integer_16) end end generate_current_address -- Generate address of `Current'. do method_body.put_opcode_integer_8 ({MD_OPCODES}.Ldarga_s, 0) end generate_result_address -- Generate address of `Result'. do if once_generation then generate_once_result_address else generate_local_address (result_position) end end generate_attribute_address (type_i: TYPE_A; attr_type: TYPE_A; a_feature_id: INTEGER) -- Generate address to attribute of `a_feature_id' in `type_i'. local local_number: INTEGER do if attached {CL_TYPE_A} type_i as cl_type and then attached cl_type.associated_class_type (current_class_type.type) as l_class_type and then l_class_type.is_generated_as_single_type then method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldflda, attribute_token (cl_type.implementation_id (current_class_type.type), a_feature_id)) else -- Attribute are accessed through their feature encapsulation. internal_generate_feature_access (type_i.static_type_id (current_class_type.type), a_feature_id, 0, True, True) Byte_context.add_local (attr_type) local_number := Byte_context.local_list.count put_dummy_local_info (attr_type, local_number) generate_local_assignment (local_number) generate_local_address (local_number) end end generate_routine_address (type_i: TYPE_A; a_feature_id: INTEGER; is_last_argument_current: BOOLEAN) -- Generate address of routine of `a_feature_id' in class `type_i' -- assuming that previous argument is Current if `is_last_argument_current' is true. local opcode: INTEGER_16 type_id: INTEGER do if type_i.is_expanded then opcode := {MD_OPCODES}.ldftn type_id := type_i.implementation_id (current_class_type.type) else opcode := {MD_OPCODES}.ldvirtftn type_id := type_i.static_type_id (current_class_type.type) -- Target object is used to calculate address. if is_last_argument_current then -- Use code sequence that can be verified -- when calling a delegate constructor. generate_check_cast (Void, type_i) method_body.put_opcode ({MD_OPCODES}.Dup) else generate_current end end method_body.put_opcode_mdtoken (opcode, feature_token (type_id, a_feature_id)) end generate_load_address (type_i: TYPE_A) -- <Precursor> do -- See comment on `generate_metamorphose' on why we chose `implementation_id'. method_body.put_opcode_mdtoken ({MD_OPCODES}.Unbox, actual_class_type_token (type_i.implementation_id (current_class_type.type))) end generate_load_address_as_external (type_i: TYPE_A) -- <Precursor> do method_body.put_opcode_mdtoken ({MD_OPCODES}.Unbox, actual_class_type_token (type_i.external_id (current_class_type.type))) end generate_load_from_address (a_type: TYPE_A) -- <Precursor> do inspect a_type.element_type when {MD_SIGNATURE_CONSTANTS}.Element_type_i then method_body.put_opcode ({MD_OPCODES}.Ldind_i) when {MD_SIGNATURE_CONSTANTS}.Element_type_i1 then method_body.put_opcode ({MD_OPCODES}.Ldind_i1) when {MD_SIGNATURE_CONSTANTS}.Element_type_i2 then method_body.put_opcode ({MD_OPCODES}.Ldind_i2) when {MD_SIGNATURE_CONSTANTS}.Element_type_i4 then method_body.put_opcode ({MD_OPCODES}.Ldind_i4) when {MD_SIGNATURE_CONSTANTS}.Element_type_i8 then method_body.put_opcode ({MD_OPCODES}.Ldind_i8) when {MD_SIGNATURE_CONSTANTS}.Element_type_u1 then method_body.put_opcode ({MD_OPCODES}.Ldind_u1) when {MD_SIGNATURE_CONSTANTS}.Element_type_u2 then method_body.put_opcode ({MD_OPCODES}.Ldind_u2) when {MD_SIGNATURE_CONSTANTS}.Element_type_u4 then method_body.put_opcode ({MD_OPCODES}.Ldind_u4) when {MD_SIGNATURE_CONSTANTS}.Element_type_u8 then method_body.put_opcode ({MD_OPCODES}.Ldind_u8) when {MD_SIGNATURE_CONSTANTS}.Element_type_boolean then method_body.put_opcode ({MD_OPCODES}.Ldind_i1) when {MD_SIGNATURE_CONSTANTS}.Element_type_char then method_body.put_opcode ({MD_OPCODES}.Ldind_i2) when {MD_SIGNATURE_CONSTANTS}.Element_type_r4 then method_body.put_opcode ({MD_OPCODES}.Ldind_r4) when {MD_SIGNATURE_CONSTANTS}.Element_type_r8 then method_body.put_opcode ({MD_OPCODES}.Ldind_r8) else -- See comment on `generate_metamorphose' to see why we -- use `implementation_id'. method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldobj, actual_class_type_token (a_type.implementation_id (current_class_type.type))) end end generate_load_from_address_as_object (a_type: TYPE_A) -- Load value of non-built-in `a_type' type from address pushed on stack. do -- See comment on `generate_metamorphose' to see why we -- use `implementation_id'. method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldobj, actual_class_type_token (a_type.implementation_id (current_class_type.type))) end generate_load_from_address_as_basic (a_type: TYPE_A) -- Load value of a basic type `a_type' from address of an Eiffel object pushed on stack. local l_table: FEATURE_TABLE l_feat: FEATURE_I do if attached {CL_TYPE_A} a_type as l_cl_type then l_table := l_cl_type.base_class.feature_table -- Try to get an attribute by name. l_feat := l_table.item_id ({PREDEFINED_NAMES}.item_name_id) if l_feat = Void or else not l_feat.is_attribute then -- Find attribute explicitly. from l_table.start until l_table.after or else l_table.item_for_iteration.is_attribute loop l_table.forth end l_feat := l_table.item_for_iteration end check l_feat_attached: l_feat /= Void -- This is ensured by {CLASS_B}.check_validity end generate_attribute (True, l_cl_type, l_feat.feature_id) end end feature -- Assignments generate_is_true_instance_of (type_i: TYPE_A) -- Generate `Isinst' byte code instruction. local l_token: INTEGER do -- We use `actual_class_type_token' because we really want to know -- if we inherit really from ANY. if type_i.is_expanded then l_token := actual_class_type_token (type_i.implementation_id (current_class_type.type)) else l_token := actual_class_type_token (type_i.static_type_id (current_class_type.type)) end method_body.put_opcode_mdtoken ({MD_OPCODES}.Isinst, l_token) end generate_is_instance_of (type_i: TYPE_A) -- Generate `Isinst' byte code instruction where ANY is replaced by SYSTEM_OBJECT. local l_token: INTEGER l_type: TYPE_A l_obj_var: INTEGER do l_type := type_i.actual_type if l_type.is_none then -- Nothing to be done because those types are mapped to -- System.Object the ancestor to all objects. So we -- simply preserve the value on the stack. elseif l_type.is_formal and then attached {FORMAL_A} l_type as l_formal_type then -- Nothing to be done because those types are mapped to -- System.Object the ancestor to all objects. So we -- simply preserve the value on the stack. byte_context.add_local (system_object_type) l_obj_var := byte_context.local_list.count put_dummy_local_info (system_object_type, l_obj_var) generate_local_assignment (l_obj_var) if attached current_class.formal_at_position (l_formal_type.position) as l_type_feature_i then generate_current generate_type_feature_call (l_type_feature_i) generate_local (l_obj_var) internal_generate_external_call (current_module.ise_runtime_token, 0, Runtime_class_name, "attempted_on_rt_type", Static_type, <<System_object_class_name, type_class_name, System_object_class_name>>, System_object_class_name, True, Void) else generate_current put_integer_32_constant (l_formal_type.position) internal_generate_external_call (current_module.ise_runtime_token, 0, Runtime_class_name, "type_of_generic_parameter", Static_type, <<System_object_class_name, "System.Int32">>, system_type_class_name, False, Void) generate_local (l_obj_var) internal_generate_external_call (current_module.ise_runtime_token, 0, Runtime_class_name, "attempted_on_type", Static_type, <<System_type_class_name, System_object_class_name>>, System_object_class_name, True, Void) end put_void method_body.put_opcode ({MD_OPCODES}.Ceq) method_body.put_opcode ({MD_OPCODES}.Ldc_i4_0) method_body.put_opcode ({MD_OPCODES}.Ceq) else -- We use `mapped_class_type_token' because if we do: -- a: ANY -- o: SYSTEM_OBJECT -- a := o -- valid because SYSTEM_OBJECT inherits from ANY -- a ?= o -- should also be valid. if type_i.is_expanded then l_token := mapped_class_type_token (type_i.implementation_id (current_class_type.type)) else l_token := mapped_class_type_token (type_i.static_type_id (current_class_type.type)) end method_body.put_opcode_mdtoken ({MD_OPCODES}.Isinst, l_token) end end generate_is_instance_of_external (type_i: CL_TYPE_A) -- Generate `Isinst' byte code instruction for external variant of the type `type_i'. do method_body.put_opcode_mdtoken ({MD_OPCODES}.Isinst, mapped_class_type_token (type_i.external_id (current_class_type.type))) end generate_check_cast (source_type, target_type: TYPE_A) -- Generate `checkcast' byte code instruction. local l_token: INTEGER l_sig: MD_TYPE_SIGNATURE l_target_type: TYPE_A do -- It makes sense to cast if and only if target is not expanded, nor a formal or NONE. -- In the last two cases it is useless because those types are mapped to System.Object. l_target_type := target_type.actual_type if is_verifiable and not l_target_type.is_expanded and not l_target_type.is_none and not l_target_type.is_formal and then (not attached source_type or else not attached {CL_TYPE_A} source_type as s or else not attached {CL_TYPE_A} l_target_type as t or else not s.base_class.simple_conform_to (t.base_class)) then if attached {NATIVE_ARRAY_TYPE_A} l_target_type as l_native_array then -- Try to optimize this a little bit more. create l_sig.make set_signature_type (l_sig, l_native_array, current_class_type) l_token := md_emit.define_type_spec (l_sig) else l_token := mapped_class_type_token (l_target_type.static_type_id (current_class_type.type)) end method_body.put_opcode_mdtoken ({MD_OPCODES}.Castclass, l_token) end end generate_attribute_assignment (need_target: BOOLEAN; type_i: TYPE_A; a_feature_id: INTEGER) -- Generate assignment to attribute of `a_feature_id' in current class. local l_class_type: CLASS_TYPE do check has_type: type_i.has_associated_class_type (current_class_type.type) end l_class_type := type_i.associated_class_type (current_class_type.type) if l_class_type.is_generated_as_single_type then method_body.put_opcode_mdtoken (if need_target then {MD_OPCODES}.Stfld else {MD_OPCODES}.Stsfld end, attribute_token (l_class_type.static_type_id, a_feature_id)) elseif l_class_type.is_expanded then method_body.put_call ({MD_OPCODES}.Call, setter_token (l_class_type.implementation_id, a_feature_id), 1, False) else method_body.put_call ({MD_OPCODES}.Callvirt, setter_token (l_class_type.static_type_id, a_feature_id), 1, False) end end generate_expanded_attribute_assignment (type_i, attr_type: TYPE_A; a_feature_id: INTEGER) -- Generate assignment to attribute of `a_feature_id' in current class -- when direct access to attribute is not possible. local l_class_type: CLASS_TYPE do check has_type: type_i.has_associated_class_type (current_class_type.type) end l_class_type := type_i.associated_class_type (current_class_type.type) if not l_class_type.is_generated_as_single_type then method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldobj, actual_class_type_token (attr_type.static_type_id (current_class_type.type))) method_body.put_call ({MD_OPCODES}.Callvirt, setter_token (l_class_type.static_type_id, a_feature_id), 1, False) end end generate_argument_assignment (n: INTEGER) -- Generate assignment to `n'-th argument of current feature. do if n <= 255 then method_body.put_opcode_integer_8 ({MD_OPCODES}.Starg_s, n.to_integer_8) else method_body.put_opcode_integer_16 ({MD_OPCODES}.Starg, n.to_integer_16) end end generate_local_assignment (n: INTEGER) -- Generate assignment to `n'-th local variable of current feature. local l_pos: INTEGER do l_pos := n + result_position inspect l_pos when 0 then method_body.put_opcode ({MD_OPCODES}.Stloc_0) when 1 then method_body.put_opcode ({MD_OPCODES}.Stloc_1) when 2 then method_body.put_opcode ({MD_OPCODES}.Stloc_2) when 3 then method_body.put_opcode ({MD_OPCODES}.Stloc_3) else if l_pos <= 255 then method_body.put_opcode_integer_8 ({MD_OPCODES}.Stloc_s, l_pos.to_integer_8) else method_body.put_opcode_integer_16 ({MD_OPCODES}.Stloc, l_pos.to_integer_16) end end end generate_result_assignment -- Generate assignment to Result variable of current feature. do if once_generation then generate_once_store_result else generate_local_assignment (result_position) end end feature -- Conversion convert_to (type: TYPE_A) -- Convert top of stack into `type'. do inspect type.element_type when {MD_SIGNATURE_CONSTANTS}.Element_type_boolean then convert_to_boolean when {MD_SIGNATURE_CONSTANTS}.Element_type_char then convert_to_character_8 when {MD_SIGNATURE_CONSTANTS}.Element_type_r4 then convert_to_real_32 when {MD_SIGNATURE_CONSTANTS}.Element_type_r8 then convert_to_real_64 when {MD_SIGNATURE_CONSTANTS}.Element_type_u1 then convert_to_natural_8 when {MD_SIGNATURE_CONSTANTS}.Element_type_u2 then convert_to_natural_16 when {MD_SIGNATURE_CONSTANTS}.Element_type_u4 then convert_to_natural_32 when {MD_SIGNATURE_CONSTANTS}.Element_type_u8 then convert_to_natural_64 when {MD_SIGNATURE_CONSTANTS}.Element_type_i then convert_to_native_int when {MD_SIGNATURE_CONSTANTS}.Element_type_i1 then convert_to_integer_8 when {MD_SIGNATURE_CONSTANTS}.Element_type_i2 then convert_to_integer_16 when {MD_SIGNATURE_CONSTANTS}.Element_type_i4 then convert_to_integer_32 when {MD_SIGNATURE_CONSTANTS}.Element_type_i8 then convert_to_integer_64 else --check -- False --end end end convert_to_native_int -- Convert top of stack into appropriate type. do method_body.put_opcode ({MD_OPCODES}.Conv_i) end convert_to_integer_8, convert_to_boolean -- Convert top of stack into appropriate type. do method_body.put_opcode ({MD_OPCODES}.Conv_i1) end convert_to_integer_16, convert_to_character_8 -- Convert top of stack into appropriate type. do method_body.put_opcode ({MD_OPCODES}.Conv_i2) end convert_to_integer_32 -- Convert top of stack into appropriate type. do method_body.put_opcode ({MD_OPCODES}.Conv_i4) end convert_to_integer_64 -- Convert top of stack into appropriate type. do method_body.put_opcode ({MD_OPCODES}.Conv_i8) end convert_to_natural_8 -- Convert top of stack into appropriate type. do method_body.put_opcode ({MD_OPCODES}.Conv_u1) end convert_to_natural_16 -- Convert top of stack into appropriate type. do method_body.put_opcode ({MD_OPCODES}.Conv_u2) end convert_to_natural_32, convert_to_character_32 -- Convert top of stack into appropriate type. do method_body.put_opcode ({MD_OPCODES}.Conv_u4) end convert_to_natural_64 -- Convert top of stack into appropriate type. do method_body.put_opcode ({MD_OPCODES}.Conv_u8) end convert_to_real_64 -- Convert top of stack into appropriate type. do method_body.put_opcode ({MD_OPCODES}.Conv_r8) end convert_to_real_32 -- Convert top of stack into appropriate type. do method_body.put_opcode ({MD_OPCODES}.Conv_r4) end feature -- Return statements generate_return (has_return_value: BOOLEAN) -- Generate simple end of routine do method_body.put_opcode ({MD_OPCODES}.Ret) if has_return_value then -- We need to remove `1' to the current stack depth since -- we remove the return value from the stack with the `ret' -- statement. method_body.update_stack_depth (-1) end end feature {NONE} -- Once management once_done_name (feature_name: STRING): STRING -- Name of the field that indicates whether once routine has been executed or not require feature_name_not_void: feature_name /= Void do Result := feature_name + "_done" ensure result_not_void: Result /= Void end once_exception_name (feature_name: STRING): STRING -- Name of the field that holds exception raised during execution of once routine require feature_name_not_void: feature_name /= Void do Result := feature_name + "_exception" ensure result_not_void: Result /= Void end once_result_name (feature_name: STRING): STRING -- Name of the field that stores result of a once function require feature_name_not_void: feature_name /= Void do Result := feature_name + "_result" ensure result_not_void: Result /= Void end once_ready_name (feature_name: STRING): STRING -- Name of flag that indicates that once data is ready to use from a different thread require feature_name_not_void: feature_name /= Void do Result := feature_name + "_ready" ensure result_not_void: Result /= Void end once_sync_name (feature_name: STRING): STRING -- Name of the field that is used to synchronize access to once routine data require feature_name_not_void: feature_name /= Void do Result := feature_name + "_sync" ensure result_not_void: Result /= Void end feature -- Once management generate_once_data (class_c: CLASS_C; a_context_type: CLASS_TYPE) -- Generate IL class that is used to store results of once routines declared in `class_c'. require class_c_not_void: class_c /= Void a_context_type_not_void: a_context_type /= Void local feature_table: FEATURE_TABLE feature_i: FEATURE_I class_constructor_token: INTEGER l_method_sig: like method_sig do -- Set current module and class set_current_module_for_class (class_c) current_class := class_c -- Avoid generating class data when there are no once routines current_class_token := 0 method_body := Void -- Generate data for once features in class `class_c' -- (they are either immediate or replicated in it) -- ca_ignore: "CA024", "Internal and external coursors have different implementation." from feature_table := class_c.feature_table feature_table.start until feature_table.after loop feature_i := feature_table.item_for_iteration if feature_i.is_once and then feature_i.is_process_or_thread_relative_once and then feature_i.access_in = class_c.class_id then if current_class_token = 0 then current_class_token := current_module.class_data_token (class_c) end sync_token := 0 generate_once_data_info (feature_i, a_context_type) if sync_token /= 0 then -- Static field has to be initialized in a class constructor if class_constructor_token = 0 then l_method_sig := method_sig l_method_sig.reset l_method_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.default_sig) l_method_sig.set_parameter_count (0) l_method_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.element_type_void, 0) uni_string.set_string (".cctor") class_constructor_token := md_emit.define_method ( uni_string, current_class_token, {MD_METHOD_ATTRIBUTES}.private | {MD_METHOD_ATTRIBUTES}.static | {MD_METHOD_ATTRIBUTES}.special_name | {MD_METHOD_ATTRIBUTES}.rt_special_name | {MD_METHOD_ATTRIBUTES}.hide_by_signature, l_method_sig, {MD_METHOD_ATTRIBUTES}.il | {MD_METHOD_ATTRIBUTES}.managed) start_new_body (class_constructor_token) end method_body.put_newobj (constructor_token (current_module.object_type_id), 0) method_body.put_opcode_mdtoken ({MD_OPCODES}.stsfld, sync_token) end end feature_table.forth end if method_body /= Void then generate_return (False) method_writer.write_current_body end end done_token, result_token, exception_token: INTEGER -- Token for static fields holding value if once has been computed, -- its value if computed. -- Ok to use token in a non-module specific code here, because they -- are only local to current feature generation. ready_token, sync_token: INTEGER -- Token for static fields holding ready-to-use flag and synchronization object -- for process-relative once routines. -- Ok to use token in a non-module specific code here, because they -- are only local to current feature generation. once_done_label: IL_LABEL -- Label which is used in test of a "done" flag `done_token' once_ready_label: IL_LABEL -- Label which is used in test of a "ready" flag `ready_token' generate_once_data_info (feat: FEATURE_I; a_context_type: CLASS_TYPE) -- Generate declaration of variables required to store data of once feature `feat'. require feat_not_void: feat /= Void feat_is_once: feat.is_once a_context_type_not_void: a_context_type /= Void local name: STRING result_sig: like field_sig result_type: TYPE_A do name := feat.feature_name -- Generate field that indicates whether result is calculated or not uni_string.set_string (once_done_name (name)) done_token := md_emit.define_field (uni_string, current_class_token, {MD_FIELD_ATTRIBUTES}.Public | {MD_FIELD_ATTRIBUTES}.Static, done_sig) if not feat.is_process_relative then current_module.define_thread_static_attribute (done_token) end -- Generate field that holds exception raised during evaluation uni_string.set_string (once_exception_name (name)) exception_token := md_emit.define_field (uni_string, current_class_token, {MD_FIELD_ATTRIBUTES}.Public | {MD_FIELD_ATTRIBUTES}.Static, exception_sig) if not feat.is_process_relative then current_module.define_thread_static_attribute (exception_token) end result_type := result_type_in (feat, a_context_type) if not result_type.is_void then -- Generate field for result result_sig := field_sig result_sig.reset set_signature_type (result_sig, result_type, a_context_type) uni_string.set_string (once_result_name (name)) result_token := md_emit.define_field (uni_string, current_class_token, {MD_FIELD_ATTRIBUTES}.Public | {MD_FIELD_ATTRIBUTES}.Static, result_sig) if not feat.is_process_relative then current_module.define_thread_static_attribute (result_token) end end Il_debug_info_recorder.record_once_info_for_class (current_class_token, done_token, result_token, exception_token, feat, current_class) if feat.is_process_relative then -- Generate flag that indicates that once data fields are ready to use uni_string.set_string (once_ready_name (name)) sync_token := md_emit.define_field ( uni_string, current_class_token, {MD_FIELD_ATTRIBUTES}.Public | {MD_FIELD_ATTRIBUTES}.Static, done_sig) -- Generate field to synchronize access to other data fields uni_string.set_string (once_sync_name (name)) sync_token := md_emit.define_field ( uni_string, current_class_token, {MD_FIELD_ATTRIBUTES}.Public | {MD_FIELD_ATTRIBUTES}.Static, sync_sig) end end generate_once_access_info (feature_i: FEATURE_I; is_once_creation: BOOLEAN) -- Initialize tokens for fields that are used to store result of `feature_i'. require feature_i_not_void: feature_i /= Void once_feature: feature_i.is_once local class_data_token: INTEGER name: STRING l_sig: like field_sig cl_token: INTEGER l_once_info: detachable OBJECT_RELATIVE_ONCE_INFO do name := feature_i.feature_name if feature_i.is_object_relative_once then cl_token := current_class_token l_once_info := current_class.object_relative_once_info_of_rout_id_set (feature_i.rout_id_set) check has_obj_relative_once_info: l_once_info /= Void end uni_string.set_string (l_once_info.called_name) done_token := md_emit.define_field (uni_string, cl_token, {MD_FIELD_ATTRIBUTES}.Private, done_sig) uni_string.set_string (l_once_info.exception_name) exception_token := md_emit.define_field (uni_string, cl_token, {MD_FIELD_ATTRIBUTES}.Private, exception_sig) if l_once_info.has_result then l_sig := field_sig l_sig.reset set_signature_type (l_sig, l_once_info.result_type_a, current_class_type) uni_string.set_string (l_once_info.result_name) result_token := md_emit.define_field (uni_string, cl_token, {MD_FIELD_ATTRIBUTES}.Private, l_sig) else result_token := 0 end Il_debug_info_recorder.record_once_info_for_class (current_class_token, done_token, result_token, exception_token, feature_i, current_class) else class_data_token := current_module.class_data_token (system.class_of_id (feature_i.access_in)) uni_string.set_string (once_done_name (name)) done_token := md_emit.define_member_ref (uni_string, class_data_token, done_sig) uni_string.set_string (once_exception_name (name)) exception_token := md_emit.define_member_ref (uni_string, class_data_token, exception_sig) if feature_i.has_return_value or else is_once_creation then l_sig := field_sig l_sig.reset set_signature_type (l_sig, result_type_in (feature_i, current_class_type), current_class_type) uni_string.set_string (once_result_name (name)) result_token := md_emit.define_member_ref (uni_string, class_data_token, l_sig) else result_token := 0 end end if feature_i.is_process_relative then uni_string.set_string (once_ready_name (name)) ready_token := md_emit.define_member_ref (uni_string, class_data_token, done_sig) uni_string.set_string (once_sync_name (name)) sync_token := md_emit.define_member_ref (uni_string, class_data_token, sync_sig) else ready_token := 0 sync_token := 0 end ensure done_token_set: done_token /= 0 result_token_set: feature_i.has_return_value = (result_token /= 0) ready_token_set: feature_i.is_process_relative = (ready_token /= 0) sync_token_set: feature_i.is_process_relative = (sync_token /= 0) end generate_once_prologue (is_once_creation: BOOLEAN) -- Generate prologue for once feature. -- The feature is used with `generate_once_epilogue' as follows: -- generate_once_prologue -- ... -- code of once feature body -- generate_once_epilogue -- require -- current_feature_not_void: byte_context.current_feature /= Void -- current_feature_is_once: byte_context.current_feature.is_once local l_once_info: detachable OBJECT_RELATIVE_ONCE_INFO do -- Body of a once feature is guarded by try/fault blocks -- to avoid storing invalid result in case of exception: -- done := True -- try { -- ... -- code of once feature body (including rescue clause) -- } -- catch (Object e) { -- exception := e -- volatile ready := True -- only in process-relative code -- rethrow -- } -- Thread-relative code looks like -- if not done then -- guarded_body -- see above -- end -- if exception /= Void then -- raise (exception) -- end -- return result -- if required -- Process-relative code uses double-check algorithm and looks like -- if not volatile ready then -- try { -- lock (sync) -- if not done then -- guarded_body -- see above -- volatile ready := True -- end -- } -- finally { -- unlock (sync) -- } -- end -- if exception /= Void then -- raise (exception) -- end -- return result -- if required -- Object-relative code -- if not done then -- guarded_body -- see above -- end -- if exception /= Void then -- raise (exception) -- end -- return result -- if required -- Initialize once code generation set_once_generation (True) if byte_context.current_feature.is_object_relative_once then set_object_relative_once_generation (True) l_once_info := current_class.object_relative_once_info_of_rout_id_set (byte_context.current_feature.rout_id_set) else set_object_relative_once_generation (False) end generate_once_access_info (byte_context.current_feature, is_once_creation) if ready_token /= 0 then check sync_token /= 0 end -- Generate synchronization for process-relative feature: -- if not volatile ready then -- try { -- lock (sync) method_body.put_opcode ({MD_OPCODES}.volatile) method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldsfld, ready_token) once_ready_label := create_label branch_on_true (once_ready_label) method_body.once_finally_block.set_try_offset (method_body.count) method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, sync_token) method_body.put_static_call (current_module.define_monitor_method_token ("Enter"), 1, False) end -- Generate code that is common for thread-relative and process-relative case: -- if not done then -- done := True -- try { if l_once_info /= Void then generate_current method_body.put_opcode_mdtoken ({MD_OPCODES}.ldfld, done_token) put_boolean_constant (True) method_body.put_opcode ({MD_OPCODES}.ceq) else method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldsfld, done_token) end once_done_label := create_label branch_on_true (once_done_label) if l_once_info /= Void then generate_current put_boolean_constant (True) method_body.put_opcode_mdtoken ({MD_OPCODES}.Stfld, done_token) else put_boolean_constant (True) method_body.put_opcode_mdtoken ({MD_OPCODES}.Stsfld, done_token) end method_body.once_catch_block.set_try_offset (method_body.count) ensure then once_generation: once_generation done_token_set: done_token /= 0 result_token_set: (byte_context.current_feature.has_return_value or is_once_creation) = (result_token /= 0) ready_token_set: byte_context.current_feature.is_process_relative = (ready_token /= 0) sync_token_set: byte_context.current_feature.is_process_relative = (sync_token /= 0) once_done_label_set: once_done_label /= Void once_ready_label_set: (ready_token /= 0) = (once_ready_label /= Void) end generate_once_epilogue -- Generate epilogue for once feature. -- require -- current_feature_not_void: byte_context.current_feature /= Void -- current_feature_is_once: byte_context.current_feature.is_once local fault_label: IL_LABEL return_label: IL_LABEL is_process_relative: BOOLEAN has_result: BOOLEAN l_once_info: detachable OBJECT_RELATIVE_ONCE_INFO local_number: INTEGER do if byte_context.current_feature.is_object_relative_once then l_once_info := current_class.object_relative_once_info_of_rout_id_set (byte_context.current_feature.rout_id_set) end -- Close try block and start fault block -- } -- catch (Object e) { -- exception := e -- volatile ready := True -- only in process-relative code -- rethrow -- } fault_label := create_label generate_leave_to (fault_label) method_body.once_catch_block.set_try_end (method_body.count) method_body.once_catch_block.set_class_token (current_module.object_type_token) method_body.update_stack_depth (1) method_body.once_catch_block.set_handler_offset (method_body.count) if l_once_info /= Void then -- Store value byte_context.add_local (System_object_type) local_number := byte_context.local_list.count put_dummy_local_info (System_object_type, local_number) generate_local_assignment (local_number) generate_current generate_local (local_number) method_body.put_opcode_mdtoken ({MD_OPCODES}.Stfld, exception_token) -- FIXME:jfiat: should we reset the "result" value? to avoid memory leaks? else method_body.put_opcode_mdtoken ({MD_OPCODES}.Stsfld, exception_token) end if ready_token /= 0 then -- Notify other threads that result is ready: -- volatile ready := True check sync_token /= 0 end check once_ready_label /= Void end is_process_relative := True put_boolean_constant (True) method_body.put_opcode ({MD_OPCODES}.volatile) method_body.put_opcode_mdtoken ({MD_OPCODES}.Stsfld, ready_token) end -- Rethrow exception to make original stack trace available to application -- as otherwise it will be lost method_body.put_rethrow method_body.once_catch_block.set_handler_end (method_body.count) mark_label (fault_label) if is_process_relative then -- Notify other threads that result is ready: -- volatile ready := True put_boolean_constant (True) method_body.put_opcode ({MD_OPCODES}.volatile) method_body.put_opcode_mdtoken ({MD_OPCODES}.Stsfld, ready_token) end -- Close "if not done" block: -- end mark_label (once_done_label) if is_process_relative then -- Unlock synchronization object and close "if not volatile ready" block in process-relative case: -- } -- finally { -- unlock (sync) -- } -- end generate_leave_to (once_ready_label) method_body.once_finally_block.set_try_end (method_body.count) method_body.once_finally_block.set_handler_offset (method_body.count) method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, sync_token) method_body.put_static_call (current_module.define_monitor_method_token ("Exit"), 1, False) method_body.put_opcode ({MD_OPCODES}.endfinally) method_body.once_finally_block.set_handler_end (method_body.count) mark_label (once_ready_label) end -- Check if there was an exception: -- if exception /= Void then -- raise (exception) -- end return_label := create_label if l_once_info /= Void then generate_current method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldfld, exception_token) put_void method_body.put_opcode ({MD_OPCODES}.ceq) put_boolean_constant (False) method_body.put_opcode ({MD_OPCODES}.ceq) else method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldsfld, exception_token) end branch_on_false (return_label) if l_once_info /= Void then generate_current method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldfld, exception_token) else method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldsfld, exception_token) end -- Only System.Exception can be saved. The type saved exception object could be changed to System.Exception. method_body.put_opcode_mdtoken ({MD_OPCODES}.Castclass, current_module.system_exception_token) method_body.put_throw mark_label (return_label) if result_token /= 0 then has_result := True -- Load result of a feature: -- return result -- if required generate_once_result end generate_return (has_result) done_token := 0 exception_token := 0 result_token := 0 ready_token := 0 sync_token := 0 once_done_label := Void once_ready_label := Void set_once_generation (False) set_object_relative_once_generation (False) ensure then done_token_unset: done_token = 0 result_token_unset: result_token = 0 ready_token_unset: ready_token = 0 sync_token_unset: sync_token = 0 once_done_label_unset: once_done_label = Void once_ready_label_unset: once_ready_label = Void not_once_generation: not once_generation not_object_relative_once_generation: not object_relative_once_generation end generate_once_result_address -- Generate test on `done' of once feature `name'. require result_token_set: result_token /= 0 do method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldsflda, result_token) end generate_once_result -- Generate access to static `result' variable to load last -- computed value of current processed once function -- require -- result_token_set: result_token /= 0 do if object_relative_once_generation then generate_current method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldfld, result_token) else method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldsfld, result_token) end end generate_once_store_result -- Generate setting of static `result' variable corresponding -- to current processed once function. local local_number: INTEGER do if object_relative_once_generation then byte_context.add_local (System_object_type) local_number := byte_context.local_list.count put_dummy_local_info (System_object_type, local_number) generate_local_assignment (local_number) generate_current generate_local (local_number) method_body.put_opcode_mdtoken ({MD_OPCODES}.Stfld, result_token) else method_body.put_opcode_mdtoken ({MD_OPCODES}.Stsfld, result_token) end end feature -- Once manifest string manipulation generate_once_string_allocation (count: INTEGER) -- Generate code that allocates memory required for `count' -- once manifest strings of the current routine. local allocate_array_label: IL_LABEL done_label: IL_LABEL do if count > 0 then allocate_array_label := create_label done_label := create_label -- Check if the array is already allocated. method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, current_module.once_string_field_token (string_type_cil)) method_body.put_opcode ({MD_OPCODES}.dup) branch_on_false (allocate_array_label) method_body.put_opcode ({MD_OPCODES}.dup) method_body.put_opcode ({MD_OPCODES}.ldlen) put_integer_32_constant (byte_context.original_body_index) method_body.put_opcode_label ({MD_OPCODES}.ble, allocate_array_label.id) put_integer_32_constant (byte_context.original_body_index) method_body.put_opcode ({MD_OPCODES}.ldelem_ref) method_body.put_opcode ({MD_OPCODES}.dup) branch_on_true (done_label) mark_label (allocate_array_label) -- Array is not allocated. -- Call allocation routine. put_integer_32_constant (byte_context.original_body_index) put_integer_32_constant (count) method_body.put_static_call (current_module.once_string_allocation_routine_token, 2, False) -- Done. mark_label (done_label) -- Remove null from stack top. method_body.put_opcode ({MD_OPCODES}.pop) end end generate_once_string (number: INTEGER; value: READABLE_STRING_32; type: INTEGER) -- Generate code for once string in a current routine with the given -- `number' and `value' using CIL string type if `is_cil_string' is `True' -- or Eiffel string type otherwise. local once_string_field_token: INTEGER assign_string_label: IL_LABEL done_label: IL_LABEL do once_string_field_token := current_module.once_string_field_token (type) assign_string_label := create_label done_label := create_label -- Check if the string is already created. method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, once_string_field_token) put_integer_32_constant (byte_context.original_body_index) method_body.put_opcode ({MD_OPCODES}.ldelem_ref) put_integer_32_constant (number) method_body.put_opcode ({MD_OPCODES}.ldelem_ref) method_body.put_opcode ({MD_OPCODES}.dup) -- String is already created. branch_on_true (done_label) -- Remove null from stack top. method_body.put_opcode ({MD_OPCODES}.pop) mark_label (assign_string_label) -- String is not stored in array. -- Let's create it and store. method_body.put_opcode_mdtoken ({MD_OPCODES}.ldsfld, once_string_field_token) put_integer_32_constant (byte_context.original_body_index) method_body.put_opcode ({MD_OPCODES}.ldelem_ref) method_body.put_opcode ({MD_OPCODES}.dup) put_integer_32_constant (number) if type = string_type_cil then put_system_string_32 (value) else if type = string_type_string_32 then put_manifest_string_32 (value) elseif type = string_type_string then put_manifest_string (value) elseif type = string_type_immutable_string_32 then put_immutable_manifest_string_32 (value) elseif type = string_type_immutable_string_8 then put_immutable_manifest_string_8 (value) end end method_body.put_opcode ({MD_OPCODES}.stelem_ref) put_integer_32_constant (number) method_body.put_opcode ({MD_OPCODES}.ldelem_ref) -- Done. mark_label (done_label) end feature -- Array manipulation generate_array_access (kind: INTEGER; a_type_id: INTEGER) -- Generate call to `item' of NATIVE_ARRAY. local l_opcode: INTEGER_16 l_token: INTEGER do if kind = Il_expanded then l_token := actual_class_type_token (a_type_id) method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldelema, l_token) method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldobj, l_token) else inspect kind when Il_i1 then l_opcode := {MD_OPCODES}.Ldelem_i1 when Il_i2 then l_opcode := {MD_OPCODES}.Ldelem_i2 when Il_i4 then l_opcode := {MD_OPCODES}.Ldelem_i4 when Il_i8, Il_u8 then l_opcode := {MD_OPCODES}.Ldelem_i8 when Il_r4 then l_opcode := {MD_OPCODES}.Ldelem_r4 when Il_r8 then l_opcode := {MD_OPCODES}.Ldelem_r8 when Il_ref then l_opcode := {MD_OPCODES}.Ldelem_ref when Il_i then l_opcode := {MD_OPCODES}.Ldelem_i when Il_u1 then l_opcode := {MD_OPCODES}.Ldelem_u1 when Il_u2 then l_opcode := {MD_OPCODES}.Ldelem_u2 when Il_u4 then l_opcode := {MD_OPCODES}.Ldelem_u4 when Il_expanded then else check not_reached: False end end method_body.put_opcode (l_opcode) end end generate_array_write_preparation (a_type_id: INTEGER) -- Prepare call to `put' from NATIVE_ARRAY in case of expanded elements. do method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldelema, actual_class_type_token (a_type_id)) end generate_array_write (kind: INTEGER; a_type_id: INTEGER) -- Generate call to `put' of NATIVE_ARRAY. local l_opcode: INTEGER_16 do if kind = il_expanded then method_body.put_opcode_mdtoken ({MD_OPCODES}.Stobj, actual_class_type_token (a_type_id)) else inspect kind when Il_i1, Il_u1 then l_opcode := {MD_OPCODES}.Stelem_i1 when Il_i2, Il_u2 then l_opcode := {MD_OPCODES}.Stelem_i2 when Il_i4, Il_u4 then l_opcode := {MD_OPCODES}.Stelem_i4 when Il_i8, Il_u8 then l_opcode := {MD_OPCODES}.Stelem_i8 when Il_r4 then l_opcode := {MD_OPCODES}.Stelem_r4 when Il_r8 then l_opcode := {MD_OPCODES}.Stelem_r8 when Il_ref then l_opcode := {MD_OPCODES}.Stelem_ref when Il_i then l_opcode := {MD_OPCODES}.Stelem_i else check not_reached: False end end method_body.put_opcode (l_opcode) end end generate_array_initialization (array_type: CL_TYPE_A; actual_generic: CLASS_TYPE) -- Initialize native array with actual parameter type -- `actual_generic' on the top of the stack. local enter_loop_label: IL_LABEL continue_loop_label: IL_LABEL array_variable: INTEGER index_variable: INTEGER do if actual_generic.is_true_expanded and not actual_generic.is_external then -- Initialize elements with their default values: -- int i = array.count; -- while (i != 0) { -- i--; -- array [i].ctor (); -- array [i].default_create (); -- } enter_loop_label := create_label continue_loop_label := create_label byte_context.add_local (array_type) array_variable := byte_context.local_list.count put_dummy_local_info (array_type, array_variable) byte_context.add_local (integer_32_type) index_variable := byte_context.local_list.count put_dummy_local_info (integer_32_type, index_variable) duplicate_top generate_local_assignment (array_variable) generate_array_count generate_local_assignment (index_variable) branch_to (enter_loop_label) mark_label (continue_loop_label) generate_local (array_variable) generate_local (index_variable) put_integer_8_constant (1) generate_binary_operator (il_minus, False) duplicate_top generate_local_assignment (index_variable) method_body.put_opcode_mdtoken ({MD_OPCODES}.ldelema, actual_class_type_token (actual_generic.static_type_id)) if attached {CL_TYPE_A} array_type.generics.first as cl_type_i then create_expanded_object (cl_type_i) method_body.put_opcode_mdtoken ({MD_OPCODES}.stobj, actual_class_type_token (actual_generic.static_type_id)) else check is_type_expected: False end end mark_label (enter_loop_label) generate_local (index_variable) branch_on_true (continue_loop_label) generate_local (array_variable) end end generate_array_creation (a_type_id: INTEGER) -- Create a new NATIVE_ARRAY [A] where `a_type_id' corresponds -- to type id of `A'. do method_body.put_opcode_mdtoken ({MD_OPCODES}.Newarr, actual_class_type_token (a_type_id)) end generate_generic_array_creation (a_formal: FORMAL_A) -- Create a new NATIVE_ARRAY [X] where X is a formal type `a_formal'. do a_formal.generate_gen_type_il (Current, True) method_body.put_opcode ({MD_OPCODES}.ldarg_0) put_type_token (any_type.implementation_id (Void)) internal_generate_external_call (current_module.ise_runtime_token, 0, generic_conformance_class_name, "create_array", Static_type, <<integer_32_class_name, type_class_name, type_info_class_name, type_handle_class_name>>, system_object_class_name, False, Void) end generate_array_count -- Get length of current NATIVE_ARRAY on stack. do method_body.put_opcode ({MD_OPCODES}.Ldlen) convert_to_integer_32 end generate_array_upper -- Generate call to `count - 1'. do method_body.put_opcode ({MD_OPCODES}.Ldlen) method_body.put_opcode ({MD_OPCODES}.Ldc_i4_1) method_body.put_opcode ({MD_OPCODES}.Sub) end generate_array_lower -- Always `0' for native arrays as they are zero-based one -- dimensional array. do -- First we pop pushed array as it is not needed and -- then we push `0'. method_body.put_opcode ({MD_OPCODES}.Pop) method_body.put_opcode ({MD_OPCODES}.Ldc_i4_0) end feature -- Exception handling rescue_label: INTEGER -- Label used for rescue clauses to mark end of `try-catch'. -- Used at entry of the `try-catch' block. catch_label: INTEGER -- The second label used for rescue clauses to mark end of `try-catch'. -- Used in `catch' block. old_label: IL_LABEL -- Label used for marking the end of `try-catch' of old expression evaluation generate_start_exception_block -- Mark starting point for a routine that has -- a rescue clause. do rescue_label := method_body.define_label catch_label := method_body.define_label method_body.exception_block.set_start_position (method_body.count) end generate_start_rescue -- Mark beginning of rescue clause. do method_body.put_opcode_label ({MD_OPCODES}.Leave, rescue_label) method_body.exception_block.set_catch_position (method_body.count) method_body.exception_block.set_type_token (current_module.system_exception_token) -- Increase rescue level method_body.put_static_call (current_module.ise_enter_rescue_token, 0, False) -- We need to increment stack depth of 1 because CLI runtime automatically -- puts the exception object on top of stack and there is no automatic -- way to add it. method_body.update_stack_depth (1) method_body.put_static_call (current_module.ise_set_last_exception_token, 1, False) end generate_leave_to (a_label: IL_LABEL) -- Instead of using `branch_to' which is forbidden in a `try-catch' clause, -- we generate a `leave' opcode that has the same semantic except that it -- should branch outside the `try-catch' clause. do method_body.put_opcode_label ({MD_OPCODES}.Leave, a_label.id) end generate_end_exception_block -- Mark end of rescue clause. do put_boolean_constant (False) method_body.put_static_call (current_module.ise_rethrow_token, 1, False) -- Never invoked, but the CLI standards need this to terminate the catch block. method_body.put_opcode_label ({MD_OPCODES}.Leave, catch_label) method_body.exception_block.set_end_position (method_body.count) method_body.mark_label (rescue_label) method_body.mark_label (catch_label) end generate_get_last_exception -- Generate value of `get_last_exception' on stack. do method_body.put_static_call (current_module.ise_get_last_exception_token, 0, True) end generate_restore_last_exception -- Restores `last_exception' using the local. do method_body.put_static_call (current_module.ise_restore_last_exception_token, 1, False) end generate_start_old_try_block (a_ex_local: INTEGER) -- Generate start of try block at entry to evaluate old expression. -- `a_ex_local' is the local declaration position for the exception. do check current_old_exception_catch_block_not_void: method_body.current_old_exception_catch_block /= Void end old_label := create_label method_body.current_old_exception_catch_block.set_start_position (method_body.count) put_void generate_local_assignment (a_ex_local) end generate_catch_old_exception_block (a_ex_local: INTEGER) -- Generate catch block for old expression evaluatation -- `a_ex_local' is the local declaration position for the exception. do check current_old_exception_catch_block_not_void: method_body.current_old_exception_catch_block /= Void end generate_leave_to (old_label) method_body.current_old_exception_catch_block.set_catch_position (method_body.count) method_body.current_old_exception_catch_block.set_type_token (current_module.system_exception_token) ---- Generate catch block to save possible exception occurs at old expression evaluation. -- We need to increment stack depth of 1 because CLI runtime automatically -- puts the exception object on top of stack and there is no automatic -- way to add it. method_body.update_stack_depth (1) generate_local_assignment (a_ex_local) generate_leave_to (old_label) method_body.current_old_exception_catch_block.set_end_position (method_body.count) mark_label (old_label) if not method_body.is_last_old_expression_exception_block then method_body.forth_old_expression_exception_block end end prepare_old_expresssion_blocks (a_count: INTEGER) -- Prepare to generate `a_count' blocks for old expression evaluation do method_body.create_old_exception_catch_blocks (a_count) end generate_raising_old_exception (a_ex_local: INTEGER) -- Generate raising old violation exception when there was exception saved local l_label: IL_LABEL do generate_local (a_ex_local) put_void l_label := create_label method_body.put_opcode ({MD_OPCODES}.Ceq) branch_on_true (l_label) -- Raise old violation generate_local (a_ex_local) method_body.put_static_call (current_module.ise_raise_old_token, 1, False) mark_label (l_label) end generate_get_rescue_level -- Generate `get_rescue_level' on stack. do method_body.put_static_call (current_module.ise_get_rescue_level_token, 0, True) end generate_set_rescue_level -- Generate `set_rescue_level' using the local. do method_body.put_static_call (current_module.ise_set_rescue_level_token, 1, False) end feature -- Assertions generate_in_assertion_status -- Generate value of `in_assertion' on stack. do method_body.put_static_call (current_module.ise_in_assertion_token, 0, True) end generate_save_supplier_precondition -- Generate code to save the current supplier precondition in a local. do if current_class_type.is_expanded then -- Type is known at compile time. put_type_instance (current_class_type.type) else -- Type is evaluated at run time. generate_current internal_generate_external_call (current_module.mscorlib_token, 0, System_object_class_name, "GetType", Normal_type, <<>>, System_type_class_name, False, Void) end internal_generate_external_call (current_module.ise_runtime_token, 0, runtime_class_name, "save_supplier_precondition", Static_type, <<System_type_class_name>>, "System.Boolean", False, Void) end generate_restore_supplier_precondition -- Restores the supplier precondition flag using the local. do internal_generate_external_call (current_module.ise_runtime_token, 0, runtime_class_name, "restore_supplier_precondition", Static_type, <<"System.Boolean">>, Void, False, Void) end generate_is_assertion_checked (level: INTEGER) -- Check wether or not we need to check assertion for current type. do if current_class_type.is_expanded then -- Type is known at compile time. put_type_instance (current_class_type.type) else -- Type is evaluated at run time. generate_current internal_generate_external_call (current_module.mscorlib_token, 0, System_object_class_name, "GetType", Normal_type, <<>>, System_type_class_name, False, Void) end put_integer_32_constant (level) generate_local (byte_context.saved_supplier_precondition) internal_generate_external_call (current_module.ise_runtime_token, 0, runtime_class_name, "is_assertion_checked", Static_type, <<System_type_class_name, Assertion_level_enum_class_name, "System.Boolean">>, "System.Boolean", False, Void) end generate_set_assertion_status -- Set `in_assertion' flag with top of stack. do method_body.put_static_call (current_module.ise_set_in_assertion_token, 1, False) end generate_in_precondition_status -- Generate value of `in_assertion' on stack. do method_body.put_static_call (current_module.ise_in_precondition_token, 0, True) end generate_set_precondition_status -- Set `in_precondition' flag with top of stack. do method_body.put_static_call (current_module.ise_set_in_precondition_token, 1, False) end generate_assertion_check (assert_type: INTEGER; tag: STRING) -- Generate test after an assertion is being generated. -- If result of test is False, we raise an exception. local type_assert: INTEGER l_label: INTEGER do inspect assert_type when In_postcondition then type_assert := {EXCEP_CONST}.postcondition when In_check, in_guard then type_assert := {EXCEP_CONST}.check_instruction when In_loop_invariant then type_assert := {EXCEP_CONST}.loop_invariant when In_loop_variant then type_assert := {EXCEP_CONST}.loop_variant when In_invariant then type_assert := {EXCEP_CONST}.class_invariant end l_label := method_body.define_label method_body.put_opcode_label ({MD_OPCODES}.Brtrue, l_label) -- Before raising the assertion violation we reset `in_assertion' but only -- when it is not a guard because guard do not use `in_assertion'. if assert_type /= in_guard then put_boolean_constant (False) generate_set_assertion_status end generate_raise_exception (type_assert, tag) method_body.mark_label (l_label) end generate_precondition_check (tag: STRING; failure_block: IL_LABEL) -- Generate test after a precondition is generated -- If result of test is False we put `tag' in an -- exception object and go check next block of inherited -- preconditions and check them. If no more block, we raise -- an exception with exception object. local l_str_token: INTEGER do if tag = Void then put_void else uni_string.set_string (tag) l_str_token := md_emit.define_string (uni_string) method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldstr, l_str_token) end method_body.put_opcode_mdtoken ({MD_OPCODES}.Stsfld, current_module.ise_assertion_tag_token) method_body.put_opcode_label ({MD_OPCODES}.Brfalse, failure_block.id) end generate_precondition_violation -- Generate a precondition violation. -- Has to be a specific one because preconditions can be weaken. do put_boolean_constant (False) generate_set_precondition_status put_boolean_constant (False) generate_set_assertion_status put_integer_32_constant ({EXCEP_CONST}.precondition) method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldsfld, current_module.ise_assertion_tag_token) method_body.put_static_call (current_module.ise_raise_code_token, 2, False) end generate_raise_exception (a_code: INTEGER; a_tag: STRING) -- Generate an exception of type EIFFEL_EXCEPTION with code -- `a_code' and with tag `a_tag'. do put_integer_32_constant (a_code) if a_tag = Void then put_void else uni_string.set_string (a_tag) method_body.put_opcode_mdtoken ({MD_OPCODES}.Ldstr, md_emit.define_string (uni_string)) end method_body.put_static_call (current_module.ise_raise_code_token, 2, False) end generate_invariant_feature (feat: INVARIANT_FEAT_I) -- Generate `_invariant' that checks `current_class_type' invariants. local l_invariant_token: INTEGER l_dotnet_invariant_token: INTEGER l_sig: like method_sig do if feat = Void or else not current_class_type.is_expanded then -- Generate instance invariant feature even though class invariant is not defined. uni_string.set_string ("_invariant") l_dotnet_invariant_token := md_emit.define_method (uni_string, current_class_token, {MD_METHOD_ATTRIBUTES}.Public | {MD_METHOD_ATTRIBUTES}.Hide_by_signature | {MD_METHOD_ATTRIBUTES}.Virtual, default_sig, {MD_METHOD_ATTRIBUTES}.Managed) end if current_class_type.is_expanded then -- Code for expanded class does not use static features. if feat = Void then -- Generate code for inherited invariants only. start_new_body (l_dotnet_invariant_token) generate_invariant_body (Void) store_locals (l_dotnet_invariant_token, current_class_type) method_writer.write_current_body else -- Generate code for immediate and inherited invariants. generate_feature (feat, False, False, False) generate_feature_code (feat, False) end else -- First we generate the `$$_invariant' feature -- which only contains invariant for Current class. if feat /= Void then generate_feature (feat, False, True, False) generate_feature_code (feat, True) l_invariant_token := implementation_feature_token (current_type_id, feat.feature_id) else -- Generate empty invariant feature that does nothing. -- Will be used in descendant. l_sig := method_sig l_sig.reset l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Default_sig) l_sig.set_parameter_count (1) l_sig.set_return_type ({MD_SIGNATURE_CONSTANTS}.Element_type_void, 0) set_signature_type (l_sig, current_class_type.type, current_class_type) uni_string.set_string ("$$_invariant") l_invariant_token := md_emit.define_method (uni_string, current_class_token, {MD_METHOD_ATTRIBUTES}.Public | {MD_METHOD_ATTRIBUTES}.Hide_by_signature | {MD_METHOD_ATTRIBUTES}.Static, l_sig, {MD_METHOD_ATTRIBUTES}.Managed) start_new_body (l_invariant_token) generate_invariant_body (Void) store_locals (l_invariant_token, current_class_type) method_writer.write_current_body end current_module.internal_invariant_token. put (l_invariant_token, current_class_type.implementation_id) -- Generate invariant feature that calls above static version. start_new_body (l_dotnet_invariant_token) generate_current method_body.put_call ({MD_OPCODES}.Call, l_invariant_token, 0, False) generate_return (False) method_writer.write_current_body end end generate_invariant_body (byte_list: BYTE_LIST [BYTE_NODE]) -- Generate body of the routine that checks class invariant of the current class -- represented by `byte_list' (if any) as well as class invariant of ancestors. local l_end_of_invariant: IL_LABEL do l_end_of_invariant := create_label generate_invariant_checked_for (l_end_of_invariant) if byte_list /= Void then byte_list.process (cil_node_generator) end generate_inherited_invariants mark_label (l_end_of_invariant) generate_return (False) end generate_inherited_invariants -- Generate call to all directly inherited invariant features. local parents: FIXED_LIST [CL_TYPE_A] cl_type: CLASS_TYPE i, id: INTEGER l_list: SEARCH_TABLE [INTEGER] do parents := current_class_type.associated_class.parents create l_list.make (parents.count) across parents as p loop cl_type := byte_context.real_type (p.item).associated_class_type (current_class_type.type) id := cl_type.implementation_id if not l_list.has (id) then l_list.force (id) if not cl_type.is_external then generate_current_as_reference if system.il_verifiable and then not current_class.simple_conform_to (cl_type.associated_class) then generate_check_cast (current_class_type.type, cl_type.type) end method_body.put_call ({MD_OPCODES}.Call, invariant_token (id), 0, False) end i := i + 1 end end end generate_invariant_checked_for (a_label: IL_LABEL) -- Generate check to find out if we should check invariant or not. do put_type_token (current_class_type.type.static_type_id (Void)) method_body.put_static_call (current_module.ise_is_invariant_checked_for_token, 1, True) branch_on_true (a_label) end generate_invariant_checking (type_i: TYPE_A; entry: BOOLEAN) -- Generate an invariant check after routine call, it assumes that -- target has already been pushed onto evaluation stack. -- Is the invariant checking `entry'? do put_boolean_constant (entry) method_body.put_static_call (current_module.ise_check_invariant_token, 2, False) end feature -- Constants generation put_default_value (type: TYPE_A) -- Put default value of `type' on IL stack. do inspect type.element_type when {MD_SIGNATURE_CONSTANTS}.Element_type_boolean then put_boolean_constant (False) when {MD_SIGNATURE_CONSTANTS}.Element_type_char then put_character_constant ('%U') when {MD_SIGNATURE_CONSTANTS}.Element_type_r8 then put_real_64_constant (0.0) when {MD_SIGNATURE_CONSTANTS}.Element_type_r4 then put_real_32_constant ({REAL_32} 0.0) when {MD_SIGNATURE_CONSTANTS}.Element_type_u1 then put_natural_8_constant (0) when {MD_SIGNATURE_CONSTANTS}.Element_type_u2 then put_natural_16_constant (0) when {MD_SIGNATURE_CONSTANTS}.Element_type_u4 then put_natural_32_constant (0) when {MD_SIGNATURE_CONSTANTS}.Element_type_u8 then put_natural_64_constant (0) when {MD_SIGNATURE_CONSTANTS}.Element_type_i then put_integer_32_constant (0) convert_to_native_int when {MD_SIGNATURE_CONSTANTS}.Element_type_i1 then put_integer_8_constant (0) when {MD_SIGNATURE_CONSTANTS}.Element_type_i2 then put_integer_16_constant (0) when {MD_SIGNATURE_CONSTANTS}.Element_type_i4 then put_integer_32_constant (0) when {MD_SIGNATURE_CONSTANTS}.Element_type_i8 then put_integer_64_constant (0) else put_void end end put_void -- Add a Void element on stack. do method_body.put_opcode ({MD_OPCODES}.Ldnull) end put_manifest_string_from_system_string_local (n: INTEGER) -- Create a manifest string by using local at position `n' which -- should be of type SYSTEM_STRING. do create_object (string_implementation_id) duplicate_top generate_local (n) internal_generate_feature_access (string_implementation_id, string_make_feat_id, 1, False, True) end put_manifest_string (s: READABLE_STRING_GENERAL) -- Put `s' on IL stack. do create_object (string_implementation_id) duplicate_top put_system_string (s) internal_generate_feature_access (string_implementation_id, string_make_feat_id, 1, False, True) end put_immutable_manifest_string_8 (s: READABLE_STRING_GENERAL) -- Put `s' on IL stack. do create_object (immutable_string_8_implementation_id) duplicate_top put_system_string (s) internal_generate_feature_access (immutable_string_8_implementation_id, immutable_string_8_make_feat_id, 1, False, True) end put_manifest_string_32_from_system_string_local (n: INTEGER) -- Create a manifest string by using local at position `n' which -- should be of type SYSTEM_STRING. do create_object (string_32_implementation_id) duplicate_top generate_local (n) internal_generate_feature_access (string_32_implementation_id, string_32_make_feat_id, 1, False, True) end put_manifest_string_32 (s: READABLE_STRING_32) -- Put `s' on IL stack. do create_object (string_32_implementation_id) duplicate_top put_system_string_32 (s) internal_generate_feature_access (string_32_implementation_id, string_32_make_feat_id, 1, False, True) end put_immutable_manifest_string_32 (s: READABLE_STRING_32) -- Put `s' on IL stack. do create_object (immutable_string_32_implementation_id) duplicate_top put_system_string_32 (s) internal_generate_feature_access (immutable_string_32_implementation_id, immutable_string_32_make_feat_id, 1, False, True) end put_system_string (s: READABLE_STRING_GENERAL) -- Put `System.String' object corresponding to `s' on IL stack. do uni_string.set_string (s) method_body.put_string (md_emit.define_string (uni_string)) end put_system_string_32 (s: READABLE_STRING_32) -- Put `System.String' object corresponding to `s' on IL stack. do uni_string.set_string (s) method_body.put_string (md_emit.define_string (uni_string)) end put_numeric_integer_constant (type: TYPE_A; i: INTEGER) -- Put `i' as a constant of type `type'. do inspect type.element_type when {MD_SIGNATURE_CONSTANTS}.Element_type_r8 then put_real_64_constant (i) when {MD_SIGNATURE_CONSTANTS}.Element_type_r4 then put_real_32_constant (i) when {MD_SIGNATURE_CONSTANTS}.Element_type_u1 then put_natural_8_constant (i.as_natural_8) when {MD_SIGNATURE_CONSTANTS}.Element_type_u2 then put_natural_16_constant (i.as_natural_16) when {MD_SIGNATURE_CONSTANTS}.Element_type_u4 then put_natural_32_constant (i.as_natural_32) when {MD_SIGNATURE_CONSTANTS}.Element_type_u8 then put_natural_64_constant (i.as_natural_64) when {MD_SIGNATURE_CONSTANTS}.Element_type_i1 then put_integer_8_constant (i) when {MD_SIGNATURE_CONSTANTS}.Element_type_i2 then put_integer_16_constant (i) when {MD_SIGNATURE_CONSTANTS}.Element_type_i4 then put_integer_32_constant (i) when {MD_SIGNATURE_CONSTANTS}.Element_type_i8 then put_integer_64_constant (i) else check False end end end put_integer_8_constant, put_integer_16_constant, put_integer_32_constant (i: INTEGER) -- Put `i' as INTEGER_8, INTEGER_16, INTEGER on IL stack do inspect i when 0 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_0) when 1 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_1) when 2 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_2) when 3 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_3) when 4 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_4) when 5 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_5) when 6 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_6) when 7 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_7) when 8 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_8) else method_body.put_opcode_integer ({MD_OPCODES}.Ldc_i4, i) end end put_integer_64_constant (i: INTEGER_64) -- Put `i' as INTEGER_64 on IL stack do method_body.put_opcode_integer_64 ({MD_OPCODES}.Ldc_i8, i) end put_natural_8_constant, put_natural_16_constant, put_natural_32_constant (n: NATURAL_32) -- Put `n' as NATURAL_8, NATURAL_16, NATURAL_32 on IL stack. do fixme ("Remove conversion to INTEGER_32 after bootstrap.") inspect n.as_integer_32 when 0 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_0) when 1 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_1) when 2 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_2) when 3 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_3) when 4 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_4) when 5 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_5) when 6 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_6) when 7 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_7) when 8 then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_8) else method_body.put_opcode_natural_32 ({MD_OPCODES}.Ldc_i4, n) end end put_natural_64_constant (n: NATURAL_64) -- Put `n' as NATURAL_64 on IL stack. do method_body.put_opcode_natural_64 ({MD_OPCODES}.Ldc_i8, n) end put_real_32_constant (r: REAL) -- Put `d' on IL stack. do method_body.put_opcode_real_32 ({MD_OPCODES}.Ldc_r4, r) end put_real_64_constant (d: DOUBLE) -- Put `d' on IL stack. do method_body.put_opcode_real_64 ({MD_OPCODES}.Ldc_r8, d) end put_character_constant (c: CHARACTER) -- Put `c' on IL stack. do method_body.put_opcode_integer ({MD_OPCODES}.Ldc_i4, c.code) end put_boolean_constant (b: BOOLEAN) -- Put `b' on IL stack. do if b then method_body.put_opcode ({MD_OPCODES}.ldc_i4_1) else method_body.put_opcode ({MD_OPCODES}.ldc_i4_0) end end feature -- Labels and branching branch_on_true (label: IL_LABEL) -- Generate a branch instruction to `label' if top of -- IL stack is True. do method_body.put_opcode_label ({MD_OPCODES}.Brtrue, label.id) end branch_on_false (label: IL_LABEL) -- Generate a branch instruction to `label' if top of -- IL stack is False. do method_body.put_opcode_label ({MD_OPCODES}.Brfalse, label.id) end branch_to (label: IL_LABEL) -- Generate a branch instruction to `label'. do method_body.put_opcode_label ({MD_OPCODES}.Br, label.id) end branch_on_condition (comparison: INTEGER_16; label: IL_LABEL) -- Generate a branch instruction to `label' if two top-level operands on -- IL stack when compared using conditional instruction `comparison' yield True. do method_body.put_opcode_label (comparison, label.id) end mark_label (label: IL_LABEL) -- Mark a portion of code with `label'. do method_body.mark_label (label.id) end create_label: IL_LABEL -- Create a new label do create Result.make (method_body.define_label) end feature -- Switch instruction put_switch_start (count: INTEGER) -- Generate start of a switch instruction with `count' items. do method_body.put_opcode_integer ({MD_OPCODES}.switch, count) switch_count := count end put_switch_label (label: IL_LABEL) -- Generate a branch to `label' in switch instruction. do switch_count := switch_count - 1 -- Labels of switch instruction are calculated relative to instruction end method_body.put_label (label.id, - switch_count * 4) end feature -- Binary operator generation generate_binary_operator (code: INTEGER; is_unsigned: BOOLEAN) -- Generate a binary operator represented by `code'. -- Look in IL_CONST for `code' definition. do inspect code when il_eq then method_body.put_opcode ({MD_OPCODES}.Ceq) when il_ne then method_body.put_opcode ({MD_OPCODES}.Ceq) method_body.put_opcode ({MD_OPCODES}.Ldc_i4_0) method_body.put_opcode ({MD_OPCODES}.Ceq) when il_le then if is_unsigned then method_body.put_opcode ({MD_OPCODES}.cgt_un) else method_body.put_opcode ({MD_OPCODES}.Cgt) end method_body.put_opcode ({MD_OPCODES}.Ldc_i4_0) method_body.put_opcode ({MD_OPCODES}.Ceq) when il_lt then if is_unsigned then method_body.put_opcode ({MD_OPCODES}.clt_un) else method_body.put_opcode ({MD_OPCODES}.Clt) end when il_ge then if is_unsigned then method_body.put_opcode ({MD_OPCODES}.clt_un) else method_body.put_opcode ({MD_OPCODES}.Clt) end method_body.put_opcode ({MD_OPCODES}.Ldc_i4_0) method_body.put_opcode ({MD_OPCODES}.Ceq) when il_gt then if is_unsigned then method_body.put_opcode ({MD_OPCODES}.cgt_un) else method_body.put_opcode ({MD_OPCODES}.Cgt) end when il_star then method_body.put_opcode ({MD_OPCODES}.Mul) when il_power then method_body.put_static_call (current_module.power_method_token, 2, True) when il_plus then method_body.put_opcode ({MD_OPCODES}.Add) when il_mod then if is_unsigned then method_body.put_opcode ({MD_OPCODES}.rem_un) else method_body.put_opcode ({MD_OPCODES}.Rem) end when il_minus then method_body.put_opcode ({MD_OPCODES}.Sub) when il_div, il_slash then if is_unsigned then method_body.put_opcode ({MD_OPCODES}.div_un) else method_body.put_opcode ({MD_OPCODES}.Div) end when il_xor then method_body.put_opcode ({MD_OPCODES}.Xor_opcode) when il_or then method_body.put_opcode ({MD_OPCODES}.Or_opcode) when il_and then method_body.put_opcode ({MD_OPCODES}.And_opcode) when il_shl then method_body.put_opcode ({MD_OPCODES}.Shl) when il_shr then if is_unsigned then method_body.put_opcode ({MD_OPCODES}.shr_un) else method_body.put_opcode ({MD_OPCODES}.Shr) end end end generate_real_comparison_routine (a_code: INTEGER; is_real_32: BOOLEAN; a_return_type: TYPE_A) -- <Precursor> local l_routine_name: STRING l_return_type: STRING do inspect a_code when il_eq, il_ne then if is_real_32 then l_routine_name := once "is_equal_real_32" else l_routine_name := once "is_equal_real_64" end when il_le then if is_real_32 then l_routine_name := once "is_less_equal_real_32" else l_routine_name := once "is_less_equal_real_64" end when il_lt then if is_real_32 then l_routine_name := once "is_less_real_32" else l_routine_name := once "is_less_real_64" end when il_ge then if is_real_32 then l_routine_name := once "is_greater_equal_real_32" else l_routine_name := once "is_greater_equal_real_64" end when il_gt then if is_real_32 then l_routine_name := once "is_greater_real_32" else l_routine_name := once "is_greater_real_64" end when il_min then if is_real_32 then l_routine_name := once "min_real_32" else l_routine_name := once "min_real_64" end when il_max then if is_real_32 then l_routine_name := once "max_real_32" else l_routine_name := once "max_real_64" end when il_three_way_comparison then if is_real_32 then l_routine_name := once "three_way_comparison_real_32" else l_routine_name := once "three_way_comparison_real_64" end end if a_return_type.is_boolean then l_return_type := "System.Boolean" elseif attached {INTEGER_A} a_return_type as l_type then l_return_type := "System.Int" l_return_type.append_integer (l_type.size) elseif a_return_type.is_real_32 then l_return_type := "System.Single" elseif a_return_type.is_real_64 then l_return_type := "System.Double" end if is_real_32 then internal_generate_external_call (current_module.ise_runtime_token, current_module.ise_runtime_type_token, Void, l_routine_name, static_type, <<"System.Single", "System.Single">>, l_return_type, False, Void) else internal_generate_external_call (current_module.ise_runtime_token, current_module.ise_runtime_type_token, Void, l_routine_name, static_type, <<"System.Double", "System.Double">>, l_return_type, False, Void) end if a_code = il_ne then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_0) method_body.put_opcode ({MD_OPCODES}.Ceq) end end feature -- Unary operator generation generate_unary_operator (code: INTEGER) -- Generate a binary operator represented by `code'. -- Look in IL_CONST for `code' definition. do inspect code when il_uplus then -- Nothing to be done here. when il_uminus then method_body.put_opcode ({MD_OPCODES}.Neg) when il_not then method_body.put_opcode ({MD_OPCODES}.Ldc_i4_0) method_body.put_opcode ({MD_OPCODES}.Ceq) when il_bitwise_not then method_body.put_opcode ({MD_OPCODES}.Not_opcode) end end feature -- Basic feature generate_upper_lower (is_upper: BOOLEAN) -- Generate upper if `is_upper', lower otherwise on CHARACTER. local l_rout_token: INTEGER l_sig: like method_sig do l_sig := method_sig l_sig.reset l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Default_sig) l_sig.set_parameter_count (1) set_method_return_type (l_sig, Character_type, current_class_type) set_signature_type (l_sig, Character_type, current_class_type) if is_upper then uni_string.set_string ("ToUpper") else uni_string.set_string ("ToLower") end l_rout_token := md_emit.define_member_ref (uni_string, current_module.char_type_token, l_sig) method_body.put_static_call (l_rout_token, 1, True) end generate_is_query_on_character (query_name: STRING) -- Generate is_`query_name' on CHARACTER returning a boolean. local l_query_token: INTEGER l_sig: like method_sig do l_sig := method_sig l_sig.reset l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Default_sig) l_sig.set_parameter_count (1) set_method_return_type (l_sig, Boolean_type, current_class_type) set_signature_type (l_sig, Character_type, current_class_type) uni_string.set_string (query_name) l_query_token := md_emit.define_member_ref (uni_string, current_module.char_type_token, l_sig) method_body.put_static_call (l_query_token, 1, True) end generate_is_query_on_real (is_real_32: BOOLEAN; query_name: STRING) -- Generate static call `query_name' on REAL_32 taking a REAL_32 as argument -- if `is_real_32', otherwise using REAL_64, and returning a boolean. local l_query_token: INTEGER l_sig: like method_sig do l_sig := method_sig l_sig.reset l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Default_sig) l_sig.set_parameter_count (1) set_method_return_type (l_sig, Boolean_type, current_class_type) if is_real_32 then set_signature_type (l_sig, Real_32_type, current_class_type) else set_signature_type (l_sig, Real_64_type, current_class_type) end uni_string.set_string (query_name) if is_real_32 then l_query_token := md_emit.define_member_ref (uni_string, current_module.real_32_type_token, l_sig) else l_query_token := md_emit.define_member_ref (uni_string, current_module.real_64_type_token, l_sig) end method_body.put_static_call (l_query_token, 1, True) end generate_math_one_argument (a_name: STRING; type: TYPE_A) -- Generate `a_name' feature call on basic types using a Math function where -- the signature is "(type): type" local l_math_token: INTEGER l_sig: like method_sig do create l_sig.make l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Default_sig) l_sig.set_parameter_count (1) set_method_return_type (l_sig, type, current_class_type) set_signature_type (l_sig, type, current_class_type) uni_string.set_string (a_name) l_math_token := md_emit.define_member_ref (uni_string, current_module.math_type_token, l_sig) method_body.put_static_call (l_math_token, 1, True) end generate_math_two_arguments (a_name: STRING; type: TYPE_A) -- Generate `a_name' feature call on basic types using a Math function where -- the signature is "(type, type): type" local l_math_token: INTEGER l_sig: like method_sig do l_sig := method_sig l_sig.reset l_sig.set_method_type ({MD_SIGNATURE_CONSTANTS}.Default_sig) l_sig.set_parameter_count (2) set_method_return_type (l_sig, type, current_class_type) set_signature_type (l_sig, type, current_class_type) set_signature_type (l_sig, type, current_class_type) uni_string.set_string (a_name) l_math_token := md_emit.define_member_ref (uni_string, current_module.math_type_token, l_sig) method_body.put_static_call (l_math_token, 2, True) end generate_to_string -- Generate call on `ToString'. do method_body.put_call ({MD_OPCODES}.Callvirt, current_module.to_string_method_token, 0, True) end generate_hash_code -- Given an INTEGER on top of stack, put on stack -- a positive INTEGER. do convert_to_integer_32 put_integer_32_constant (0x7FFFFFFF) method_body.put_opcode ({MD_OPCODES}.And_opcode) end generate_out (type: TYPE_A) -- Generate `out' on basic types. local local_number: INTEGER do -- Generate `out' representation in IL format generate_external_metamorphose (type) generate_to_string -- Store value byte_context.add_local (System_string_type) local_number := byte_context.local_list.count put_dummy_local_info (System_string_type, local_number) generate_local_assignment (local_number) put_manifest_string_from_system_string_local (local_number) if type.is_pointer or type.is_typed_pointer then -- Handling a POINTER type, we need to prepend `0x' to the output. duplicate_top put_manifest_string ("0x") internal_generate_feature_access (string_type_id, string_prepend_feat_id, 1, False, True) end end feature -- Line info put_line_info (n: INTEGER) -- Generate debug information at line `n'. local l_pos: INTEGER do if is_debug_info_enabled and then not stop_breakpoints_generation then l_pos := dbg_offsets_count dbg_offsets.force (method_body.count, l_pos) dbg_start_lines.force (n + pragma_offset, l_pos) dbg_start_columns.force (0, l_pos) dbg_end_lines.force (n + pragma_offset, l_pos) dbg_end_columns.force (1000, l_pos) dbg_offsets_count := l_pos + 1 Il_debug_info_recorder.record_line_info (current_class_type, Byte_context.current_feature, method_body.count, n) method_body.put_nop end end put_silent_line_info (n: INTEGER) -- Generate debug information at line `n'. -- But in case of dotnet debugger inside eStudio -- ignore those 'dummy' nope. do if is_debug_info_enabled and then not stop_breakpoints_generation then Il_debug_info_recorder.ignore_next_debug_info put_line_info (n) end end put_debug_info (location: LOCATION_AS) -- Generate debug information for `location' to enable to -- find corresponding Eiffel class file in IL code. local l_pos: INTEGER do if is_debug_info_enabled and then not stop_breakpoints_generation then l_pos := dbg_offsets_count dbg_offsets.force (method_body.count, l_pos) dbg_start_lines.force (location.line + pragma_offset, l_pos) dbg_start_columns.force (location.column, l_pos) dbg_end_lines.force (location.line + pragma_offset, l_pos) dbg_end_columns.force (location.final_column, l_pos) dbg_offsets_count := l_pos + 1 Il_debug_info_recorder.record_line_info (current_class_type, Byte_context.current_feature, method_body.count, location.line) method_body.put_nop end end put_ghost_debug_infos (a_line_n:INTEGER; a_nb: INTEGER) -- Generate `a_nb' ghost debug informations, -- this is to deal with the not generated debug clauses -- but displayed in eStudio during debugging do if is_debug_info_enabled then Il_debug_info_recorder.record_ghost_debug_infos (current_class_type, Byte_context.current_feature, method_body.count, a_line_n, a_nb) end end put_silent_debug_info (location: LOCATION_AS) -- Generate debug information for `location' to enable to -- find corresponding Eiffel class file in IL code. -- But in case of dotnet debugger inside eStudio -- ignore those 'dummy' nope. do if is_debug_info_enabled and then not stop_breakpoints_generation then Il_debug_info_recorder.ignore_next_debug_info put_debug_info (location) end end flush_sequence_points (a_class_type: CLASS_TYPE) -- Flush all sequence points. local l_sequence_point_list: LINKED_LIST [like sequence_point] l_document: DBG_DOCUMENT_WRITER do if is_debug_info_enabled then if internal_document /= Void then l_document := current_module.dbg_pragma_documents (internal_document) else l_document := dbg_documents (a_class_type.associated_class.class_id) end dbg_writer.open_local_signature (l_document, method_body.local_token) dbg_writer.define_sequence_points ( l_document, dbg_offsets_count, dbg_offsets, dbg_start_lines, dbg_start_columns, dbg_end_lines, dbg_end_columns) dbg_writer.close_local_signature (l_document) l_sequence_point_list := current_module.method_sequence_points.item (current_feature_token) if l_sequence_point_list = Void then create l_sequence_point_list.make current_module.method_sequence_points.put (l_sequence_point_list, current_feature_token) end l_sequence_point_list.extend ([dbg_offsets_count, dbg_offsets, dbg_start_lines, dbg_start_columns, dbg_end_lines, dbg_end_columns, a_class_type.associated_class.class_id]) -- Reset offsets. create dbg_offsets.make_filled (0, 0, 5) create dbg_start_lines.make_filled (0, 0, 5) create dbg_start_columns.make_filled (0, 0, 5) create dbg_end_lines.make_filled (0, 0, 5) create dbg_end_columns.make_filled (0, 0, 5) dbg_offsets_count := 0 end end set_pragma_offset (a_offset: INTEGER) -- Set line pragma offset for debug info. do pragma_offset := a_offset ensure then pragma_offset_set: pragma_offset = a_offset end set_default_document -- Restore debug document to default. do internal_document := Void ensure then internal_document_void: internal_document = Void end set_stop_breakpoints_generation (a_bool: BOOLEAN) -- Should breakpoints not be generated? do stop_breakpoints_generation := a_bool ensure then set: stop_breakpoints_generation = a_bool end set_document (a_doc: STRING) -- Set debug document to `a_doc'. do internal_document := a_doc ensure then internal_document_set: internal_document = a_doc end internal_document: STRING -- Document used to generate debug info as stated by pragma declaration if any pragma_offset: INTEGER -- Offset in document used for debug info as stated by pragma declaration stop_breakpoints_generation: BOOLEAN -- Should breakpoints not be generated? feature {INTERNAL_COMPILER_STRING_EXPORTER} -- Compilation error handling last_error: STRING -- Last exception which occurred during IL generation feature -- Convenience generate_call_on_void_target_exception -- Generate call on void target exception. do internal_generate_external_call (current_module.ise_runtime_token, 0, runtime_class_name, "generate_call_on_void_target_exception", static_type, <<>>, Void, False, Void) end feature -- Generic conformance generate_class_type_instance (cl_type: CL_TYPE_A) -- Generate a CLASS_TYPE instance corresponding to `cl_type'. local l_rt_type_id: INTEGER l_cl_type_id: INTEGER do if cl_type.is_basic then l_rt_type_id := basic_type_id l_cl_type_id := cl_type.external_id (current_class_type.type) else l_rt_type_id := class_type_id l_cl_type_id := cl_type.implementation_id (current_class_type.type) end create_object (l_rt_type_id) duplicate_top put_type_token (l_cl_type_id) internal_generate_external_call (current_module.ise_runtime_token, 0, class_type_class_name, "set_type", Normal_type, <<type_handle_class_name>>, Void, True, Void) end generate_generic_type_instance (n: INTEGER) -- Generate a GENERIC_TYPE instance corresponding that will hold `n' items. do create_object (generic_type_id) duplicate_top put_integer_32_constant (n) generate_array_creation (runtime_type_id) end generate_tuple_type_instance (n: INTEGER) -- Generate a RT_TUPLE_TYPE instance corresponding that will hold `n' items. do create_object (tuple_type_id) duplicate_top put_integer_32_constant (n) generate_array_creation (runtime_type_id) end generate_generic_type_settings (gen_type: TYPE_A) -- Generate a CLASS_TYPE instance corresponding to `cl_type'. do internal_generate_external_call (current_module.ise_runtime_token, 0, generic_type_class_name, "set_generics", Normal_type, <<type_array_class_name>>, Void, True, Void); duplicate_top put_type_token (gen_type.implementation_id (current_class_type.type)) internal_generate_external_call (current_module.ise_runtime_token, 0, generic_type_class_name, "set_type", Normal_type, <<type_handle_class_name>>, Void, True, Void) end generate_none_type_instance -- Generate a NONE_TYPE instance. do create_object (none_type_id) end generate_generating_type_instance (a_gen_type: TYPE_A) -- Generate an instance of the generic type `a_gen_type' where the type -- of the actual generic parameter is the type of the object on top -- of the stack. -- Useful to generate {ANY}.generating_type. local l_obj_var: INTEGER do -- First we store the top to a local variable. byte_context.add_local (any_type) l_obj_var := Byte_context.local_list.count put_dummy_local_info (any_type, l_obj_var) generate_local_assignment (l_obj_var) -- Create the RT_GENERIC_TYPE instance create_object (generic_type_id) duplicate_top put_integer_32_constant (1) generate_array_creation (runtime_type_id) -- Write the type of current object to the type array at position `0'. duplicate_top put_integer_32_constant (0) generate_local (l_obj_var) load_type generate_array_write ({IL_CONST}.il_ref, 0) -- Now set the RT_GENERIC_TYPE instance with the proper details generate_generic_type_settings (a_gen_type) -- Create the `gen_type' instance. create_generic_object (a_gen_type.implementation_id (current_class_type.type)) end feature {NONE} -- Implementation: generation generate_type_feature (a_type_feature: TYPE_FEATURE_I) -- Generate type description for `a_type_feature'. require a_type_feature_not_void: a_type_feature /= Void local l_cl_type: CL_TYPE_A l_gen_type: GEN_TYPE_A l_tuple_type: TUPLE_TYPE_A l_formal_type: FORMAL_A l_type_i: TYPE_A l_org_type_i: TYPE_A l_type_id, i, nb: INTEGER do l_type_i := a_type_feature.type -- We are now evaluation `l_type_i' in the context of current CLASS_TYPE -- generation. check -- If we have some formals, we are clearly in a generic class. is_generic_type: l_type_i.has_formal_generic implies current_class_type.is_generic end l_org_type_i := l_type_i l_type_i := l_type_i.adapted_in (current_class_type) if l_org_type_i.is_formal and then l_type_i.has_formal_generic then -- The case similar to "A [expanded B [G#1, G#2]]". -- Because no features are generated to resolve G#1 and G#2, -- the type is set to be a formal generic like for "A [G]" debug ("fixme") fixme ("Support the case of A [expanded B [G#1, G#2]]") end l_type_i := l_org_type_i end if attached {FORMAL_A} l_type_i as f then l_formal_type := f l_type_id := formal_type_id elseif l_type_i.is_none then l_type_id := none_type_id elseif attached {CL_TYPE_A} l_type_i as c then l_cl_type := c if l_cl_type.is_basic then l_type_id := basic_type_id elseif attached {GEN_TYPE_A} l_cl_type as g then l_gen_type := g if attached {TUPLE_TYPE_A} l_gen_type as t then l_tuple_type := t l_type_id := tuple_type_id else l_type_id := generic_type_id end else l_type_id := class_type_id end end start_new_body (feature_token (current_type_id, a_type_feature.feature_id)) -- Set position of `result' local variable. Does not make sense to -- call `put_result_info' as we don't know its associated CL_TYPE_A. result_position := 0 create_object (l_type_id) if l_type_id = formal_type_id then duplicate_top put_integer_32_constant (l_formal_type.position) internal_generate_external_call (current_module.ise_runtime_token, 0, formal_type_class_name, "set_position", Normal_type, <<integer_32_class_name>>, Void, True, Void) elseif l_type_id = none_type_id then -- Nothing to be done, it is enough to create an instance of NONE_TYPE elseif l_type_id = class_type_id then -- Non-generic class. duplicate_top put_type_token (l_cl_type.implementation_id (current_class_type.type)) internal_generate_external_call (current_module.ise_runtime_token, 0, class_type_class_name, "set_type", Normal_type, <<type_handle_class_name>>, Void, True, Void) elseif l_type_id = basic_type_id then duplicate_top -- Make sure to use `external_id' like in `generate_class_type_instance' -- otherwise eweasel test#exec223 would fail. put_type_token (l_cl_type.external_id (current_class_type.type)) internal_generate_external_call (current_module.ise_runtime_token, 0, basic_type_class_name, "set_type", Normal_type, <<type_handle_class_name>>, Void, True, Void) else duplicate_top put_integer_32_constant (l_gen_type.generics.count) generate_array_creation (runtime_type_id) from i := l_gen_type.generics.lower check i_start_at_one: i = 1 end nb := l_gen_type.generics.upper until i > nb loop duplicate_top put_integer_32_constant (i - 1) l_gen_type.generics.i_th (i).generate_gen_type_il (Current, True) generate_array_write ({IL_CONST}.il_ref, 0) i := i + 1 end internal_generate_external_call (current_module.ise_runtime_token, 0, generic_type_class_name, "set_generics", normal_type, <<type_array_class_name>>, Void, True, Void) duplicate_top put_type_token (l_gen_type.implementation_id (current_class_type.type)) internal_generate_external_call (current_module.ise_runtime_token, 0, generic_type_class_name, "set_type", normal_type, <<type_handle_class_name>>, Void, True, Void) end generate_return (True) method_writer.write_current_body end feature {CIL_CODE_GENERATOR} -- Implementation: convenience System_string_type: TYPE_A -- Type of string object once Result := System.system_string_class.compiled_class.types.first.type end System_object_type: TYPE_A -- Type of Object object once Result := System.system_object_class.compiled_class.types.first.type end system_type_type: TYPE_A -- Type of Type object once Result := System.system_type_class.compiled_class.types.first.type end string_type: TYPE_A -- Type of string object once Result := System.string_8_class.compiled_class.types.first.type end string_implementation_id: INTEGER -- Type ID of string implementation. once Result := string_type.implementation_id (Void) end string_type_id: INTEGER -- Type of string interface. once Result := string_type.static_type_id (Void) end string_prepend_feat_id: INTEGER -- Feature ID of `make_from_cil' of STRING. once Result := System.string_8_class.compiled_class. feature_table.item ("prepend").feature_id ensure string_prepend_feat_id_positive: Result > 0 end string_make_feat_id: INTEGER -- Feature ID of `make_from_cil' of STRING. once Result := System.string_8_class.compiled_class. feature_table.item_id ({PREDEFINED_NAMES}.make_from_cil_name_id).feature_id ensure string_make_feat_id_positive: Result > 0 end string_32_type: TYPE_A -- Type of string object once Result := System.string_32_class.compiled_class.types.first.type end string_32_implementation_id: INTEGER -- Type ID of string implementation. once Result := string_32_type.implementation_id (Void) end string_32_type_id: INTEGER -- Type of string interface. once Result := string_32_type.static_type_id (Void) end string_32_prepend_feat_id: INTEGER -- Feature ID of `make_from_cil' of STRING. once Result := System.string_32_class.compiled_class. feature_table.item ("prepend").feature_id ensure string_32_prepend_feat_id_positive: Result > 0 end string_32_make_feat_id: INTEGER -- Feature ID of `make_from_cil' of STRING. once Result := System.string_32_class.compiled_class. feature_table.item_id ({PREDEFINED_NAMES}.make_from_cil_name_id).feature_id ensure string_32_make_feat_id_positive: Result > 0 end immutable_string_8_type: TYPE_A -- Type of IMMUTABLE_STRING_8 object once Result := System.immutable_string_8_class.compiled_class.types.first.type end immutable_string_8_implementation_id: INTEGER -- Type ID of IMMUTABLE_STRING_8 implementation. once Result := immutable_string_8_type.implementation_id (Void) end immutable_string_8_type_id: INTEGER -- Type of IMMUTABLE_STRING_8 interface. once Result := immutable_string_8_type.static_type_id (Void) end immutable_string_8_make_feat_id: INTEGER -- Feature ID of `make_from_cil' of STRING. once Result := System.immutable_string_8_class.compiled_class. feature_table.item_id ({PREDEFINED_NAMES}.make_from_cil_name_id).feature_id ensure immutable_string_8_make_feat_id_positive: Result > 0 end immutable_string_32_type: TYPE_A -- Type of IMMUTABLE_STRING_32 object once Result := System.immutable_string_32_class.compiled_class.types.first.type end immutable_string_32_implementation_id: INTEGER -- Type ID of IMMUTABLE_STRING_32 implementation. once Result := immutable_string_32_type.implementation_id (Void) end immutable_string_32_type_id: INTEGER -- Type of IMMUTABLE_STRING_32 interface. once Result := immutable_string_32_type.static_type_id (Void) end immutable_string_32_make_feat_id: INTEGER -- Feature ID of `make_from_cil' of STRING. once Result := System.immutable_string_32_class.compiled_class. feature_table.item_id ({PREDEFINED_NAMES}.make_from_cil_name_id).feature_id ensure immutable_string_32_make_feat_id_positive: Result > 0 end any_type: CL_TYPE_A -- Type of ANY once Result := system.any_class.compiled_class.actual_type end any_type_id: INTEGER -- Type of ANY interface. once Result := any_type.static_type_id (Void) end is_equal_feat_id: INTEGER -- Feature ID of `is_equal' of ANY. once Result := System.any_class.compiled_class.feature_with_rout_id (is_equal_rout_id).feature_id ensure is_equal_feat_id_positive: Result > 0 end is_equal_rout_id: INTEGER -- Routine ID of `is_equal' of ANY. once Result := System.any_class.compiled_class. feature_table.item_id ({PREDEFINED_NAMES}.is_equal_name_id).rout_id_set.first ensure is_equal_rout_id_positive: Result > 0 end copy_feat_id: INTEGER -- Feature ID of `copy' of ANY. once Result := System.any_class.compiled_class.feature_with_rout_id (copy_rout_id).feature_id ensure copy_feat_id_positive: Result > 0 end copy_rout_id: INTEGER -- Routine ID of `copy' of ANY. once Result := System.any_class.compiled_class. feature_table.item_id ({PREDEFINED_NAMES}.copy_name_id).rout_id_set.first ensure copy_rout_id_positive: Result > 0 end equals_rout_id: INTEGER -- Routine ID of `equals' of SYSTEM_OBJECT. local c: CLASS_C f: FEATURE_I once c := System.system_object_class.compiled_class if c.feature_table.has_overloaded ({PREDEFINED_NAMES}.equals_name_id) then across c.feature_table.overloaded_items ({PREDEFINED_NAMES}.equals_name_id) as l from l.start f := l.item l.forth until -- "public virtual bool Equals (System.Object)" not f.is_class and then f.argument_count = 1 and then f.arguments.first.same_as (c.actual_type) loop f := l.item end else f := c.feature_table.item_id ({PREDEFINED_NAMES}.equals_name_id) end if f /= Void then Result := f.rout_id_set.first else check has_equals_rout_id: False then -- Raise an exception, as "equals" is required. end end ensure equals_rout_id_positive: Result > 0 end finalize_rout_id: INTEGER -- Routine ID of `finalize' of SYSTEM_OBJECT. once Result := System.system_object_class.compiled_class.feature_table. item_id ({PREDEFINED_NAMES}.finalize_name_id).rout_id_set.first ensure finalize_rout_id_positive: Result > 0 end get_hash_code_rout_id: INTEGER -- Routine ID of `get_hash_code' of SYSTEM_OBJECT. once Result := System.system_object_class.compiled_class.feature_table. item_id ({PREDEFINED_NAMES}.get_hash_code_name_id).rout_id_set.first ensure get_hash_code_rout_id_positive: Result > 0 end to_string_rout_id: INTEGER -- Routine ID of `to_string' of SYSTEM_OBJECT. once Result := System.system_object_class.compiled_class.feature_table. item_id ({PREDEFINED_NAMES}.to_string_name_id).rout_id_set.first ensure to_string_rout_id_positive: Result > 0 end out_feat_id: INTEGER -- Feature ID of `out' of ANY. once Result := system.any_class.compiled_class.feature_table. item_id ({PREDEFINED_NAMES}.out_name_id).feature_id ensure out_feat_id_positive: Result > 0 end to_cil_feat: TUPLE [static_type_id: INTEGER; feature_id: INTEGER] -- Feature ID of `to_cil' of STRING. local l_class: CLASS_C once l_class := system.string_8_class.compiled_class.feature_table. item_id ({PREDEFINED_NAMES}.to_cil_name_id).written_class Result := [l_class.types.first.static_type_id, l_class.feature_table.item_id ({PREDEFINED_NAMES}.to_cil_name_id).feature_id] ensure to_cil_feat_valid: Result /= Void and then (Result.static_type_id > 0 and Result.feature_id > 0) end hashable_class_id: INTEGER -- Class ID of `HASHABLE' if present, `0' otherwise. local l_hash_classes: LIST [CLASS_I] l_hash_class: CLASS_I once l_hash_classes := universe.classes_with_name ("HASHABLE") if l_hash_classes.count = 1 then l_hash_class := l_hash_classes.first if l_hash_class.is_compiled then Result := l_hash_class.compiled_class.class_id end end ensure hashable_class_id_non_negative: Result >= 0 end hashable_type: CL_TYPE_A -- Type `HASHABLE', Void otherwise. once if hashable_class_id > 0 then create Result.make (hashable_class_id) end end hash_code_rout_id: INTEGER -- Routine ID of `hash_code' from HASHABLE if found, -- otherwise `0'. local l_hash_class: CLASS_C once if hashable_class_id > 0 then l_hash_class := system.class_of_id (hashable_class_id) check has_feature_table: l_hash_class.has_feature_table end Result := l_hash_class.feature_table. item_id ({PREDEFINED_NAMES}.hash_code_name_id).rout_id_set.first end ensure hash_code_rout_id_non_negative: Result >= 0 end hash_code_feat_id: INTEGER -- Feature ID of `hash_code' from HASHABLE if found, -- otherwise `0'. local l_hash_class: CLASS_C once if hashable_class_id > 0 then l_hash_class := system.class_of_id (hashable_class_id) check has_feature_table: l_hash_class.has_feature_table end Result := l_hash_class.feature_table. item_id ({PREDEFINED_NAMES}.hash_code_name_id).feature_id end ensure hash_code_feat_id_non_negative: Result >= 0 end feature {CIL_CODE_GENERATOR, IL_MODULE, CUSTOM_ATTRIBUTE_GENERATOR} -- Custom attribute definition define_custom_attribute (token: INTEGER; ctor_token: INTEGER; data: MD_CUSTOM_ATTRIBUTE) -- Define a custom attribute on `token' using constructor `ctor_token' with -- arguments `data'. -- Same as `md_emit.define_custom_attribute' but we do not care about return type. do md_emit.define_custom_attribute (token, ctor_token, data).do_nothing end feature {NONE} -- Once per type definition current_class_token: INTEGER -- Token of current class being generated. feature -- Once per feature definition result_position: INTEGER -- Position of `Result' local variable. feature -- Mapping between Eiffel compiler and generated tokens is_using_multi_assemblies: BOOLEAN -- Use multi-assemblies instead of multi-modules for workbench compilation. il_module_file_name (a_id: INTEGER): STRING do if is_using_multi_assemblies then Result := "assembly_" if a_id < 10 then Result.append_character ('0') end else Result := "module_" end Result.append (a_id.out) Result.append (".dll") end il_module_for_class (a_class: CLASS_C): IL_MODULE -- Perform lookup for module associated with `a_class'. If not -- found then create a module used for reference only. require a_class_not_void: a_class /= Void local l_type_id: INTEGER l_module_name: STRING do if is_single_module then l_type_id := 1 else l_type_id := a_class.class_id // System.msil_classes_per_module + 1 end Result := internal_il_modules.item (l_type_id) if Result = Void then l_module_name := il_module_file_name (l_type_id) create Result.make ( l_module_name, location_path.extended (l_module_name).name, c_module_name, Void, Current, Void, l_type_id, is_debug_info_enabled, False, is_using_multi_assemblies) internal_il_modules.put (Result, l_type_id) end ensure module_not_void: Result /= Void end il_module (a_class_type: CLASS_TYPE): IL_MODULE -- Perform lookup for module associated with `a_class_type'. If not -- found then create a module used for reference only. require a_class_type_not_void: a_class_type /= Void do Result := il_module_for_class (a_class_type.associated_class) ensure module_not_void: Result /= Void end internal_il_modules: ARRAY [detachable IL_MODULE] -- Array of IL_MODULE indexed by CLASS_TYPE.packet_number external_class_mapping: HASH_TABLE [CL_TYPE_A, STRING] -- Quickly find a type given its external name. constructor_token (a_type_id: INTEGER): INTEGER -- Token identifier for default constructor of `a_type_id'. require valid_type_id: a_type_id > 0 do Result := current_module.constructor_token (a_type_id) ensure constructor_token_valid: Result /= 0 end inherited_constructor_token (a_type_id, a_feature_id: INTEGER): INTEGER -- Given a `a_feature_id' in `a_type_id' return associated -- constructor token. require valid_type_id: a_type_id > 0 valid_feature_id: a_feature_id > 0 do Result := current_module.inherited_constructor_token (a_type_id, a_feature_id) ensure feature_token_valid: Result /= 0 end actual_class_type_token (a_type_id: INTEGER): INTEGER -- Given `a_type_id' returns its associated metadata token. require valid_type_id: a_type_id > 0 do Result := current_module.actual_class_type_token (a_type_id) ensure class_token_valid: Result /= 0 end mapped_class_type_token (a_type_id: INTEGER): INTEGER -- Given `a_type_id' returns its associated metadata token -- to be used in signatures and code generation token where -- ANY needs to be mapped into System.Object. require valid_type_id: a_type_id > 0 do Result := current_module.mapped_class_type_token (a_type_id) ensure class_token_valid: Result /= 0 end invariant_token (a_type_id: INTEGER): INTEGER -- Metadata token of invariant feature in class type `a_type_id'. require type_id_valid: a_type_id > 0 do Result := current_module.invariant_token (a_type_id) ensure invariant_token_valid: Result /= 0 end class_types: ARRAY [CLASS_TYPE] -- List all class types in system indexed using both `implementation_id' and -- `static_type_id'. local i, nb: INTEGER l_class_type: CLASS_TYPE do Result := internal_class_types if Result = Void then -- Collect all class types in system and initialize `internal_class_types'. from i := System.class_types.lower nb := System.class_types.upper create Result.make_filled (Void, 0, System.static_type_id_counter.count) until i > nb loop l_class_type := System.class_types.item (i) if l_class_type /= Void then Result.put (l_class_type, l_class_type.static_type_id) Result.put (l_class_type, l_class_type.implementation_id) Result.put (l_class_type, l_class_type.external_id) end i := i + 1 end internal_class_types := Result end ensure class_types_not_void: Result /= Void class_types_not_empty: Result.count > 0 end feature_token (a_type_id, a_feature_id: INTEGER): INTEGER -- Given a `a_feature_id' in `a_type_id' return associated -- token require valid_type_id: a_type_id > 0 valid_feature_id: a_feature_id > 0 do Result := current_module.feature_token (a_type_id, a_feature_id) ensure feature_token_valid: Result /= 0 end setter_token (a_type_id, a_feature_id: INTEGER): INTEGER -- Given an attribute `a_feature_id' in `a_type_id' return associated -- token that sets it. require valid_type_id: a_type_id > 0 valid_feature_id: a_feature_id > 0 do Result := current_module.setter_token (a_type_id, a_feature_id) ensure setter_token_valid: Result /= 0 end signature (a_type_id, a_feature_id: INTEGER): TUPLE [class_type: CLASS_TYPE; routine_id: INTEGER] -- Given a `a_feature_id' in `a_type_id' retrieves its associated signature. require valid_type_id: a_type_id > 0 valid_feature_id: a_feature_id > 0 do Result := current_module.signature (a_type_id, a_feature_id) ensure result_not_void: Result /= Void end implementation_signature (a_type_id, a_feature_id: INTEGER): like signature -- Given a `a_feature_id' in `a_type_id' retrieves its associated -- signature. require valid_type_id: a_type_id > 0 valid_feature_id: a_feature_id > 0 do Result := current_module.implementation_signature (a_type_id, a_feature_id) ensure result_not_void: Result /= Void end implementation_feature_token (a_type_id, a_feature_id: INTEGER): INTEGER -- Given a `a_feature_id' in `a_type_id' return associated -- token require valid_type_id: a_type_id > 0 valid_feature_id: a_feature_id > 0 do Result := current_module.implementation_feature_token (a_type_id, a_feature_id) ensure valid_result: Result /= 0 end attribute_token (a_type_id, a_feature_id: INTEGER): INTEGER -- Given a `a_feature_id' in `a_type_id' return associated -- token require valid_type_id: a_type_id > 0 valid_feature_id: a_feature_id > 0 do Result := current_module.attribute_token (a_type_id, a_feature_id) ensure valid_result: Result /= 0 end file_token: HASH_TABLE [INTEGER, IL_MODULE] -- File token associated to `a_module' in `main_module'. table_token (a_table: ARRAY [HASH_TABLE [INTEGER, INTEGER]]; a_type_id, a_feature_id: INTEGER): INTEGER -- Given a `a_feature_id' in `a_type_id' return associated -- token require a_table_not_void: a_table /= Void valid_type_id: a_type_id > 0 valid_feature_id: a_feature_id > 0 local l_feats: HASH_TABLE [INTEGER, INTEGER] do l_feats := a_table.item (a_type_id) if l_feats /= Void then Result := l_feats.item (a_feature_id) end end sequence_point: TUPLE [ offset_count: INTEGER; -- Offset count offsets: ARRAY [INTEGER]; -- Offsets start_lines: ARRAY [INTEGER]; -- Start lines start_columns: ARRAY [INTEGER]; -- Start columns end_lines: ARRAY [INTEGER]; -- End lines end_columns: ARRAY [INTEGER]; -- End columns written_class_id: INTEGER -- Written in class ID ] -- For type definition purpose. do end local_debug_info: TUPLE [INTEGER, INTEGER, INTEGER, like local_types] -- For type definition purpose. do end dbg_documents (a_class_id: INTEGER): DBG_DOCUMENT_WRITER -- Associated document to `a_class_id'. require in_debug_mode: is_debug_info_enabled do Result := current_module.dbg_documents (a_class_id) ensure dbg_documents_not_void: Result /= Void end internal_class_types: ARRAY [CLASS_TYPE] -- Array of CLASS_TYPE in system indexed by `implementation_id' and -- `static_type_id' of CLASS_TYPE. insert_feature (a_token, a_type_id, a_feature_id: INTEGER) -- Insert `a_token' of `a_feature_id' in `a_type_id'. require valid_token: a_token /= 0 valid_type_id: a_type_id > 0 valid_feature_id: a_feature_id > 0 do current_module.insert_feature (a_token, a_type_id, a_feature_id) ensure inserted: feature_token (a_type_id, a_feature_id) = a_token end insert_setter (a_token, a_type_id, a_feature_id: INTEGER) -- Insert `a_token' of `a_feature_id' in `a_type_id'. require valid_token: a_token /= 0 valid_type_id: a_type_id > 0 valid_feature_id: a_feature_id > 0 do current_module.insert_setter (a_token, a_type_id, a_feature_id) ensure inserted: setter_token (a_type_id, a_feature_id) = a_token end insert_implementation_feature (a_token, a_type_id, a_feature_id: INTEGER) -- Insert `a_token' of `a_feature_id' in `a_type_id'. require valid_token: a_token /= 0 valid_type_id: a_type_id > 0 valid_feature_id: a_feature_id > 0 do current_module.insert_implementation_feature (a_token, a_type_id, a_feature_id) ensure inserted: implementation_feature_token (a_type_id, a_feature_id) = a_token end insert_attribute (a_token, a_type_id, a_feature_id: INTEGER) -- Insert `a_token' of `a_feature_id' in `a_type_id'. require valid_token: a_token /= 0 valid_type_id: a_type_id > 0 valid_feature_id: a_feature_id > 0 do current_module.insert_attribute (a_token, a_type_id, a_feature_id) ensure inserted: attribute_token (a_type_id, a_feature_id) = a_token end insert_implementation_signature (a_signature: like signature; a_type_id, a_feature_id: INTEGER) -- Insert `a_token' of `a_feature_id' in `a_type_id'. require a_signature_not_void: a_signature /= Void valid_type_id: a_type_id > 0 valid_feature_id: a_feature_id > 0 do current_module.insert_implementation_signature (a_signature, a_type_id, a_feature_id) ensure inserted: implementation_signature (a_type_id, a_feature_id).is_equal (a_signature) end insert_signature (a_signature: like signature; a_type_id, a_feature_id: INTEGER) -- Insert `a_token' of `a_feature_id' in `a_type_id'. require a_signature_not_void: a_signature /= Void valid_type_id: a_type_id > 0 valid_feature_id: a_feature_id > 0 do current_module.insert_signature (a_signature, a_type_id, a_feature_id) ensure inserted: signature (a_type_id, a_feature_id).is_equal (a_signature) end feature {NONE} -- Implementation: Helpers same_signature (a_feat, a_other_feat: FEATURE_I; a_type, a_other_type: CLASS_TYPE): BOOLEAN -- Special treatement to know whether or not `a_other_feat' in `a_other_type' has the same signature -- as `a_feat' defined in `a_type'. require a_parent_feat_not_void: a_feat /= Void a_other_feat_not_void: a_other_feat /= Void a_type_not_void: a_type /= Void a_other_type_not_void: a_other_type /= Void compatible: a_feat.argument_count = a_other_feat.argument_count local i, nb: INTEGER_32 l_type, l_other_type: TYPE_A do -- In this routine and wherever else we do a signature comparison to know whether or not -- a cast needs to be generated we use `is_safe_equivalent'. However as shown in eweasel -- test#incr078 sometime two types are not equivalent even if they are. The issue arises -- with an expanded class TEST2 which is used as `TEST2' and `expanded TEST2'. Because -- of the useless extra `expanded' mark the types are not equivalent. Currently, we avoid -- the problem by only doing the cast if the type is not expanded. l_type := result_type_in (a_feat, a_type).adapted_in (a_type) l_other_type := result_type_in (a_other_feat, a_other_type).adapted_in (a_other_type) Result := l_type.is_safe_equivalent (l_other_type) if Result then from nb := a_feat.argument_count i := 1 until i > nb loop l_type := argument_actual_type_in (a_feat.arguments.i_th (i), a_type).adapted_in (a_type) l_other_type := argument_actual_type_in (a_other_feat.arguments.i_th (i), a_other_type).adapted_in (a_other_type) if not l_type.is_safe_equivalent (l_other_type) then Result := False -- Jump out of loop i := nb end i := i + 1 end end end feature {NONE} -- Implementation: name mangling escape_type_name (n: STRING): STRING -- Escape type name `n' so that it can be used as a custom attribute value for Type argument. require n_attached: n /= Void n_not_empty: not n.is_empty local i: INTEGER do Result := n i := Result.count if Result.item (i) = '&' then from until i = 0 or else not (once "&[]").has (Result.item (i)) loop -- Escape the character. Result.insert_character ('\', i) i := i - 1 end end ensure result_attached: Result /= Void result_not_empty: not Result.is_empty end feature {NONE} -- Storage properties: LIST [INTEGER] -- Feature id's of features that have associated properties -- (valid for the current class only) once create {ARRAYED_LIST [INTEGER]} Result.make (0) ensure result_attached: Result /= Void end postponed_property_setters: LIST [PAIR [INTEGER, INTEGER]] -- Feature id's of features that have associated property setters -- that are not generated yet once create {ARRAYED_LIST [PAIR [INTEGER, INTEGER]]} Result.make (0) ensure result_attached: Result /= Void end feature -- Inline agents generate_il_inline_agents (eif_cl: EIFFEL_CLASS_C; inline_agent_processor: PROCEDURE [FEATURE_I]) -- Generate IL code for inline agents in `eif_cl' require eif_cl_not_void: eif_cl /= Void inline_agent_processor_attached: inline_agent_processor /= Void do if eif_cl.has_inline_agents then -- Generate. across eif_cl.inline_agent_table as a loop inline_agent_processor (a.item) end end end note ca_ignore: "CA011", "CA011: too many arguments", "CA033", "CA033: very long class", "CA093", "CA093: manifest array type mismatch" copyright: "Copyright (c) 1984-2024, Eiffel Software" license: "GPL version 2 (see http://www.eiffel.com/licensing/gpl.txt)" licensing_options: "http://www.eiffel.com/licensing" copying: "[ This file is part of Eiffel Software's Eiffel Development Environment. Eiffel Software's Eiffel Development Environment 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, version 2 of the License (available at the URL listed under "license" above). Eiffel Software's Eiffel Development Environment 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 Eiffel Software's Eiffel Development Environment; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ]" source: "[ Eiffel Software 5949 Hollister Ave., Goleta, CA 93117 USA Telephone 805-685-1006, Fax 805-685-6869 Website http://www.eiffel.com Customer support http://support.eiffel.com ]" end