note
	description: "Eiffel class instanciated and used from the Eiffel runtime."
	status: "See notice at end of class."
	legal: "See notice at end of class."
	date: "$Date: 2019-03-20 17:08:56 +0000 (Wed, 20 Mar 2019) $"
	revision: "$Revision: 102984 $"

class 
	RT_EXTENSION

inherit
	RT_EXTENSION_GENERAL

create 
	default_create

feature -- Notification

	notify (a_id: INTEGER_32; a_data: TUPLE)
			-- Notify operation a_id with data a_data
		require
			a_data_attached: a_data /= Void
		local
			retried: BOOLEAN
		do
			if not retried then
				inspect a_id
				when Op_enter_feature then
					if attached {like events_feature_argument} a_data as t_ef then
						process_enter_feature (t_ef)
					else
						check
							valid_tuple_data: False
						end
					end
					reset_events_feature_argument (a_data)
				when Op_leave_feature then
					if attached {like events_feature_argument} a_data as t_lf then
						process_leave_feature (t_lf)
					else
						check
							valid_tuple_data: False
						end
					end
					reset_events_feature_argument (a_data)
				when Op_rescue_feature then
					if attached {like events_feature_argument} a_data as t_rf then
						process_rescue_feature (t_rf)
					else
						check
							valid_tuple_data: False
						end
					end
					reset_events_feature_argument (a_data)
				when Op_rt_hook then
					if attached {like events_feature_argument} a_data as t_rh then
						process_rt_hook (t_rh)
					else
						check
							valid_tuple_data: False
						end
					end
					reset_events_feature_argument (a_data)
				when Op_rt_assign_attrib then
					if attached {like events_assign_argument} a_data as t_att then
						process_rt_assign_attrib (t_att)
					else
						check
							valid_tuple_data: False
						end
					end
					reset_events_assign_argument (a_data)
				when Op_rt_assign_local then
					if attached {like events_assign_argument} a_data as t_loc then
						process_rt_assign_local (t_loc)
					else
						check
							valid_tuple_data: False
						end
					end
					reset_events_assign_argument (a_data)
				else
					debug ("rt_extension")
						dtrace ("Error: " + out + " ->" + a_id.out + "%N")
					end
				end
			end
		rescue
			dtrace ("Error: Rescue -> RT_EXTENSION.notify (" + a_id.out + ", a_data)%N")
			retried := True
			retry
		end

	notify_argument (a_id: INTEGER_32): detachable TUPLE
			-- Empty argument container for operation a_id.
		local
			retried: BOOLEAN
		do
			if not retried then
				Result := Cached_arguments [a_id]
				if Result = Void then
					inspect a_id
					when Op_enter_feature, Op_leave_feature, Op_rescue_feature, Op_rt_hook then
						create {like events_feature_argument} Result
					when Op_rt_assign_attrib, Op_rt_assign_local then
						create {like events_assign_argument} Result
					else
						debug ("rt_extension")
							dtrace ("Error: RT_EXTENSION.notify_argument (" + a_id.out + "): unmatched id !%N")
						end
					end
					Cached_arguments [a_id] := Result
				end
			end
		rescue
			dtrace ("Error: Rescue -> RT_EXTENSION.notify_argument (" + a_id.out + ")%N")
			retried := True
			retry
		end

	Cached_arguments: ARRAY [detachable TUPLE]
			-- Cached argument to use less temporary objects
		once ("THREAD")
			create Result.make_filled (Void, Op_enter_feature, Op_rt_assign_local)
		ensure
			result_attached: Result /= Void
		end
	
feature {NONE} -- Execution replay

	events_feature_argument: TUPLE [ref: detachable ANY; cid: INTEGER_32; fid: INTEGER_32; a_dep: INTEGER_32]
			-- Argument for process_*_feature.
			-- used only as anchor for type declaration
		do
			check
					False
			then
			end
		ensure
				False
		end

	events_assign_argument: TUPLE [ref: detachable ANY; a_dep: INTEGER_32; a_pos: INTEGER_32; a_type: INTEGER_32; a_xpm_info: INTEGER_32]
			-- Argument for process_*_assign.
			-- used only as anchor for type declaration
		do
			check
					False
			then
			end
		ensure
				False
		end

	reset_events_feature_argument (t: TUPLE)
			-- Reset argument for process_*_feature.
		require
			t_attached: t /= Void
		do
			if attached {like events_feature_argument} t as ot then
				ot.ref := Void
				ot.cid := 0
				ot.fid := 0
				ot.a_dep := 0
			end
		end

	reset_events_assign_argument (t: TUPLE)
			-- Reset argument for process_*_feature.
		require
			t_attached: t /= Void
		do
			if attached {like events_assign_argument} t as ot then
				ot.ref := Void
				ot.a_dep := 0
				ot.a_pos := 0
				ot.a_type := 0
				ot.a_xpm_info := 0
			end
		end

	process_enter_feature (a_data: like events_feature_argument)
			-- Execution enters a feature
		require
			a_data_attached: a_data /= Void
			execution_recording_not_void: execution_recorder /= Void
		do
			if attached execution_recorder as r then
				if attached {ANY} a_data.ref as ref then
					r.enter_feature (ref, a_data.cid, a_data.fid, a_data.a_dep)
				else
					check
						ref_should_not_be_void: False
					end
				end
			end
		end

	process_rescue_feature (a_data: like events_feature_argument)
			-- Execution enters a feature
		require
			a_data_attached: a_data /= Void
			execution_recording_not_void: execution_recorder /= Void
		do
			if attached execution_recorder as r then
				if attached {ANY} a_data.ref as ref then
					r.enter_rescue (ref, a_data.cid, a_data.fid, a_data.a_dep)
				else
					check
						ref_should_not_be_void: False
					end
				end
			end
		end

	process_leave_feature (a_data: like events_feature_argument)
			-- Execution leaves a feature
		require
			a_data_attached: a_data /= Void
			execution_recording_not_void: execution_recorder /= Void
		do
			if attached execution_recorder as r then
				if attached {ANY} a_data.ref as ref then
					r.leave_feature (ref, a_data.cid, a_data.fid, a_data.a_dep)
				else
					check
						ref_should_not_be_void: False
					end
				end
			end
		end

	process_rt_hook (a_data: TUPLE [unused_ref: detachable ANY; a_dep: INTEGER_32; bp_i: INTEGER_32; bp_ni: INTEGER_32])
			-- Execution reach a RTHOOK or RTNHOOK point
		require
			a_data_attached: a_data /= Void
			execution_recording_not_void: execution_recorder /= Void
		do
			if attached execution_recorder as r then
				r.notify_rt_hook (a_data.a_dep, a_data.bp_i, a_data.bp_ni)
			end
		end

	process_rt_assign_attrib (a_data: like events_assign_argument)
			-- Local variable assignment event
		require
			a_data_attached: a_data /= Void
			execution_recording_not_void: execution_recorder /= Void
		do
			if attached execution_recorder as r and then r.recording_values and then attached a_data.ref as ot_ref then
				r.notify_rt_assign_attribute (a_data.a_dep, ot_ref, a_data.a_pos, a_data.a_type.to_natural_32, a_data.a_xpm_info)
			end
		end

	process_rt_assign_local (a_data: like events_assign_argument)
			-- Local variable assignment event
		require
			a_data_attached: a_data /= Void
			execution_recording_not_void: execution_recorder /= Void
			no_ref: a_data.ref = Void
		do
			if attached execution_recorder as r and then r.recording_values then
				r.notify_rt_assign_local (a_data.a_dep, a_data.a_pos, a_data.a_type.to_natural_32, a_data.a_xpm_info)
			end
		end

	new_execution_recorder: RT_DBG_EXECUTION_RECORDER
			-- New Execution recorder.
			-- You can overwrite default parameters in this feature.
			-- Check {RT_DBG_EXECUTION_RECORDER}.make to see the default values.
		do
			create Result.make (Execution_recorder_parameters)
		ensure
			result_attached: Result /= Void
		end

	execution_recorder: detachable like new_execution_recorder
			-- Once per thread record.
		do
			Result := Execution_recorder_cell.item
		end

	Execution_recorder_parameters: separate RT_DBG_EXECUTION_PARAMETERS
			-- Once per process record parameters.
		once ("PROCESS")
			create Result.make
		ensure
			result_attached: Result /= Void
		end

	set_execution_recorder_parameters (a_maximum_record_count: INTEGER_32; a_flatten_when_closing: BOOLEAN; a_keep_calls_record: BOOLEAN; a_recording_values: BOOLEAN)
			-- Set execution recorder parameters
		local
			p: like Execution_recorder_parameters
		do
			p := Execution_recorder_parameters
			set_execution_recorder_parameters_to (a_maximum_record_count, a_flatten_when_closing, a_keep_calls_record, a_recording_values, p)
			if attached execution_recorder as r then
				r.update_parameters (p)
			end
		end

	set_execution_recorder_parameters_to (a_maximum_record_count: INTEGER_32; a_flatten_when_closing: BOOLEAN; a_keep_calls_record: BOOLEAN; a_recording_values: BOOLEAN; p: like Execution_recorder_parameters)
			-- Set execution recorder parameters to p.
		do
			p.set_maximum_record_count (a_maximum_record_count)
			p.set_flatten_when_closing (a_flatten_when_closing)
			p.set_keep_calls_records (a_keep_calls_record)
			p.set_recording_values (a_recording_values)
		end

	Execution_recorder_cell: CELL [detachable RT_DBG_EXECUTION_RECORDER]
			-- Cell containing the once per thread recorder, if activated.
		once ("THREAD")
			create Result.put (Void)
		ensure
			result_attached: Result /= Void
		end
	
feature -- Execution replay		

	activate_execution_replay_recording (b: BOOLEAN; ref: ANY; cid: INTEGER_32; fid: INTEGER_32; dep: INTEGER_32; break_index: INTEGER_32)
			-- Start or Stop execution replay recording
		require
			ref_attached: ref /= Void
		local
			r: like execution_recorder
		do
			if b then
				check
						execution_recorder = Void
				end
				r := new_execution_recorder
				Execution_recorder_cell.replace (r)
				r.start_recording (ref, cid, fid, dep, break_index)
			else
				r := execution_recorder
				if r /= Void then
					r.stop_recording
				end
				Execution_recorder_cell.replace (Void)
			end
		ensure
			recorder_if_on: b implies execution_recorder /= Void
			no_recorder_if_off: not b implies execution_recorder = Void
		end
	
feature -- debug purpose: to remove

	test_activate_recording (ref: ANY; fid: INTEGER_32; dep: INTEGER_32; bpline: INTEGER_32)
		require
			ref_attached: ref /= Void
		do
			activate_execution_replay_recording (True, ref, ref.generating_type.type_id, fid, dep, bpline)
			c_activate_recording
		end

	frozen c_activate_recording
		external
			"C inline use %"eif_main.h%""
		alias
			"[
				#ifdef WORKBENCH
					EIF_GET_CONTEXT
					is_inside_rt_eiffel_code = 0;
					exec_recording_enabled = 1;
					set_debug_mode (1);
				#endif
			]"
		end

	frozen c_is_inside_rt_eiffel_code: INTEGER_32
		external
			"C inline use %"eif_debug.h%""
		alias
			"[
				#ifdef WORKBENCH
					EIF_GET_CONTEXT
					return is_inside_rt_eiffel_code;
				#else
					return 0;
				#endif
			]"
		end
	
feature -- SCOOP Access	

	scoop_processor_id_from_object (a_object: ANY): INTEGER_32
			-- SCOOP Processor id for object a_object.
		external
			"C inline use %"eif_scoop.h%""
		alias
			"RTS_PID(eif_access($a_object))"
		end
	
invariant
	no_attribute: (create {REFLECTED_REFERENCE_OBJECT}.make (Current)).field_count = 0

note
	library: "EiffelBase: Library of reusable components for Eiffel."
	copyright: "Copyright (c) 1984-2019, Eiffel Software and others"
	license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
	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 -- class RT_EXTENSION

Generated by ISE EiffelStudio