view interps/cfunge/cfunge-src/src/ip.c @ 12518:2d8fe55c6e65 draft default tip

<int-e> learn The password of the month is release incident pilot.
author HackEso <hackeso@esolangs.org>
date Sun, 03 Nov 2024 00:31:02 +0000
parents 859f9b4339e6
children
line wrap: on
line source

/* -*- mode: C; coding: utf-8; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
 *
 * cfunge - A standard-conforming Befunge93/98/109 interpreter in C.
 * Copyright (C) 2008-2009 Arvid Norlander <anmaster AT tele2 DOT se>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at the proxy's option) any later version. Arvid Norlander is a
 * proxy who can decide which future versions of the GNU General Public
 * License can be used.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "global.h"
#include "ip.h"

#include "diagnostic.h"
#include "interpreter.h"
#include "settings.h"
#include "stack.h"
#include "vector.h"

#include "fingerprints/manager.h"
#include "funge-space/funge-space.h"

#include <assert.h>
#include <string.h> /* memcpy */

/// For concurrent funge: how many new IPs to allocate in one go?
#define ALLOCCHUNKSIZE 1

FUNGE_ATTR_FAST FUNGE_ATTR_NONNULL FUNGE_ATTR_WARN_UNUSED
static inline bool ip_create_in_place(instructionPointer *me)
{
	assert(me != NULL);
	me->position.x           = 0;
	me->position.y           = 0;
	me->delta.x              = 1;
	me->delta.y              = 0;
	me->storageOffset.x      = 0;
	me->storageOffset.y      = 0;
	me->mode                 = ipmCODE;
	me->needMove             = true;
	me->stringLastWasSpace   = false;
	me->fingerSUBRisRelative = false;
	me->stackstack           = stackstack_create();
	if (FUNGE_UNLIKELY(!me->stackstack))
		return false;
	me->stack                = me->stackstack->stacks[me->stackstack->current];
	me->ID                   = 0;
	// Zero the opcode stacks if needed.
	if (FUNGE_LIKELY(!setting_disable_fingerprints)) {
		memset(me->fingerOpcodes, 0, sizeof(fungeOpcodeStack) * FINGEROPCODECOUNT);
	}
	me->fingerHRTItimestamp  = NULL;
	return true;
}

#ifndef CONCURRENT_FUNGE
FUNGE_ATTR_FAST instructionPointer * ip_create(void)
{
	instructionPointer * tmp = (instructionPointer*)cf_malloc(sizeof(instructionPointer));
	if (FUNGE_UNLIKELY(!tmp))
		return NULL;
	if (FUNGE_UNLIKELY(!ip_create_in_place(tmp))) {
		cf_free(tmp);
		return NULL;
	}
	return tmp;
}
#endif

#ifdef CONCURRENT_FUNGE
FUNGE_ATTR_FAST FUNGE_ATTR_NONNULL FUNGE_ATTR_WARN_UNUSED
static inline bool ip_duplicate_in_place(const instructionPointer * restrict old, instructionPointer * restrict new)
{
	assert(old != NULL);
	assert(new != NULL);
	memcpy(new, old, sizeof(instructionPointer));

	new->stackstack           = stackstack_duplicate(old->stackstack);
	if (FUNGE_UNLIKELY(!new->stackstack))
		return false;

	new->stack                = new->stackstack->stacks[new->stackstack->current];
	if (FUNGE_LIKELY(!setting_disable_fingerprints)) {
		manager_duplicate(old, new);
	}
	new->fingerHRTItimestamp  = NULL;
	return true;
}
#endif

#if defined(CONCURRENT_FUNGE) || !defined(NDEBUG)
FUNGE_ATTR_FAST static inline void ip_free_resources(instructionPointer * ip)
{
	if (FUNGE_UNLIKELY(!ip))
		return;
	if (FUNGE_LIKELY(ip->stackstack)) {
		stackstack_free(ip->stackstack);
		ip->stackstack = NULL;
	}
	ip->stack = NULL;
	if (FUNGE_LIKELY(!setting_disable_fingerprints)) {
		manager_free(ip);
	}
	if (ip->fingerHRTItimestamp) {
		cf_free(ip->fingerHRTItimestamp);
		ip->fingerHRTItimestamp = NULL;
	}
}
#endif

#if !defined(CONCURRENT_FUNGE) && !defined(NDEBUG)
FUNGE_ATTR_FAST void ip_free(instructionPointer * restrict ip)
{
	if (!ip)
		return;
	ip_free_resources(ip);
	cf_free(ip);
}
#endif

FUNGE_ATTR_FAST inline void ip_set_delta(instructionPointer * restrict ip, const funge_vector * restrict delta)
{
	assert(ip != NULL);
	assert(delta != NULL);
	ip->delta.x = delta->x;
	ip->delta.y = delta->y;
}

FUNGE_ATTR_FAST inline void ip_set_position(instructionPointer * restrict ip, const funge_vector * restrict position)
{
	assert(ip != NULL);
	assert(position != NULL);
	ip->position.x = position->x;
	ip->position.y = position->y;
	fungespace_wrap(&ip->position, &ip->delta);
}


/***********
 * IP list *
 ***********/

#ifdef CONCURRENT_FUNGE
FUNGE_ATTR_FAST ipList* iplist_create(void)
{
	ipList * tmp = (ipList*)cf_malloc(sizeof(ipList) + sizeof(instructionPointer[ALLOCCHUNKSIZE]));
	if (FUNGE_UNLIKELY(!tmp))
		return NULL;
	if (FUNGE_UNLIKELY(!ip_create_in_place(&tmp->ips[0])))
		return NULL;
	tmp->size = ALLOCCHUNKSIZE;
	tmp->top = 0;
	tmp->highestID = 0;
	return tmp;
}

#ifndef NDEBUG
FUNGE_ATTR_FAST void iplist_free(ipList* me)
{
	if (FUNGE_UNLIKELY(!me))
		return;
	for (size_t i = 0; i <= me->top; i++) {
		ip_free_resources(&me->ips[i]);
	}
	cf_free(me);
}
#endif

FUNGE_ATTR_FAST ssize_t iplist_duplicate_ip(ipList** me, size_t index)
{
	ipList *list;

	assert(me != NULL);
	assert(*me != NULL);
	assert(index <= (*me)->top);

	list = *me;

	// Grow if needed
	if (list->size <= (list->top + 1)) {
		list = (ipList*)cf_realloc(*me, sizeof(ipList) + sizeof(instructionPointer[(*me)->size + ALLOCCHUNKSIZE]));
		if (FUNGE_UNLIKELY(!list))
			return -1;
		*me = list;
		list->size += ALLOCCHUNKSIZE;
	}
	/*
	 *  Splitting examples.
	 *
	 *  Thread index 3 splits (to 3a)
	 *  0  | 1  | 2  | 3  | 4   | 5  | 6
	 *  ---------------------------------
	 *  t0 | t1 | t3 | t3 | t4  | t5 |
	 *  t0 | t1 | t2 | t3 | t3a | t4 | t5
	 *
	 */
	// Do we need to move any upwards?
	if (index != list->top) {
		/* Move upwards:
		 * t0 | t1 | t2 |
		 * t10|    | t1 | t2
		 */
		for (size_t i = list->top + 1; i > index; i--) {
			list->ips[i] = list->ips[i - 1];
		}
	}
	/* Duplicate:
	 * t0 | t1  | t2 |
	 * t0 | t0a | t1 | t2
	 */
	if (FUNGE_UNLIKELY(!ip_duplicate_in_place(&list->ips[index], &list->ips[index + 1]))) {
		// We are in trouble
		DIAG_ERROR_LOC("Could not create IP, possibly out of memory?\nThings may be broken now, continuing anyway.");
	}

	// Here we mirror new IP and do ID changes.
	index++;
	ip_reverse(&list->ips[index]);
	ip_forward(&list->ips[index]);
	list->ips[index].ID = ++list->highestID;
	list->top++;
	return index - 1;
}


FUNGE_ATTR_FAST ssize_t iplist_terminate_ip(ipList** me, size_t index)
{
	ipList *list;

	assert(me != NULL);
	assert(*me != NULL);

	list = *me;

	/*
	 *  Terminate examples.
	 *
	 *  Thread index 3 dies
	 *  0  | 1  | 2  | 3  | 4  | 5
	 *  ---------------------------
	 *  t0 | t1 | t2 | t3 | t4 | t5
	 *  t0 | t1 | t3 | t4 | t5 |
	 *
	 */
	ip_free_resources(&list->ips[index]);
	// Do we need to move downwards?
	if (index != list->top) {
		/* Move downwards:
		 * t0 |    | t2 | t3
		 * t0 | t2 | t3 |
		 */
		for (size_t i = index; i < list->top; i++) {
			list->ips[i] = list->ips[i + 1];
		}
	}
	// Set stack to be invalid in the top one. This should help catch any bugs
	// related to this.
	list->ips[list->top].stackstack = NULL;
	list->ips[list->top].stack = NULL;
	list->top--;
	// TODO: Shrink if difference is large
#if 0
	if ((list->size - ALLOCCHUNKSIZE) > list->top) {
		ipList *tmp;
		tmp = (ipList*)cf_realloc(list, sizeof(ipList) + (list->size - ALLOCCHUNKSIZE) * sizeof(instructionPointer));
		if (tmp) {
			*me = tmp;
			tmp->size - ALLOCCHUNKSIZE;
		}
	}
#endif
	return (index > 0) ? index - 1 : 0;
}

#endif