#include "master.hpp"

namespace factor
{

void safepoint_state::enqueue_safepoint(factor_vm *parent) volatile
{
	parent->code->guard_safepoint();
}

void safepoint_state::enqueue_fep(factor_vm *parent) volatile
{
	if (parent->fep_p)
		fatal_error("Low-level debugger interrupted", 0);
	atomic::store(&fep_p, true);
	enqueue_safepoint(parent);
}

void safepoint_state::enqueue_samples(factor_vm *parent, cell samples, cell pc, bool foreign_thread_p) volatile
{
	if (atomic::load(&parent->sampling_profiler_p))
	{
		atomic::fetch_add(&sample_counts.sample_count, samples);
		if (foreign_thread_p)
			atomic::fetch_add(&sample_counts.foreign_thread_sample_count, samples);
		else {
			if (atomic::load(&parent->current_gc_p))
				atomic::fetch_add(&sample_counts.gc_sample_count, samples);
			if (atomic::load(&parent->current_jit_count) > 0)
				atomic::fetch_add(&sample_counts.jit_sample_count, samples);
			if (!parent->code->seg->in_segment_p(pc))
				atomic::fetch_add(&sample_counts.foreign_sample_count, samples);
		}
		enqueue_safepoint(parent);
	}
}

void safepoint_state::handle_safepoint(factor_vm *parent, cell pc) volatile
{
	parent->code->unguard_safepoint();
	parent->faulting_p = false;

	if (atomic::load(&fep_p))
	{
		if (atomic::load(&parent->sampling_profiler_p))
			parent->end_sampling_profiler();
		std::cout << "Interrupted\n";
		parent->factorbug();
		atomic::store(&fep_p, false);
	}
	else if (atomic::load(&parent->sampling_profiler_p))
	{
		FACTOR_ASSERT(parent->code->seg->in_segment_p(pc));
		code_block *block = parent->code->code_block_for_address(pc);
		bool prolog_p = (cell)block->entry_point() == pc;

		parent->record_sample(prolog_p);
	}
}

}